diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 8dc2303883c44a3a4ad40e059a734378c6887e6f..4f7dac6a327ee188433624ae348a8691d0eb4bf9 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -15,6 +15,7 @@ stages: - linting - static-analysis - unit-tests + - integration-tests linting: stage: linting script: @@ -34,3 +35,27 @@ unit_test: script: - cd devices - tox -e py37 +integration_test: + stage: integration-tests + allow_failure: true + tags: + - privileged + services: + - name: docker:20.10.8-dind + variables: + DOCKER_TLS_CERTDIR: "/certs" +# Everything below does not work currently, we need a privileged container +# that can run the dind service + before_script: + - sudo apt update + - sudo apt install -y docker.io + - export USER=$(id | awk -F'=' '{print $2}' | awk -F'(' '{print $2}' | awk -F')' '{print $1}') + - echo $USER +# - sudo usermod -aG docker $USER + - sudo docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY + script: + - touch /home/$USER/.Xauthority + - source bootstrap/etc/lofar20rc.sh + - export HOSTNAME=$(cat /run/systemd/netif/leases/2 | grep ^ADDRESS= | awk -F'=' '{print $2}') + - echo $HOSTNAME + - sudo $CI_PROJECT_DIR/sbin/run_integration_test.sh diff --git a/CDB/LOFAR_ConfigDb.json b/CDB/LOFAR_ConfigDb.json index 705f701556224fa4936e35916993aa2d4d05107e..197686104afa47aeb018b0c5caade4d286a4fe9b 100644 --- a/CDB/LOFAR_ConfigDb.json +++ b/CDB/LOFAR_ConfigDb.json @@ -684,6 +684,24 @@ "OPC_Time_Out": [ "5.0" ], + "FPGA_sdp_info_station_id_RW_default": [ + "901", + "901", + "901", + "901", + "901", + "901", + "901", + "901", + "901", + "901", + "901", + "901", + "901", + "901", + "901", + "901" + ], "polled_attr": [ "fpga_temp_r", "1000", @@ -735,6 +753,60 @@ ], "OPC_Time_Out": [ "5.0" + ], + "FPGA_sst_offload_hdr_eth_destination_mac_RW_default": [ + "6c:2b:59:97:cb:de", + "6c:2b:59:97:cb:de", + "6c:2b:59:97:cb:de", + "6c:2b:59:97:cb:de", + "6c:2b:59:97:cb:de", + "6c:2b:59:97:cb:de", + "6c:2b:59:97:cb:de", + "6c:2b:59:97:cb:de", + "6c:2b:59:97:cb:de", + "6c:2b:59:97:cb:de", + "6c:2b:59:97:cb:de", + "6c:2b:59:97:cb:de", + "6c:2b:59:97:cb:de", + "6c:2b:59:97:cb:de", + "6c:2b:59:97:cb:de", + "6c:2b:59:97:cb:de" + ], + "FPGA_sst_offload_hdr_ip_destination_address_RW_default": [ + "10.99.250.250", + "10.99.250.250", + "10.99.250.250", + "10.99.250.250", + "10.99.250.250", + "10.99.250.250", + "10.99.250.250", + "10.99.250.250", + "10.99.250.250", + "10.99.250.250", + "10.99.250.250", + "10.99.250.250", + "10.99.250.250", + "10.99.250.250", + "10.99.250.250", + "10.99.250.250" + ], + "FPGA_sst_offload_hdr_udp_destination_port_RW_default": [ + "5001", + "5001", + "5001", + "5001", + "5001", + "5001", + "5001", + "5001", + "5001", + "5001", + "5001", + "5001", + "5001", + "5001", + "5001", + "5001" ] } } diff --git a/CDB/integration_ConfigDb.json b/CDB/integration_ConfigDb.json new file mode 100644 index 0000000000000000000000000000000000000000..b2f9cca6dc8db917942f35bb8be25e4cb88bdb93 --- /dev/null +++ b/CDB/integration_ConfigDb.json @@ -0,0 +1,64 @@ +{ + "servers": { + "PCC": { + "LTS": { + "PCC": { + "LTS/PCC/1": { + "properties": { + "OPC_Server_Name": [ + "pypcc-sim" + ], + "OPC_Server_Port": [ + "4842" + ], + "OPC_Time_Out": [ + "5.0" + ] + } + } + } + } + }, + "SDP": { + "LTS": { + "SDP": { + "LTS/SDP/1": { + "properties": { + "OPC_Server_Name": [ + "sdptr-sim" + ], + "OPC_Server_Port": [ + "4840" + ], + "OPC_Time_Out": [ + "5.0" + ] + } + } + } + } + }, + "SST": { + "LTS": { + "SST": { + "LTS/SST/1": { + "properties": { + "SST_Client_Port": [ + "5001" + ], + "OPC_Server_Name": [ + "sdptr-sim" + ], + "OPC_Server_Port": [ + "4840" + ], + "OPC_Time_Out": [ + "5.0" + ] + } + } + } + } + } + } +} diff --git a/devices/.stestr.conf b/devices/.stestr.conf index ddc59860d5117ed8bdc44faeea1d893760b5520e..07147c8697683f270e9388da8b914c20cb8e4c45 100644 --- a/devices/.stestr.conf +++ b/devices/.stestr.conf @@ -1,3 +1,3 @@ [DEFAULT] -test_path=./test +test_path=${TESTS_DIR:-./test} top_dir=./ diff --git a/devices/common/lofar_environment.py b/devices/common/lofar_environment.py new file mode 100644 index 0000000000000000000000000000000000000000..7c191e12b42c4ceb3f400c0d57e305826057eee2 --- /dev/null +++ b/devices/common/lofar_environment.py @@ -0,0 +1,6 @@ +# +# Change manually the method to switch between modes +# + +def isProduction(): + return False diff --git a/devices/devices/hardware_device.py b/devices/devices/hardware_device.py index 524c378c1256eb5cc09fb9af12b21d5d0f781a09..c0e7df614d95e40f9816f9332f2832c8f3d4166c 100644 --- a/devices/devices/hardware_device.py +++ b/devices/devices/hardware_device.py @@ -14,8 +14,8 @@ from abc import ABCMeta, abstractmethod # PyTango imports -from tango.server import Device, command, DeviceMeta -from tango import DevState, DebugIt +from tango.server import Device, command, DeviceMeta, attribute +from tango import DevState, DebugIt, Attribute, DeviceProxy # Additional import from clients.attribute_wrapper import attribute_wrapper @@ -161,7 +161,6 @@ class hardware_device(Device, metaclass=AbstractDeviceMetas): self.configure_for_fault() self.set_state(DevState.FAULT) - # functions that can or must be overloaded def configure_for_fault(self): pass @@ -192,3 +191,36 @@ class hardware_device(Device, metaclass=AbstractDeviceMetas): self.Off() self.debug_stream("Shut down. Good bye.") + + @command() + @only_in_states([DevState.STANDBY, DevState.ON]) + @DebugIt() + @log_exceptions() + def set_defaults(self): + """ Set hardware points to their default value. + + A hardware point XXX is set to the value of the object member named XXX_default, if it exists. + XXX_default can be f.e. a constant, or a device_property. + """ + + # we cannot write directly to our attribute, as that would not + # trigger a write_{name} call. See https://www.tango-controls.org/community/forum/c/development/c/accessing-own-deviceproxy-class/?page=1#post-2021 + + # obtain a proxy to myself, to write values + proxy = DeviceProxy(self.get_name()) + + # for all my members + for name in dir(self): + attr = getattr(self, name) + # check if it's an attribute, and there is a default value available + if isinstance(attr, Attribute) and hasattr(self, f"{name}_default"): + try: + default_value = getattr(self, f"{name}_default") + + # set the attribute to the configured default + self.debug_stream(f"Setting attribute {name} to {default_value}") + proxy.write_attribute(name, default_value) + except Exception as e: + # log which attribute we're addressing + raise Exception(f"Cannot assign default to attribute {name}") from e + diff --git a/devices/devices/sdp/sdp.py b/devices/devices/sdp/sdp.py index b611f5a9f0289981da65b16fa9dd5224261a1749..c1730ab621f0da57bc486240ec662c84f6cde1ed 100644 --- a/devices/devices/sdp/sdp.py +++ b/devices/devices/sdp/sdp.py @@ -69,6 +69,23 @@ class SDP(hardware_device): mandatory=True ) + FPGA_processing_enable_RW_default = device_property( + dtype='DevVarBooleanArray', + mandatory=False, + default_value=[True] * 16 + ) + + FPGA_wg_enable_RW_default = device_property( + dtype='DevVarBooleanArray', + mandatory=False, + default_value=[[False] * 12] * 16 + ) + + FPGA_sdp_info_station_id_RW_default = device_property( + dtype='DevVarULongArray', + mandatory=True + ) + # ---------- # Attributes # ---------- diff --git a/devices/devices/sdp/sst.py b/devices/devices/sdp/sst.py index 1a62a4edcf28c84f7be865d38f7d5312417b497e..792162fd50adcefdb420fd621e853261d83da17b 100644 --- a/devices/devices/sdp/sst.py +++ b/devices/devices/sdp/sst.py @@ -48,6 +48,21 @@ class SST(Statistics): # Device Properties # ----------------- + FPGA_sst_offload_hdr_eth_destination_mac_RW_default = device_property( + dtype='DevVarStringArray', + mandatory=True + ) + + FPGA_sst_offload_hdr_ip_destination_address_RW_default = device_property( + dtype='DevVarStringArray', + mandatory=True + ) + + FPGA_sst_offload_hdr_udp_destination_port_RW_default = device_property( + dtype='DevVarUShortArray', + mandatory=True + ) + # ---------- # Attributes # ---------- diff --git a/devices/integration_test/README.md b/devices/integration_test/README.md new file mode 100644 index 0000000000000000000000000000000000000000..3292bfa0049b5c2312f8e0536e00cc581433ed61 --- /dev/null +++ b/devices/integration_test/README.md @@ -0,0 +1,26 @@ +# Integration Tests + +## Approach + +A special docker container is build to perform the integration tests. This +container will be build by the makefiles but should only be started by the +dedicated integration test script. This script will ensure that other containers +are running and are in the required state. + +* Launch pypcc-sim and sdptr-sim simulators. +* Reconfigure dsconfig to use these simulators. +* Create and start the integration-test container. + +## Running + +**Warning running these tests will make changes to your CDB database config!** + +```shell +source bootstrap/etc/lofar20rc.sh +$LOFAR20_DIR/sbin/run_integration_test.sh +``` + +## Limitations + +Our makefile will always launch the new container upon creation, resulting in +the integration tests actually being run twice. \ No newline at end of file diff --git a/devices/integration_test/__init__.py b/devices/integration_test/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/devices/integration_test/base.py b/devices/integration_test/base.py new file mode 100644 index 0000000000000000000000000000000000000000..92601ec2d440753ae7f7be22fcbfad0c5028875c --- /dev/null +++ b/devices/integration_test/base.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# +# This file is part of the LOFAR 2.0 Station Software +# +# +# +# Distributed under the terms of the APACHE license. +# See LICENSE.txt for more info. + +import unittest +import testscenarios + + +class BaseIntegrationTestCase(testscenarios.WithScenarios, unittest.TestCase): + """Integration test base class.""" + + def setUp(self): + super().setUp() + + +class IntegrationTestCase(BaseIntegrationTestCase): + """Integration test case base class for all unit tests.""" + + def setUp(self): + super().setUp() diff --git a/devices/integration_test/client/__init__.py b/devices/integration_test/client/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/devices/integration_test/client/test_apsct_sim.py b/devices/integration_test/client/test_apsct_sim.py new file mode 100644 index 0000000000000000000000000000000000000000..775c34cd207699f7febb435000314c65db97b66a --- /dev/null +++ b/devices/integration_test/client/test_apsct_sim.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +# +# This file is part of the LOFAR 2.0 Station Software +# +# +# +# Distributed under the terms of the APACHE license. +# See LICENSE.txt for more info. + +from opcua import Client + +from integration_test import base + + +class TestAPSCTSim(base.IntegrationTestCase): + + def setUp(self): + super(TestAPSCTSim, self).setUp() + + def test_opcua_connection(self): + """Check if we can connect to apsct-sim""" + + #TODO(Corne): Replace to APSCT name once simulator name has changed + client = Client("opc.tcp://pypcc-sim:4842") + root_node = None + + try: + client.connect() + root_node = client.get_root_node() + finally: + client.disconnect() + + self.assertNotEqual(None, root_node) diff --git a/devices/integration_test/client/test_sdptr_sim.py b/devices/integration_test/client/test_sdptr_sim.py new file mode 100644 index 0000000000000000000000000000000000000000..3ba48e7d761c7ef366c8690e2d114c773de7311d --- /dev/null +++ b/devices/integration_test/client/test_sdptr_sim.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +# +# This file is part of the LOFAR 2.0 Station Software +# +# +# +# Distributed under the terms of the APACHE license. +# See LICENSE.txt for more info. + +from opcua import Client + +from integration_test import base + + +class TestSDPTRSim(base.IntegrationTestCase): + + def setUp(self): + super(TestSDPTRSim, self).setUp() + + def test_opcua_connection(self): + """Check if we can connect to sdptr-sim""" + + client = Client("opc.tcp://sdptr-sim:4840") + root_node = None + + try: + client.connect() + root_node = client.get_root_node() + finally: + client.disconnect() + + self.assertNotEqual(None, root_node) diff --git a/devices/integration_test/devices/__init__.py b/devices/integration_test/devices/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/devices/integration_test/devices/test_device_pcc.py b/devices/integration_test/devices/test_device_pcc.py new file mode 100644 index 0000000000000000000000000000000000000000..b3b7a4672dbb18790d19144aeb35bcacd68e4bfb --- /dev/null +++ b/devices/integration_test/devices/test_device_pcc.py @@ -0,0 +1,58 @@ +# -*- coding: utf-8 -*- +# +# This file is part of the LOFAR 2.0 Station Software +# +# +# +# Distributed under the terms of the APACHE license. +# See LICENSE.txt for more info. + +import time + +from tango import DeviceProxy +from tango._tango import DevState + +from integration_test import base + + +class TestDevicePCC(base.IntegrationTestCase): + + def setUp(self): + super(TestDevicePCC, self).setUp() + + def tearDown(self): + """Turn device Off in teardown to prevent blocking tests""" + d = DeviceProxy("LTS/PCC/1") + + try: + d.Off() + except Exception as e: + """Failing to turn Off devices should not raise errors here""" + print(f"Failed to turn device off in teardown {e}") + + def test_device_proxy_pcc(self): + """Test if we can successfully create a DeviceProxy and fetch state""" + + d = DeviceProxy("LTS/PCC/1") + + self.assertEqual(DevState.OFF, d.state()) + + def test_device_pcc_initialize(self): + """Test if we can transition to standby""" + + d = DeviceProxy("LTS/PCC/1") + + d.initialise() + + self.assertEqual(DevState.STANDBY, d.state()) + + def test_device_pcc_on(self): + """Test if we can transition to on""" + + d = DeviceProxy("LTS/PCC/1") + + d.initialise() + + d.on() + + self.assertEqual(DevState.ON, d.state()) diff --git a/devices/integration_test/devices/test_device_sdp.py b/devices/integration_test/devices/test_device_sdp.py new file mode 100644 index 0000000000000000000000000000000000000000..cfd656748054cb21e0e3bb2110ce60072d9fb28a --- /dev/null +++ b/devices/integration_test/devices/test_device_sdp.py @@ -0,0 +1,59 @@ +# -*- coding: utf-8 -*- +# +# This file is part of the LOFAR 2.0 Station Software +# +# +# +# Distributed under the terms of the APACHE license. +# See LICENSE.txt for more info. + +import time + +from tango import DeviceProxy +from tango._tango import DevState + +from integration_test import base + + +class TestDeviceSDP(base.IntegrationTestCase): + + def setUp(self): + """Intentionally recreate the device object in each test""" + super(TestDeviceSDP, self).setUp() + + def tearDown(self): + """Turn device Off in teardown to prevent blocking tests""" + d = DeviceProxy("LTS/SDP/1") + + try: + d.Off() + except Exception as e: + """Failing to turn Off devices should not raise errors here""" + print(f"Failed to turn device off in teardown {e}") + + def test_device_proxy_sdp(self): + """Test if we can successfully create a DeviceProxy and fetch state""" + + d = DeviceProxy("LTS/SDP/1") + + self.assertEqual(DevState.OFF, d.state()) + + def test_device_sdp_initialize(self): + """Test if we can transition to standby""" + + d = DeviceProxy("LTS/SDP/1") + + d.initialise() + + self.assertEqual(DevState.STANDBY, d.state()) + + def test_device_sdp_on(self): + """Test if we can transition to on""" + + d = DeviceProxy("LTS/SDP/1") + + d.initialise() + + d.on() + + self.assertEqual(DevState.ON, d.state()) diff --git a/devices/toolkit/startup.py b/devices/toolkit/startup.py index 0f4bcbe702b1bd1edb873234763d56455b6009b4..e1cc092b01b3714d80f0b8ca827856bde451c78b 100644 --- a/devices/toolkit/startup.py +++ b/devices/toolkit/startup.py @@ -1,36 +1,49 @@ #! /usr/bin/env python3 +import tango +import logging +logger = logging.getLogger() -def startup(device: str, force_restart: bool): +def startup(device: str, force_restart: bool) -> tango.DeviceProxy: ''' Start a LOFAR Tango device: pcc = startup(device = 'LTS/PCC/1', force_restart = False) ''' - import tango proxy = tango.DeviceProxy(device) state = proxy.state() + # go to OFF, but only if force_restart is True if force_restart is True: - print("Forcing device {} restart.".format(device)) + logger.warning(f"Forcing device {device} restart.") proxy.off() state = proxy.state() if state is not tango._tango.DevState.OFF: - print("Device {} cannot perform off although restart has been enforced, state = {}. Please investigate.".format(device, state)) + logger.error(f"Device {device} cannot perform off although restart has been enforced, state = {state}. Please investigate.") return proxy + if state is not tango._tango.DevState.OFF: - print("Device {} is not in OFF state, cannot start it. state = {}".format(device, state)) + logger.error(f"Device {device} is not in OFF state, cannot start it. state = {state}") return proxy - print("Device {} is in OFF, performing initialisation.".format(device)) + + # Initialise device + logger.info(f"Device {device} is in OFF, performing initialisation.") proxy.initialise() state = proxy.state() if state is not tango._tango.DevState.STANDBY: - print("Device {} cannot perform initialise, state = {}. Please investigate.".format(device, state)) + logger.error(f"Device {device} cannot perform initialise, state = {state}. Please investigate.") return proxy - print("Device {} is in STANDBY, performing on.".format(device)) + + # Set default values + logger.info(f"Device {device} is in STANDBY, setting default values.") + proxy.set_defaults() + + # Turn on device + logger.info(f"Device {device} is in STANDBY, performing on.") proxy.on() state = proxy.state() if state is not tango._tango.DevState.ON: - print("Device {} cannot perform on, state = {}. Please investigate.".format(device, state)) + logger.error(f"Device {device} cannot perform on, state = {state}. Please investigate.") else: - print("Device {} has successfully reached ON state.".format(device)) + logger.info(f"Device {device} has successfully reached ON state.") + return proxy diff --git a/devices/tox.ini b/devices/tox.ini index 18c6cda38751d7bc447e8fb23d92e63b64288ddb..94d33c3e392272ac7341e039791f567cf2a7b9b4 100644 --- a/devices/tox.ini +++ b/devices/tox.ini @@ -17,6 +17,14 @@ deps = -r{toxinidir}/test-requirements.txt -r{toxinidir}/../docker-compose/lofar-device-base/lofar-requirements.txt commands = stestr run {posargs} +[testenv:integration] +; Warning running integration tests will make changes to your docker system! +; These tests should only be run by the integration-test docker container. +passenv = TANGO_HOST +setenv = TESTS_DIR=./integration_test +commands = + stestr run --serial + ; TODO(Corne): Integrate Hacking to customize pep8 rules [testenv:pep8] commands = diff --git a/docker-compose/archiver.yml b/docker-compose/archiver.yml index 41d5df160e011ca1aad79828bf2fd3c941958620..8006ece3b86f0013a5eedc1e066dc4c2f07b73af 100644 --- a/docker-compose/archiver.yml +++ b/docker-compose/archiver.yml @@ -15,7 +15,7 @@ services: - MYSQL_USER=tango - MYSQL_PASSWORD=tango - TANGO_HOST=${TANGO_HOST} - restart: on-failure + restart: unless-stopped hdbpp-es: image: ${LOCAL_DOCKER_REGISTRY_HOST}/${LOCAL_DOCKER_REGISTRY_USER}/tango-archiver:2021-05-28 @@ -34,6 +34,7 @@ services: wait-for-it.sh archiver-maria-db:3306 --timeout=30 --strict -- wait-for-it.sh ${TANGO_HOST} --timeout=30 --strict -- hdbppes-srv 01" + restart: unless-stopped hdbpp-cm: image: ${LOCAL_DOCKER_REGISTRY_HOST}/${LOCAL_DOCKER_REGISTRY_USER}/tango-archiver:${TANGO_ARCHIVER_VERSION} diff --git a/docker-compose/elk.yml b/docker-compose/elk.yml index cce66839b499caa0b8948eaeb0c5cc65176be2c9..bf6e22e3de6ea82571acba0ac8e7c69f3eeb2941 100644 --- a/docker-compose/elk.yml +++ b/docker-compose/elk.yml @@ -38,3 +38,4 @@ services: - "5959:5959" # logstash tcp json input depends_on: - elk-configure-host + restart: unless-stopped diff --git a/docker-compose/integration-test.yml b/docker-compose/integration-test.yml new file mode 100644 index 0000000000000000000000000000000000000000..e6a0e54939179ba0c4f5b043da3191dd9e11945d --- /dev/null +++ b/docker-compose/integration-test.yml @@ -0,0 +1,29 @@ +# +# Docker compose file that launches integration tests +# +# Defines: +# - integration: Integration testing +# +version: '2' + +services: + integration-test: + build: + context: itango + args: + SOURCE_IMAGE: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}-tango-itango:${TANGO_ITANGO_VERSION} + container_name: ${CONTAINER_NAME_PREFIX}integration-test + networks: + - control + volumes: + - ${TANGO_LOFAR_CONTAINER_MOUNT} + environment: + - TANGO_HOST=${TANGO_HOST} + working_dir: ${TANGO_LOFAR_CONTAINER_DIR}/devices + entrypoint: + - /usr/local/bin/wait-for-it.sh + - ${TANGO_HOST} + - --timeout=30 + - --strict + - -- + - tox -e integration diff --git a/docker-compose/itango.yml b/docker-compose/itango.yml index 941974e8770823c6a680de9ffcf95f301163663d..34161eb43f752716f28d44170898d94c4b6d76cd 100644 --- a/docker-compose/itango.yml +++ b/docker-compose/itango.yml @@ -37,4 +37,4 @@ services: - --strict - -- - /venv/bin/itango3 - restart: on-failure + restart: unless-stopped diff --git a/docker-compose/jupyter.yml b/docker-compose/jupyter.yml index 36cc0acbcd32631a9cf8e6bb1f10ecfb77362cf0..989601cf8d858f493ba47ed607a9e4cd5a6d2770 100644 --- a/docker-compose/jupyter.yml +++ b/docker-compose/jupyter.yml @@ -38,4 +38,4 @@ services: - --strict - -- - /usr/bin/tini -- /usr/local/bin/jupyter-notebook --port=8888 --no-browser --ip=0.0.0.0 --allow-root --NotebookApp.token= --NotebookApp.password= - restart: on-failure + restart: unless-stopped diff --git a/docker-compose/jupyter/Dockerfile b/docker-compose/jupyter/Dockerfile index 2382319bc1a26e4e9f75b4ee8bdb45c893d23528..29f736cdca2fc843750612c6780ea7ad2dfa516e 100644 --- a/docker-compose/jupyter/Dockerfile +++ b/docker-compose/jupyter/Dockerfile @@ -5,12 +5,31 @@ FROM ${SOURCE_IMAGE} # that are needed for temporary storage the proper owner and access rights. ARG CONTAINER_EXECUTION_UID=1000 +# Create homedir +ENV HOME=/home/user +RUN sudo mkdir -p ${HOME} +RUN sudo chown ${CONTAINER_EXECUTION_UID} -R ${HOME} +USER ${CONTAINER_EXECUTION_UID} + RUN sudo pip3 install jupyter RUN sudo pip3 install ipykernel RUN sudo pip3 install jupyter_bokeh # Install matplotlib, jupyterplot RUN sudo pip3 install matplotlib jupyterplot +# Allow Download as -> PDF via html +RUN sudo pip3 install nbconvert +RUN sudo pip3 install notebook-as-pdf +# pyppeteer-install installs in the homedir, so run it as the user that will execute the notebook +RUN pyppeteer-install + +# see https://github.com/jupyter/nbconvert/issues/1434 +RUN sudo bash -c "echo DEFAULT_ARGS += [\\\"--no-sandbox\\\"] >> /usr/local/lib/python3.7/dist-packages/pyppeteer/launcher.py" +RUN sudo apt-get install -y gconf-service libasound2 libatk1.0-0 libatk-bridge2.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget libcairo-gobject2 libxinerama1 libgtk2.0-0 libpangoft2-1.0-0 libthai0 libpixman-1-0 libxcb-render0 libharfbuzz0b libdatrie1 libgraphite2-3 libgbm1 + +# Allow Download as -> PDF via LaTeX +RUN sudo apt-get install -y texlive-xetex texlive-fonts-recommended texlive-latex-recommended + # Configure jupyter_bokeh RUN sudo mkdir -p /usr/share/jupyter /usr/etc RUN sudo chmod a+rwx /usr/share/jupyter /usr/etc @@ -19,6 +38,7 @@ RUN sudo jupyter nbextension enable jupyter_bokeh --py --sys-prefix # Install profiles for ipython & jupyter COPY ipython-profiles /opt/ipython-profiles/ +RUN sudo chown ${CONTAINER_EXECUTION_UID} -R /opt/ipython-profiles COPY jupyter-kernels /usr/local/share/jupyter/kernels/ # Install patched jupyter executable @@ -34,8 +54,3 @@ ENV JUPYTER_RUNTIME_DIR=/tmp ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /usr/bin/tini RUN sudo chmod +x /usr/bin/tini -# Make sure Jupyter can write to the home directory -ENV HOME=/home/user -RUN sudo mkdir -p ${HOME} -RUN sudo chown ${CONTAINER_EXECUTION_UID} -R ${HOME} -RUN sudo chown ${CONTAINER_EXECUTION_UID} -R /opt/ipython-profiles diff --git a/docker-compose/pypcc-sim/Dockerfile b/docker-compose/pypcc-sim/Dockerfile index 4040339b1dc98ebe8e02b51c6b3b75aab55bb3d4..bf3e34d6a5a7c4660aebb4e0006e8fc73ec5665a 100644 --- a/docker-compose/pypcc-sim/Dockerfile +++ b/docker-compose/pypcc-sim/Dockerfile @@ -1,7 +1,9 @@ FROM ubuntu:20.04 +COPY requirements.txt /requirements.txt + RUN apt-get update && apt-get install -y python3 python3-pip python3-yaml git && \ - pip3 install opcua numpy recordclass && \ + pip3 install -r requirements.txt && \ git clone --depth 1 --branch master https://git.astron.nl/lofar2.0/pypcc WORKDIR /pypcc diff --git a/docker-compose/pypcc-sim/requirements.txt b/docker-compose/pypcc-sim/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..2cd015945c044fcd1e39a823f49a807fc519ac67 --- /dev/null +++ b/docker-compose/pypcc-sim/requirements.txt @@ -0,0 +1,3 @@ +opcua +numpy +recordclass>=0.16,<0.16.1 \ No newline at end of file diff --git a/docker-compose/sdptr-sim/Dockerfile b/docker-compose/sdptr-sim/Dockerfile index ed6ac8d35059fda67231a0dc17c71c3a5983b13c..fa23fe4d6458f4b7023c24b36774566cbac2163c 100644 --- a/docker-compose/sdptr-sim/Dockerfile +++ b/docker-compose/sdptr-sim/Dockerfile @@ -17,4 +17,4 @@ RUN cd /sdptr && \ bash -c "make -j `nproc` install" WORKDIR /sdptr/src -CMD ["sdptr", "--configfile=uniboard.conf", "--nodaemon"] +CMD ["sdptr", "--type=LTS", "--configfile=uniboard.conf", "--nodaemon"] diff --git a/docker-compose/tango.yml b/docker-compose/tango.yml index b3a860d7b55ea71c5e2bc23895b7b57040e3f216..9fa0f5cde06f91b7cdc078f5c6481b013442e5ae 100644 --- a/docker-compose/tango.yml +++ b/docker-compose/tango.yml @@ -28,7 +28,7 @@ services: - tangodb:/var/lib/mysql ports: - "3306:3306" - restart: on-failure + restart: unless-stopped databaseds: image: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}-tango-cpp:${TANGO_CPP_VERSION} @@ -55,4 +55,4 @@ services: - "2" - -ORBendPoint - giop:tcp::10000 - restart: on-failure + restart: unless-stopped diff --git a/sbin/run_integration_test.sh b/sbin/run_integration_test.sh new file mode 100755 index 0000000000000000000000000000000000000000..d54163625541c13816bf0309c09a2713ce35add9 --- /dev/null +++ b/sbin/run_integration_test.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +# Check if lofar20rc.sh is sourced and environment variables are set. +if [ -z "$LOFAR20_DIR" ]; then + echo "\$LOFAR20_DIR is unset or blank, is lofar20rc.sh sourced correctly?" + exit 1 +fi + +# Start all required containers +cd "$LOFAR20_DIR/docker-compose" || exit 1 +make start databaseds dsconfig device-sdp device-pcc jupyter elk sdptr-sim pypcc-sim + +# Update the dsconfig +cd "$TANGO_LOFAR_LOCAL_DIR" || exit 1 +sbin/update_ConfigDb.sh CDB/integration_ConfigDb.json + +# Start the integration test +cd "$LOFAR20_DIR/docker-compose" || exit 1 +make start integration-test + +# Run the integration test with the output displayed on stdout +docker start -a integration-test \ No newline at end of file