From 8e15ef7969593874e6678846b93f666ce8dd6986 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Corn=C3=A9=20Lukken?= <lukken@astron.nl>
Date: Fri, 4 Nov 2022 09:16:14 +0000
Subject: [PATCH] L2SS-988: Docker health status with make await used by
 integration script

---
 README.md                                     |  1 +
 docker-compose/Makefile                       | 27 +++++++++++++++++++
 docker-compose/archiver-timescale.yml         |  6 +++++
 docker-compose/device-antennafield.yml        |  6 +++++
 docker-compose/device-apsct.yml               |  6 +++++
 docker-compose/device-apspu.yml               |  6 +++++
 docker-compose/device-beamlet.yml             |  6 +++++
 docker-compose/device-boot.yml                |  6 +++++
 docker-compose/device-bst.yml                 |  6 +++++
 docker-compose/device-ccd.yml                 |  6 +++++
 docker-compose/device-digitalbeam.yml         |  6 +++++
 docker-compose/device-docker.yml              |  6 +++++
 docker-compose/device-observation-control.yml |  6 +++++
 docker-compose/device-observation.yml         |  6 +++++
 docker-compose/device-pcon.yml                |  6 +++++
 docker-compose/device-psoc.yml                |  6 +++++
 docker-compose/device-recv.yml                |  6 +++++
 docker-compose/device-sdp.yml                 |  6 +++++
 docker-compose/device-sst.yml                 |  6 +++++
 docker-compose/device-temperature-manager.yml |  6 +++++
 docker-compose/device-tilebeam.yml            |  6 +++++
 docker-compose/device-unb2.yml                |  6 +++++
 docker-compose/device-xst.yml                 |  6 +++++
 docker-compose/lofar-device-base/Dockerfile   |  1 +
 docker-compose/logstash.yml                   |  6 +++++
 sbin/run_integration_test.sh                  | 16 +++++------
 tangostationcontrol/VERSION                   |  2 +-
 tangostationcontrol/setup.cfg                 |  1 +
 .../tangostationcontrol/common/entrypoint.py  |  5 ++++
 .../tangostationcontrol/common/health.py      | 20 ++++++++++++++
 .../default/statistics/test_writer_sst.py     |  2 +-
 tangostationcontrol/tox.ini                   |  2 +-
 32 files changed, 197 insertions(+), 12 deletions(-)
 create mode 100644 tangostationcontrol/tangostationcontrol/common/health.py

diff --git a/README.md b/README.md
index 795e8a0aa..da4288bc3 100644
--- a/README.md
+++ b/README.md
@@ -115,6 +115,7 @@ Next change the version in the following places:
 
 # Release Notes
 
+* 0.4.0 Have most containers report health status and add `make await` command
 * 0.3.1 Fix for applying boot device dsconfig
 * 0.3.0 Initial version of deployment scripts and functionality
 * 0.2.0 Extend `Beamlet` device with FPGA source address attributes
diff --git a/docker-compose/Makefile b/docker-compose/Makefile
index 0ca1c240b..0d570999b 100644
--- a/docker-compose/Makefile
+++ b/docker-compose/Makefile
@@ -13,6 +13,9 @@ ATTACH_COMPOSE_FILE_ARGS := $(foreach yml,$(filter-out tango.yml,$(COMPOSE_FILES
 # But we allow to overwrite it.
 NETWORK_MODE ?= tangonet
 
+# Timeout used to await services to become healthy
+TIMEOUT ?= 300
+
 SCRATCH ?= /tmp
 
 # Host name through which others can reach our control interfaces.
@@ -50,6 +53,8 @@ else ifeq (attach,$(firstword $(MAKECMDGOALS)))
     ifndef TANGO_HOST
         $(error TANGO_HOST must specify the Tango database device, e.g., make TANGO_HOST=powersupply-databaseds:10000 ...)
     endif
+else ifeq (await,$(firstword $(MAKECMDGOALS)))
+    SERVICE_TARGET = true
 else ifeq (run,$(firstword $(MAKECMDGOALS)))
     RUN_TARGET = true
 else ifeq (integration,$(firstword $(MAKECMDGOALS)))
@@ -220,6 +225,28 @@ restart: ## restart a service (usage: make restart <servicename>)
 attach:  ## attach a service to an existing Tango network
 	$(DOCKER_COMPOSE_ARGS) docker-compose $(ATTACH_COMPOSE_FILE_ARGS) up --no-recreate -d $(SERVICE)
 
+time := 0
+await:  ## Await every container with total max timeout of 300, do not reset timeout
+	for i in $(SERVICE); do \
+		current_service=$$($(DOCKER_COMPOSE_ARGS) docker-compose $(COMPOSE_FILE_ARGS) ps -q $${i}); \
+		if [ -z "$${current_service}" ]; then \
+		    continue; \
+        fi; \
+        service_has_health=$$(docker inspect -f '{{.State.Health.Status}}' $${current_service}); \
+        if [ -z "$${service_has_health}" ]; then \
+            continue; \
+        fi; \
+		while [ "$$(docker inspect -f '{{.State.Health.Status}}' $${current_service})" != "healthy" ] ; do \
+			sleep 1; \
+			time=$$(expr $$time + 1); \
+			if [ $${time} -gt $(TIMEOUT) ]; then \
+				echo "Timeout reached waiting for $${i} to become healthy"; \
+				exit 1; \
+			fi; \
+		done; \
+		echo "Service $${i} is healthy"; \
+	done
+
 status:  ## show the container status
 	$(DOCKER_COMPOSE_ARGS) docker-compose $(COMPOSE_FILE_ARGS) ps
 
diff --git a/docker-compose/archiver-timescale.yml b/docker-compose/archiver-timescale.yml
index 405ef8687..303256f13 100644
--- a/docker-compose/archiver-timescale.yml
+++ b/docker-compose/archiver-timescale.yml
@@ -25,6 +25,12 @@ services:
       - POSTGRES_PASSWORD=${PG_SUPERUSER_PASSWORD}
       - PG_HDB_PASSWORD=${PG_HDB_PASSWORD}
       - TANGO_HOST=${TANGO_HOST}
+    healthcheck:
+      test: nc -z -v localhost 5432
+      interval: 1m
+      timeout: 30s
+      retries: 3
+      start_period: 30s
     logging:
       driver: syslog
       options:
diff --git a/docker-compose/device-antennafield.yml b/docker-compose/device-antennafield.yml
index 1227a4b32..32bf15bf4 100644
--- a/docker-compose/device-antennafield.yml
+++ b/docker-compose/device-antennafield.yml
@@ -43,6 +43,12 @@ services:
       - TANGO_HOST=${TANGO_HOST}
       - TANGO_ZMQ_EVENT_PORT=5815
       - TANGO_ZMQ_HEARTBEAT_PORT=5915
+    healthcheck:
+      test: l2ss-health STAT/AntennaField/1
+      interval: 1m
+      timeout: 30s
+      retries: 3
+      start_period: 30s
     working_dir: /opt/lofar/tango
     entrypoint:
       - bin/start-ds.sh
diff --git a/docker-compose/device-apsct.yml b/docker-compose/device-apsct.yml
index 6cf44394a..e90644f83 100644
--- a/docker-compose/device-apsct.yml
+++ b/docker-compose/device-apsct.yml
@@ -42,6 +42,12 @@ services:
       - TANGO_HOST=${TANGO_HOST}
       - TANGO_ZMQ_EVENT_PORT=5809
       - TANGO_ZMQ_HEARTBEAT_PORT=5909
+    healthcheck:
+      test: l2ss-health STAT/Apsct/1
+      interval: 1m
+      timeout: 30s
+      retries: 3
+      start_period: 30s
     working_dir: /opt/lofar/tango
     entrypoint:
       - bin/start-ds.sh
diff --git a/docker-compose/device-apspu.yml b/docker-compose/device-apspu.yml
index fd9f8942f..3d6dcff86 100644
--- a/docker-compose/device-apspu.yml
+++ b/docker-compose/device-apspu.yml
@@ -42,6 +42,12 @@ services:
       - TANGO_HOST=${TANGO_HOST}
       - TANGO_ZMQ_EVENT_PORT=5810
       - TANGO_ZMQ_HEARTBEAT_PORT=5910
+    healthcheck:
+      test: l2ss-health STAT/Apspu/1
+      interval: 1m
+      timeout: 30s
+      retries: 3
+      start_period: 30s
     working_dir: /opt/lofar/tango
     entrypoint:
       - bin/start-ds.sh
diff --git a/docker-compose/device-beamlet.yml b/docker-compose/device-beamlet.yml
index 3094b64b5..ab27d681d 100644
--- a/docker-compose/device-beamlet.yml
+++ b/docker-compose/device-beamlet.yml
@@ -42,6 +42,12 @@ services:
       - TANGO_HOST=${TANGO_HOST}
       - TANGO_ZMQ_EVENT_PORT=5812
       - TANGO_ZMQ_HEARTBEAT_PORT=5912
+    healthcheck:
+      test: l2ss-health STAT/Beamlet/1
+      interval: 1m
+      timeout: 30s
+      retries: 3
+      start_period: 30s
     working_dir: /opt/lofar/tango
     entrypoint:
       - bin/start-ds.sh
diff --git a/docker-compose/device-boot.yml b/docker-compose/device-boot.yml
index 2e9f8aa9d..9e2579a2c 100644
--- a/docker-compose/device-boot.yml
+++ b/docker-compose/device-boot.yml
@@ -41,6 +41,12 @@ services:
       - TANGO_HOST=${TANGO_HOST}
       - TANGO_ZMQ_EVENT_PORT=5808
       - TANGO_ZMQ_HEARTBEAT_PORT=5908
+    healthcheck:
+      test: l2ss-health STAT/BOOT/1
+      interval: 1m
+      timeout: 30s
+      retries: 3
+      start_period: 30s
     working_dir: /opt/lofar/tango
     entrypoint:
       - bin/start-ds.sh
diff --git a/docker-compose/device-bst.yml b/docker-compose/device-bst.yml
index 64be2362d..9d66573df 100644
--- a/docker-compose/device-bst.yml
+++ b/docker-compose/device-bst.yml
@@ -45,6 +45,12 @@ services:
       - TANGO_HOST=${TANGO_HOST}
       - TANGO_ZMQ_EVENT_PORT=5817
       - TANGO_ZMQ_HEARTBEAT_PORT=5917
+    healthcheck:
+      test: l2ss-health STAT/BST/1
+      interval: 1m
+      timeout: 30s
+      retries: 3
+      start_period: 30s
     working_dir: /opt/lofar/tango
     entrypoint:
       - bin/start-ds.sh
diff --git a/docker-compose/device-ccd.yml b/docker-compose/device-ccd.yml
index ad53c0afa..314d6398e 100644
--- a/docker-compose/device-ccd.yml
+++ b/docker-compose/device-ccd.yml
@@ -42,6 +42,12 @@ services:
       - TANGO_HOST=${TANGO_HOST}
       - TANGO_ZMQ_EVENT_PORT=5821
       - TANGO_ZMQ_HEARTBEAT_PORT=5921
+    healthcheck:
+      test: l2ss-health STAT/CCD/1
+      interval: 1m
+      timeout: 30s
+      retries: 3
+      start_period: 30s
     working_dir: /opt/lofar/tango
     entrypoint:
       - bin/start-ds.sh
diff --git a/docker-compose/device-digitalbeam.yml b/docker-compose/device-digitalbeam.yml
index 3e4424dee..0a2d9583a 100644
--- a/docker-compose/device-digitalbeam.yml
+++ b/docker-compose/device-digitalbeam.yml
@@ -42,6 +42,12 @@ services:
       - TANGO_HOST=${TANGO_HOST}
       - TANGO_ZMQ_EVENT_PORT=5813
       - TANGO_ZMQ_HEARTBEAT_PORT=5913
+    healthcheck:
+      test: l2ss-health STAT/DigitalBeam/1
+      interval: 1m
+      timeout: 30s
+      retries: 3
+      start_period: 30s
     working_dir: /opt/lofar/tango
     entrypoint:
       - bin/start-ds.sh
diff --git a/docker-compose/device-docker.yml b/docker-compose/device-docker.yml
index 0d3935796..8c5fc4d75 100644
--- a/docker-compose/device-docker.yml
+++ b/docker-compose/device-docker.yml
@@ -44,6 +44,12 @@ services:
       - TANGO_HOST=${TANGO_HOST}
       - TANGO_ZMQ_EVENT_PORT=5805
       - TANGO_ZMQ_HEARTBEAT_PORT=5905
+    healthcheck:
+      test: l2ss-health STAT/Docker/1
+      interval: 1m
+      timeout: 30s
+      retries: 3
+      start_period: 30s
     working_dir: /opt/lofar/tango
     entrypoint:
       - bin/start-ds.sh
diff --git a/docker-compose/device-observation-control.yml b/docker-compose/device-observation-control.yml
index 3eb2e4cdd..4a3567049 100644
--- a/docker-compose/device-observation-control.yml
+++ b/docker-compose/device-observation-control.yml
@@ -41,6 +41,12 @@ services:
       - TANGO_HOST=${TANGO_HOST}
       - TANGO_ZMQ_EVENT_PORT=5803
       - TANGO_ZMQ_HEARTBEAT_PORT=5903
+    healthcheck:
+      test: l2ss-health STAT/ObservationControl/1
+      interval: 1m
+      timeout: 30s
+      retries: 3
+      start_period: 30s
     working_dir: /opt/lofar/tango
     entrypoint:
       - bin/start-ds.sh
diff --git a/docker-compose/device-observation.yml b/docker-compose/device-observation.yml
index a002d06f4..c0ac58f6c 100644
--- a/docker-compose/device-observation.yml
+++ b/docker-compose/device-observation.yml
@@ -40,6 +40,12 @@ services:
       - TANGO_HOST=${TANGO_HOST}
       - TANGO_ZMQ_EVENT_PORT=5818
       - TANGO_ZMQ_HEARTBEAT_PORT=5918
+    healthcheck:
+      test: nc -z -v device-observation 5718
+      interval: 1m
+      timeout: 30s
+      retries: 3
+      start_period: 30s
     working_dir: /opt/lofar/tango
     entrypoint:
       - bin/start-ds.sh
diff --git a/docker-compose/device-pcon.yml b/docker-compose/device-pcon.yml
index 3165b6ee0..4f1c8bd4c 100644
--- a/docker-compose/device-pcon.yml
+++ b/docker-compose/device-pcon.yml
@@ -37,6 +37,12 @@ services:
       - TANGO_HOST=${TANGO_HOST}
       - TANGO_ZMQ_EVENT_PORT=5820
       - TANGO_ZMQ_HEARTBEAT_PORT=5920
+    healthcheck:
+      test: l2ss-health STAT/pcon/1
+      interval: 1m
+      timeout: 30s
+      retries: 3
+      start_period: 30s
     working_dir: /opt/lofar/tango
     entrypoint:
       - bin/start-ds.sh
diff --git a/docker-compose/device-psoc.yml b/docker-compose/device-psoc.yml
index 25e33b3b2..a98c1195b 100644
--- a/docker-compose/device-psoc.yml
+++ b/docker-compose/device-psoc.yml
@@ -37,6 +37,12 @@ services:
       - TANGO_HOST=${TANGO_HOST}
       - TANGO_ZMQ_EVENT_PORT=5819
       - TANGO_ZMQ_HEARTBEAT_PORT=5919
+    healthcheck:
+      test: l2ss-health STAT/PSOC/1
+      interval: 1m
+      timeout: 30s
+      retries: 3
+      start_period: 30s
     working_dir: /opt/lofar/tango
     entrypoint:
       - bin/start-ds.sh
diff --git a/docker-compose/device-recv.yml b/docker-compose/device-recv.yml
index bec614c9b..70e20752e 100644
--- a/docker-compose/device-recv.yml
+++ b/docker-compose/device-recv.yml
@@ -42,6 +42,12 @@ services:
       - TANGO_HOST=${TANGO_HOST}
       - TANGO_ZMQ_EVENT_PORT=5807
       - TANGO_ZMQ_HEARTBEAT_PORT=5907
+    healthcheck:
+      test: l2ss-health STAT/RECV/1
+      interval: 1m
+      timeout: 30s
+      retries: 3
+      start_period: 30s
     working_dir: /opt/lofar/tango
     entrypoint:
       - bin/start-ds.sh
diff --git a/docker-compose/device-sdp.yml b/docker-compose/device-sdp.yml
index e3691921c..7d68d7f15 100644
--- a/docker-compose/device-sdp.yml
+++ b/docker-compose/device-sdp.yml
@@ -42,6 +42,12 @@ services:
       - TANGO_HOST=${TANGO_HOST}
       - TANGO_ZMQ_EVENT_PORT=5801
       - TANGO_ZMQ_HEARTBEAT_PORT=5901
+    healthcheck:
+      test: l2ss-health STAT/SDP/1
+      interval: 1m
+      timeout: 30s
+      retries: 3
+      start_period: 30s
     working_dir: /opt/lofar/tango
     entrypoint:
       - bin/start-ds.sh
diff --git a/docker-compose/device-sst.yml b/docker-compose/device-sst.yml
index 53d24c8fe..7892f3e2a 100644
--- a/docker-compose/device-sst.yml
+++ b/docker-compose/device-sst.yml
@@ -45,6 +45,12 @@ services:
       - TANGO_HOST=${TANGO_HOST}
       - TANGO_ZMQ_EVENT_PORT=5802
       - TANGO_ZMQ_HEARTBEAT_PORT=5902
+    healthcheck:
+      test: l2ss-health STAT/SST/1
+      interval: 1m
+      timeout: 30s
+      retries: 3
+      start_period: 30s
     working_dir: /opt/lofar/tango
     entrypoint:
       - bin/start-ds.sh
diff --git a/docker-compose/device-temperature-manager.yml b/docker-compose/device-temperature-manager.yml
index 8cf747710..5e8b3ab1e 100644
--- a/docker-compose/device-temperature-manager.yml
+++ b/docker-compose/device-temperature-manager.yml
@@ -37,6 +37,12 @@ services:
       - TANGO_HOST=${TANGO_HOST}
       - TANGO_ZMQ_EVENT_PORT=5816
       - TANGO_ZMQ_HEARTBEAT_PORT=5916
+    healthcheck:
+      test: l2ss-health STAT/TemperatureManager/1
+      interval: 1m
+      timeout: 30s
+      retries: 3
+      start_period: 30s
     working_dir: /opt/lofar/tango
     entrypoint:
       - bin/start-ds.sh
diff --git a/docker-compose/device-tilebeam.yml b/docker-compose/device-tilebeam.yml
index fcc4eefb4..e7e4b7541 100644
--- a/docker-compose/device-tilebeam.yml
+++ b/docker-compose/device-tilebeam.yml
@@ -38,6 +38,12 @@ services:
       - TANGO_HOST=${TANGO_HOST}
       - TANGO_ZMQ_EVENT_PORT=5811
       - TANGO_ZMQ_HEARTBEAT_PORT=5911
+    healthcheck:
+      test: l2ss-health STAT/TileBeam/1
+      interval: 1m
+      timeout: 30s
+      retries: 3
+      start_period: 30s
     working_dir: /opt/lofar/tango
     entrypoint:
       - bin/start-ds.sh
diff --git a/docker-compose/device-unb2.yml b/docker-compose/device-unb2.yml
index 9727d72c1..223e3e504 100644
--- a/docker-compose/device-unb2.yml
+++ b/docker-compose/device-unb2.yml
@@ -42,6 +42,12 @@ services:
       - TANGO_HOST=${TANGO_HOST}
       - TANGO_ZMQ_EVENT_PORT=5804
       - TANGO_ZMQ_HEARTBEAT_PORT=5904
+    healthcheck:
+      test: l2ss-health STAT/UNB2/1
+      interval: 1m
+      timeout: 30s
+      retries: 3
+      start_period: 30s
     working_dir: /opt/lofar/tango
     entrypoint:
       - bin/start-ds.sh
diff --git a/docker-compose/device-xst.yml b/docker-compose/device-xst.yml
index 44b61c734..fc07c7463 100644
--- a/docker-compose/device-xst.yml
+++ b/docker-compose/device-xst.yml
@@ -45,6 +45,12 @@ services:
       - TANGO_HOST=${TANGO_HOST}
       - TANGO_ZMQ_EVENT_PORT=5806
       - TANGO_ZMQ_HEARTBEAT_PORT=5906
+    healthcheck:
+      test: l2ss-health STAT/XST/1
+      interval: 1m
+      timeout: 30s
+      retries: 3
+      start_period: 30s
     working_dir: /opt/lofar/tango
     entrypoint:
       - bin/start-ds.sh
diff --git a/docker-compose/lofar-device-base/Dockerfile b/docker-compose/lofar-device-base/Dockerfile
index 0d7c98235..676fb6a38 100644
--- a/docker-compose/lofar-device-base/Dockerfile
+++ b/docker-compose/lofar-device-base/Dockerfile
@@ -7,6 +7,7 @@ RUN sudo apt-get install -y g++ gcc && sudo apt-get clean
 RUN sudo apt-get install -y shellcheck graphviz && sudo apt-get clean
 RUN sudo apt-get install -y python3-dev libboost-python-dev pkg-config && sudo apt-get clean
 RUN sudo apt-get install -y rsync && sudo apt-get clean
+RUN sudo apt-get install -y netcat && sudo apt-get clean
 
 COPY lofar-device-base/lofar-requirements.txt /lofar-requirements.txt
 
diff --git a/docker-compose/logstash.yml b/docker-compose/logstash.yml
index 73a13e346..0a19ad3df 100644
--- a/docker-compose/logstash.yml
+++ b/docker-compose/logstash.yml
@@ -18,6 +18,12 @@ services:
       options:
         max-size: "100m"
         max-file: "10"
+    healthcheck:
+      test: python -c "import socket; s = socket.socket(); s.settimeout(10); s.connect(('$HOSTNAME', 1514));"
+      interval: 1m
+      timeout: 30s
+      retries: 3
+      start_period: 30s
     networks:
       - control
     ports:
diff --git a/sbin/run_integration_test.sh b/sbin/run_integration_test.sh
index 563b2c7fb..57e7e4d2c 100755
--- a/sbin/run_integration_test.sh
+++ b/sbin/run_integration_test.sh
@@ -31,9 +31,9 @@ function integration_test {
     # shellcheck disable=SC2145
     echo "make restart ${restarts[@]} ..."
     make restart "${restarts[@]}"
+    make await "${restarts[@]}"
   fi
-  #TODO(L2SS-988): Use healthcheck to wait for containers to become ready
-  sleep 30
+
   echo "make integration ${1} ..."
   make integration "${1}"
 }
@@ -76,6 +76,8 @@ 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 list is used to explitly word split when supplied to commands, must
+# disable shellcheck SC2086 for each case.
 DEVICES="device-boot device-apsct device-ccd device-apspu device-sdp device-recv device-bst device-sst device-unb2 device-xst device-beamlet device-digitalbeam device-tilebeam device-psoc device-pcon device-antennafield device-temperature-manager device-observation device-observation-control"
 
 SIMULATORS="sdptr-sim recv-sim unb2-sim apsct-sim apspu-sim ccd-sim"
@@ -108,10 +110,6 @@ integration_test dummy
 # make start elk # L2SS-970: elk temporarily disabled
 make start logstash
 
-# Give elk time to start
-# TODO(L2SS-988): Use a nicer more reliable mechanism
-sleep 10
-
 # Update the dsconfig
 # Do not remove `bash`, otherwise statement ignored by gitlab ci shell!
 bash "${LOFAR20_DIR}"/sbin/update_ConfigDb.sh "${LOFAR20_DIR}"/CDB/LOFAR_ConfigDb.json
@@ -132,9 +130,9 @@ make start $DEVICES
 # Archive devices: archive-timescale first
 make start archiver-timescale
 
-# Give devices time to restart
-# TODO(L2SS-988): Use a nicer more reliable mechanism
-sleep 70
+# Wait for archiver and devices to restart
+# shellcheck disable=SC2086
+make await archiver-timescale $DEVICES
 
 # Give archiver-timescale time to start
 # shellcheck disable=SC2016
diff --git a/tangostationcontrol/VERSION b/tangostationcontrol/VERSION
index 9e11b32fc..1d0ba9ea1 100644
--- a/tangostationcontrol/VERSION
+++ b/tangostationcontrol/VERSION
@@ -1 +1 @@
-0.3.1
+0.4.0
diff --git a/tangostationcontrol/setup.cfg b/tangostationcontrol/setup.cfg
index bea7c5441..38eed462b 100644
--- a/tangostationcontrol/setup.cfg
+++ b/tangostationcontrol/setup.cfg
@@ -63,6 +63,7 @@ console_scripts =
     l2ss-parse-statistics-packet = tangostationcontrol.statistics.packet:main
     l2ss-random-data = tangostationcontrol.test.devices.random_data:main
     l2ss-version = tangostationcontrol:print_version
+    l2ss-health = tangostationcontrol.common.health:main
 
 [options.package_data]
 * = *.json, *.mib
diff --git a/tangostationcontrol/tangostationcontrol/common/entrypoint.py b/tangostationcontrol/tangostationcontrol/common/entrypoint.py
index d5b9d4952..94e231e52 100644
--- a/tangostationcontrol/tangostationcontrol/common/entrypoint.py
+++ b/tangostationcontrol/tangostationcontrol/common/entrypoint.py
@@ -1,3 +1,8 @@
+# -*- coding: utf-8 -*-
+#
+# Distributed under the terms of the APACHE license.
+# See LICENSE.txt for more info.
+
 import sys
 
 from tango.server import run
diff --git a/tangostationcontrol/tangostationcontrol/common/health.py b/tangostationcontrol/tangostationcontrol/common/health.py
new file mode 100644
index 000000000..ab7ed2815
--- /dev/null
+++ b/tangostationcontrol/tangostationcontrol/common/health.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+#
+# Distributed under the terms of the APACHE license.
+# See LICENSE.txt for more info.
+
+import sys
+
+from tango import DeviceProxy
+
+def main(*args, **kwargs):
+    """Main function health check"""
+
+    # Remove first argument as it is the filename
+    args = sys.argv[1:]
+
+    try:
+        DeviceProxy(args[0]).ping()
+        return 0
+    except BaseException:
+        return 1
diff --git a/tangostationcontrol/tangostationcontrol/integration_test/default/statistics/test_writer_sst.py b/tangostationcontrol/tangostationcontrol/integration_test/default/statistics/test_writer_sst.py
index 90c1c9161..cac23a518 100644
--- a/tangostationcontrol/tangostationcontrol/integration_test/default/statistics/test_writer_sst.py
+++ b/tangostationcontrol/tangostationcontrol/integration_test/default/statistics/test_writer_sst.py
@@ -82,7 +82,7 @@ class TestStatisticsWriterSST(BaseIntegrationTestCase):
                     '2021-09-20T12:17:40.000+00:00'
                 )
                 self.assertIsNotNone(stat)
-                self.assertEqual("0.3.1", stat.station_version_id)
+                self.assertEqual("0.4.0", stat.station_version_id)
                 self.assertEqual("0.1", stat.writer_version_id)
 
     def test_insert_tango_SST_statistics(self):
diff --git a/tangostationcontrol/tox.ini b/tangostationcontrol/tox.ini
index d528ccc75..fe85f17de 100644
--- a/tangostationcontrol/tox.ini
+++ b/tangostationcontrol/tox.ini
@@ -118,4 +118,4 @@ commands =
 [flake8]
 filename = *.py,.stestr.conf,.txt
 ignore = B014, B019, W291, W293, W391, E111, E114, E121, E122, E123, E124, E126, E127, E128, E131, E201, E201, E202, E203, E221, E222, E225, E226, E231, E241, E251, E252, E261, E262, E265, E271, E301, E302, E303, E305, E306, E401, E402, E501, E502, E701, E712, E721, E731, F403, F523, F541, F841, H301, H306, H401, H403, H404, H405, W503
-exclude=.tox,build,.egg-info,libhdbpp-python, SNMP_mib_loading
+exclude=.tox,build,.egg-info,libhdbpp-python,SNMP_mib_loading
-- 
GitLab