diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 8f2357ca9880bb6e384c069e31df9c43d71ffe5d..5c6e486d84dde4fcd4c4c02db86bc0cc72152c39 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -103,6 +103,7 @@ docker_build_image_all: - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-boot latest - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-docker latest - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-observation_control latest + - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-pdu latest - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-recv latest - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-sdp latest - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-sst latest @@ -253,6 +254,17 @@ docker_build_image_device_apspu: script: # Do not remove 'bash' or statement will be ignored by primitive docker shell - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-apspu $tag +docker_build_image_device_pdu: + extends: .base_docker_images_except + only: + refs: + - merge_requests + changes: + - docker-compose/device-pdu.yml + - docker-compose/lofar-device-base/* + script: +# Do not remove 'bash' or statement will be ignored by primitive docker shell + - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh device-pdu $tag docker_build_image_device_tilebeam: extends: .base_docker_images_except only: diff --git a/CDB/LOFAR_ConfigDb.json b/CDB/LOFAR_ConfigDb.json index 75da3c1142f40bb4034d7100812bd5dbe3ecf983..2032c4de777aa785dc8bfcff70c73da0bfc197b3 100644 --- a/CDB/LOFAR_ConfigDb.json +++ b/CDB/LOFAR_ConfigDb.json @@ -14,6 +14,13 @@ } } }, + "PDU": { + "STAT": { + "PDU": { + "STAT/PDU/1": {} + } + } + }, "TileBeam": { "STAT": { "TileBeam": { diff --git a/docker-compose/archiver-timescale.yml b/docker-compose/archiver-timescale.yml index a154b96d3338a039237b5d6f1933933c0969ecb3..a0f3e02f27a40cfe49009002026ecc2ebed68f47 100644 --- a/docker-compose/archiver-timescale.yml +++ b/docker-compose/archiver-timescale.yml @@ -1,5 +1,8 @@ version: '2' +volumes: + archiver-timescale-data: {} + services: archiver-timescale: image: timescaledb @@ -12,6 +15,8 @@ services: - "5432:5432/tcp" extra_hosts: - "host.docker.internal:host-gateway" + volumes: + - alerta-postgres-data:/var/lib/postgresql/data depends_on: - databaseds environment: diff --git a/docker-compose/device-pdu.yml b/docker-compose/device-pdu.yml new file mode 100644 index 0000000000000000000000000000000000000000..524748d14dff00d69a35f219c702f095da4b2d2a --- /dev/null +++ b/docker-compose/device-pdu.yml @@ -0,0 +1,42 @@ +# +# Requires: +# - lofar-device-base.yml +# +version: '2' + +volumes: + iers-data: {} + +services: + device-pdu: + image: device-pdu + # build explicitly, as docker-compose does not understand a local image + # being shared among services. + build: + context: .. + dockerfile: docker-compose/lofar-device-base/Dockerfile + args: + SOURCE_IMAGE: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}-tango-itango:${TANGO_ITANGO_VERSION} + container_name: ${CONTAINER_NAME_PREFIX}device-pdu + logging: + driver: "json-file" + options: + max-size: "100m" + max-file: "10" + networks: + - control + ports: + - "5714:5714" # unique port for this DS + extra_hosts: + - "host.docker.internal:host-gateway" + volumes: + - ..:/opt/lofar/tango:rw + environment: + - TANGO_HOST=${TANGO_HOST} + working_dir: /opt/lofar/tango + entrypoint: + - bin/start-ds.sh + # configure CORBA to _listen_ on 0:port, but tell others we're _reachable_ through ${HOSTNAME}:port, since CORBA + # can't know about our Docker port forwarding + - l2ss-pdu PDU STAT -v -ORBendPoint giop:tcp:0:5714 -ORBendPointPublish giop:tcp:${HOSTNAME}:5714 + restart: unless-stopped diff --git a/docker-compose/jupyter/ipython-profiles/stationcontrol-jupyter/startup/01-devices.py b/docker-compose/jupyter/ipython-profiles/stationcontrol-jupyter/startup/01-devices.py index cf3e092e8f3b8a58ada27252a7862a00f49ad870..1434393a85f0ed506d30303964f43c6c5ee0fa33 100644 --- a/docker-compose/jupyter/ipython-profiles/stationcontrol-jupyter/startup/01-devices.py +++ b/docker-compose/jupyter/ipython-profiles/stationcontrol-jupyter/startup/01-devices.py @@ -8,6 +8,7 @@ xst = DeviceProxy("STAT/XST/1") unb2 = DeviceProxy("STAT/UNB2/1") boot = DeviceProxy("STAT/Boot/1") tilebeam = DeviceProxy("STAT/TileBeam/1") +pdu = DeviceProxy("STAT/PDU/1") beamlet = DeviceProxy("STAT/Beamlet/1") digitalbeam = DeviceProxy("STAT/DigitalBeam/1") docker = DeviceProxy("STAT/Docker/1") diff --git a/sbin/run_integration_test.sh b/sbin/run_integration_test.sh index aec2d1d4082c04460a52476ac506597c28aa45eb..b703eae61fb5572463f58c3079d133ed30ad37ee 100755 --- a/sbin/run_integration_test.sh +++ b/sbin/run_integration_test.sh @@ -20,12 +20,13 @@ sleep 1 # dsconfig container must be up and running... # shellcheck disable=SC2016 echo '/usr/local/bin/wait-for-it.sh ${TANGO_HOST} --strict --timeout=300 -- true' | make run dsconfig bash - -DEVICES="device-boot device-apsct device-apspu device-sdp device-recv device-sst device-unb2 device-xst device-beamlet device-digitalbeam device-tilebeam" +DEVICES="device-boot device-apsct device-apspu device-sdp device-pdu device-recv device-sst device-unb2 device-xst device-beamlet device-digitalbeam device-tilebeam device-pdu" SIMULATORS="sdptr-sim recv-sim unb2-sim apsct-sim apspu-sim" # Build only the required images, please do not build everything that makes CI # take really long to finish, especially grafana / jupyter / prometheus. # jupyter is physically large > 2.5gb and overlayfs is really slow. + # shellcheck disable=SC2086 make build $DEVICES $SIMULATORS make build elk integration-test diff --git a/tangostationcontrol/docs/source/devices/pdu.rst b/tangostationcontrol/docs/source/devices/pdu.rst new file mode 100644 index 0000000000000000000000000000000000000000..ca78ad3c5b890bb53e422f11df17ff1530ec5376 --- /dev/null +++ b/tangostationcontrol/docs/source/devices/pdu.rst @@ -0,0 +1,7 @@ +.. _pdu: + +PDU +==================== + +The ``pdu == DeviceProxy("STAT/PDU/1")`` device controls the Power Distribution +Unit (PDU) diff --git a/tangostationcontrol/docs/source/index.rst b/tangostationcontrol/docs/source/index.rst index 97f8272100311a1b4cb758a4b47d3b9fc93d4e28..c0b64b2a83975abf0636157347354506c0532d9d 100644 --- a/tangostationcontrol/docs/source/index.rst +++ b/tangostationcontrol/docs/source/index.rst @@ -24,6 +24,7 @@ Even without having access to any LOFAR2.0 hardware, you can install the full st devices/digitalbeam devices/boot devices/docker + devices/pdu devices/recv devices/sdp devices/sst-xst diff --git a/tangostationcontrol/setup.cfg b/tangostationcontrol/setup.cfg index e9d1b0ada4513e0973785c5e2f99e5d78ada9350..997b7947d27f34b8c30db7eb320bb5384b546d38 100644 --- a/tangostationcontrol/setup.cfg +++ b/tangostationcontrol/setup.cfg @@ -35,6 +35,7 @@ where=./ console_scripts = l2ss-apsct = tangostationcontrol.devices.apsct:main l2ss-apspu = tangostationcontrol.devices.apspu:main + l2ss-pdu = tangostationcontrol.devices.pdu:main l2ss-tilebeam = tangostationcontrol.devices.tilebeam:main l2ss-beamlet = tangostationcontrol.devices.sdp.beamlet:main l2ss-digitalbeam = tangostationcontrol.devices.sdp.digitalbeam:main diff --git a/tangostationcontrol/tangostationcontrol/devices/README.md b/tangostationcontrol/tangostationcontrol/devices/README.md index 08eaf1f67e6f47f9f323e387f5714cf2ff5359a6..19d72e35c4f09d06d500d997d5255c1abdd53b77 100644 --- a/tangostationcontrol/tangostationcontrol/devices/README.md +++ b/tangostationcontrol/tangostationcontrol/devices/README.md @@ -10,10 +10,11 @@ If a new device is added, it will (likely) need to be referenced in several plac - Adjust `docker-compose/jupyter/ipython-profiles/stationcontrol-jupyter/startup/01-devices.py` to make an alias for it available in Jupyter, - Adjust `tangostationcontrol/tangostationcontrol/devices/boot.py` to add the device to the station initialisation sequence, - Add to `docker-compose/` to create a YaML file to start the device in a docker container. NOTE: it needs a unique 57xx port assigned, + current _unused_ port value: 5715 - Adjust `tangostationcontrol/setup.cfg` to add an entry point for the device in the package installation, - Add to `tangostationcontrol/tangostationcontrol/integration_test/default/devices/` to add an integration test, - Adjust `sbin/run_integration_test.sh` to have the device started when running the integration tests, - Adjust `.gitlab-ci.yml` to add the device to the `docker_build_image_all` step and to create a `docker_build_image_device_XXX` step, -- Add to `docs/source/devices/` to mention the device in the end-user documentation. -- Adjust `docs/source/index.rst` to include the newly created file in `docs/source/devices/`. +- Add to `tangostationcontrol/docs/source/devices/` to mention the device in the end-user documentation. +- Adjust `tangostationcontrol/docs/source/index.rst` to include the newly created file in `docs/source/devices/`. diff --git a/tangostationcontrol/tangostationcontrol/devices/boot.py b/tangostationcontrol/tangostationcontrol/devices/boot.py index 47dcc3741e2f5e72aa3bb7fa2c6fb35f551d9fdc..450df1b6fc233219168d3320a8acd8591361cb13 100644 --- a/tangostationcontrol/tangostationcontrol/devices/boot.py +++ b/tangostationcontrol/tangostationcontrol/devices/boot.py @@ -233,6 +233,7 @@ class Boot(lofar_device): dtype='DevVarStringArray', mandatory=False, default_value=["STAT/Docker/1", # Docker controls the device containers, so it goes before anything else + "STAT/PDU/1", # PDU boot early to detect power delivery failure as fast as possible "STAT/APSPU/1", # APS Power Units control other hardware we want to initialise "STAT/APSCT/1", "STAT/RECV/1", # RCUs are input for SDP, so initialise them first diff --git a/tangostationcontrol/tangostationcontrol/devices/pdu.py b/tangostationcontrol/tangostationcontrol/devices/pdu.py new file mode 100644 index 0000000000000000000000000000000000000000..88a1af8d1d8264fc6214fc8db779a5cb10e684a2 --- /dev/null +++ b/tangostationcontrol/tangostationcontrol/devices/pdu.py @@ -0,0 +1,57 @@ +# -*- coding: utf-8 -*- +# +# Distributed under the terms of the APACHE license. +# See LICENSE.txt for more info. + +""" PDU Device Server for LOFAR2.0 + +""" + +# Additional import +from tangostationcontrol.common.entrypoint import entry +from tangostationcontrol.devices.lofar_device import lofar_device +from tangostationcontrol.common.lofar_logging import device_logging_to_python, log_exceptions + +import logging + +logger = logging.getLogger() + +__all__ = ["PDU", "main"] + + +@device_logging_to_python() +class PDU(lofar_device): + # ----------------- + # Device Properties + # ----------------- + + # ---------- + # Attributes + # ---------- + + # -------- + # overloaded functions + # -------- + + def init_device(self): + super().init_device() + + @log_exceptions() + def configure_for_initialise(self): + super().configure_for_initialise() + + @log_exceptions() + def configure_for_on(self): + super().configure_for_on() + + @log_exceptions() + def configure_for_off(self): + super().configure_for_off() + + +# ---------- +# Run server +# ---------- +def main(**kwargs): + """Main function of the PDU module.""" + return entry(PDU, **kwargs) diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py b/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py index dd4179e47840488b1033d9612a4a5015f0ec2a49..f356c0dfc0e70632d8f57d40dbf32b31d90a49c4 100644 --- a/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py +++ b/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py @@ -98,8 +98,8 @@ class SDP(opcua_device): # ---------- FPGA_firmware_version_R = attribute_wrapper(comms_annotation=["FPGA_firmware_version_R"], datatype=numpy.str, dims=(16,)) - FPGA_boot_image_R = attribute_wrapper(comms_annotation=["FPGA_boot_image_R"], datatype=numpy.uint32, dims=(16,), doc="Active FPGA image (0=factory, 1=user)") - FPGA_boot_image_RW = attribute_wrapper(comms_annotation=["FPGA_boot_image_RW"], datatype=numpy.uint32, dims=(16,), access=AttrWriteType.READ_WRITE) + FPGA_boot_image_R = attribute_wrapper(comms_annotation=["FPGA_boot_image_R"], datatype=numpy.int32, dims=(16,), doc="Active FPGA image (0=factory, 1=user)") + FPGA_boot_image_RW = attribute_wrapper(comms_annotation=["FPGA_boot_image_RW"], datatype=numpy.int32, dims=(16,), access=AttrWriteType.READ_WRITE) FPGA_global_node_index_R = attribute_wrapper(comms_annotation=["FPGA_global_node_index_R"], datatype=numpy.uint32, dims=(16,)) FPGA_hardware_version_R = attribute_wrapper(comms_annotation=["FPGA_hardware_version_R"], datatype=numpy.str, dims=(16,)) FPGA_pps_present_R = attribute_wrapper(comms_annotation=["FPGA_pps_present_R"], datatype=numpy.bool_, dims=(16,)) diff --git a/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_pdu.py b/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_pdu.py new file mode 100644 index 0000000000000000000000000000000000000000..8ffefd83a8bba8fe1a04b8d929a5c403cb0d8262 --- /dev/null +++ b/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_pdu.py @@ -0,0 +1,17 @@ +# -*- 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 .base import AbstractTestBases + + +class TestDevicePDU(AbstractTestBases.TestDeviceBase): + + def setUp(self): + """Intentionally recreate the device object in each test""" + super().setUp("STAT/PDU/1")