diff --git a/docker/.make/.make-release-support b/docker/.make/.make-release-support new file mode 100644 index 0000000000000000000000000000000000000000..f1f3a2cb9fb3ea0ce3a173a35c3c9fe316d75156 --- /dev/null +++ b/docker/.make/.make-release-support @@ -0,0 +1,106 @@ +#!/bin/bash +# +# Copyright 2015 Xebia Nederland B.V. +# Modifications copyright 2019 SKA Organisation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +function hasChanges() { + test -n "$(git status -s .)" +} + +function getRelease() { + awk -F= '/^release=/{print $2}' .release +} + +function getBaseTag() { + sed -n -e "s/^tag=\(.*\)$(getRelease)\$/\1/p" .release +} + +function getTag() { + if [ -z "$1" ] ; then + awk -F= '/^tag/{print $2}' .release + else + echo "$(getBaseTag)$1" + fi +} + +function setRelease() { + if [ -n "$1" ] ; then + sed -i.x -e "s/^tag=.*/tag=$(getTag $1)/" .release + sed -i.x -e "s/^release=.*/release=$1/g" .release + rm -f .release.x + runPreTagCommand "$1" + else + echo "ERROR: missing release version parameter " >&2 + return 1 + fi +} + +function runPreTagCommand() { + if [ -n "$1" ] ; then + COMMAND=$(sed -n -e "s/@@RELEASE@@/$1/g" -e 's/^pre_tag_command=\(.*\)/\1/p' .release) + if [ -n "$COMMAND" ] ; then + if ! OUTPUT=$(bash -c "$COMMAND" 2>&1) ; then echo $OUTPUT >&2 && exit 1 ; fi + fi + else + echo "ERROR: missing release version parameter " >&2 + return 1 + fi +} + +function tagExists() { + tag=${1:-$(getTag)} + test -n "$tag" && test -n "$(git tag | grep "^$tag\$")" +} + +function differsFromRelease() { + tag=$(getTag) + ! tagExists $tag || test -n "$(git diff --shortstat -r $tag .)" +} + +function getVersion() { + result=$(getRelease) + + if differsFromRelease; then + result="$result-$(git log -n 1 --format=%h .)" + fi + + if hasChanges ; then + result="$result-dirty" + fi + echo $result +} + +function nextPatchLevel() { + version=${1:-$(getRelease)} + major_and_minor=$(echo $version | cut -d. -f1,2) + patch=$(echo $version | cut -d. -f3) + version=$(printf "%s.%d" $major_and_minor $(($patch + 1))) + echo $version +} + +function nextMinorLevel() { + version=${1:-$(getRelease)} + major=$(echo $version | cut -d. -f1); + minor=$(echo $version | cut -d. -f2); + version=$(printf "%d.%d.0" $major $(($minor + 1))) ; + echo $version +} + +function nextMajorLevel() { + version=${1:-$(getRelease)} + major=$(echo $version | cut -d. -f1); + version=$(printf "%d.0.0" $(($major + 1))) + echo $version +} diff --git a/docker/.make/Makefile.mk b/docker/.make/Makefile.mk new file mode 100644 index 0000000000000000000000000000000000000000..c8196593ee69d4cdb75be9779299b1955cd6025c --- /dev/null +++ b/docker/.make/Makefile.mk @@ -0,0 +1,137 @@ +# +# Copyright 2015 Xebia Nederland B.V. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +ifeq ($(strip $(PROJECT)),) + NAME=$(shell basename $(CURDIR)) +else + NAME=$(PROJECT) +endif + +RELEASE_SUPPORT := $(shell dirname $(abspath $(lastword $(MAKEFILE_LIST))))/.make-release-support + +ifeq ($(strip $(DOCKER_REGISTRY_HOST)),) + DOCKER_REGISTRY_HOST = nexus.engageska-portugal.pt +endif + +ifeq ($(strip $(DOCKER_REGISTRY_USER)),) + DOCKER_REGISTRY_USER = ska-docker +endif + +IMAGE=$(DOCKER_REGISTRY_HOST)/$(DOCKER_REGISTRY_USER)/$(NAME) + +#VERSION = release version + git sha +VERSION=$(shell . $(RELEASE_SUPPORT) ; getVersion) + +#BASE_VERSION +BASE_VERSION=$(shell . $(RELEASE_SUPPORT) ; getRelease) + +#TAG = project name + release version +TAG=$(shell . $(RELEASE_SUPPORT); getTag) + +#DEFAULT_TAG = image name + BASE_VERSION +DEFAULT_TAG=$(IMAGE):$(BASE_VERSION) + + +SHELL=/bin/bash + +DOCKER_BUILD_CONTEXT=.. +DOCKER_FILE_PATH=Dockerfile + +.PHONY: pre-build docker-build post-build build release patch-release minor-release major-release tag check-status check-release showver \ + push pre-push do-push post-push + +build: pre-build docker-build post-build ## build the application image + +pre-build: + +post-build: + +pre-push: + +post-push: + +docker-build: .release + @echo "Building image: $(IMAGE):$(VERSION)" + @echo "NAME: $(NAME)" + docker build $(DOCKER_BUILD_ARGS) -t $(IMAGE):$(VERSION) $(DOCKER_BUILD_CONTEXT) -f $(DOCKER_FILE_PATH) --build-arg DOCKER_REGISTRY_HOST=$(DOCKER_REGISTRY_HOST) --build-arg DOCKER_REGISTRY_USER=$(DOCKER_REGISTRY_USER) + @DOCKER_MAJOR=$(shell docker -v | sed -e 's/.*version //' -e 's/,.*//' | cut -d\. -f1) ; \ + DOCKER_MINOR=$(shell docker -v | sed -e 's/.*version //' -e 's/,.*//' | cut -d\. -f2) ; \ + if [ $$DOCKER_MAJOR -eq 1 ] && [ $$DOCKER_MINOR -lt 10 ] ; then \ + echo docker tag -f $(IMAGE):$(VERSION) $(IMAGE):latest ;\ + docker tag -f $(IMAGE):$(VERSION) $(IMAGE):latest ;\ + else \ + echo docker tag $(IMAGE):$(VERSION) $(IMAGE):latest ;\ + docker tag $(IMAGE):$(VERSION) $(IMAGE):latest ; \ + fi + +release: check-status check-release build push + +push: pre-push do-push post-push ## push the image to the Docker registry + +do-push: ## Push the image tagged as $(IMAGE):$(VERSION) and $(DEFAULT_TAG) + @echo -e "Tagging: $(IMAGE):$(VERSION) -> $(DEFAULT_TAG)" + docker tag $(IMAGE):$(VERSION) $(DEFAULT_TAG) + @echo -e "Pushing: $(IMAGE):$(VERSION)" + docker push $(IMAGE):$(VERSION) + @echo -e "Pushing: $(DEFAULT_TAG)" + docker push $(DEFAULT_TAG) + +tag_latest: do-push ## Tag the images as latest + @echo "Tagging: $(DEFAULT_TAG) -> $(IMAGE):latest" + @docker tag $(DEFAULT_TAG) $(IMAGE):latest + +push_latest: tag_latest ## Push the image tagged as :latest + @echo "Pushing: $(IMAGE):latest" + @docker push $(IMAGE):latest + +snapshot: build push + +showver: .release + @. $(RELEASE_SUPPORT); getVersion + +bump-patch-release: VERSION := $(shell . $(RELEASE_SUPPORT); nextPatchLevel) +bump-patch-release: .release tag + +bump-minor-release: VERSION := $(shell . $(RELEASE_SUPPORT); nextMinorLevel) +bump-minor-release: .release tag + +bump-major-release: VERSION := $(shell . $(RELEASE_SUPPORT); nextMajorLevel) +bump-major-release: .release tag + +patch-release: tag-patch-release release + @echo $(VERSION) + +minor-release: tag-minor-release release + @echo $(VERSION) + +major-release: tag-major-release release + @echo $(VERSION) + +tag: TAG=$(shell . $(RELEASE_SUPPORT); getTag $(VERSION)) +tag: check-status +# @. $(RELEASE_SUPPORT) ; ! tagExists $(TAG) || (echo "ERROR: tag $(TAG) for version $(VERSION) already tagged in git" >&2 && exit 1) ; + @. $(RELEASE_SUPPORT) ; setRelease $(VERSION) +# git add . +# git commit -m "bumped to version $(VERSION)" ; +# git tag $(TAG) ; +# @ if [ -n "$(shell git remote -v)" ] ; then git push --tags ; else echo 'no remote to push tags to' ; fi + +check-status: + @. $(RELEASE_SUPPORT) ; ! hasChanges || (echo "ERROR: there are still outstanding changes" >&2 && exit 1) ; + +check-release: .release + @. $(RELEASE_SUPPORT) ; tagExists $(TAG) || (echo "ERROR: version not yet tagged in git. make [minor,major,patch]-release." >&2 && exit 1) ; + @. $(RELEASE_SUPPORT) ; ! differsFromRelease $(TAG) || (echo "ERROR: current directory differs from tagged $(TAG). make [minor,major,patch]-release." ; exit 1) diff --git a/docker/.release b/docker/.release new file mode 100644 index 0000000000000000000000000000000000000000..87dca79f7d33c662b775fc4365b82a6e9e2af259 --- /dev/null +++ b/docker/.release @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# +# This file is part of the CSP.LMC prototype project +# +# +# Distributed under the terms of the BSD-3-Clause license. +# See LICENSE.txt for more info. + +"""Release information for Python Package""" + +name = """csplmc-subelement""" +version = "0.1.0" +version_info = version.split(".") +description = """SKA CSP.LMC Subelement Classes""" +author = "E.G" +author_email = "elisabetta.giani@inaf.it" +license = """BSD-3-Clause""" +url = """www.tango-controls.org""" +copyright = """""" + +release=0.1.0 +tag=csp-lmc-subelement-0.1.0 diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..11f75668e4981db977a215ee9cf095f711561453 --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,11 @@ +FROM nexus.engageska-portugal.pt/ska-docker/ska-python-buildenv:9.3.1 AS buildenv +FROM nexus.engageska-portugal.pt/ska-docker/ska-python-runtime:9.3.1 AS runtime + +# create ipython profile to so that itango doesn't fail if ipython hasn't run yet +RUN ipython profile create +#RUN python3 -m pip install --user pytest-forked +ENV PATH=/home/tango/.local/bin:$PATH +#install csp-lmc-common with dependencies +RUN python3 -m pip install -e . --user --extra-index-url https://nexus.engageska-portugal.pt/repository/pypi/simple + +CMD ["/venv/bin/python", "/app/cspse/lmc/SubElementMaster.py" ] diff --git a/docker/Makefile b/docker/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..540912c95d020cc24b529552240d9d024f54ffbb --- /dev/null +++ b/docker/Makefile @@ -0,0 +1,197 @@ +# +# Project makefile for a Tango project. You should normally only need to modify +# DOCKER_REGISTRY_USER and PROJECT below. +# + +# +# DOCKER_REGISTRY_HOST, DOCKER_REGISTRY_USER and PROJECT are combined to define +# the Docker tag for this project. The definition below inherits the standard +# value for DOCKER_REGISTRY_HOST (=rnexus.engageska-portugal.pt) and overwrites +# DOCKER_REGISTRY_USER and PROJECT to give a final Docker tag of +# nexus.engageska-portugal.pt/tango-example/csplmc +# + +DOCKER_REGISTRY_USER:=ska-docker +PROJECT = csp-lmc-subelement + +# +# include makefile to pick up the standard Make targets, e.g., 'make build' +# build, 'make push' docker push procedure, etc. The other Make targets +# ('make interactive', 'make test', etc.) are defined in this file. +# +include .make/Makefile.mk + +# +# IMAGE_TO_TEST defines the tag of the Docker image to test +# +IMAGE_TO_TEST = $(DOCKER_REGISTRY_HOST)/$(DOCKER_REGISTRY_USER)/$(PROJECT):latest + +# +# CACHE_VOLUME is the name of the Docker volume used to cache eggs and wheels +# used during the test procedure. The volume is not used during the build +# procedure +# +CACHE_VOLUME = $(PROJECT)-test-cache + +# optional docker run-time arguments +DOCKER_RUN_ARGS = + +# +# Never use the network=host mode when running CI jobs, and add extra +# distinguishing identifiers to the network name and container names to +# prevent collisions with jobs from the same project running at the same +# time. +# +ifneq ($(CI_JOB_ID),) +NETWORK_MODE := tangonet-$(CI_JOB_ID) +CONTAINER_NAME_PREFIX := $(PROJECT)-$(CI_JOB_ID)- +else +CONTAINER_NAME_PREFIX := $(PROJECT)- +endif + +COMPOSE_FILES := $(wildcard *.yml) +COMPOSE_FILE_ARGS := $(foreach yml,$(COMPOSE_FILES),-f $(yml)) + +ifeq ($(OS),Windows_NT) + $(error Sorry, Windows is not supported yet) +else + UNAME_S := $(shell uname -s) + ifeq ($(UNAME_S),Linux) + DISPLAY ?= :0.0 + NETWORK_MODE ?= host + XAUTHORITY_MOUNT := /tmp/.X11-unix:/tmp/.X11-unix + XAUTHORITY ?= /hosthome/.Xauthority + # /bin/sh (=dash) does not evaluate 'docker network' conditionals correctly + SHELL := /bin/bash + endif + ifeq ($(UNAME_S),Darwin) + IF_INTERFACE := $(shell netstat -nr | awk '{ if ($$1 ~/default/) { print $$6} }') + DISPLAY := $(shell ifconfig $(IF_INTERFACE) | awk '{ if ($$1 ~/inet$$/) { print $$2} }'):0 + # network_mode = host doesn't work on MacOS, so fix to the internal network + NETWORK_MODE := tangonet + XAUTHORITY_MOUNT := $(HOME):/hosthome:ro + XAUTHORITY := /hosthome/.Xauthority + endif +endif + +# +# When running in network=host mode, point devices at a port on the host +# machine rather than at the container. +# +ifeq ($(NETWORK_MODE),host) +TANGO_HOST := $(shell hostname):10000 +MYSQL_HOST := $(shell hostname):3306 +else +# distinguish the bridge network from others by adding the project name +NETWORK_MODE := $(NETWORK_MODE)-$(PROJECT) +TANGO_HOST := $(CONTAINER_NAME_PREFIX)databaseds:10000 +MYSQL_HOST := $(CONTAINER_NAME_PREFIX)tangodb:3306 +endif + + +DOCKER_COMPOSE_ARGS := DISPLAY=$(DISPLAY) XAUTHORITY=$(XAUTHORITY) TANGO_HOST=$(TANGO_HOST) \ + NETWORK_MODE=$(NETWORK_MODE) XAUTHORITY_MOUNT=$(XAUTHORITY_MOUNT) MYSQL_HOST=$(MYSQL_HOST) \ + DOCKER_REGISTRY_HOST=$(DOCKER_REGISTRY_HOST) DOCKER_REGISTRY_USER=$(DOCKER_REGISTRY_USER) \ + CONTAINER_NAME_PREFIX=$(CONTAINER_NAME_PREFIX) COMPOSE_IGNORE_ORPHANS=true + +# +# Defines a default make target so that help is printed if make is called +# without a target +# +.DEFAULT_GOAL := help + +# +# defines a function to copy the ./test-harness directory into the container +# and then runs the requested make target in the container. The container is: +# +# 1. attached to the network of the docker-compose test system +# 2. uses a persistent volume to cache Python eggs and wheels so that fewer +# downloads are required +# 3. uses a transient volume as a working directory, in which untarred files +# and test output can be written in the container and subsequently copied +# to the host +# +make = tar -c test-harness/ | \ + docker run -i --rm --network=$(NETWORK_MODE) \ + -e TANGO_HOST=$(TANGO_HOST) \ + -v $(CACHE_VOLUME):/home/tango/.cache \ + -v /build -w /build -u tango $(DOCKER_RUN_ARGS) $(IMAGE_TO_TEST) \ + bash -c "sudo chown -R tango:tango /build && \ + tar x --strip-components 1 --warning=all && \ + make TANGO_HOST=$(TANGO_HOST) $1" + +test: DOCKER_RUN_ARGS = --volumes-from=$(BUILD) +test: build up ## test the application + @echo "BUILD: $(BUILD)" + $(INIT_CACHE) + $(call make,test); \ + status=$$?; \ + rm -fr build; \ + #docker-compose $(COMPOSE_FILE_ARGS) logs; + docker cp $(BUILD):/build .; \ + docker rm -f -v $(BUILD); \ + $(MAKE) down; \ + exit $$status + +lint: DOCKER_RUN_ARGS = --volumes-from=$(BUILD) +lint: build up ## lint the application (static code analysis) + $(INIT_CACHE) + $(call make,lint); \ + status=$$?; \ + docker cp $(BUILD):/build .; \ + $(MAKE) down; \ + exit $$status + +pull: ## download the application image + docker pull $(IMAGE_TO_TEST) + +up: build ## start develop/test environment +ifneq ($(NETWORK_MODE),host) + docker network inspect $(NETWORK_MODE) &> /dev/null || ([ $$? -ne 0 ] && docker network create $(NETWORK_MODE)) +endif + #$(DOCKER_COMPOSE_ARGS) docker-compose $(COMPOSE_FILE_ARGS) pull + #to pull only the mid-cbf-mcs image remove comment on row below. + #docker pull $(DOCKER_REGISTRY_HOST)/$(DOCKER_REGISTRY_USER)/mid-cbf-mcs:latest + $(DOCKER_COMPOSE_ARGS) docker-compose -f se-tangodb.yml up -d + # put a sleep to wait TANGO DB + @sleep 10 + $(DOCKER_COMPOSE_ARGS) docker-compose $(COMPOSE_FILE_ARGS) up -d + +piplock: build ## overwrite Pipfile.lock with the image version + docker run $(IMAGE_TO_TEST) cat /app/Pipfile.lock > $(CURDIR)/Pipfile.lock + +interactive: up +interactive: ## start an interactive session using the project image (caution: R/W mounts source directory to /app) + docker run --rm -it -p 3000:3000 --name=$(CONTAINER_NAME_PREFIX)dev -e TANGO_HOST=$(TANGO_HOST) --network=$(NETWORK_MODE) \ + -v $(CURDIR):/app $(IMAGE_TO_TEST) /bin/bash + +down: ## stop develop/test environment and any interactive session + docker ps | grep $(CONTAINER_NAME_PREFIX)dev && docker stop $(PROJECT)-dev || true + $(DOCKER_COMPOSE_ARGS) docker-compose $(COMPOSE_FILE_ARGS) down +ifneq ($(NETWORK_MODE),host) + docker network inspect $(NETWORK_MODE) &> /dev/null && ([ $$? -eq 0 ] && docker network rm $(NETWORK_MODE)) || true +endif + +dsconfigdump: up ## dump the entire configuration to the file dsconfig.json + docker exec -it $(CONTAINER_NAME_PREFIX)dsconfigdump python -m dsconfig.dump + docker exec -it $(CONTAINER_NAME_PREFIX)dsconfigdump python -m dsconfig.dump > dsconfig.json + +dsconfigadd: up ## Add a configuration json file (environment variable DSCONFIG_JSON_FILE) to the database + -docker exec -it $(CONTAINER_NAME_PREFIX)dsconfigdump json2tango -u -w -a $(DSCONFIG_JSON_FILE) + +dsconfigcheck: up ## check a json file (environment variable DSCONFIG_JSON_FILE) according to the project lib-maxiv-dsconfig json schema + -docker exec -it $(CONTAINER_NAME_PREFIX)dsconfigdump json2tango -a $(DSCONFIG_JSON_FILE) + +help: ## show this help. + @grep -hE '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' + +.PHONY: all test up down help + +# Creates Docker volume for use as a cache, if it doesn't exist already +INIT_CACHE = \ + docker volume ls | grep $(CACHE_VOLUME) || \ + docker create --name $(CACHE_VOLUME) -v $(CACHE_VOLUME):/cache $(IMAGE_TO_TEST) + +# http://cakoose.com/wiki/gnu_make_thunks +BUILD_GEN = $(shell docker create -v /build $(IMAGE_TO_TEST)) +BUILD = $(eval BUILD := $(BUILD_GEN))$(BUILD) diff --git a/docker/config/csplmc_dsconfig.json b/docker/config/csplmc_dsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..83dbae68ba3d9bf32fe5e2e589b86ba3bf171144 --- /dev/null +++ b/docker/config/csplmc_dsconfig.json @@ -0,0 +1,240 @@ +{ + "servers": { + "CspSubElementMaster": { + "master": { + "CspSubElementMaster": { + "subelement/sub_elt/master": { + "attribute_properties": { + "adminMode": { + "abs_change": [ + "-1", + "1" + ], + "__value": [ + "0" + ] + }, + "healthState": { + "abs_change": [ + "-1", + "1" + ] + } + }, + "properties": { + "Rack": [ + "subelement/rack/01", + "subelement/rack/02", + "subelement/rack/03", + "subelement/rack/04" + ], + "polled_attr": [ + "healthstate", + "1000", + "adminmode", + "1000", + "state", + "1000", + "oncommandprogress", + "2000", + "offcommandprogress", + "2000", + "standbycommandprogress", + "2000", + "oncmdtimeoutexpired", + "1000", + "offcmdtimeoutexpired", + "1000", + "standbycmdtimeoutexpired", + "1000", + "oncmdfailure", + "1000", + "offcmdfailure", + "1000", + "standbycmdfailure", + "1000" + ] + } + } + } + } + }, + "CspCapabilityMonitor": { + "searchbeams": { + "CspCapabilityMonitor": { + "subelement/capability/pss_pipeline_monitor": { + "attribute_properties": { + "adminMode": { + "__value": [ + "0" + ] + } + }, + "properties": { + "CapabilityDevices": [ + "subelement/pipelines/0001", + "subelement/pipelines/0002", + "subelement/pipelines/0003" + ] + } + } + } + }, + "timingbeams": { + "CspCapabilityMonitor": { + "subelement/capability/pstbeams_monitor": { + "attribute_properties": { + "adminMode": { + "__value": [ + "0" + ] + } + }, + "properties": { + "CapabilityDevices": [ + "subelement/pstbeam/01", + "subelement/pstbeam/02", + "subelement/pstbeam/03" + ] + } + } + } + }, + "vlbibeams": { + "CspCapabilityMonitor": { + "subelement/capability/vlbi_beams_monitor": { + "attribute_properties": { + "adminMode": { + "__value": [ + "0" + ] + } + }, + "properties": { + "CapabilityDevices": [ + "subelement/vlbi_beam/01", + "subelement/vlbi_beam/02", + "subelement/vlbi_beam/03" + ] + } + } + } + } + }, + "CspSubElementSubarray": { + "subarray1": { + "CspSubElementSubarray": { + "subelement/sub_elt/subarray_01": { + "attribute_properties": { + "adminMode": { + "abs_change": [ + "-1", + "1" + ], + "__value": [ + "0" + ] + }, + "healthState": { + "abs_change": [ + "-1", + "1" + ] + }, + "obsState": { + "abs_change": [ + "-1", + "1" + ] + } + }, + "properties": { + "SubID": [ + "1" + ], + "polled_attr": [ + "state", + "1000", + "healthstate", + "1000", + "adminmode", + "1000", + "obsstate", + "1000", + "obsmode", + "1000" + ] + } + } + } + }, + "subarray2": { + "SubElementSubarray": { + "subelement/sub_elt/subarray_02": { + "attribute_properties": { + "adminMode": { + "abs_change": [ + "-1", + "1" + ], + "__value": [ + "0" + ] + }, + "healthState": { + "abs_change": [ + "-1", + "1" + ] + }, + "obsState": { + "abs_change": [ + "-1", + "1" + ] + } + }, + "properties": { + "SubID": [ + "2" + ], + "polled_attr": [ + "state", + "1000", + "healthstate", + "1000", + "adminmode", + "1000", + "obsstate", + "1000", + "obsmode", + "1000" + ] + } + } + } + } + }, + "DataBaseds": { + "2": { + "DataBase": { + "sys/database/2": {} + } + } + }, + "TangoAccessControl": { + "1": { + "TangoAccessControl": { + "sys/access_control/1": {} + } + } + }, + "TangoTest": { + "test": { + "TangoTest": { + "sys/tg_test/1": {} + } + } + } + } +} diff --git a/docker/se-lmc.yml b/docker/se-lmc.yml new file mode 100644 index 0000000000000000000000000000000000000000..af6db57a2492da01ab2e6d467551c0db3822d105 --- /dev/null +++ b/docker/se-lmc.yml @@ -0,0 +1,67 @@ +# +# Docker compose file for TANGO database and database device server +# +# Defines: +# - tangodb: MariaDB database with TANGO schema +# - databaseds: TANGO database device server +# - rsyslog-csplmc: rsyslog service for logger +# - cspmaster: CspMaster device +# +# Requires: +# - None +# +version: '2.2' + +services: + se_dsconfig: + image: nexus.engageska-portugal.pt/ska-docker/tango-dsconfig:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}se_dsconfig + depends_on: + - databaseds + environment: + - TANGO_HOST=${TANGO_HOST} + command: > + sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=60 --strict -- + json2tango -w -a -u data/config/csplmc_dsconfig.json && sleep infinity" + volumes: + - .:/data + + sesubarray01: + image: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}/csp-lmc-subelement:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}sesubarray01 + depends_on: + - se_dsconfig + - semaster + environment: + - TANGO_HOST=${TANGO_HOST} + command: > + sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=30 --strict -- + retry --max=5 -- tango_admin --ping-device subelement/sub_elt/master &&\ + /venv/bin/python -m cspse.lmc.SubElementSubarray subarray1" + sesubarray02: + image: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}/csp-lmc-subelement:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}sesubarray02 + depends_on: + - se_dsconfig + - semaster + environment: + - TANGO_HOST=${TANGO_HOST} + command: > + sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=30 --strict -- + retry --max=5 -- tango_admin --ping-device subelement/sub_elt/master &&\ + /venv/bin/python -m cspse.lmc.SubElementSubarray subarray2" + + semaster: + image: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}/csp-lmc-subelement:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}semaster + depends_on: + - se_dsconfig + environment: + - TANGO_HOST=${TANGO_HOST} + command: > + sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=30 --strict -- CspSubElementMaster master" + diff --git a/docker/se-tangodb.yml b/docker/se-tangodb.yml new file mode 100644 index 0000000000000000000000000000000000000000..72090df60df3c46b64a78aa810ee6c5b07ca5629 --- /dev/null +++ b/docker/se-tangodb.yml @@ -0,0 +1,50 @@ +# +# Docker compose file for TANGO database and database device server +# +# Defines: +# - tangodb: MariaDB database with TANGO schema +# - databaseds: TANGO database device server +# +# Requires: +# - None +# +version: '2.2' +volumes: + se-tangodb: {} + +services: + tangodb: + image: nexus.engageska-portugal.pt/ska-docker/tango-db:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}tangodb + environment: + - MYSQL_ROOT_PASSWORD=secret + - MYSQL_DATABASE=tango + - MYSQL_USER=tango + - MYSQL_PASSWORD=tango + volumes: + - se-tangodb:/var/lib/mysql + + databaseds: + image: nexus.engageska-portugal.pt/ska-docker/tango-cpp:latest + depends_on: + - tangodb + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}databaseds + environment: + - MYSQL_HOST=${MYSQL_HOST} + - MYSQL_DATABASE=tango + - MYSQL_USER=tango + - MYSQL_PASSWORD=tango + - TANGO_HOST=${TANGO_HOST} + entrypoint: + - /usr/local/bin/wait-for-it.sh + - ${MYSQL_HOST} + - --timeout=70 + - --strict + - -- + - /usr/local/bin/DataBaseds + - "2" + - -ORBendPoint + - giop:tcp::10000 + diff --git a/docker/test-harness/Makefile b/docker/test-harness/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f951fe00248c44767e0e81434564b7c0f5f6512d --- /dev/null +++ b/docker/test-harness/Makefile @@ -0,0 +1,31 @@ +# Use bash shell with pipefail option enabled so that the return status of a +# piped command is the value of the last (rightmost) commnand to exit with a +# non-zero status. This lets us pipe output into tee but still exit on test +# failures. +SHELL = /bin/bash +.SHELLFLAGS = -o pipefail -c + +all: test lint + +# wait for the device to be available before beginning the test +# A temporary volume is mounted at /build when 'make test' is executing. +# The following steps copy across useful output to this volume which can +# then be extracted to form the CI summary for the test procedure. +test: + # option -k 'dir_name' excludes 'dir_name' contents + cd /app && python setup.py test | tee setup_py_test.stdout + mkdir -p /build/reports && \ + if [ -d /build ]; then \ + mv /app/setup_py_test.stdout /build/csp-lmc-subelement-setup-test.stdout; \ + mv /app/htmlcov /build/csp-lmc-subelement_htmlcov; \ + mv /app/build/reports/csp-lmc-subelement-unit-tests.xml /build/reports; \ + mv /app/coverage.xml /build; \ + fi; +lint: + pip3 install pylint2junit; \ + mkdir -p /build/reports; \ + cd /app && pylint --output-format=parseable csp_lmc_common | tee /build/csp-lmc-subelement-code-analysis.stdout; \ + cd /app && pylint --output-format=pylint2junit.JunitReporter cspse/lmc > /build/reports/csp-lmc-subelement-linting.xml; + +.PHONY: all test lint + diff --git a/docker/test-harness/README.md b/docker/test-harness/README.md new file mode 100644 index 0000000000000000000000000000000000000000..a3c9a496bbd5104392d08378de98af67f349183f --- /dev/null +++ b/docker/test-harness/README.md @@ -0,0 +1,3 @@ +This directory is uploaded to the container when 'make test' is executed. Files +in this directory will be found inside /build once uploaded to the container. + diff --git a/setup.cfg b/setup.cfg index 428ca67b3a5faefd4367cd0cd16a75311aee9d45..90ecf5789f9198495ae56daa35e81460c6f240bf 100644 --- a/setup.cfg +++ b/setup.cfg @@ -11,8 +11,16 @@ source = cspse [tool:pytest] testpaths = tests -addopts = --cov --json-report --json-report-file=htmlcov/report.json --cov-report term --cov-report html --cov-report xml --pylint --pylint-error-types=EF --junitxml=./build/reports/unit-tests.xml +addopts = --cov=cspse + --json-report + --json-report-file=htmlcov/report.json + --cov-report=term + --cov-report=html + --cov-report=xml + --junitxml=build/reports/csp-lmc-subelement-unit-tests.xml +junit_family=legacy +console_output_style = progress # Define `python setup.py build_sphinx` [build_sphinx] source-dir = docs diff --git a/setup.py b/setup.py index 0f0f99b65bf5829eea247102e0b000f28d65f84a..25947e60b6af751f95f34c693e69441b56e50bae 100644 --- a/setup.py +++ b/setup.py @@ -1,16 +1,25 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -from setuptools import setup +import os +import sys +from setuptools import setup, find_packages + +setup_dir = os.path.dirname(os.path.abspath(__file__)) + +# make sure we use latest info from local code +sys.path.insert(0, setup_dir) + +INFO = {} with open('README.md') as readme_file: - readme = readme_file.read() + long_description = readme_file.read() RELEASE_FILENAME = os.path.join(setup_dir, 'cspse','lmc','release.py') exec(open(RELEASE_FILENAME).read(), INFO) setup( - name=INFO['name'] - version=INFO['version'] + name=INFO['name'], + version=INFO['version'], description=INFO['description'], author=INFO['author'], author_email=INFO['author_email'], @@ -20,7 +29,6 @@ setup( long_description=long_description, keywords="csp lmc ska tango", include_package_data=True, - license="BSD license", zip_safe=False, classifiers=[ 'Development Status :: 3 - Alpha', @@ -34,7 +42,7 @@ setup( install_requires=[ 'pytango >=9.3.1', 'future', - 'lmcbaseclasses > 0.5.0', + 'csp-lmc-common > 0.5.0', ], setup_requires=[ # dependency for `python setup.py test` @@ -50,6 +58,11 @@ setup( 'pycodestyle', 'mock' ], + entry_points={ + "console_scripts": [ + "CspSubElementMaster=cspse.lmc.subelement_master:main", + ] + }, extras_require={ 'dev': ['prospector[with_pyroma]', 'yapf', 'isort'], }