diff --git a/.gitignore b/.gitignore index 7f249738c56e97da80aaecaebb99c528eba78d3a..60c6519f7724a7ca08cac3263b595400dba9fdd2 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,8 @@ **/.project **/.pydevproject **/.settings/org.eclipse.core.resources.prefs +tangostationcontrol/dist +tangostationcontrol/build +**/.ipynb_checkpoints +**/pending_log_messages.db +**/.eggs diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0371a7f7f806a9a6e9ac5c22d8c5562c6880a4eb..27593ca877e544634c42b303a1dc3d756df4cb41 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -2,10 +2,8 @@ # images is in place. image: artefact.skao.int/ska-tango-images-tango-itango:9.3.5 variables: + GIT_SUBMODULE_STRATEGY: recursive PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip" - # The PBR dependency requires a set version, not actually used - # Instead `util/lofar_git.py:get_version()` is used. - PBR_VERSION: "0.1" cache: paths: - .cache/pip @@ -15,21 +13,29 @@ stages: - static-analysis - unit-tests - integration-tests + - packaging newline_at_eof: - stage: linting - before_script: - - pip3 install -r devices/test-requirements.txt - script: - - flake8 --filename *.sh,*.conf,*.md,*.yml --select=W292 --exclude .tox,.egg-info,docker + stage: linting + before_script: + - pip3 install -r tangostationcontrol/test-requirements.txt + script: +# TODO(Corne): Ignore shell files in submodules more cleanly + - flake8 --filename *.sh,*.conf,*.md,*.yml --select=W292 --exclude docker-compose/tango-prometheus-exporter,.tox,.egg-info,docker python_linting: stage: linting + before_script: + - sudo apt-get update + - sudo apt-get install -y git script: - - cd devices + - cd tangostationcontrol - tox -e pep8 bandit: stage: static-analysis + before_script: + - sudo apt-get update + - sudo apt-get install -y git script: - - cd devices + - cd tangostationcontrol - tox -e bandit shellcheck: stage: static-analysis @@ -37,6 +43,7 @@ shellcheck: - sudo apt-get update - sudo apt-get install -y shellcheck script: +# TODO(Corne): Ignore shell files in submodules - shellcheck **/*.sh unit_test: stage: unit-tests @@ -44,29 +51,47 @@ unit_test: - sudo apt-get update - sudo apt-get install -y git script: - - cd devices - - tox --recreate -e py37 -integration_test: + - cd tangostationcontrol + - tox -e py37 +integration_test_docker: stage: integration-tests - allow_failure: true + image: docker:latest tags: - privileged services: - - name: docker:20.10.8-dind + - name: docker: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 + - apk add --update make bash docker-compose + - apk add --update bind-tools + - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY + script: + - touch /root/.Xauthority +# Hack BASH_SOURCE into sourced files, docker its sh shell won't set this + - export BASH_SOURCE=$(pwd)/bootstrap/etc/lofar20rc.sh +# Hack HOSTNAME env variable into host.docker.internal, set in docker-compose + - export HOSTNAME=host.docker.internal +# - export HOSTNAME=$(hostname -i) +# - export HOSTNAME=$(cat /run/systemd/netif/leases/2 | grep ^ADDRESS= | awk -F'=' '{print $2}') +# source the lofarrc file and mask its non zero exit code + - . bootstrap/etc/lofar20rc.sh || true +# TANGO_HOST must be unset our databaseds will be unreachable + - unset TANGO_HOST +# Allow integration test to execute + - chmod u+x $CI_PROJECT_DIR/sbin/run_integration_test.sh +# Do not remove 'bash' or statement will be ignored by primitive docker shell + - bash $CI_PROJECT_DIR/sbin/run_integration_test.sh +wheel_packaging: + stage: packaging + artifacts: + paths: + - tangostationcontrol/dist/*.whl + before_script: + - sudo apt-get update + - sudo apt-get install -y git + - pip3 install -r tangostationcontrol/test-requirements.txt + - pip3 install -r docker-compose/itango/lofar-requirements.txt 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 + - cd tangostationcontrol + - python setup.py bdist_wheel diff --git a/CDB/stations/DTS_ConfigDb.json b/CDB/stations/DTS_ConfigDb.json index 685a3d62da82e40aa05ea409c20f2475e3472ea5..48f333e2b01a05a9b2ae700cedee61e5fb396579 100644 --- a/CDB/stations/DTS_ConfigDb.json +++ b/CDB/stations/DTS_ConfigDb.json @@ -63,7 +63,7 @@ "LTS/SDP/1": { "properties": { "OPC_Server_Name": [ - "dop36.astron.nl" + "10.99.0.252" ], "OPC_Server_Port": [ "4840" @@ -100,7 +100,7 @@ "LTS/SST/1": { "properties": { "OPC_Server_Name": [ - "dop36.astron.nl" + "10.99.0.252" ], "OPC_Server_Port": [ "4840" @@ -127,22 +127,22 @@ "0c:c4:7a:c0:30:f1" ], "FPGA_sst_offload_hdr_ip_destination_address_RW_default": [ - "10.99.0.1", - "10.99.0.1", - "10.99.0.1", - "10.99.0.1", - "10.99.0.1", - "10.99.0.1", - "10.99.0.1", - "10.99.0.1", - "10.99.0.1", - "10.99.0.1", - "10.99.0.1", - "10.99.0.1", - "10.99.0.1", - "10.99.0.1", - "10.99.0.1", - "10.99.0.1" + "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" ] } } @@ -155,7 +155,7 @@ "LTS/XST/1": { "properties": { "OPC_Server_Name": [ - "dop36.astron.nl" + "10.99.0.252" ], "OPC_Server_Port": [ "4840" @@ -182,22 +182,22 @@ "0c:c4:7a:c0:30:f1" ], "FPGA_xst_offload_hdr_ip_destination_address_RW_default": [ - "10.99.0.1", - "10.99.0.1", - "10.99.0.1", - "10.99.0.1", - "10.99.0.1", - "10.99.0.1", - "10.99.0.1", - "10.99.0.1", - "10.99.0.1", - "10.99.0.1", - "10.99.0.1", - "10.99.0.1", - "10.99.0.1", - "10.99.0.1", - "10.99.0.1", - "10.99.0.1" + "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" ] } } diff --git a/CDB/stations/LTS_ConfigDb.json b/CDB/stations/LTS_ConfigDb.json index 672ff0210a9bad8ed6c48db2f648393b8cee0069..6cacf3eb75ddd1ba85097b91b18eec66783834bd 100644 --- a/CDB/stations/LTS_ConfigDb.json +++ b/CDB/stations/LTS_ConfigDb.json @@ -1,49 +1,5 @@ { "servers": { - "APSCT": { - "LTS": { - "APSCT": { - "LTS/APSCT/1": { - "properties": { - "OPC_Server_Name": [ - "ltspi.astron.nl" - ], - "OPC_Server_Port": [ - "4842" - ], - "OPC_Time_Out": [ - "5.0" - ], - "OPC_Node_Path_prefix": [ - "PCC" - ] - } - } - } - } - }, - "APSPU": { - "LTS": { - "APSPU": { - "LTS/APSPU/1": { - "properties": { - "OPC_Server_Name": [ - "ltspi.astron.nl" - ], - "OPC_Server_Port": [ - "4842" - ], - "OPC_Time_Out": [ - "5.0" - ], - "OPC_Node_Path_prefix": [ - "PCC" - ] - } - } - } - } - }, "RECV": { "LTS": { "RECV": { @@ -53,10 +9,9 @@ "ltspi.astron.nl" ], "OPC_Server_Port": [ - "4842" + "4840" ], "OPC_Node_Path_prefix": [ - "PCC" ], "OPC_Time_Out": [ "5.0" @@ -72,7 +27,7 @@ "LTS/SDP/1": { "properties": { "OPC_Server_Name": [ - "dop36.astron.nl" + "dop369.astron.nl" ], "OPC_Server_Port": [ "4840" @@ -115,7 +70,7 @@ "5101" ], "OPC_Server_Name": [ - "dop36.astron.nl" + "dop369.astron.nl" ], "OPC_Server_Port": [ "4840" @@ -194,7 +149,7 @@ "5102" ], "OPC_Server_Name": [ - "dop36.astron.nl" + "dop369.astron.nl" ], "OPC_Server_Port": [ "4840" @@ -260,28 +215,6 @@ } } } - }, - "UNB2": { - "LTS": { - "UNB2": { - "LTS/UNB2/1": { - "properties": { - "OPC_Server_Name": [ - "despi.astron.nl" - ], - "OPC_Server_Port": [ - "4842" - ], - "OPC_Node_Path_prefix": [ - "PCC" - ], - "OPC_Time_Out": [ - "5.0" - ] - } - } - } - } } } } diff --git a/CDB/stations/simulators_configDb.json b/CDB/stations/simulators_ConfigDb.json similarity index 100% rename from CDB/stations/simulators_configDb.json rename to CDB/stations/simulators_ConfigDb.json diff --git a/bin/dump_ConfigDb.sh b/bin/dump_ConfigDb.sh index 7745c18482000fe2e7a726e27b6fa5eeae57e88e..0dc634c458b76cd5d3c13e2d7dab6e905f66248a 100755 --- a/bin/dump_ConfigDb.sh +++ b/bin/dump_ConfigDb.sh @@ -1,4 +1,4 @@ #!/bin/bash -# writes the JSON dump to stdout -docker exec -it dsconfig python -m dsconfig.dump +# writes the JSON dump to stdout, Do not change -i into -it incompatible with gitlab ci! +docker exec -i "${CONTAINER_NAME_PREFIX}"dsconfig python -m dsconfig. diff --git a/bin/itango_console.sh b/bin/itango_console.sh index fb4c9b8a285adca3211633fb89e6e9e59bd01087..c2474781787257c6ab3ee0656659415f09380b29 100755 --- a/bin/itango_console.sh +++ b/bin/itango_console.sh @@ -1,2 +1,2 @@ #!/bin/bash -exec docker exec -it itango itango3 +exec docker exec -it "${CONTAINER_NAME_PREFIX}"itango itango3 diff --git a/bin/itango_shell.sh b/bin/itango_shell.sh index abab9ef8515fd5ce1a1bf2d6d452a538426a499a..334953de3cca29ff459f6c861637c0859b1da97b 100755 --- a/bin/itango_shell.sh +++ b/bin/itango_shell.sh @@ -1,2 +1,2 @@ #!/bin/bash -exec docker exec -it itango /bin/bash +exec docker exec -it "${CONTAINER_NAME_PREFIX}"itango /bin/bash diff --git a/bin/start-DS.sh b/bin/start-DS.sh deleted file mode 100755 index 83a6eec6dd30f2e496fa03ffc6f7351d8e9a664d..0000000000000000000000000000000000000000 --- a/bin/start-DS.sh +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/bash -function help() -{ - why="${1}" - echo -e "*** Cannot start the Python device server.\\n${why}\\n\\n* The Python file for the device server must be the 1st parameter that is provided.\\n* The instance of this device server must be the 2nd parameter that is provided." - exit -1 -} - -# Check if the mandatory parameters are present: -# ${1}: device server's Python file -# ${2}: instance of the device server's executable in the configDB -case ${#} in - 0) - help "The device server's Python file and the instance are missing." - ;; - 1) - help "The device server's instance is missing." - ;; - *) - deviceServer="${1}" - shift - instance="${1}" - shift - ;; -esac - -# Find the path to the device server's Python file that is -# relative to the /hosthome directory (in Docker the user's -# mounted ${HOME}). -# ATTENTION -# This is assuming that the device server's Python file exists -# on the Docker's host in the user's ${HOME} directory. -runThis=$(basename "${deviceServer}") -runThis=${runThis//.sh/.py} -if [ -f "${runThis}" ]; then - myDir=${PWD} -else - myDir=${PWD}/$(dirname "${deviceServer}") -fi -deviceServerPath=${myDir/${HOME}/\/hosthome} - -# Tango log lines start with a UNIX timestamp. Replace them with the UTC time. -docker exec -it itango python3 "${deviceServerPath}/${runThis}" "${instance}" "${@}" | perl -ne 'use Time::Piece; s/^([0-9]+)/gmtime($1)->strftime("%F %T")/e; print;' diff --git a/bin/start-ds.sh b/bin/start-ds.sh new file mode 100755 index 0000000000000000000000000000000000000000..e7fab7e9331b4512f9caf13bb9096146605fd4d9 --- /dev/null +++ b/bin/start-ds.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +# Serves as entrypoint script for docker containers + +# Check required support file exists +if [[ ! -f "/usr/local/bin/wait-for-it.sh" ]]; then + >&2 echo "/usr/local/bin/wait-for-it.sh file does not exist!" + exit 1 +fi + +# Check required environment variable is set +if [[ ! $TANGO_HOST ]]; then + >&2 echo "TANGO_HOST environment variable unset!" + exit 1 +fi + +# Check if configured for specific version +if [[ $TANGOSTATIONCONTROL ]]; then + # TODO (Corne): Download version from artifacts or pypi. + # Consider exit 2 an UnImplementedError + exit 2 +else + # Install the package, exit 1 if it fails + cd tangostationcontrol || exit 1 + mkdir -p /tmp/tangostationcontrol + python3 setup.py build --build-base /tmp/tangostationcontrol egg_info --egg-base /tmp/tangostationcontrol bdist_wheel --dist-dir /tmp/tangostationcontrol || exit 1 + # shellcheck disable=SC2012 + sudo pip install "$(ls -Art /tmp/tangostationcontrol/*.whl | tail -n 1)" +fi + +/usr/local/bin/wait-for-it.sh "$TANGO_HOST" --timeout=30 --strict -- "$@" diff --git a/bootstrap/etc/lofar20rc.sh b/bootstrap/etc/lofar20rc.sh index 9a9dd658b56f5d30bb1ff8c5de692bd8fe2164de..6e4a5c9bc8d6a78c1b61cca02159ee01291d3805 100755 --- a/bootstrap/etc/lofar20rc.sh +++ b/bootstrap/etc/lofar20rc.sh @@ -16,6 +16,14 @@ if [ ! -f "${LOFAR20_DIR}/.git/hooks/post-checkout" ]; then alias git="cp ${LOFAR20_DIR}/bin/update_submodules.sh ${LOFAR20_DIR}/.git/hooks/post-checkout; cp ${LOFAR20_DIR}/bin/update_submodules.sh ${LOFAR20_DIR}/.git/hooks/post-merge; unalias git; git" fi +if [ ! -z ${CI_BUILD_ID+x} ]; then + export CONTAINER_NAME_PREFIX=${CI_BUILD_ID}- +elif [ ! -z ${CI_JOB_ID+x} ]; then + export CONTAINER_NAME_PREFIX=${CI_JOB_ID}- +else + unset CONTAINER_NAME_PREFIX +fi + # This needs to be modified for a development environment. # In case you run multiple Docker networks on the same host in parallel, you need to specify a unique # network name for each of them. @@ -26,7 +34,6 @@ export NETWORK_MODE=tangonet # Example: export TANGO_HOST=station-xk25.astron.nl:10000 export TANGO_HOST=$(hostname):10000 - # # NO MODIFICATION BEYOND THIS POINT! # diff --git a/devices/.stestr.conf b/devices/.stestr.conf deleted file mode 100644 index 07147c8697683f270e9388da8b914c20cb8e4c45..0000000000000000000000000000000000000000 --- a/devices/.stestr.conf +++ /dev/null @@ -1,3 +0,0 @@ -[DEFAULT] -test_path=${TESTS_DIR:-./test} -top_dir=./ diff --git a/devices/LICENSE.txt b/devices/LICENSE.txt deleted file mode 100644 index c9978b8eee263aebfdd8d0a016e447940682ba8b..0000000000000000000000000000000000000000 --- a/devices/LICENSE.txt +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright 2021 ASTRON Netherlands Institute for Radio Astronomy - -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. diff --git a/devices/__init__.py b/devices/__init__.py deleted file mode 100644 index 82b2af0e96f75105253e501e47f8861218132f63..0000000000000000000000000000000000000000 --- a/devices/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -from util.lofar_git import get_version - -__version__ = get_version() - diff --git a/devices/common/lofar_git.py b/devices/common/lofar_git.py deleted file mode 100644 index f4f6217280fe612fa2e9a7830c1f026c1e36a815..0000000000000000000000000000000000000000 --- a/devices/common/lofar_git.py +++ /dev/null @@ -1,84 +0,0 @@ -import git # pip3 install gitpython -import os -from functools import lru_cache - -def get_repo(starting_directory: str = os.path.dirname(os.path.abspath(__file__))) -> git.Repo: - """ Try finding the repository by traversing up the tree. - - By default, the repository containing this module is returned. - """ - - directory = starting_directory - - try: - return git.Repo(directory) - except git.InvalidGitRepositoryError: - pass - - # We now have to traverse up the tree - while directory != "/" and os.path.exists(directory): - # Go to parent - directory = os.path.abspath(directory + os.path.sep + "..") - - try: - return git.Repo(directory) - except git.InvalidGitRepositoryError: - pass - - raise git.InvalidGitRepositoryError("Could not find git repository root in {}".format(starting_directory)) - - -@lru_cache(maxsize=None) -def get_version(repo: git.Repo = None) -> str: - """ Return a version string for the current commit. - - There is a practical issue: the repository changes over time, f.e. switching branches with 'git checkout'. We want - to know the version that is running in memory, not the one that is on disk. - - As a work-around, we cache the version information, in that it is at least consistent. It is up to the caller - to request the version early enough. - - The version string is one of: - - <tag> - - <branch> [<commit>] - - In both cases, a "*" prefix indicates this code is not production ready. Code is considered production ready if - it is a tag and there are no local modifications. - - """ - - if repo is None: - repo = get_repo() - - commit = repo.commit() - tags = {tag.commit: tag for tag in repo.tags} - - if commit in tags: - # a tag = production ready - commit_str = "{}".format(tags[commit]) - production_ready = True - elif repo.head.is_detached: - # no active branch - commit_str = "<detached HEAD> [{}]".format(commit) - production_ready = False - else: - # HEAD of a branch - branch = repo.active_branch - commit_str = "{} [{}]".format(branch, commit) - production_ready = False - - if repo.is_dirty(): - production_ready = False - - return "{}{}".format("*" if not production_ready else "", commit_str) - - -# at least cache the current repo version immediately -try: - _ = get_version() -except: - pass - - -if __name__ == "__main__": - print(get_version()) diff --git a/devices/devices/sdp/sdp.py b/devices/devices/sdp/sdp.py deleted file mode 100644 index 6cdfe9a2b2788f1b3466bbdb38a4ca5c83e9780f..0000000000000000000000000000000000000000 --- a/devices/devices/sdp/sdp.py +++ /dev/null @@ -1,192 +0,0 @@ -# -*- coding: utf-8 -*- -# -# This file is part of the SDP project -# -# -# -# Distributed under the terms of the APACHE license. -# See LICENSE.txt for more info. - -""" SDP Device Server for LOFAR2.0 - -""" - -# TODO(Corne): Remove sys.path.append hack once packaging is in place! -import os, sys -currentdir = os.path.dirname(os.path.realpath(__file__)) -parentdir = os.path.dirname(currentdir) -parentdir = os.path.dirname(parentdir) -sys.path.append(parentdir) - -# PyTango imports -from tango.server import run -from tango.server import device_property, attribute -from tango import AttrWriteType -# Additional import - -from clients.attribute_wrapper import attribute_wrapper -from devices.opcua_device import opcua_device - -from common.lofar_logging import device_logging_to_python, log_exceptions - -import numpy - -__all__ = ["SDP", "main"] - -@device_logging_to_python() -class SDP(opcua_device): - # ----------------- - # Device Properties - # ----------------- - - TR_fpga_mask_RW_default = device_property( - dtype='DevVarBooleanArray', - mandatory=False, - default_value=[True] * 16 - ) - - 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 - ) - - # If we enable the waveform generator, we want some sane defaults. - - FPGA_wg_amplitude_RW = device_property( - dtype='DevVarDoubleArray', - mandatory=False, - default_value=[[0.1] * 12] * 16 - ) - - FPGA_wg_frequency_RW = device_property( - dtype='DevVarDoubleArray', - mandatory=False, - # Emit a signal on subband 102 - default_value=[[102 * 200e6/1024] * 12] * 16 - ) - - FPGA_wg_phase_RW = device_property( - dtype='DevVarDoubleArray', - mandatory=False, - default_value=[[0.0] * 12] * 16 - ) - - FPGA_sdp_info_station_id_RW_default = device_property( - dtype='DevVarULongArray', - mandatory=False, - default_value=[0] * 16 - ) - - FPGA_subband_weights_RW_default = device_property( - dtype='DevVarULongArray', - mandatory=False, - default_value=[[8192] * 12 * 512] * 16 - ) - - first_default_settings = [ - # set the masks first, as those filter any subsequent settings - 'TR_fpga_mask_RW' - ] - - # ---------- - # Attributes - # ---------- - - FPGA_beamlet_output_enable_R = attribute_wrapper(comms_annotation=["2:FPGA_beamlet_output_enable_R"], datatype=numpy.bool_, dims=(16,)) - FPGA_beamlet_output_enable_RW = attribute_wrapper(comms_annotation=["2:FPGA_beamlet_output_enable_RW"], datatype=numpy.bool_, dims=(16,), access=AttrWriteType.READ_WRITE) - FPGA_beamlet_output_hdr_eth_destination_mac_R = attribute_wrapper(comms_annotation=["2:FPGA_beamlet_output_hdr_eth_destination_mac_R"], datatype=numpy.str, dims=(16,)) - FPGA_beamlet_output_hdr_eth_destination_mac_RW = attribute_wrapper(comms_annotation=["2:FPGA_beamlet_output_hdr_eth_destination_mac_RW"], datatype=numpy.str, dims=(16,), access=AttrWriteType.READ_WRITE) - FPGA_beamlet_output_hdr_ip_destination_address_R = attribute_wrapper(comms_annotation=["2:FPGA_beamlet_output_hdr_ip_destination_address_R"], datatype=numpy.str, dims=(16,)) - FPGA_beamlet_output_hdr_ip_destination_address_RW = attribute_wrapper(comms_annotation=["2:FPGA_beamlet_output_hdr_ip_destination_address_RW"], datatype=numpy.str, dims=(16,), access=AttrWriteType.READ_WRITE) - FPGA_beamlet_output_hdr_udp_destination_port_R = attribute_wrapper(comms_annotation=["2:FPGA_beamlet_output_hdr_udp_destination_port_R"], datatype=numpy.uint16, dims=(16,)) - FPGA_beamlet_output_hdr_udp_destination_port_RW = attribute_wrapper(comms_annotation=["2:FPGA_beamlet_output_hdr_udp_destination_port_RW"], datatype=numpy.uint16, dims=(16,), access=AttrWriteType.READ_WRITE) - FPGA_beamlet_output_scale_R = attribute_wrapper(comms_annotation=["2:FPGA_beamlet_output_scale_R"], datatype=numpy.uint32, dims=(16,)) - FPGA_beamlet_output_scale_RW = attribute_wrapper(comms_annotation=["2:FPGA_beamlet_output_scale_RW"], datatype=numpy.uint32, dims=(16,), access=AttrWriteType.READ_WRITE) - FPGA_firmware_version_R = attribute_wrapper(comms_annotation=["2:FPGA_firmware_version_R"], datatype=numpy.str, dims=(16,)) - FPGA_global_node_index_R = attribute_wrapper(comms_annotation=["2:FPGA_global_node_index_R"], datatype=numpy.uint32, dims=(16,)) - FPGA_hardware_version_R = attribute_wrapper(comms_annotation=["2:FPGA_hardware_version_R"], datatype=numpy.str, dims=(16,)) - FPGA_processing_enable_R = attribute_wrapper(comms_annotation=["2:FPGA_processing_enable_R"], datatype=numpy.bool_, dims=(16,)) - FPGA_processing_enable_RW = attribute_wrapper(comms_annotation=["2:FPGA_processing_enable_RW"], datatype=numpy.bool_, dims=(16,), access=AttrWriteType.READ_WRITE) - FPGA_scrap_R = attribute_wrapper(comms_annotation=["2:FPGA_scrap_R"], datatype=numpy.int32, dims=(8192,)) - FPGA_scrap_RW = attribute_wrapper(comms_annotation=["2:FPGA_scrap_RW"], datatype=numpy.int32, dims=(8192,), access=AttrWriteType.READ_WRITE) - FPGA_sdp_info_antenna_band_index_R = attribute_wrapper(comms_annotation=["2:FPGA_sdp_info_antenna_band_index_R"], datatype=numpy.uint32, dims=(16,)) - FPGA_sdp_info_block_period_R = attribute_wrapper(comms_annotation=["2:FPGA_sdp_info_block_period_R"], datatype=numpy.uint32, dims=(16,)) - FPGA_sdp_info_f_adc_R = attribute_wrapper(comms_annotation=["2:FPGA_sdp_info_f_adc_R"], datatype=numpy.uint32, dims=(16,)) - FPGA_sdp_info_fsub_type_R = attribute_wrapper(comms_annotation=["2:FPGA_sdp_info_fsub_type_R"], datatype=numpy.uint32, dims=(16,)) - FPGA_sdp_info_nyquist_sampling_zone_index_R = attribute_wrapper(comms_annotation=["2:FPGA_sdp_info_nyquist_sampling_zone_index_R"], datatype=numpy.uint32, dims=(16,)) - FPGA_sdp_info_nyquist_sampling_zone_index_RW = attribute_wrapper(comms_annotation=["2:FPGA_sdp_info_nyquist_sampling_zone_index_RW"], datatype=numpy.uint32, dims=(16,), access=AttrWriteType.READ_WRITE) - FPGA_sdp_info_observation_id_R = attribute_wrapper(comms_annotation=["2:FPGA_sdp_info_observation_id_R"], datatype=numpy.uint32, dims=(16,)) - FPGA_sdp_info_observation_id_RW = attribute_wrapper(comms_annotation=["2:FPGA_sdp_info_observation_id_RW"], datatype=numpy.uint32, dims=(16,), access=AttrWriteType.READ_WRITE) - FPGA_sdp_info_station_id_R = attribute_wrapper(comms_annotation=["2:FPGA_sdp_info_station_id_R"], datatype=numpy.uint32, dims=(16,)) - FPGA_sdp_info_station_id_RW = attribute_wrapper(comms_annotation=["2:FPGA_sdp_info_station_id_RW"], datatype=numpy.uint32, dims=(16,), access=AttrWriteType.READ_WRITE) - FPGA_subband_weights_R = attribute_wrapper(comms_annotation=["2:FPGA_subband_weights_R"], datatype=numpy.uint32, dims=(12 * 512, 16)) - FPGA_subband_weights_RW = attribute_wrapper(comms_annotation=["2:FPGA_subband_weights_RW"], datatype=numpy.uint32, dims=(12 * 512, 16), access=AttrWriteType.READ_WRITE) - FPGA_temp_R = attribute_wrapper(comms_annotation=["2:FPGA_temp_R"], datatype=numpy.float_, dims=(16,)) - FPGA_weights_R = attribute_wrapper(comms_annotation=["2:FPGA_weights_R"], datatype=numpy.int16, dims=(12 * 488 * 2, 16)) - FPGA_weights_RW = attribute_wrapper(comms_annotation=["2:FPGA_weights_RW"], datatype=numpy.int16, dims=(12 * 488 * 2, 16), access=AttrWriteType.READ_WRITE) - FPGA_wg_amplitude_R = attribute_wrapper(comms_annotation=["2:FPGA_wg_amplitude_R"], datatype=numpy.float_, dims=(12, 16)) - FPGA_wg_amplitude_RW = attribute_wrapper(comms_annotation=["2:FPGA_wg_amplitude_RW"], datatype=numpy.float_, dims=(12, 16), access=AttrWriteType.READ_WRITE) - FPGA_wg_enable_R = attribute_wrapper(comms_annotation=["2:FPGA_wg_enable_R"], datatype=numpy.bool_, dims=(12, 16)) - FPGA_wg_enable_RW = attribute_wrapper(comms_annotation=["2:FPGA_wg_enable_RW"], datatype=numpy.bool_, dims=(12, 16), access=AttrWriteType.READ_WRITE) - FPGA_wg_frequency_R = attribute_wrapper(comms_annotation=["2:FPGA_wg_frequency_R"], datatype=numpy.float_, dims=(12, 16)) - FPGA_wg_frequency_RW = attribute_wrapper(comms_annotation=["2:FPGA_wg_frequency_RW"], datatype=numpy.float_, dims=(12, 16), access=AttrWriteType.READ_WRITE) - FPGA_wg_phase_R = attribute_wrapper(comms_annotation=["2:FPGA_wg_phase_R"], datatype=numpy.float_, dims=(12, 16)) - FPGA_wg_phase_RW = attribute_wrapper(comms_annotation=["2:FPGA_wg_phase_RW"], datatype=numpy.float_, dims=(12, 16), access=AttrWriteType.READ_WRITE) - TR_fpga_mask_R = attribute_wrapper(comms_annotation=["2:TR_fpga_mask_R"], datatype=numpy.bool_, dims=(16,)) - TR_fpga_mask_RW = attribute_wrapper(comms_annotation=["2:TR_fpga_mask_RW"], datatype=numpy.bool_, dims=(16,), access=AttrWriteType.READ_WRITE) - TR_fpga_communication_error_R = attribute_wrapper(comms_annotation=["2:TR_fpga_communication_error_R"], datatype=numpy.bool_, dims=(16,)) - TR_sdp_config_first_fpga_nr_R = attribute_wrapper(comms_annotation=["2:TR_sdp_config_first_fpga_nr_R"], datatype=numpy.uint32) - TR_sdp_config_nof_beamsets_R = attribute_wrapper(comms_annotation=["2:TR_sdp_config_nof_beamsets_R"], datatype=numpy.uint32) - TR_sdp_config_nof_fpgas_R = attribute_wrapper(comms_annotation=["2:TR_sdp_config_nof_fpgas_R"], datatype=numpy.uint32) - TR_software_version_R = attribute_wrapper(comms_annotation=["2:TR_software_version_R"], datatype=numpy.str) - TR_start_time_R = attribute_wrapper(comms_annotation=["2:TR_start_time_R"], datatype=numpy.int64) - TR_tod_R = attribute_wrapper(comms_annotation=["2:TR_tod_R"], datatype=numpy.int64, dims=(2,)) - TR_tod_pps_delta_R = attribute_wrapper(comms_annotation=["2:TR_tod_pps_delta_R"], datatype=numpy.double) - - S_pn = 12 # Number of ADC signal inputs per Processing Node (PN) FPGA. - N_pn = 16 # Number of FPGAs per antenna band that is controlled via the SC - SDP interface. - - # OPC-UA MP only points for AIT - FPGA_signal_input_mean_R = attribute_wrapper(comms_annotation=["2:FPGA_signal_input_mean_R"], datatype=numpy.double , dims=(S_pn, N_pn)) - FPGA_signal_input_rms_R = attribute_wrapper(comms_annotation=["2:FPGA_signal_input_rms_R"], datatype=numpy.double, dims=(S_pn, N_pn)) - - FPGA_jesd204b_csr_rbd_count_R = attribute_wrapper(comms_annotation=["2:FPGA_jesd204b_csr_rbd_count_R"], datatype=numpy.uint32, dims=(S_pn, N_pn)) - FPGA_jesd204b_csr_dev_syncn_R = attribute_wrapper(comms_annotation=["2:FPGA_jesd204b_csr_dev_syncn_R"], datatype=numpy.uint32, dims=(S_pn, N_pn)) - FPGA_jesd204b_rx_err0_R = attribute_wrapper(comms_annotation=["2:FPGA_jesd204b_rx_err0_R"], datatype=numpy.uint32, dims=(S_pn, N_pn)) - FPGA_jesd204b_rx_err1_R = attribute_wrapper(comms_annotation=["2:FPGA_jesd204b_rx_err1_R"], datatype=numpy.uint32, dims=(S_pn, N_pn)) - - FPGA_bsn_monitor_input_bsn_R = attribute_wrapper(comms_annotation=["2:FPGA_bsn_monitor_input_bsn_R"], datatype=numpy.int64, dims=(N_pn,)) - FPGA_bsn_monitor_input_nof_packets_R = attribute_wrapper(comms_annotation=["2:FPGA_bsn_monitor_input_nof_packets_R"], datatype=numpy.int32, dims=(N_pn,)) - FPGA_bsn_monitor_input_nof_valid_R = attribute_wrapper(comms_annotation=["2:FPGA_bsn_monitor_input_nof_valid_R"], datatype=numpy.int32, dims=(N_pn,)) - FPGA_bsn_monitor_input_nof_err_R = attribute_wrapper(comms_annotation=["2:FPGA_bsn_monitor_input_nof_err_R"], datatype=numpy.int32, dims=(N_pn,)) - - - # -------- - # overloaded functions - # -------- - - # -------- - # Commands - # -------- - -# ---------- -# Run server -# ---------- -def main(args=None, **kwargs): - """Main function of the SDP module.""" - - from common.lofar_logging import configure_logger - configure_logger() - - return run((SDP,), args=args, **kwargs) - - -if __name__ == '__main__': - main() diff --git a/devices/requirements.txt b/devices/requirements.txt deleted file mode 100644 index 8e11e2f537bf59f3602379c853976696df7524f0..0000000000000000000000000000000000000000 --- a/devices/requirements.txt +++ /dev/null @@ -1,5 +0,0 @@ -# the order of packages is of significance, because pip processes them in the -# order of appearance. Changing the order has an impact on the overall -# integration process, which may cause wedges in the gate later. - -pbr>=2.0 # Apache-2.0 diff --git a/devices/setup.cfg b/devices/setup.cfg deleted file mode 100644 index 55b29032e6aefc1787179c054b701b7fc51323ac..0000000000000000000000000000000000000000 --- a/devices/setup.cfg +++ /dev/null @@ -1,30 +0,0 @@ -[metadata] -name = TangoStationControl -summary = LOFAR 2.0 Station Control -description_file = - README.md -description_content_type = text/x-rst; charset=UTF-8 -author = ASTRON -home_page = https://astron.nl -project_urls = - Bug Tracker = https://support.astron.nl/jira/projects/L2SS/issues/ - Source Code = https://git.astron.nl/lofar2.0/tango -license = Apache-2 -classifier = - Environment :: Console - License :: Apache Software License - Operating System :: POSIX :: Linux - Programming Language :: Python - Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 - Programming Language :: Python :: 3.7 - Programming Language :: Python :: 3.8 - Programming Language :: Python :: 3.9 - -[files] -package_dir=./ - -[entry_points] -console_scripts = - SDP = SDP:main - RECV = RECV:main diff --git a/devices/setup.py b/devices/setup.py deleted file mode 100644 index 4fa0ce44d0caa9b174fc65a699e63b31e43aee9b..0000000000000000000000000000000000000000 --- a/devices/setup.py +++ /dev/null @@ -1,4 +0,0 @@ -import setuptools - -# Requires: setup.cfg -setuptools.setup(setup_requires=['pbr>=2.0.0'], pbr=True) diff --git a/devices/test/common/test_lofar_git.py b/devices/test/common/test_lofar_git.py deleted file mode 100644 index 52a1c7d876fc2827757f082e0f44a0a64b1ffc78..0000000000000000000000000000000000000000 --- a/devices/test/common/test_lofar_git.py +++ /dev/null @@ -1,100 +0,0 @@ -# -*- 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 git -from unittest import mock - -from common import lofar_git - -from test import base - - -class TestLofarGit(base.TestCase): - - def setUp(self): - super(TestLofarGit, self).setUp() - - # Clear the cache as this function of lofar_git uses LRU decorator - # This is a good demonstration of how unit tests in Python can have - # permanent effects, typically fixtures are needed to restore these. - lofar_git.get_version.cache_clear() - - def test_get_version(self): - """Test if attributes of get_repo are correctly used by get_version""" - - with mock.patch.object(lofar_git, 'get_repo') as m_get_repo: - m_commit = mock.Mock() - m_commit.return_value = "123456" - - m_is_dirty = mock.Mock() - m_is_dirty.return_value = True - - m_head = mock.Mock(is_detached=False) - - m_get_repo.return_value = mock.Mock( - active_branch="main", commit=m_commit, tags=[], - is_dirty=m_is_dirty, head=m_head) - - # No need for special string equal in Python - self.assertEqual("*main [123456]", lofar_git.get_version()) - - def test_get_version_tag(self): - """Test if get_version determines production_ready for tagged commit""" - - with mock.patch.object(lofar_git, 'get_repo') as m_get_repo: - m_commit = mock.Mock() - m_commit.return_value = "123456" - - m_is_dirty = mock.Mock() - m_is_dirty.return_value = False - - m_head = mock.Mock(is_detached=False) - - m_tag = mock.Mock(commit="123456") - m_tag.__str__ = mock.Mock(return_value= "version-1.2") - - m_get_repo.return_value = mock.Mock( - active_branch="main", commit=m_commit, - tags=[m_tag], is_dirty=m_is_dirty, head=m_head) - - self.assertEqual("version-1.2", lofar_git.get_version()) - - @mock.patch.object(lofar_git, 'get_repo') - def test_get_version_tag_dirty(self, m_get_repo): - """Test if get_version determines dirty tagged commit""" - - m_commit = mock.Mock() - m_commit.return_value = "123456" - - m_is_dirty = mock.Mock() - m_is_dirty.return_value = False - - m_head = mock.Mock(is_detached=False) - - m_tag = mock.Mock(commit="123456") - m_tag.__str__ = mock.Mock(return_value= "version-1.2") - - # Now m_get_repo is mocked using a decorator - m_get_repo.return_value = mock.Mock( - active_branch="main", commit=m_commit, - tags=[m_tag], is_dirty=m_is_dirty, head=m_head) - - self.assertEqual("version-1.2", lofar_git.get_version()) - - def test_catch_repo_error(self): - """Test if invalid git directories will raise error""" - - with mock.patch.object(lofar_git, 'get_repo') as m_get_repo: - - # Configure lofar_git.get_repo to raise InvalidGitRepositoryError - m_get_repo.side_effect = git.InvalidGitRepositoryError - - # Test that error is raised by get_version - self.assertRaises( - git.InvalidGitRepositoryError, lofar_git.get_version) diff --git a/docker-compose/Makefile b/docker-compose/Makefile index 649e63518d5f1276a2f1fb696d90a2b79fef0f24..d85ff1df88d91db097bdd22b060cfc03b681a04f 100644 --- a/docker-compose/Makefile +++ b/docker-compose/Makefile @@ -13,7 +13,8 @@ ATTACH_COMPOSE_FILE_ARGS := $(foreach yml,$(filter-out tango.yml,$(COMPOSE_FILES # But we allow to overwrite it. NETWORK_MODE ?= tangonet -# Host name through which others can reach our control interfaces +# Host name through which others can reach our control interfaces. +# Needs to be resolvable from the containers and clients. ifneq (,$(wildcard /run/WSL)) # Microsoft Windows Subsystem for Linux HOSTNAME ?= host.docker.internal @@ -21,6 +22,10 @@ else HOSTNAME ?= $(shell hostname -f) endif +# Host name to which to send our container logs. Needs to be resolvable from +# the host. +LOG_HOSTNAME ?= localhost + # If the first make argument is "start" or "stop"... ifeq (start,$(firstword $(MAKECMDGOALS))) SERVICE_TARGET = true @@ -113,6 +118,7 @@ DOCKER_COMPOSE_ARGS := DISPLAY=$(DISPLAY) \ TANGO_HOST=$(TANGO_HOST) \ MYSQL_HOST=$(MYSQL_HOST) \ HOSTNAME=$(HOSTNAME) \ + LOG_HOSTNAME=$(LOG_HOSTNAME) \ NETWORK_MODE=$(NETWORK_MODE) \ XAUTHORITY_MOUNT=$(XAUTHORITY_MOUNT) \ CONTAINER_NAME_PREFIX=$(CONTAINER_NAME_PREFIX) \ @@ -130,7 +136,7 @@ pull: ## pull the images from the Docker hub build: ## rebuild images # docker-compose does not support build dependencies, so manage those here $(DOCKER_COMPOSE_ARGS) docker-compose -f lofar-device-base.yml -f networks.yml build --progress=plain - $(DOCKER_COMPOSE_ARGS) docker-compose $(COMPOSE_FILE_ARGS) build --progress=plain $(SERVICE) + $(DOCKER_COMPOSE_ARGS) docker-compose $(COMPOSE_FILE_ARGS) build --parallel --progress=plain $(SERVICE) build-nocache: ## rebuild images from scratch # docker-compose does not support build dependencies, so manage those here diff --git a/docker-compose/archiver.yml b/docker-compose/archiver.yml index afccb4cc31ba4c0ede903f109febed09d583e6df..e7d2b531779a47ee57abc9bc66e2308468382098 100644 --- a/docker-compose/archiver.yml +++ b/docker-compose/archiver.yml @@ -3,7 +3,7 @@ version: '2' services: archiver-maria-db: image: ${LOCAL_DOCKER_REGISTRY_HOST}/${LOCAL_DOCKER_REGISTRY_USER}/mariadb_hdbpp:2021-05-28 - container_name: archiver-maria-db + container_name: ${CONTAINER_NAME_PREFIX}archiver-maria-db networks: - control ports: @@ -17,13 +17,19 @@ services: - MYSQL_USER=tango - MYSQL_PASSWORD=tango - TANGO_HOST=${TANGO_HOST} + logging: + driver: syslog + options: + syslog-address: udp://${LOG_HOSTNAME}:1514 + syslog-format: rfc3164 + tag: "{{.Name}}" restart: unless-stopped hdbpp-es: image: ${LOCAL_DOCKER_REGISTRY_HOST}/${LOCAL_DOCKER_REGISTRY_USER}/tango-archiver:2021-05-28 networks: - control - container_name: hdbpp-es + container_name: ${CONTAINER_NAME_PREFIX}hdbpp-es depends_on: - databaseds - dsconfig @@ -36,13 +42,19 @@ services: wait-for-it.sh archiver-maria-db:3306 --timeout=30 --strict -- wait-for-it.sh ${TANGO_HOST} --timeout=30 --strict -- hdbppes-srv 01" + logging: + driver: syslog + options: + syslog-address: udp://${LOG_HOSTNAME}:1514 + syslog-format: rfc3164 + tag: "{{.Name}}" restart: unless-stopped hdbpp-cm: image: ${LOCAL_DOCKER_REGISTRY_HOST}/${LOCAL_DOCKER_REGISTRY_USER}/tango-archiver:${TANGO_ARCHIVER_VERSION} networks: - control - container_name: hdbpp-cm + container_name: ${CONTAINER_NAME_PREFIX}hdbpp-cm depends_on: - databaseds - dsconfig @@ -55,10 +67,16 @@ services: wait-for-it.sh archiver-maria-db:3306 --timeout=30 --strict -- wait-for-it.sh ${TANGO_HOST} --timeout=30 --strict -- hdbppcm-srv 01" + logging: + driver: syslog + options: + syslog-address: udp://${LOG_HOSTNAME}:1514 + syslog-format: rfc3164 + tag: "{{.Name}}" dsconfig: image: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}-tango-dsconfig:${TANGO_DSCONFIG_VERSION} - container_name: dsconfig + container_name: ${CONTAINER_NAME_PREFIX}dsconfig networks: - control depends_on: @@ -73,5 +91,11 @@ services: - ..:/opt/lofar/tango:rw - ${HOME}:/hosthome - ../docker/tango/tango-archiver:/tango-archiver + logging: + driver: syslog + options: + syslog-address: udp://${LOG_HOSTNAME}:1514 + syslog-format: rfc3164 + tag: "{{.Name}}" restart: unless-stopped diff --git a/docker-compose/device-apsct.yml b/docker-compose/device-apsct.yml index f17919a227a12b9846ba7a272254faaaee4d496a..36a21fb6c81bce72c0f708e5aca924eb0de9e14f 100644 --- a/docker-compose/device-apsct.yml +++ b/docker-compose/device-apsct.yml @@ -26,6 +26,8 @@ services: - control ports: - "5709:5709" # unique port for this DS + extra_hosts: + - "host.docker.internal:host-gateway" volumes: - ..:/opt/lofar/tango:rw environment: diff --git a/docker-compose/device-apspu.yml b/docker-compose/device-apspu.yml index 30da5a6c2aba5daef2452f906693c41e7fece330..f1ea50c89d5194c6829fcf29446090edae33e686 100644 --- a/docker-compose/device-apspu.yml +++ b/docker-compose/device-apspu.yml @@ -26,6 +26,8 @@ services: - control ports: - "5710:5710" # unique port for this DS + extra_hosts: + - "host.docker.internal:host-gateway" volumes: - ..:/opt/lofar/tango:rw environment: diff --git a/docker-compose/device-boot.yml b/docker-compose/device-boot.yml index 58a9aa7df81eab368464f4ca69ddab54129b7ace..131e5644399eeae7b0e043a7aca9829d45a9a167 100644 --- a/docker-compose/device-boot.yml +++ b/docker-compose/device-boot.yml @@ -25,17 +25,15 @@ services: - control ports: - "5708:5708" # unique port for this DS + extra_hosts: + - "host.docker.internal:host-gateway" volumes: - ..:/opt/lofar/tango:rw environment: - TANGO_HOST=${TANGO_HOST} entrypoint: - - /usr/local/bin/wait-for-it.sh - - ${TANGO_HOST} - - --timeout=30 - - --strict - - -- + - 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 - - python3 -u /opt/lofar/tango/devices/devices/boot.py LTS -v -ORBendPoint giop:tcp:0:5708 -ORBendPointPublish giop:tcp:${HOSTNAME}:5708 + - l2ss-boot Boot LTS -v -ORBendPoint giop:tcp:0:5708 -ORBendPointPublish giop:tcp:${HOSTNAME}:5708 restart: unless-stopped diff --git a/docker-compose/device-docker.yml b/docker-compose/device-docker.yml index d9e1e1e35233177ab271db395773538ed8c74ffa..93e7cd8eaca8ea2ad6a024fa6fab7a1902b693c1 100644 --- a/docker-compose/device-docker.yml +++ b/docker-compose/device-docker.yml @@ -26,19 +26,18 @@ services: - control ports: - "5705:5705" # unique port for this DS + extra_hosts: + - "host.docker.internal:host-gateway" volumes: - ..:/opt/lofar/tango:rw - /var/run/docker.sock:/var/run/docker.sock:rw # we want to control our sibling containers, NOT do docker-in-docker (dind) user: 1000:${DOCKER_GID} # uid 1000 is the default "tango" user environment: - TANGO_HOST=${TANGO_HOST} + working_dir: /opt/lofar/tango entrypoint: - - /usr/local/bin/wait-for-it.sh - - ${TANGO_HOST} - - --timeout=30 - - --strict - - -- + - 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 - - python3 -u /opt/lofar/tango/devices/devices/docker_device.py LTS -v -ORBendPoint giop:tcp:0:5705 -ORBendPointPublish giop:tcp:${HOSTNAME}:5705 + - l2ss-docker-device Docker LTS -v -ORBendPoint giop:tcp:0:5705 -ORBendPointPublish giop:tcp:${HOSTNAME}:5705 restart: unless-stopped diff --git a/docker-compose/device-observation_control.yml b/docker-compose/device-observation_control.yml index 827a558a10167d29f3e0bd3402f3f84debcd3c23..d15fb8a8e708ce7e01e27a300348a5f47b09aa24 100644 --- a/docker-compose/device-observation_control.yml +++ b/docker-compose/device-observation_control.yml @@ -25,17 +25,16 @@ services: - control ports: - "5703:5703" # 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: - - /usr/local/bin/wait-for-it.sh - - ${TANGO_HOST} - - --timeout=30 - - --strict - - -- + - 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 - - python3 -u /opt/lofar/tango/devices/devices/observation_control.py LTS -v -ORBendPoint giop:tcp:0:5703 -ORBendPointPublish giop:tcp:${HOSTNAME}:5703 + - l2ss-observation-control ObservationControl LTS -v -ORBendPoint giop:tcp:0:5703 -ORBendPointPublish giop:tcp:${HOSTNAME}:5703 restart: unless-stopped diff --git a/docker-compose/device-recv.yml b/docker-compose/device-recv.yml index f3bc3eea12b51b44cacbeb790d0666ced24ae169..c1269ab89e34798b8766ced06d7df3394cbaf3b7 100644 --- a/docker-compose/device-recv.yml +++ b/docker-compose/device-recv.yml @@ -26,17 +26,16 @@ services: - control ports: - "5707:5707" # 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: - - /usr/local/bin/wait-for-it.sh - - ${TANGO_HOST} - - --timeout=30 - - --strict - - -- + - 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 - - python3 -u /opt/lofar/tango/devices/devices/recv.py LTS -v -ORBendPoint giop:tcp:0:5707 -ORBendPointPublish giop:tcp:${HOSTNAME}:5707 + - l2ss-receiver RECV LTS -v -ORBendPoint giop:tcp:0:5707 -ORBendPointPublish giop:tcp:${HOSTNAME}:5707 restart: unless-stopped diff --git a/docker-compose/device-sdp.yml b/docker-compose/device-sdp.yml index 8fefa3f355eda485ea757f0859924e317b9245ee..0768d39cd4a75d4d92abd59f42cbb436ac4c2f48 100644 --- a/docker-compose/device-sdp.yml +++ b/docker-compose/device-sdp.yml @@ -26,17 +26,16 @@ services: - control ports: - "5701:5701" # 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: - - /usr/local/bin/wait-for-it.sh - - ${TANGO_HOST} - - --timeout=30 - - --strict - - -- + - 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 - - python3 -u /opt/lofar/tango/devices/devices/sdp/sdp.py LTS -v -ORBendPoint giop:tcp:0:5701 -ORBendPointPublish giop:tcp:${HOSTNAME}:5701 + - l2ss-sdp SDP LTS -v -ORBendPoint giop:tcp:0:5701 -ORBendPointPublish giop:tcp:${HOSTNAME}:5701 restart: unless-stopped diff --git a/docker-compose/device-sst.yml b/docker-compose/device-sst.yml index 7d922a61badf6575d15c6f0a0489a6fac3683367..3924b4bf18c1a221a8859a32a73f9ccccb4fdfc1 100644 --- a/docker-compose/device-sst.yml +++ b/docker-compose/device-sst.yml @@ -29,17 +29,16 @@ services: - "5001:5001/udp" # port to receive SST UDP packets on - "5101:5101/tcp" # port to emit SST TCP packets on - "5702:5702" # 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: - - /usr/local/bin/wait-for-it.sh - - ${TANGO_HOST} - - --timeout=30 - - --strict - - -- + - 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 - - python3 -u /opt/lofar/tango/devices/devices/sdp/sst.py LTS -v -ORBendPoint giop:tcp:0:5702 -ORBendPointPublish giop:tcp:${HOSTNAME}:5702 + - l2ss-sst SST LTS -v -ORBendPoint giop:tcp:0:5702 -ORBendPointPublish giop:tcp:${HOSTNAME}:5702 restart: unless-stopped diff --git a/docker-compose/device-unb2.yml b/docker-compose/device-unb2.yml index 6844ee2b6994c11fb53469535925284be42410c0..9e9f8797ce62f57c3fd3434dd41c36412df2150f 100644 --- a/docker-compose/device-unb2.yml +++ b/docker-compose/device-unb2.yml @@ -26,17 +26,16 @@ services: - control ports: - "5704:5704" # 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: - - /usr/local/bin/wait-for-it.sh - - ${TANGO_HOST} - - --timeout=30 - - --strict - - -- + - 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 - - python3 -u /opt/lofar/tango/devices/devices/unb2.py LTS -v -ORBendPoint giop:tcp:0:5704 -ORBendPointPublish giop:tcp:${HOSTNAME}:5704 + - l2ss-unb2 UNB2 LTS -v -ORBendPoint giop:tcp:0:5704 -ORBendPointPublish giop:tcp:${HOSTNAME}:5704 restart: unless-stopped diff --git a/docker-compose/device-xst.yml b/docker-compose/device-xst.yml index c634e5d83fc7b28f2b8438ae59dffb7157a03f54..6d7a1036dfa965750bcf7212ae865a1b71e3de3a 100644 --- a/docker-compose/device-xst.yml +++ b/docker-compose/device-xst.yml @@ -29,17 +29,16 @@ services: - "5002:5002/udp" # port to receive XST UDP packets on - "5102:5102/tcp" # port to emit XST TCP packets on - "5706:5706" # 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: - - /usr/local/bin/wait-for-it.sh - - ${TANGO_HOST} - - --timeout=30 - - --strict - - -- + - 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 - - python3 -u /opt/lofar/tango/devices/devices/sdp/xst.py LTS -v -ORBendPoint giop:tcp:0:5706 -ORBendPointPublish giop:tcp:${HOSTNAME}:5706 + - l2ss-xst XST LTS -v -ORBendPoint giop:tcp:0:5706 -ORBendPointPublish giop:tcp:${HOSTNAME}:5706 restart: unless-stopped diff --git a/docker-compose/elk.yml b/docker-compose/elk.yml index bf6e22e3de6ea82571acba0ac8e7c69f3eeb2941..67f13baee061a74ebd08320f1e9f2f9f3e72f646 100644 --- a/docker-compose/elk.yml +++ b/docker-compose/elk.yml @@ -34,7 +34,8 @@ services: - "5601:5601" # kibana - "9200:9200" # elasticsearch - "5044:5044" # logstash beats input - - "1514:1514" # logstash syslog input + - "1514:1514/tcp" # logstash syslog input + - "1514:1514/udp" # logstash syslog input - "5959:5959" # logstash tcp json input depends_on: - elk-configure-host diff --git a/docker-compose/elk/logstash/conf.d/20-parse-grafana.conf b/docker-compose/elk/logstash/conf.d/20-parse-grafana.conf new file mode 100644 index 0000000000000000000000000000000000000000..37db44fda67109d7ef8a6beac1193004968a2349 --- /dev/null +++ b/docker-compose/elk/logstash/conf.d/20-parse-grafana.conf @@ -0,0 +1,16 @@ +filter { + if [program] == "grafana" { + kv { } + mutate { + rename => { + "t" => "timestamp" + "lvl" => "level" + "msg" => "message" + } + uppercase => [ "level" ] + } + date { + match => [ "timestamp", "ISO8601" ] + } + } +} diff --git a/docker-compose/elk/logstash/conf.d/21-parse-prometheus.conf b/docker-compose/elk/logstash/conf.d/21-parse-prometheus.conf new file mode 100644 index 0000000000000000000000000000000000000000..b8323625f329af02f9ff33556e408b94ecf7e0b6 --- /dev/null +++ b/docker-compose/elk/logstash/conf.d/21-parse-prometheus.conf @@ -0,0 +1,15 @@ +filter { + if [program] == "prometheus" { + kv { } + mutate { + rename => { + "ts" => "timestamp" + "msg" => "message" + } + uppercase => [ "level" ] + } + date { + match => [ "timestamp", "ISO8601" ] + } + } +} diff --git a/docker-compose/elk/logstash/conf.d/22-parse-tango-rest.conf b/docker-compose/elk/logstash/conf.d/22-parse-tango-rest.conf new file mode 100644 index 0000000000000000000000000000000000000000..5df0cd92bd32625a1eb91220bf4e7a9827799523 --- /dev/null +++ b/docker-compose/elk/logstash/conf.d/22-parse-tango-rest.conf @@ -0,0 +1,14 @@ +filter { + if [program] == "tango-rest" { + grok { + match => { + "message" => "%{TIMESTAMP_ISO8601:timestamp} %{WORD:level} %{GREEDYDATA:message}" + } + "overwrite" => [ "timestamp", "level", "message" ] + } + date { + match => [ "timestamp", "YYYY-MM-dd HH:mm:ss,SSS" ] + timezone => "UTC" + } + } +} diff --git a/docker-compose/elk/logstash/conf.d/23-parse-maria-db.conf b/docker-compose/elk/logstash/conf.d/23-parse-maria-db.conf new file mode 100644 index 0000000000000000000000000000000000000000..0a23fddd078e5e967bc5f791e020faaa20ed632a --- /dev/null +++ b/docker-compose/elk/logstash/conf.d/23-parse-maria-db.conf @@ -0,0 +1,32 @@ +filter { + # mark all our mariadb instances + grok { + match => { + "program" => [ "archiver-maria-db", "tangodb" ] + } + add_tag => [ "mariadb" ] + } + + # parse mariadb output + if "mariadb" in [tags] { + grok { + match => { + "message" => [ + "%{TIMESTAMP_ISO8601:timestamp} .%{WORD:level}. %{GREEDYDATA:message}", + "%{TIMESTAMP_ISO8601:timestamp} 0 .%{WORD:level}. %{GREEDYDATA:message}" + ] + } + "overwrite" => [ "timestamp", "level", "message" ] + } + mutate { + gsub => [ + "level", "Note", "Info" + ] + uppercase => [ "level" ] + } + date { + match => [ "timestamp", "YYYY-MM-dd HH:mm:ssZZ", "YYYY-MM-dd HH:mm:ss", "YYYY-MM-dd H:mm:ss" ] + timezone => "UTC" + } + } +} diff --git a/docker-compose/grafana.yml b/docker-compose/grafana.yml index b9060c70a53ecfb4d4027ebe1e78d9fe658050f6..29c93c52c4dc05849aad10fabac12712c12dd4d7 100644 --- a/docker-compose/grafana.yml +++ b/docker-compose/grafana.yml @@ -23,4 +23,10 @@ services: # - grafana-configs:/etc/grafana ports: - "3000:3000" + logging: + driver: syslog + options: + syslog-address: udp://${LOG_HOSTNAME}:1514 + syslog-format: rfc3164 + tag: "{{.Name}}" restart: unless-stopped diff --git a/docker-compose/grafana/Dockerfile b/docker-compose/grafana/Dockerfile index bc766bcd3b0d71f346fd70e34fa27dd91fc27b04..e51cce5eeaa0310c1ecd698d8d797e3163ce4457 100644 --- a/docker-compose/grafana/Dockerfile +++ b/docker-compose/grafana/Dockerfile @@ -1,5 +1,9 @@ FROM grafana/grafana +# Install some plugins +RUN grafana-cli plugins install briangann-datatable-panel +RUN grafana-cli plugins install ae3e-plotly-panel + COPY grafana.ini /etc/grafana/ # Add default configuration through provisioning (see https://grafana.com/docs/grafana/latest/administration/provisioning) diff --git a/docker-compose/grafana/dashboards/home.json b/docker-compose/grafana/dashboards/home.json index 6d4641a656c20b40ceaa8a18d2b02da47b0b55ba..f1b7a626e2ca470f513d22cadf240345cacf2f25 100644 --- a/docker-compose/grafana/dashboards/home.json +++ b/docker-compose/grafana/dashboards/home.json @@ -22,7 +22,7 @@ "fiscalYearStartMonth": 0, "gnetId": null, "graphTooltip": 0, - "id": 6, + "id": 5, "links": [], "liveNow": false, "panels": [ @@ -484,6 +484,196 @@ ], "type": "table" }, + { + "datasource": "ELK logs", + "description": "List of the errors in the selected timespan", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "displayMode": "auto", + "filterable": true + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "@timestamp" + }, + "properties": [ + { + "id": "custom.width", + "value": 149 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "level" + }, + "properties": [ + { + "id": "custom.width", + "value": 62 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "program" + }, + "properties": [ + { + "id": "custom.width", + "value": 287 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "extra.logger_name" + }, + "properties": [ + { + "id": "custom.width", + "value": 72 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "extra.lofar_id" + }, + "properties": [ + { + "id": "custom.width", + "value": 196 + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 24, + "x": 0, + "y": 10 + }, + "id": 56, + "options": { + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "8.2.1", + "targets": [ + { + "alias": "", + "bucketAggs": [], + "metrics": [ + { + "hide": false, + "id": "1", + "settings": { + "limit": "500" + }, + "type": "logs" + } + ], + "query": "level:(ERROR or CRIT or FATAL)", + "refId": "A", + "timeField": "@timestamp" + } + ], + "title": "Error Log", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": { + "@version": true, + "_id": true, + "_index": true, + "_source": true, + "_type": true, + "extra.func_name": true, + "extra.interpreter": true, + "extra.interpreter_version": true, + "extra.line": true, + "extra.logger_name": true, + "extra.logstash_async_version": true, + "extra.path": true, + "extra.process_name": true, + "extra.software_version": true, + "extra.tango_device": true, + "extra.thread_name": true, + "highlight": true, + "host": true, + "logsource": true, + "pid": true, + "port": true, + "sort": true, + "tags": true, + "type": true + }, + "indexByName": { + "@timestamp": 0, + "@version": 5, + "_id": 6, + "_index": 7, + "_source": 8, + "_type": 9, + "extra.func_name": 10, + "extra.interpreter": 11, + "extra.interpreter_version": 12, + "extra.line": 13, + "extra.lofar_id": 4, + "extra.logger_name": 14, + "extra.logstash_async_version": 15, + "extra.path": 16, + "extra.process_name": 17, + "extra.software_version": 18, + "extra.tango_device": 19, + "extra.thread_name": 20, + "highlight": 21, + "host": 2, + "level": 1, + "logsource": 22, + "message": 23, + "pid": 24, + "port": 25, + "program": 3, + "sort": 26, + "tags": 27, + "type": 28 + }, + "renameByName": {} + } + } + ], + "type": "table" + }, { "collapsed": false, "datasource": null, @@ -491,7 +681,301 @@ "h": 1, "w": 24, "x": 0, - "y": 10 + "y": 15 + }, + "id": 49, + "panels": [], + "title": "APSCT & APSPU", + "type": "row" + }, + { + "datasource": "Prometheus", + "description": "State of APSCT", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 1 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 21, + "x": 0, + "y": 16 + }, + "id": 24, + "options": { + "colorMode": "background", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "name" + }, + "pluginVersion": "8.2.1", + "targets": [ + { + "exemplar": true, + "expr": "1-device_attribute{device=\"lts/apsct/1\",name=\"APSCT_PWR_on_R\"}", + "interval": "", + "legendFormat": "Power", + "refId": "A" + }, + { + "exemplar": true, + "expr": "device_attribute{device=\"lts/apsct/1\",name=\"APSCTTR_I2C_error_R\"}", + "hide": false, + "interval": "", + "legendFormat": "I2C", + "refId": "B" + }, + { + "exemplar": true, + "expr": "device_attribute{device=\"lts/apsct/1\",name=\"APSCT_PLL_200MHz_error_R\"}", + "hide": false, + "interval": "", + "legendFormat": "PLL", + "refId": "C" + }, + { + "exemplar": true, + "expr": "1-device_attribute{device=\"lts/apsct/1\",name=\"APSCT_PLL_200MHz_locked_R\"}", + "hide": false, + "interval": "", + "legendFormat": "PLL Lock", + "refId": "D" + }, + { + "exemplar": true, + "expr": "1-device_attribute{device=\"lts/apsct/1\",name=\"APSCT_INPUT_10MHz_good_R\"}", + "hide": false, + "interval": "", + "legendFormat": "10MHz", + "refId": "E" + }, + { + "exemplar": true, + "expr": "1-device_attribute{device=\"lts/apsct/1\",name=\"APSCT_INPUT_PPS_good_R\"}", + "hide": false, + "interval": "", + "legendFormat": "PPS", + "refId": "F" + }, + { + "exemplar": true, + "expr": "device_attribute{device=\"lts/apsct/1\",name=\"APSCT_PPS_ignore_R\"}", + "hide": false, + "interval": "", + "legendFormat": "PPS used", + "refId": "G" + } + ], + "title": "APS Clock State", + "type": "stat" + }, + { + "datasource": "Prometheus", + "description": "State of APSPU", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 1 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 21, + "y": 16 + }, + "id": 50, + "options": { + "colorMode": "background", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "name" + }, + "pluginVersion": "8.2.1", + "targets": [ + { + "exemplar": true, + "expr": "device_attribute{device=\"lts/apspu/1\",name=\"APSPUTR_I2C_error_R\"}", + "hide": false, + "interval": "", + "legendFormat": "I2C", + "refId": "B" + } + ], + "title": "APS Power Unit State", + "type": "stat" + }, + { + "collapsed": true, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 19 + }, + "id": 53, + "panels": [], + "title": "UNB2", + "type": "row" + }, + { + "datasource": "Prometheus", + "description": "State of Unboard 2 I2C Bus", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "transparent", + "value": null + }, + { + "color": "green", + "value": 1 + }, + { + "color": "red", + "value": 2 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 20 + }, + "id": 54, + "options": { + "colorMode": "background", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "name" + }, + "pluginVersion": "8.2.1", + "targets": [ + { + "exemplar": true, + "expr": "(1 + (device_attribute{device=\"lts/unb2/1\",name=\"UNB2TR_I2C_bus_error_R\"} != bool 0)) * on(x) device_attribute{device=\"lts/recv/1\",name=\"RCU_mask_RW\"}", + "hide": false, + "interval": "", + "legendFormat": "I2C {{x}}", + "refId": "A" + }, + { + "exemplar": true, + "expr": "(1 + device_attribute{device=\"lts/unb2/1\",name=\"UNB2TR_I2C_bus_PS_error_R\"}) * on(x) device_attribute{device=\"lts/recv/1\",name=\"RCU_mask_RW\"}", + "hide": false, + "interval": "", + "legendFormat": "PS {{x}}", + "refId": "B" + }, + { + "exemplar": true, + "expr": "(1 + sum by (x) (device_attribute{device=\"lts/unb2/1\",name=\"UNB2TR_I2C_bus_FPGA_PS_error_R\"})) * on(x) device_attribute{device=\"lts/recv/1\",name=\"RCU_mask_RW\"}", + "hide": false, + "interval": "", + "legendFormat": "FPGA PS {{x}}", + "refId": "C" + }, + { + "exemplar": true, + "expr": "(1 + sum by (x) (device_attribute{device=\"lts/unb2/1\",name=\"UNB2TR_I2C_bus_DDR4_error_R\"})) * on(x) device_attribute{device=\"lts/recv/1\",name=\"RCU_mask_RW\"}", + "hide": false, + "interval": "", + "legendFormat": "DDR {{x}}", + "refId": "D" + }, + { + "exemplar": true, + "expr": "(1 + sum by (x) (device_attribute{device=\"lts/unb2/1\",name=\"UNB2TR_I2C_bus_QSFP_error_R\"})) * on(x) device_attribute{device=\"lts/recv/1\",name=\"RCU_mask_RW\"}", + "hide": false, + "interval": "", + "legendFormat": "QSFP {{x}}", + "refId": "E" + } + ], + "title": "UNB2 I2C State", + "type": "stat" + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 23 }, "id": 17, "panels": [], @@ -530,12 +1014,12 @@ "h": 8, "w": 6, "x": 0, - "y": 11 + "y": 24 }, "id": 21, "options": { "colorMode": "background", - "graphMode": "area", + "graphMode": "none", "justifyMode": "auto", "orientation": "auto", "reduceOptions": { @@ -552,13 +1036,14 @@ "targets": [ { "exemplar": true, - "expr": "sum by (x)(1 + (device_attribute{device=\"lts/recv/1\",name=\"RCU_ADC_lock_R\"} == bool 129)) * on(x) device_attribute{device=\"lts/recv/1\",name=\"RCU_mask_RW\"} - 3", + "expr": "sum by (x)(1 + (device_attribute{device=\"lts/recv/1\",name=\"RCU_ADC_locked_R\"})) * on(x) device_attribute{device=\"lts/recv/1\",name=\"RCU_mask_RW\"} - 3", + "instant": false, "interval": "", "legendFormat": "{{y}}", "refId": "A" } ], - "title": "RCU ADC lock", + "title": "RCU Clock Lock", "type": "stat" }, { @@ -593,12 +1078,12 @@ "h": 8, "w": 6, "x": 6, - "y": 11 + "y": 24 }, "id": 25, "options": { "colorMode": "background", - "graphMode": "area", + "graphMode": "none", "justifyMode": "auto", "orientation": "auto", "reduceOptions": { @@ -615,17 +1100,20 @@ "targets": [ { "exemplar": true, - "expr": "(2 - device_attribute{device=\"lts/recv/1\",name=\"RCU_I2C_STATUS_R\"}) * on(x) device_attribute{device=\"lts/recv/1\",name=\"RCU_mask_RW\"}", + "expr": "(1 + (device_attribute{device=\"lts/recv/1\",name=\"RECVTR_I2C_error_R\"} == bool 0)) * on(x) device_attribute{device=\"lts/recv/1\",name=\"RCU_mask_RW\"}", + "hide": false, + "instant": false, "interval": "", "legendFormat": "{{y}}", "refId": "A" } ], - "title": "RCU I2C status", + "title": "RCU I2C State", "type": "stat" }, { "datasource": "Prometheus", + "description": "", "fieldConfig": { "defaults": { "color": { @@ -636,12 +1124,16 @@ "mode": "absolute", "steps": [ { - "color": "green", + "color": "transparent", "value": null }, { "color": "red", "value": 1 + }, + { + "color": "green", + "value": 2 } ] } @@ -649,12 +1141,12 @@ "overrides": [] }, "gridPos": { - "h": 5, - "w": 3, + "h": 8, + "w": 6, "x": 12, - "y": 11 + "y": 24 }, - "id": 24, + "id": 51, "options": { "colorMode": "background", "graphMode": "none", @@ -674,37 +1166,15 @@ "targets": [ { "exemplar": true, - "expr": "1-device_attribute{device=\"lts/apsct/1\",name=\"APSCT_PWR_on_R\"}", - "interval": "", - "legendFormat": "Power", - "refId": "A" - }, - { - "exemplar": true, - "expr": "device_attribute{device=\"lts/apsct/1\",name=\"APSCT_I2C_error_R\"}", - "hide": false, - "interval": "", - "legendFormat": "I2C", - "refId": "B" - }, - { - "exemplar": true, - "expr": "device_attribute{device=\"lts/apsct/1\",name=\"APSCT_PLL_200MHz_error_R\"}", - "hide": false, - "interval": "", - "legendFormat": "PLL", - "refId": "C" - }, - { - "exemplar": true, - "expr": "1-device_attribute{device=\"lts/apsct/1\",name=\"APSCT_PLL_200MHz_locked_R\"}", + "expr": "(1 + device_attribute{device=\"lts/recv/1\",name=\"RCU_PWR_good_R\"}) * on(x) device_attribute{device=\"lts/recv/1\",name=\"RCU_mask_RW\"}", "hide": false, + "instant": false, "interval": "", - "legendFormat": "PLL Lock", - "refId": "D" + "legendFormat": "{{y}}", + "refId": "A" } ], - "title": "Clock", + "title": "RCU Power good", "type": "stat" }, { @@ -714,7 +1184,7 @@ "h": 1, "w": 24, "x": 0, - "y": 19 + "y": 32 }, "id": 19, "panels": [], @@ -754,7 +1224,7 @@ "h": 8, "w": 5, "x": 0, - "y": 20 + "y": 33 }, "id": 11, "options": { @@ -822,7 +1292,7 @@ "h": 8, "w": 5, "x": 5, - "y": 20 + "y": 33 }, "id": 9, "options": { @@ -896,7 +1366,7 @@ "h": 4, "w": 3, "x": 10, - "y": 20 + "y": 33 }, "id": 12, "options": { @@ -938,7 +1408,7 @@ "h": 1, "w": 24, "x": 0, - "y": 28 + "y": 41 }, "id": 27, "panels": [], @@ -978,7 +1448,7 @@ "h": 8, "w": 5, "x": 0, - "y": 29 + "y": 42 }, "id": 28, "options": { @@ -1076,7 +1546,7 @@ "h": 8, "w": 5, "x": 5, - "y": 29 + "y": 42 }, "id": 29, "options": { @@ -1185,7 +1655,7 @@ "h": 8, "w": 5, "x": 10, - "y": 29 + "y": 42 }, "id": 30, "options": { @@ -1278,7 +1748,7 @@ "h": 8, "w": 5, "x": 15, - "y": 29 + "y": 42 }, "id": 33, "options": { @@ -1373,7 +1843,7 @@ "h": 8, "w": 3, "x": 20, - "y": 29 + "y": 42 }, "id": 34, "options": { @@ -1410,7 +1880,7 @@ "h": 1, "w": 24, "x": 0, - "y": 37 + "y": 50 }, "id": 36, "panels": [], @@ -1447,10 +1917,10 @@ "overrides": [] }, "gridPos": { - "h": 8, + "h": 4, "w": 5, "x": 0, - "y": 38 + "y": 51 }, "id": 37, "options": { @@ -1548,7 +2018,7 @@ "h": 8, "w": 5, "x": 5, - "y": 38 + "y": 51 }, "id": 38, "options": { @@ -1657,7 +2127,7 @@ "h": 8, "w": 5, "x": 10, - "y": 38 + "y": 51 }, "id": 39, "options": { @@ -1750,7 +2220,7 @@ "h": 8, "w": 5, "x": 15, - "y": 38 + "y": 51 }, "id": 40, "options": { @@ -1845,7 +2315,7 @@ "h": 8, "w": 3, "x": 20, - "y": 38 + "y": 51 }, "id": 41, "options": { @@ -1905,10 +2375,10 @@ "overrides": [] }, "gridPos": { - "h": 8, + "h": 4, "w": 5, "x": 0, - "y": 46 + "y": 55 }, "id": 45, "options": { @@ -1959,5 +2429,5 @@ "timezone": "", "title": "Home", "uid": "nC8N_kO7k", - "version": 5 + "version": 6 } diff --git a/docker-compose/grafana/dashboards/sensors.json b/docker-compose/grafana/dashboards/sensors.json index 95e39f60d024ea355119a24d72cbd9bdd9c178fe..43c85da09acc89c8ef487d60e8f46a5bd8605d3c 100644 --- a/docker-compose/grafana/dashboards/sensors.json +++ b/docker-compose/grafana/dashboards/sensors.json @@ -22,7 +22,6 @@ "fiscalYearStartMonth": 0, "gnetId": null, "graphTooltip": 0, - "id": 4, "links": [], "liveNow": false, "panels": [ @@ -75,7 +74,6 @@ } }, "mappings": [], - "min": 0, "thresholds": { "mode": "absolute", "steps": [ @@ -99,7 +97,7 @@ "x": 0, "y": 1 }, - "id": 2, + "id": 6, "options": { "legend": { "calcs": [], @@ -114,7 +112,7 @@ "targets": [ { "exemplar": true, - "expr": "device_attribute{device=\"lts/recv/1\",name=\"RCU_temperature_R\"} - 273.15", + "expr": "device_attribute{device=\"lts/sdp/1\",name=\"FPGA_temp_R\"} != 0", "format": "time_series", "hide": false, "instant": false, @@ -123,13 +121,13 @@ "refId": "A" } ], - "title": "RCU temperatures", + "title": "FPGA Temperatures", "transformations": [], "type": "timeseries" }, { "datasource": "Prometheus", - "description": "Temperature sensors of each node on each board", + "description": "", "fieldConfig": { "defaults": { "color": { @@ -202,14 +200,14 @@ "targets": [ { "exemplar": true, - "expr": "device_attribute{device=\"lts/unb2/1\",name=\"UNB2_FPGA_POL_CORE_TEMP_R\"}", + "expr": "device_attribute{device=\"lts/unb2/1\",name=\"UNB2_FPGA_POL_CORE_TEMP_R\"} ", "interval": "", "legendFormat": "Core board {{x}} node {{y}}", "refId": "A" }, { "exemplar": true, - "expr": "device_attribute{device=\"lts/unb2/1\",name=\"UNB2_FPGA_POL_ERAM_TEMP_R\"}", + "expr": "device_attribute{device=\"lts/unb2/1\",name=\"UNB2_FPGA_POL_ERAM_TEMP_R\"} ", "hide": false, "interval": "", "legendFormat": "ERAM board {{x}} node {{y}}", @@ -217,7 +215,7 @@ }, { "exemplar": true, - "expr": "device_attribute{device=\"lts/unb2/1\",name=\"UNB2_FPGA_POL_RXGXB_TEMP_R\"}", + "expr": "device_attribute{device=\"lts/unb2/1\",name=\"UNB2_FPGA_POL_RXGXB_TEMP_R\"} ", "hide": false, "interval": "", "legendFormat": "TrRx board {{x}} node {{y}}", @@ -225,7 +223,7 @@ }, { "exemplar": true, - "expr": "device_attribute{device=\"lts/unb2/1\",name=\"UNB2_FPGA_POL_TXGB_TEMP_R\"}", + "expr": "device_attribute{device=\"lts/unb2/1\",name=\"UNB2_FPGA_POL_TXGB_TEMP_R\"} ", "hide": false, "interval": "", "legendFormat": "TrHx board {{x}} node {{y}}", @@ -233,23 +231,28 @@ }, { "exemplar": true, - "expr": "device_attribute{device=\"lts/unb2/1\",name=\"UNB2_FPGA_POL_PGM_TEMP_R\"}", + "expr": "device_attribute{device=\"lts/unb2/1\",name=\"UNB2_FPGA_POL_PGM_TEMP_R\"} ", "hide": false, "interval": "", "legendFormat": "IO board {{x}} node {{y}}", "refId": "E" }, { + "exemplar": true, + "expr": "device_attribute{device=\"lts/unb2/1\",name=\"UNB2_FPGA_POL_HGXB_TEMP_R\"} ", "hide": false, + "interval": "", + "legendFormat": "HGXB board {{x}} node {{y}}", "refId": "F" } ], - "title": "Uniboard2 Node Temperatures", + "title": "Uniboard2 FPGA POL Temperatures", + "transformations": [], "type": "timeseries" }, { "datasource": "Prometheus", - "description": "Temperature sensors of the power supply on each board", + "description": "", "fieldConfig": { "defaults": { "color": { @@ -308,7 +311,7 @@ "x": 10, "y": 1 }, - "id": 8, + "id": 22, "options": { "legend": { "calcs": [], @@ -322,62 +325,287 @@ "targets": [ { "exemplar": true, - "expr": "device_attribute{device=\"lts/unb2/1\",name=\"UNB2_POL_QSFP_N01_TEMP_R\"}", + "expr": "device_attribute{device=\"lts/unb2/1\",name=\"UNB2_FPGA_QSFP_CAGE_TEMP_R\"}", "interval": "", - "legendFormat": "QSFP N01 board {{x}} ", + "legendFormat": "FPGA QSFP Cage {{x}}, {{y}} ", "refId": "A" + } + ], + "title": "Uniboard2 QSFP Cage Temperatures", + "type": "timeseries" + }, + { + "datasource": "Prometheus", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic", + "seriesBy": "max" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "line" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 85 + } + ] + }, + "unit": "celsius" }, - { - "exemplar": true, - "expr": "device_attribute{device=\"lts/unb2/1\",name=\"UNB2_POL_QSFP_N23_TEMP_R\"}", - "hide": false, - "interval": "", - "legendFormat": "QSFP N23 board {{x}}", - "refId": "B" + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 5, + "x": 15, + "y": 1 + }, + "id": 23, + "options": { + "legend": { + "calcs": [], + "displayMode": "hidden", + "placement": "bottom" }, + "tooltip": { + "mode": "single" + } + }, + "targets": [ { "exemplar": true, - "expr": "device_attribute{device=\"lts/unb2/1\",name=\"UNB2_POL_SWITCH_1V2_TEMP_R\"}", - "hide": false, + "expr": "device_attribute{device=\"lts/unb2/1\",name=\"UNB2_FPGA_DDR4_SLOT_TEMP_R\"}", "interval": "", - "legendFormat": "Switch 1v2 board {{x}}", - "refId": "C" + "legendFormat": "FPGA QSFP Cage {{x}}, {{y}} ", + "refId": "A" + } + ], + "title": "Uniboard2 DDR4 Temperatures", + "type": "timeseries" + }, + { + "datasource": "Prometheus", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "celsius" }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 5, + "x": 0, + "y": 9 + }, + "id": 2, + "options": { + "legend": { + "calcs": [], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.1.2", + "targets": [ { "exemplar": true, - "expr": "device_attribute{device=\"lts/unb2/1\",name=\"UNB2_POL_SWITCH_PHY_TEMP_R\"}", + "expr": "device_attribute{device=\"lts/recv/1\",name=\"RCU_TEMP_R\"}", + "format": "time_series", "hide": false, + "instant": false, "interval": "", - "legendFormat": "Switch PHY board {{x}}", - "refId": "D" + "legendFormat": "{{x}}", + "refId": "A" + } + ], + "title": "RCU Temperatures", + "transformations": [], + "type": "timeseries" + }, + { + "datasource": "Prometheus", + "description": "Temperatures reported by APSCT and APSPU", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic", + "seriesBy": "max" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "line" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 85 + } + ] + }, + "unit": "celsius" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 5, + "x": 5, + "y": 9 + }, + "id": 24, + "options": { + "legend": { + "calcs": [], + "displayMode": "hidden", + "placement": "bottom" }, + "tooltip": { + "mode": "single" + } + }, + "targets": [ { "exemplar": true, - "expr": "device_attribute{device=\"lts/unb2/1\",name=\"UNB2_POL_CLOCK_TEMP_R\"}", - "hide": false, + "expr": "device_attribute{device=\"lts/apsct/1\",name=~\"APSCT_TEMP_R\"}", "interval": "", - "legendFormat": "Clock PWR board {{x}}", - "refId": "E" + "legendFormat": "{{name}}", + "refId": "A" }, { "exemplar": true, - "expr": "device_attribute{device=\"lts/unb2/1\",name=\"UNB2_DC_DC_48V_12V_TEMP_R\"}", + "expr": "device_attribute{device=\"lts/apspu/1\",name=~\"APSPU_.*_TEMP_R\"}", "hide": false, "interval": "", - "legendFormat": "DC-DC board {{x}}", - "refId": "F" + "legendFormat": "{{name}}", + "refId": "B" } ], - "title": "Uniboard2 Power Supply Temperatures", + "title": "APS Temperatures", "type": "timeseries" }, { "datasource": "Prometheus", - "description": "", + "description": "Temperature sensors of the power supply on each board", "fieldConfig": { "defaults": { "color": { - "mode": "palette-classic" + "mode": "palette-classic", + "seriesBy": "max" }, "custom": { "axisLabel": "", @@ -397,14 +625,14 @@ "scaleDistribution": { "type": "linear" }, - "showPoints": "auto", + "showPoints": "never", "spanNulls": false, "stacking": { "group": "A", "mode": "none" }, "thresholdsStyle": { - "mode": "off" + "mode": "line" } }, "mappings": [], @@ -417,7 +645,7 @@ }, { "color": "red", - "value": 80 + "value": 85 } ] }, @@ -429,9 +657,9 @@ "h": 8, "w": 5, "x": 15, - "y": 1 + "y": 9 }, - "id": 6, + "id": 8, "options": { "legend": { "calcs": [], @@ -442,21 +670,56 @@ "mode": "single" } }, - "pluginVersion": "8.1.2", "targets": [ { "exemplar": true, - "expr": "device_attribute{device=\"lts/sdp/1\",name=\"FPGA_temp_R\"}", - "format": "time_series", - "hide": false, - "instant": false, + "expr": "device_attribute{device=\"lts/unb2/1\",name=\"UNB2_POL_QSFP_N01_TEMP_R\"} ", "interval": "", - "legendFormat": "{{x}}", + "legendFormat": "QSFP N01 board {{x}}", "refId": "A" + }, + { + "exemplar": true, + "expr": "device_attribute{device=\"lts/unb2/1\",name=\"UNB2_POL_QSFP_N23_TEMP_R\"} ", + "hide": false, + "interval": "", + "legendFormat": "QSFP N23 board {{x}}", + "refId": "B" + }, + { + "exemplar": true, + "expr": "device_attribute{device=\"lts/unb2/1\",name=\"UNB2_POL_SWITCH_1V2_TEMP_R\"} ", + "hide": false, + "interval": "", + "legendFormat": "Switch 1v2 board {{x}}", + "refId": "C" + }, + { + "exemplar": true, + "expr": "device_attribute{device=\"lts/unb2/1\",name=\"UNB2_POL_SWITCH_PHY_TEMP_R\"} ", + "hide": false, + "interval": "", + "legendFormat": "Switch PHY board {{x}}", + "refId": "D" + }, + { + "exemplar": true, + "expr": "device_attribute{device=\"lts/unb2/1\",name=\"UNB2_POL_CLOCK_TEMP_R\"} ", + "hide": false, + "interval": "", + "legendFormat": "Clock PWR board {{x}}", + "refId": "E" + }, + { + "exemplar": true, + "expr": "device_attribute{device=\"lts/unb2/1\",name=\"UNB2_DC_DC_48V_12V_TEMP_R\"} ", + "hide": false, + "interval": "", + "legendFormat": "DC-DC board {{x}}", + "refId": "F" } ], - "title": "FPGA temperatures", - "transformations": [], + "title": "Uniboard2 Power Supply Temperatures", "type": "timeseries" }, { @@ -466,7 +729,7 @@ "h": 1, "w": 24, "x": 0, - "y": 9 + "y": 17 }, "id": 18, "panels": [], @@ -534,7 +797,7 @@ "h": 8, "w": 5, "x": 0, - "y": 10 + "y": 18 }, "id": 21, "options": { @@ -619,7 +882,7 @@ "h": 8, "w": 5, "x": 5, - "y": 10 + "y": 18 }, "id": 10, "options": { @@ -736,7 +999,7 @@ "h": 8, "w": 5, "x": 10, - "y": 10 + "y": 18 }, "id": 12, "options": { @@ -808,7 +1071,7 @@ "h": 1, "w": 24, "x": 0, - "y": 18 + "y": 26 }, "id": 20, "panels": [], @@ -878,7 +1141,7 @@ "h": 8, "w": 5, "x": 0, - "y": 19 + "y": 27 }, "id": 14, "options": { @@ -923,5 +1186,5 @@ "timezone": "", "title": "Sensors", "uid": "KMRmQzd7z", - "version": 3 + "version": 1 } diff --git a/docker-compose/integration-test.yml b/docker-compose/integration-test.yml index e0d1c6baf58948cdbee5a71ff2f859ab429dcd4b..defb45e3c3183516131795b283372ca784635d8c 100644 --- a/docker-compose/integration-test.yml +++ b/docker-compose/integration-test.yml @@ -15,11 +15,13 @@ services: container_name: ${CONTAINER_NAME_PREFIX}integration-test networks: - control + extra_hosts: + - "host.docker.internal:host-gateway" volumes: - ..:/opt/lofar/tango:rw environment: - TANGO_HOST=${TANGO_HOST} - working_dir: /opt/lofar/tango/devices + working_dir: /opt/lofar/tango/tangostationcontrol entrypoint: - /usr/local/bin/wait-for-it.sh - ${TANGO_HOST} diff --git a/docker-compose/itango.yml b/docker-compose/itango.yml index 5b0874f2f3c936c1b57915580ac79be81b5edcb9..9b01c4ea25e2abc5849c9a98c29cc7601ba1115f 100644 --- a/docker-compose/itango.yml +++ b/docker-compose/itango.yml @@ -21,6 +21,8 @@ services: container_name: ${CONTAINER_NAME_PREFIX}itango networks: - control + extra_hosts: + - "host.docker.internal:host-gateway" volumes: - ..:/opt/lofar/tango:rw - ${HOME}:/hosthome diff --git a/docker-compose/itango/lofar-requirements.txt b/docker-compose/itango/lofar-requirements.txt index 1349c50ca993b51bb866a7880e3e7fb185049de8..b193887dbfdb59a4bc143ce6dd48a720ec5ad00c 100644 --- a/docker-compose/itango/lofar-requirements.txt +++ b/docker-compose/itango/lofar-requirements.txt @@ -1,8 +1,4 @@ +# Do not put tangostationcontrol dependencies here parso == 0.7.1 jedi == 0.17.2 -asyncua -astropy -python-logstash-async -gitpython -PyMySQL[rsa] -sqlalchemy +astropy diff --git a/docker-compose/jupyter/Dockerfile b/docker-compose/jupyter/Dockerfile index 8be3e9f3900b01e80893d38aedcb4f6397aa8fd0..5393cece6a74ff1de85e9c37ce6a8307e3a66cf5 100644 --- a/docker-compose/jupyter/Dockerfile +++ b/docker-compose/jupyter/Dockerfile @@ -25,6 +25,7 @@ RUN sudo pip3 install notebook-as-pdf # 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 update -y 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 diff --git a/docker-compose/lofar-device-base.yml b/docker-compose/lofar-device-base.yml index 22ecabca37c526867afe52461d7ce432964f8385..ce110ed85ba0cfb20b607ab7d08e70505d2392e8 100644 --- a/docker-compose/lofar-device-base.yml +++ b/docker-compose/lofar-device-base.yml @@ -20,5 +20,9 @@ services: args: SOURCE_IMAGE: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}-tango-itango:${TANGO_ITANGO_VERSION} container_name: ${CONTAINER_NAME_PREFIX}lofar-device-base + # These parameters are just visual queues, you have to define them again + # in derived docker-compose files! networks: - control + extra_hosts: + - "host.docker.internal:host-gateway" diff --git a/docker-compose/lofar-device-base/lofar-requirements.txt b/docker-compose/lofar-device-base/lofar-requirements.txt index 31b22c71689b481357cef56bf4940c1575a3b01d..10ad55d977c97793a352c13da323d84d3c826c0e 100644 --- a/docker-compose/lofar-device-base/lofar-requirements.txt +++ b/docker-compose/lofar-device-base/lofar-requirements.txt @@ -1,7 +1,5 @@ -asyncua +# Do not put tangostationcontrol dependencies here astropy -python-logstash-async -gitpython -PyMySQL[rsa] -sqlalchemy -docker + +# requirements to build tangocontrol +GitPython >= 3.1.24 # BSD diff --git a/docker-compose/prometheus.yml b/docker-compose/prometheus.yml index a0971c48fde4551809a936594aadcb6a79076712..604f4bf4bde93dd6d68aaf7f3b1da2fd3f884e83 100644 --- a/docker-compose/prometheus.yml +++ b/docker-compose/prometheus.yml @@ -16,4 +16,10 @@ services: - control ports: - "9090:9090" + logging: + driver: syslog + options: + syslog-address: udp://${LOG_HOSTNAME}:1514 + syslog-format: rfc3164 + tag: "{{.Name}}" restart: unless-stopped diff --git a/docker-compose/rest.yml b/docker-compose/rest.yml index b76ed39c5319b10403a93db6736ce8d640380efc..467319399d6f3fec12a74068fea182195014b59e 100644 --- a/docker-compose/rest.yml +++ b/docker-compose/rest.yml @@ -33,3 +33,10 @@ services: - /usr/bin/supervisord - --configuration - /etc/supervisor/supervisord.conf + logging: + driver: syslog + options: + syslog-address: udp://${LOG_HOSTNAME}:1514 + syslog-format: rfc3164 + tag: "{{.Name}}" + restart: unless-stopped diff --git a/docker-compose/sdptr-sim/Dockerfile b/docker-compose/sdptr-sim/Dockerfile index fa23fe4d6458f4b7023c24b36774566cbac2163c..57fe98141f180a4d15a1e2d87c2c67be8f5894ff 100644 --- a/docker-compose/sdptr-sim/Dockerfile +++ b/docker-compose/sdptr-sim/Dockerfile @@ -16,5 +16,7 @@ RUN cd /sdptr && \ ./configure && \ bash -c "make -j `nproc` install" +COPY simulator.conf /sdptr/src/simulator.conf + WORKDIR /sdptr/src -CMD ["sdptr", "--type=LTS", "--configfile=uniboard.conf", "--nodaemon"] +CMD ["sdptr", "--type=simulator", "--configfile=simulator.conf", "--nodaemon"] diff --git a/docker-compose/sdptr-sim/simulator.conf b/docker-compose/sdptr-sim/simulator.conf new file mode 100644 index 0000000000000000000000000000000000000000..5ad69a8aed4807b815eeea18993d2b06e747b29f --- /dev/null +++ b/docker-compose/sdptr-sim/simulator.conf @@ -0,0 +1,19 @@ +# sdptr.conf +# configuration file for the SDP Translator. +# +# this config file holds settings for all [type]. +# +# # settings per type +# [LB_CORE] # [ant_band_station_type] +# n_fpgas = 16 # 8 or 16 +# first_pfga_nr = 0 # 0 for LB or 16 for HB +# ip_prefix = 10.99. # first part of ip (last part is hardware dependent) +# n_beamsets = 1 # 1 for 'LB', 'HB Remote' and 'HB International' and 2 for 'HB Core' + + +[simulator] +n_fpgas = 16 +first_fpga_nr = 0 +ip_prefix = 127.0. +n_beamsets = 1 + diff --git a/docker-compose/tango-prometheus-exporter/ska-tango-grafana-exporter b/docker-compose/tango-prometheus-exporter/ska-tango-grafana-exporter index 774d39a40ca19c9d979ad22565e57b4af3e9a831..dddb23ff587f6e9c837cdb77e7955e94272eca6f 160000 --- a/docker-compose/tango-prometheus-exporter/ska-tango-grafana-exporter +++ b/docker-compose/tango-prometheus-exporter/ska-tango-grafana-exporter @@ -1 +1 @@ -Subproject commit 774d39a40ca19c9d979ad22565e57b4af3e9a831 +Subproject commit dddb23ff587f6e9c837cdb77e7955e94272eca6f diff --git a/docker-compose/tango.yml b/docker-compose/tango.yml index 9fa0f5cde06f91b7cdc078f5c6481b013442e5ae..937cc5c8ecbe00b553d4692988e6cc2e5d7c51ef 100644 --- a/docker-compose/tango.yml +++ b/docker-compose/tango.yml @@ -28,6 +28,12 @@ services: - tangodb:/var/lib/mysql ports: - "3306:3306" + logging: + driver: syslog + options: + syslog-address: udp://${LOG_HOSTNAME}:1514 + syslog-format: rfc3164 + tag: "{{.Name}}" restart: unless-stopped databaseds: @@ -55,4 +61,10 @@ services: - "2" - -ORBendPoint - giop:tcp::10000 + logging: + driver: syslog + options: + syslog-address: udp://${LOG_HOSTNAME}:1514 + syslog-format: rfc3164 + tag: "{{.Name}}" restart: unless-stopped diff --git a/docs/source/developer.rst b/docs/source/developer.rst index 517dfa324298e9451bfa5f9b25eef9726476686e..38b18bc5d199546d93e0387788b640350471b61d 100644 --- a/docs/source/developer.rst +++ b/docs/source/developer.rst @@ -59,3 +59,40 @@ For more information, see: - https://huihoo.org/ace_tao/ACE-5.2+TAO-1.2/TAO/docs/ORBEndpoint.html - http://omniorb.sourceforge.net/omni42/omniNames.html - https://sourceforge.net/p/omniorb/svn/HEAD/tree/trunk/omniORB/src/lib/omniORB/orbcore/tcp/tcpEndpoint.cc + +Logging +------------------------- + +The ELK stack collects the logs from the containers, as well as any external processes that send theirs. It is the *Logstash* part of ELK that is responsible for this. The following interfaces are available for this purpose: + ++-------------+------------+-------------------------------------------------------------------------------------------------------------+ +| Interface | Port | Note | ++=============+============+=============================================================================================================+ +| Syslog | 1514/udp | Recommended over TCP, as the ELK stack might be down. | ++-------------+------------+-------------------------------------------------------------------------------------------------------------+ +| Syslog | 1514/tcp | | ++-------------+------------+-------------------------------------------------------------------------------------------------------------+ +| JSON | 5959/tcp | From python, recommended is the `LogStash Async <https://pypi.org/project/python-logstash-async/>`_ module. | ++-------------+------------+-------------------------------------------------------------------------------------------------------------+ +| Beats | 5044/tcp | Use `FileBeat <https://www.elastic.co/beats/filebeat>`_ to watch logs locally, and forward them to ELK. | ++-------------+------------+-------------------------------------------------------------------------------------------------------------+ + +We recommend making sure the contents of your log lines are parsed correctly, especially if logs are routed to the *Syslog* input. These configurations are stored in ``docker-compose/elk/logstash/conf.d``. An example: + +.. literalinclude:: ../../docker-compose/elk/logstash/conf.d/22-parse-tango-rest.conf + +Log from Python +````````````````` + +The ``common.lofar_logging`` module provides an easy way to log to the ELK stack from a Python Tango device. + +Log from Docker +````````````````` + +Not all Docker containers run our Python programs, and can forward the logs themselves. For those, we use the ``syslog`` log driver in Docker. Extend the ``docker compose`` files with: + +.. literalinclude:: ../../docker-compose/rest.yml + :start-at: logging: + :end-before: restart: + +Logs forwarded in this way are provided with the container name, their timestamp, and a log level guessed by Docker. It is thus wise to parse the message content further in Logstash (see above). diff --git a/docs/source/faq.rst b/docs/source/faq.rst index 8e35fceab3ec6ea07124e1181fccffdbe3cea679..1ed4fceacb85e6862c6f49d725fd4c53eb096081 100644 --- a/docs/source/faq.rst +++ b/docs/source/faq.rst @@ -66,7 +66,9 @@ SSTs/XSTs Some SSTs/XSTs packets do arrive, but not all, and/or the matrices remain zero? `````````````````````````````````````````````````````````````````````````````````````````````````````````````` -So ``sst.nof_packets_received`` / ``xst.nof_packets_received`` is increasing, telling you packets are arriving. But they're apparently dropped or contain zeroes. First, check the following settings: +So ``sst.nof_packets_received`` / ``xst.nof_packets_received`` is increasing, telling you packets are arriving. But they're apparently dropped or contain zeroes. + +The ``sdp.set_defaults()`` command, followed by ``sst.set_defaults()`` / ``xst.set_defaults()``, should reset that device to its default settings, which should result in a working system again. If not, or if the default configuration is not correct, check the following settings: - ``sdp.TR_fpga_mask_RW[x] == True``, to make sure we're actually configuring the FPGAs, - ``sdp.FPGA_wg_enable_RW[x] == False``, or the Waveform Generator might be replacing our the antenna data with zeroes, @@ -84,7 +86,7 @@ I am not receiving any XSTs and/or SSTs packets from SDP! Are you sure? If ``sst.nof_packets_received`` / ``xst.nof_packets_received`` is actually increasing, the packets are arriving, but are not parsable by the SST/XST device. If so, see the previous question. -Many settings need to be correct for the statistics emitted by the SDP FPGAs to reach our devices correctly. Here is a brief overview: +The ``sdp.set_defaults()`` command, followed by ``sst.set_defaults()`` / ``xst.set_defaults()``, should reset that device to its default settings, which should result in a working system again. If not, or if the default configuration is not correct, check the following settings: - ``sdp.TR_fpga_mask_RW[x] == True``, to make sure we're actually configuring the FPGAs, - ``sdp.FPGA_communication_error_R[x] == False``, to verify the FPGAs can be reached by SDP, diff --git a/docs/source/interfaces/logs.rst b/docs/source/interfaces/logs.rst index 960efcd95b5306ab1904ffd8519e36af85099f0f..fa0d29765c5d228454222a8f4a8d3d8f935c46be 100644 --- a/docs/source/interfaces/logs.rst +++ b/docs/source/interfaces/logs.rst @@ -15,11 +15,11 @@ ELK To monitor the logs remotely, or to browse older logs, use the *ELK stack* that is included on the station, and served on http://localhost:5601. ELK, or ElasticSearch + Logstash + Kibana, is a popular log collection and querying system. Currently, the following logs are collected in our ELK installation: - Logs of all devices, -- Logs of the Jupyter notebook server. +- Logs of the Docker containers. If you browse to the ELK stack (actually, it is Kibana providing the GUI), your go-to is the *Discover* view at http://localhost:5601/app/discover. There, you can construct (and save, load) a dashboard that provides a custom view of the logs, based on the *index pattern* ``logstash-*``. There is a lot to take in, and there are excellent Kibana tutorials on the web. -To get going, use for example `this dashboard <http://localhost:5601/app/discover#/?_g=(filters:!(),refreshInterval:(pause:!t,value:0),time:(from:now-60m,to:now))&_a=(columns:!(extra.lofar_id,level,message),filters:!(),index:'1e8ca200-1be0-11ec-a85f-b97e4206c18b',interval:auto,query:(language:kuery,query:''),sort:!())>`_, which shows the logs of the last hour, with some useful columns added to the default timestamp and message columns. Expand the time range if no logs appear, to look further back. You should see something like: +To get going, use for example `this dashboard <http://localhost:5601/app/discover#/?_g=(filters:!(),refreshInterval:(pause:!t,value:0),time:(from:now-1h,to:now))&_a=(columns:!(extra.lofar_id,program,level,message),filters:!(),index:'1e8ca200-1be0-11ec-a85f-b97e4206c18b',interval:auto,query:(language:kuery,query:'extra.lofar_id.keyword%20:%20*'),sort:!())>`_, which shows the logs of the last hour, with some useful columns added to the default timestamp and message columns. Expand the time range if no logs appear, to look further back. You should see something like: .. image:: elk_last_hour.png diff --git a/sbin/load_ConfigDb.sh b/sbin/load_ConfigDb.sh index 03ab449a026b5de41056f16de0d2e566a00adfbb..0fe57087a89dc08ebef51d4679a687ebbf6a144a 100755 --- a/sbin/load_ConfigDb.sh +++ b/sbin/load_ConfigDb.sh @@ -9,10 +9,10 @@ fi # copy file into container to read it from container, as the file's location # in the container won't be the same as on the host. -docker cp "${file}" dsconfig:/tmp/dsconfig-load-settings.json || exit 1 +docker cp "${file}" "${CONTAINER_NAME_PREFIX}"dsconfig:/tmp/dsconfig-update-settings.json || exit 1 -# write settings -docker exec -it dsconfig json2tango --write /tmp/dsconfig-load-settings.json +# update settings, Do not change -i into -it this will break integration tests in gitlab ci! +docker exec -i "${CONTAINER_NAME_PREFIX}"dsconfig json2tango --write /tmp/dsconfig-update-settings.json # somehow json2tango does not return 0 on success exit 0 diff --git a/sbin/run_integration_test.sh b/sbin/run_integration_test.sh index 2175f2774e771ac31e9dcd1cb1ade68da51f923e..4e988f7fce03eaf4142193c8156ddbcf60ace0bf 100755 --- a/sbin/run_integration_test.sh +++ b/sbin/run_integration_test.sh @@ -9,16 +9,22 @@ if [ -z "$LOFAR20_DIR" ]; then LOFAR20_DIR=$(readlink -f "${LOFAR20_DIR_RELATIVE}") fi -# Start and stop sequence cd "$LOFAR20_DIR/docker-compose" || exit 1 + +# Make sure builds are recent, and use our building parameters. +make build + +# Start and stop sequence make stop device-sdp device-recv device-sst device-unb2 device-xst sdptr-sim recv-sim unb2-sim apsct-sim apspu-sim -make start databaseds dsconfig jupyter elk +make start databaseds dsconfig elk # Give dsconfig and databaseds time to start -sleep 15 +sleep 60 # Update the dsconfig -"${LOFAR20_DIR}"/sbin/update_ConfigDb.sh "${LOFAR20_DIR}"/CDB/integration_ConfigDb.json +# Do not remove `bash`, otherwise statement ignored by gitlab ci shell! +bash "${LOFAR20_DIR}"/sbin/update_ConfigDb.sh "${LOFAR20_DIR}"/CDB/LOFAR_ConfigDb.json +bash "${LOFAR20_DIR}"/sbin/update_ConfigDb.sh "${LOFAR20_DIR}"/CDB/stations/simulators_ConfigDb.json cd "$LOFAR20_DIR/docker-compose" || exit 1 make start sdptr-sim recv-sim unb2-sim apsct-sim apspu-sim @@ -28,12 +34,16 @@ sleep 5 make start device-sdp device-recv device-sst device-unb2 device-xst -# Give the devices time to start -sleep 5 +# Give devices time to restart +# TODO(Corne Lukken): Use a nicer more reliable mechanism +sleep 60 # Start the integration test cd "$LOFAR20_DIR/docker-compose" || exit 1 make start integration-test +# Give devices time to restart +sleep 60 + # Run the integration test with the output displayed on stdout -docker start -a integration-test +docker start -a "${CONTAINER_NAME_PREFIX}"integration-test diff --git a/sbin/update_ConfigDb.sh b/sbin/update_ConfigDb.sh index 8d71c312fc94ba4dba45b17c05a966f62fa9ff34..1255f1ea141a75940f2cd858dfc2b40818bd6ec2 100755 --- a/sbin/update_ConfigDb.sh +++ b/sbin/update_ConfigDb.sh @@ -9,10 +9,10 @@ fi # copy file into container to read it from container, as the file's location # in the container won't be the same as on the host. -docker cp "${file}" dsconfig:/tmp/dsconfig-update-settings.json || exit 1 +docker cp "${file}" "${CONTAINER_NAME_PREFIX}"dsconfig:/tmp/dsconfig-update-settings.json || exit 1 -# update settings -docker exec -it dsconfig json2tango --write --update /tmp/dsconfig-update-settings.json +# update settings, Do not change -i into -it this will break integration tests in gitlab ci! +docker exec -i "${CONTAINER_NAME_PREFIX}"dsconfig json2tango --write --update /tmp/dsconfig-update-settings.json # somehow json2tango does not return 0 on success exit 0 diff --git a/tangostationcontrol/.stestr.conf b/tangostationcontrol/.stestr.conf new file mode 100644 index 0000000000000000000000000000000000000000..59b161cddad8a253059cf201b8872bc946f78c64 --- /dev/null +++ b/tangostationcontrol/.stestr.conf @@ -0,0 +1,3 @@ +[DEFAULT] +test_path=${TESTS_DIR:-./tangostationcontrol/test} +top_dir=./ diff --git a/devices/README.md b/tangostationcontrol/README.md similarity index 91% rename from devices/README.md rename to tangostationcontrol/README.md index 0604c3a4d1d90b7d99ab1f35cee1922c6ee99371..0fef1b58aa82065b03353315cdd63ded8e2a3cd2 100644 --- a/devices/README.md +++ b/tangostationcontrol/README.md @@ -3,7 +3,7 @@ This code provides an attribute_wrapper class in place of attributes for tango devices. the attribute wrappers contain additional code that moves a lot of the complexity and redundant code to the background. -The tango Device class is also abstracted further to a "hardware_device" class. This class wraps +The tango Device class is also abstracted further to a "lofar_device" class. This class wraps The only things required on the users part are to declare the attributes using the attribute_wrapper (see `example/example_device`), declare what client the attribute has to use in the initialisation and provide support for the used clients. diff --git a/tangostationcontrol/requirements.txt b/tangostationcontrol/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..b1620255b5a45c9e3f653661e65de6732fd93a07 --- /dev/null +++ b/tangostationcontrol/requirements.txt @@ -0,0 +1,13 @@ +# the order of packages is of significance, because pip processes them in the +# order of appearance. Changing the order has an impact on the overall +# integration process, which may cause wedges in the gate later. + +asyncua >= 0.9.90 # LGPLv3 +PyMySQL[rsa] >= 1.0.2 # MIT +sqlalchemy >= 1.4.26 #MIT +GitPython >= 3.1.24 # BSD +snmp >= 0.1.7 # GPL3 +h5py >= 3.5.0 # BSD +psutil >= 5.8.0 # BSD +docker >= 5.0.3 # Apache 2 +python-logstash-async >= 2.3.0 # MIT \ No newline at end of file diff --git a/tangostationcontrol/setup.cfg b/tangostationcontrol/setup.cfg new file mode 100644 index 0000000000000000000000000000000000000000..daee0edbff26ee8f44613d75dd8a6bcd411906e0 --- /dev/null +++ b/tangostationcontrol/setup.cfg @@ -0,0 +1,56 @@ +[metadata] +name = tangostationcontrol +version = attr: tangostationcontrol.__version__ +summary = LOFAR 2.0 Station Control +description_file = + README.md +description_content_type = text/x-rst; charset=UTF-8 +author = ASTRON +home_page = https://astron.nl +project_urls = + Bug Tracker = https://support.astron.nl/jira/projects/L2SS/issues/ + Source Code = https://git.astron.nl/lofar2.0/tango +license = Apache-2 +classifier = + Environment :: Console + License :: Apache Software License + Operating System :: POSIX :: Linux + Programming Language :: Python + Programming Language :: Python :: 3 + Programming Language :: Python :: 3.6 + Programming Language :: Python :: 3.7 + Programming Language :: Python :: 3.8 + Programming Language :: Python :: 3.9 + Programming Language :: Python :: 3.10 + +[options] +package_dir= + =./ +packages=find: +python_requires = >=3.6 + +[options.packages.find] +where=./ + +[options.entry_points] +console_scripts = + l2ss-boot = tangostationcontrol.devices.boot:main + l2ss-docker-device = tangostationcontrol.devices.docker_device:main + l2ss-observation = tangostationcontrol.devices.observation:main + l2ss-observation-control = tangostationcontrol.devices.observation_control:main + l2ss-receiver = tangostationcontrol.devices.recv:main + l2ss-sdp = tangostationcontrol.devices.sdp.sdp:main + l2ss-sst = tangostationcontrol.devices.sdp.sst:main + l2ss-unb2 = tangostationcontrol.devices.unb2:main + l2ss-xst = tangostationcontrol.devices.sdp.xst:main + l2ss-statistics-reader = tangostationcontrol.statistics_writer.statistics_reader:main + l2ss-statistics-writer = tangostationcontrol.statistics_writer.statistics_writer:main + +# The following entry points should eventually be removed / replaced + l2ss-cold-start = tangostationcontrol.toolkit.lts_cold_start:main + l2ss-hardware-device-template = tangostationcontrol.examples.HW_device_template:main + l2ss-ini-device = tangostationcontrol.examples.load_from_disk.ini_device:main + l2ss-parse-statistics-packet = tangostationcontrol.devices.sdp.statistics_packet:main + l2ss-random-data = tangostationcontrol.test.devices.random_data:main + l2ss-snmp = tangostationcontrol.examples.snmp.snmp:main + l2ss-version = tangostationcontrol.common.lofar_version:main diff --git a/tangostationcontrol/setup.py b/tangostationcontrol/setup.py new file mode 100644 index 0000000000000000000000000000000000000000..6356812fdc2951fff6af9659feca273df06efca3 --- /dev/null +++ b/tangostationcontrol/setup.py @@ -0,0 +1,7 @@ +import setuptools + +with open('requirements.txt') as f: + required = f.read().splitlines() + +# Requires: setup.cfg +setuptools.setup(install_requires=required) diff --git a/tangostationcontrol/tangostationcontrol/__init__.py b/tangostationcontrol/tangostationcontrol/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..c6e48f3e8c0b11146b60c5fb7b8b2285fd7124d0 --- /dev/null +++ b/tangostationcontrol/tangostationcontrol/__init__.py @@ -0,0 +1,3 @@ +from tangostationcontrol.common.lofar_version import get_version + +__version__ = get_version() diff --git a/devices/clients/README.md b/tangostationcontrol/tangostationcontrol/clients/README.md similarity index 100% rename from devices/clients/README.md rename to tangostationcontrol/tangostationcontrol/clients/README.md diff --git a/devices/devices/__init__.py b/tangostationcontrol/tangostationcontrol/clients/__init__.py similarity index 100% rename from devices/devices/__init__.py rename to tangostationcontrol/tangostationcontrol/clients/__init__.py diff --git a/devices/clients/attribute_wrapper.py b/tangostationcontrol/tangostationcontrol/clients/attribute_wrapper.py similarity index 94% rename from devices/clients/attribute_wrapper.py rename to tangostationcontrol/tangostationcontrol/clients/attribute_wrapper.py index e55a662142cb89f62775fb7ac2189c063593df37..f9cc13b3bfa8738414fa265c5a2154c0c471a493 100644 --- a/devices/clients/attribute_wrapper.py +++ b/tangostationcontrol/tangostationcontrol/clients/attribute_wrapper.py @@ -2,7 +2,7 @@ from tango.server import attribute from tango import AttrWriteType import numpy -from devices.device_decorators import only_when_on, fault_on_error +from tangostationcontrol.devices.device_decorators import only_when_on, fault_on_error import logging logger = logging.getLogger() @@ -154,7 +154,7 @@ class attribute_wrapper(attribute): try: self.read_function, self.write_function = client.setup_attribute(self.comms_annotation, self) except Exception as e: - raise Exception("Exception while setting %s attribute with annotation: '%s'", client.__class__.__name__, self.comms_annotation) from e + raise Exception(f"Exception while setting {client.__class__.__name__} attribute with annotation: {self.comms_annotation}") from e async def async_set_comm_client(self, client): """ @@ -163,7 +163,7 @@ class attribute_wrapper(attribute): try: self.read_function, self.write_function = await client.setup_attribute(self.comms_annotation, self) except Exception as e: - raise Exception("Exception while setting %s attribute with annotation: '%s'", client.__class__.__name__, self.comms_annotation) from e + raise Exception(f"Exception while setting {client.__class__.__name__} attribute with annotation: {self.comms_annotation}") from e def set_pass_func(self): def pass_func(value=None): diff --git a/devices/clients/comms_client.py b/tangostationcontrol/tangostationcontrol/clients/comms_client.py similarity index 100% rename from devices/clients/comms_client.py rename to tangostationcontrol/tangostationcontrol/clients/comms_client.py diff --git a/devices/clients/docker_client.py b/tangostationcontrol/tangostationcontrol/clients/docker_client.py similarity index 100% rename from devices/clients/docker_client.py rename to tangostationcontrol/tangostationcontrol/clients/docker_client.py diff --git a/devices/clients/opcua_client.py b/tangostationcontrol/tangostationcontrol/clients/opcua_client.py similarity index 96% rename from devices/clients/opcua_client.py rename to tangostationcontrol/tangostationcontrol/clients/opcua_client.py index bf68edd19318648f1c8313f349a63671000382c7..145c0ebe68c3824d764dd4417a81afeae8ce0247 100644 --- a/devices/clients/opcua_client.py +++ b/tangostationcontrol/tangostationcontrol/clients/opcua_client.py @@ -1,11 +1,10 @@ -from threading import Thread import socket import numpy import asyncua import asyncio from asyncua import Client -from clients.comms_client import AsyncCommClient +from tangostationcontrol.clients.comms_client import AsyncCommClient import logging logger = logging.getLogger() @@ -86,7 +85,9 @@ class OPCUAConnection(AsyncCommClient): ping the client to make sure the connection with the client is still functional. """ try: - await self.client.send_hello() + # do a cheap call. NOTE: send_hello is not allowed after establishing a connection, + # so cannot be used here. see https://reference.opcfoundation.org/v104/Core/docs/Part6/7.1.3/ + _ = await self.client.get_namespace_array() except Exception as e: raise IOError("Lost connection to server %s: %s", self._servername(), e) diff --git a/devices/clients/statistics_client.py b/tangostationcontrol/tangostationcontrol/clients/statistics_client.py similarity index 98% rename from devices/clients/statistics_client.py rename to tangostationcontrol/tangostationcontrol/clients/statistics_client.py index 3fd470fbf0319e45242abbc3a79362584628f844..2790197bdb90f2483d872f0dfd5978fa088d4980 100644 --- a/devices/clients/statistics_client.py +++ b/tangostationcontrol/tangostationcontrol/clients/statistics_client.py @@ -6,7 +6,7 @@ from .comms_client import AsyncCommClient from .tcp_replicator import TCPReplicator from .udp_receiver import UDPReceiver -from devices.sdp.statistics_collector import StatisticsConsumer +from tangostationcontrol.devices.sdp.statistics_collector import StatisticsConsumer logger = logging.getLogger() diff --git a/devices/clients/statistics_client_thread.py b/tangostationcontrol/tangostationcontrol/clients/statistics_client_thread.py similarity index 100% rename from devices/clients/statistics_client_thread.py rename to tangostationcontrol/tangostationcontrol/clients/statistics_client_thread.py diff --git a/devices/clients/tcp_replicator.py b/tangostationcontrol/tangostationcontrol/clients/tcp_replicator.py similarity index 99% rename from devices/clients/tcp_replicator.py rename to tangostationcontrol/tangostationcontrol/clients/tcp_replicator.py index 5ac6e492d977cf14452d4f97bd213c0d12af7cbb..8b820cc765daa193fe142f4a3f49ef7a3f643c76 100644 --- a/devices/clients/tcp_replicator.py +++ b/tangostationcontrol/tangostationcontrol/clients/tcp_replicator.py @@ -6,7 +6,7 @@ from threading import Thread import asyncio import logging -from clients.statistics_client_thread import StatisticsClientThread +from tangostationcontrol.clients.statistics_client_thread import StatisticsClientThread logger = logging.getLogger() diff --git a/devices/clients/udp_receiver.py b/tangostationcontrol/tangostationcontrol/clients/udp_receiver.py similarity index 98% rename from devices/clients/udp_receiver.py rename to tangostationcontrol/tangostationcontrol/clients/udp_receiver.py index 8a9d1429945cdd5c41c47bf45edc5034c1cafa0c..2bda038a1fb0646af2d2e14082e10ca3d7866816 100644 --- a/devices/clients/udp_receiver.py +++ b/tangostationcontrol/tangostationcontrol/clients/udp_receiver.py @@ -7,7 +7,7 @@ import socket import time from typing import List # not needed for python3.9+, where we can use the type "list[Queue]" directly -from clients.statistics_client_thread import StatisticsClientThread +from tangostationcontrol.clients.statistics_client_thread import StatisticsClientThread logger = logging.getLogger() diff --git a/devices/devices/sdp/__init__.py b/tangostationcontrol/tangostationcontrol/common/__init__.py similarity index 100% rename from devices/devices/sdp/__init__.py rename to tangostationcontrol/tangostationcontrol/common/__init__.py diff --git a/devices/common/baselines.py b/tangostationcontrol/tangostationcontrol/common/baselines.py similarity index 100% rename from devices/common/baselines.py rename to tangostationcontrol/tangostationcontrol/common/baselines.py diff --git a/tangostationcontrol/tangostationcontrol/common/entrypoint.py b/tangostationcontrol/tangostationcontrol/common/entrypoint.py new file mode 100644 index 0000000000000000000000000000000000000000..d5b9d4952ee08180162b3bdca7417fff31f456f0 --- /dev/null +++ b/tangostationcontrol/tangostationcontrol/common/entrypoint.py @@ -0,0 +1,21 @@ +import sys + +from tango.server import run + +from tangostationcontrol.common.lofar_logging import configure_logger + + +def entry(Device, **kwargs): + """General device entrypoint""" + + # Remove first argument which is filename + args = sys.argv[1:] + + # Setup logging + configure_logger() + + # Start the device server + if type(Device) is tuple: + return run(Device, args=args, **kwargs) + else: + return run((Device,), args=args, **kwargs) diff --git a/devices/common/lofar_logging.py b/tangostationcontrol/tangostationcontrol/common/lofar_logging.py similarity index 99% rename from devices/common/lofar_logging.py rename to tangostationcontrol/tangostationcontrol/common/lofar_logging.py index 826e484e6e2bd321c343b814ccb734472e8bf73c..46d417c67987b1cec37897552ad35446ac7fdae1 100644 --- a/devices/common/lofar_logging.py +++ b/tangostationcontrol/tangostationcontrol/common/lofar_logging.py @@ -1,12 +1,11 @@ import logging from functools import wraps from tango.server import Device -import sys import traceback import socket import time -from .lofar_git import get_version +from .lofar_version import get_version class TangoLoggingHandler(logging.Handler): level_to_device_stream = { diff --git a/tangostationcontrol/tangostationcontrol/common/lofar_version.py b/tangostationcontrol/tangostationcontrol/common/lofar_version.py new file mode 100644 index 0000000000000000000000000000000000000000..89cb22f9fe6b76caf438984c673b21d00bc25645 --- /dev/null +++ b/tangostationcontrol/tangostationcontrol/common/lofar_version.py @@ -0,0 +1,103 @@ +import git +import os +import functools +import pkg_resources +import re + +def get_repo(starting_directory: str = os.path.dirname(os.path.abspath(__file__)), limit = 10) -> git.Repo: + """ Try finding the repository by traversing up the tree. + + By default, the repository containing this module is returned. + """ + + directory = starting_directory + + try: + return git.Repo(directory) + except git.InvalidGitRepositoryError: + pass + + # We now have to traverse up the tree up until limit diretories + for i in range(limit): + if directory == "/" or not os.path.exists(directory): + break + + directory = os.path.abspath(directory + os.path.sep + "..") + + try: + return git.Repo(directory) + except git.InvalidGitRepositoryError: + pass + + # Could not find a repo within the limit so return None + return None + + +@functools.lru_cache(maxsize=None) +def get_version(repo: git.Repo = None) -> str: + """ Return a version string for the current commit. + + There is a practical issue: the repository changes over time, f.e. switching branches with 'git checkout'. We want + to know the version that is running in memory, not the one that is on disk. + + As a work-around, we cache the version information, in that it is at least consistent. It is up to the caller + to request the version early enough. + + The version string is of the following pattern: + - ${MAJOR}.${MINOR}.${PATCH}[.${BRANCH}$.{COMMIT}][.dirty] + + For releases only ${MAJOR}.${MINOR}.${PATCH} should be set. Versioning is + achieved by tagging commits using the `v${MAJOR}.${MINOR}.${PATCH}` pattern. + The leading `v` is none optional! + + """ + + if repo is None: + repo = get_repo() + + # When we can't find a git repo anymore, we must be packaged. Extract the + # package version directly + if repo is None: + try: + return pkg_resources.require("tangostationcontrol")[0].version + except Exception: + pass + + # Filter all tags so that they must match vMAJOR.MINOR.PATCH or + # vMAJOR.MINOR.PATCH.BRANCHCOMMIT + reg = re.compile(r'^v[0-9](\.[0-9]){2}(\.[a-z]*[0-9]*)?') + + commit = repo.commit() + filtered_tags = [tag.name for tag in repo.tags if reg.search(tag.name)] + # Order tags from newest to oldest + tags = {tag.commit: tag for tag in reversed(repo.tags) if tag.name in filtered_tags} + + # Find closest tag for commit + closest_tag = type('',(object,),{"name": 'v0.0.0'})() + for item in commit.iter_items(repo, commit): + if item.type == 'commit' and item in tags: + closest_tag = tags[item] + break + + if commit in tags: + # a tag = production ready + commit_str = "{}".format(tags[commit].name[1:]) + elif repo.head.is_detached: + # no active branch + commit_str = "{}.{}".format(closest_tag.name[1:], commit) + else: + # HEAD of a branch + branch = repo.active_branch + commit_str = "{}.{}.{}".format(closest_tag.name[1:], branch, commit) + + return "{}{}".format(commit_str, ".dirty" if repo.is_dirty() else "") + +# at least cache the current repo version immediately +try: + _ = get_version() +except: + pass + + +def main(args=None, **kwargs): + print(get_version()) diff --git a/devices/examples/__init__.py b/tangostationcontrol/tangostationcontrol/devices/__init__.py similarity index 100% rename from devices/examples/__init__.py rename to tangostationcontrol/tangostationcontrol/devices/__init__.py diff --git a/devices/devices/abstract_device.py b/tangostationcontrol/tangostationcontrol/devices/abstract_device.py similarity index 86% rename from devices/devices/abstract_device.py rename to tangostationcontrol/tangostationcontrol/devices/abstract_device.py index 5b65c3a6c02fd487920e02efed2394de275f1a9d..8250e4e481dc9d27ec88654b6fef777d0e9bc4e4 100644 --- a/devices/devices/abstract_device.py +++ b/tangostationcontrol/tangostationcontrol/devices/abstract_device.py @@ -20,7 +20,7 @@ logger = logging.getLogger() class AbstractDeviceMetas(DeviceMeta, ABCMeta): - """Collects meta classes to allow hardware_device to be both a Device and an ABC. """ + """Collects meta classes to allow lofar_device to be both a Device and an ABC. """ def __new__(mcs, name, bases, namespace, **kwargs): cls = ABCMeta.__new__(mcs, name, bases, namespace, **kwargs) diff --git a/devices/devices/apsct.py b/tangostationcontrol/tangostationcontrol/devices/apsct.py similarity index 87% rename from devices/devices/apsct.py rename to tangostationcontrol/tangostationcontrol/devices/apsct.py index c8b0cb0ad8843fc44fd6c3e298d3a6cfd15d6f5f..78a0626d8a12985d944c752e544aff93209373be 100644 --- a/devices/devices/apsct.py +++ b/tangostationcontrol/tangostationcontrol/devices/apsct.py @@ -46,11 +46,14 @@ class APSCT(opcua_device): # Attributes # ---------- + APSCTTR_I2C_error_R = attribute_wrapper(comms_annotation=["APSCTTR_I2C_error_R" ],datatype=numpy.int64 ) + APSCTTR_monitor_rate_RW = attribute_wrapper(comms_annotation=["APSCTTR_monitor_rate_RW" ],datatype=numpy.int64 , access=AttrWriteType.READ_WRITE) APSCTTR_translator_busy_R = attribute_wrapper(comms_annotation=["APSCTTR_translator_busy_R" ],datatype=numpy.bool_ ) - APSCT_I2C_error_R = attribute_wrapper(comms_annotation=["APSCT_I2C_error_R" ],datatype=numpy.int64 ) - APSCT_ID_R = attribute_wrapper(comms_annotation=["APSCT_ID_R" ],datatype=numpy.int64 ) APSCT_INPUT_10MHz_good_R = attribute_wrapper(comms_annotation=["APSCT_INPUT_10MHz_good_R" ],datatype=numpy.bool_ ) APSCT_INPUT_PPS_good_R = attribute_wrapper(comms_annotation=["APSCT_INPUT_PPS_good_R" ],datatype=numpy.bool_ ) + APSCT_PCB_ID_R = attribute_wrapper(comms_annotation=["APSCT_PCB_ID_R" ],datatype=numpy.int64 ) + APSCT_PCB_number_R = attribute_wrapper(comms_annotation=["APSCT_PCB_number_R" ],datatype=numpy.str ) + APSCT_PCB_version_R = attribute_wrapper(comms_annotation=["APSCT_PCB_version_R" ],datatype=numpy.str ) APSCT_PLL_160MHz_error_R = attribute_wrapper(comms_annotation=["APSCT_PLL_160MHz_error_R" ],datatype=numpy.bool_ ) APSCT_PLL_160MHz_locked_R = attribute_wrapper(comms_annotation=["APSCT_PLL_160MHz_locked_R" ],datatype=numpy.bool_ ) APSCT_PLL_200MHz_error_R = attribute_wrapper(comms_annotation=["APSCT_PLL_200MHz_error_R" ],datatype=numpy.bool_ ) @@ -67,8 +70,7 @@ class APSCT(opcua_device): APSCT_PWR_PLL_200MHz_3V3_R = attribute_wrapper(comms_annotation=["APSCT_PWR_PLL_200MHz_3V3_R"],datatype=numpy.float64) APSCT_PWR_PLL_200MHz_on_R = attribute_wrapper(comms_annotation=["APSCT_PWR_PLL_200MHz_on_R" ],datatype=numpy.bool_ ) APSCT_PWR_PPSDIST_3V3_R = attribute_wrapper(comms_annotation=["APSCT_PWR_PPSDIST_3V3_R" ],datatype=numpy.float64) - APSCT_temperature_R = attribute_wrapper(comms_annotation=["APSCT_temperature_R" ],datatype=numpy.float64) - APSCT_version_R = attribute_wrapper(comms_annotation=["APSCT_version_R" ],datatype=numpy.str ) + APSCT_TEMP_R = attribute_wrapper(comms_annotation=["APSCT_TEMP_R" ],datatype=numpy.float64) # -------- # overloaded functions diff --git a/devices/devices/apspu.py b/tangostationcontrol/tangostationcontrol/devices/apspu.py similarity index 72% rename from devices/devices/apspu.py rename to tangostationcontrol/tangostationcontrol/devices/apspu.py index cec9e56364a7c78d8938d0fb9241a840d1e0f95e..3daab9c071a73b75a4d28def984d4794d4aa7aef 100644 --- a/devices/devices/apspu.py +++ b/tangostationcontrol/tangostationcontrol/devices/apspu.py @@ -43,22 +43,24 @@ class APSPU(opcua_device): # Attributes # ---------- + APSPUTR_I2C_error_R = attribute_wrapper(comms_annotation=["APSPUTR_I2C_error_R" ],datatype=numpy.int64 ) + APSPUTR_monitor_rate_RW = attribute_wrapper(comms_annotation=["APSPUTR_monitor_rate_RW" ],datatype=numpy.int64 , access=AttrWriteType.READ_WRITE) APSPUTR_translator_busy_R = attribute_wrapper(comms_annotation=["APSPUTR_translator_busy_R" ],datatype=numpy.bool_ ) - APSPU_FAN1_RMS_R = attribute_wrapper(comms_annotation=["APSPU_FAN1_RMS_R" ],datatype=numpy.float64) - APSPU_FAN2_RMS_R = attribute_wrapper(comms_annotation=["APSPU_FAN2_RMS_R" ],datatype=numpy.float64) - APSPU_FAN3_RMS_R = attribute_wrapper(comms_annotation=["APSPU_FAN3_RMS_R" ],datatype=numpy.float64) - APSPU_I2C_error_R = attribute_wrapper(comms_annotation=["APSPU_I2C_error_R" ],datatype=numpy.int64 ) - APSPU_ID_R = attribute_wrapper(comms_annotation=["APSPU_ID_R" ],datatype=numpy.int64 ) + APSPU_FAN1_RPM_R = attribute_wrapper(comms_annotation=["APSPU_FAN1_RPM_R" ],datatype=numpy.float64) + APSPU_FAN2_RPM_R = attribute_wrapper(comms_annotation=["APSPU_FAN2_RPM_R" ],datatype=numpy.float64) + APSPU_FAN3_RPM_R = attribute_wrapper(comms_annotation=["APSPU_FAN3_RPM_R" ],datatype=numpy.float64) APSPU_LBA_IOUT_R = attribute_wrapper(comms_annotation=["APSPU_LBA_IOUT_R" ],datatype=numpy.float64) APSPU_LBA_TEMP_R = attribute_wrapper(comms_annotation=["APSPU_LBA_TEMP_R" ],datatype=numpy.float64) APSPU_LBA_VOUT_R = attribute_wrapper(comms_annotation=["APSPU_LBA_VOUT_R" ],datatype=numpy.float64) + APSPU_PCB_ID_R = attribute_wrapper(comms_annotation=["APSPU_PCB_ID_R" ],datatype=numpy.int64 ) + APSPU_PCB_number_R = attribute_wrapper(comms_annotation=["APSPU_PCB_number_R" ],datatype=numpy.str ) + APSPU_PCB_version_R = attribute_wrapper(comms_annotation=["APSPU_PCB_version_R" ],datatype=numpy.str ) APSPU_RCU2A_IOUT_R = attribute_wrapper(comms_annotation=["APSPU_RCU2A_IOUT_R" ],datatype=numpy.float64) APSPU_RCU2A_TEMP_R = attribute_wrapper(comms_annotation=["APSPU_RCU2A_TEMP_R" ],datatype=numpy.float64) APSPU_RCU2A_VOUT_R = attribute_wrapper(comms_annotation=["APSPU_RCU2A_VOUT_R" ],datatype=numpy.float64) APSPU_RCU2D_IOUT_R = attribute_wrapper(comms_annotation=["APSPU_RCU2D_IOUT_R" ],datatype=numpy.float64) APSPU_RCU2D_TEMP_R = attribute_wrapper(comms_annotation=["APSPU_RCU2D_TEMP_R" ],datatype=numpy.float64) APSPU_RCU2D_VOUT_R = attribute_wrapper(comms_annotation=["APSPU_RCU2D_VOUT_R" ],datatype=numpy.float64) - APSPU_version_R = attribute_wrapper(comms_annotation=["APSPU_version_R" ],datatype=numpy.str ) # -------- # overloaded functions diff --git a/devices/devices/boot.py b/tangostationcontrol/tangostationcontrol/devices/boot.py similarity index 93% rename from devices/devices/boot.py rename to tangostationcontrol/tangostationcontrol/devices/boot.py index 5d9540aa52ffa1f177b3cd615110676f73466343..897f2cfb557c4f3a24464360309eba4226fe19cf 100644 --- a/devices/devices/boot.py +++ b/tangostationcontrol/tangostationcontrol/devices/boot.py @@ -13,12 +13,6 @@ Boots the rest of the station software. """ -# TODO(Corne): Remove sys.path.append hack once packaging is in place! -import os, sys -currentdir = os.path.dirname(os.path.realpath(__file__)) -parentdir = os.path.dirname(currentdir) -sys.path.append(parentdir) - # PyTango imports from tango import DebugIt from tango.server import run, command @@ -29,10 +23,9 @@ import numpy from device_decorators import * -from clients.attribute_wrapper import attribute_wrapper -from devices.hardware_device import hardware_device -from common.lofar_logging import device_logging_to_python, log_exceptions -from common.lofar_git import get_version +from tangostationcontrol.common.entry 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() @@ -191,7 +184,7 @@ class DevicesInitialiser(Thread): self.set_status(f"[restarting {device_name}] Succesfully started.") @device_logging_to_python() -class Boot(hardware_device): +class Boot(lofar_device): # ----------------- # Device Properties # ----------------- @@ -294,14 +287,6 @@ class Boot(hardware_device): # ---------- # Run server # ---------- -def main(args=None, **kwargs): - """Main function of the RECV module.""" - - from common.lofar_logging import configure_logger - configure_logger() - - return run((Boot,), args=args, **kwargs) - - -if __name__ == '__main__': - main() +def main(**kwargs): + """Main function of the Boot module.""" + return entry(Boot, **kwargs) diff --git a/devices/devices/device_decorators.py b/tangostationcontrol/tangostationcontrol/devices/device_decorators.py similarity index 100% rename from devices/devices/device_decorators.py rename to tangostationcontrol/tangostationcontrol/devices/device_decorators.py diff --git a/devices/devices/docker_device.py b/tangostationcontrol/tangostationcontrol/devices/docker_device.py similarity index 91% rename from devices/devices/docker_device.py rename to tangostationcontrol/tangostationcontrol/devices/docker_device.py index f8a83dd41f9a81a217dcab9a2dc54201ecff1025..b7193ecb1408e58394e84de1e317dbae5e569a5f 100644 --- a/devices/devices/docker_device.py +++ b/tangostationcontrol/tangostationcontrol/devices/docker_device.py @@ -11,14 +11,7 @@ """ -# TODO(Corne): Remove sys.path.append hack once packaging is in place! -import os, sys -currentdir = os.path.dirname(os.path.realpath(__file__)) -parentdir = os.path.dirname(currentdir) -sys.path.append(parentdir) - # PyTango imports -from tango import DebugIt from tango.server import run, command from tango.server import device_property, attribute from tango import AttrWriteType @@ -28,15 +21,17 @@ import asyncio from device_decorators import * -from clients.docker_client import DockerClient -from clients.attribute_wrapper import attribute_wrapper -from devices.hardware_device import hardware_device -from common.lofar_logging import device_logging_to_python, log_exceptions +# Additional import +from tangostationcontrol.common.entrypoint import entry +from tangostationcontrol.clients.docker_client import DockerClient +from tangostationcontrol.clients.attribute_wrapper import attribute_wrapper +from tangostationcontrol.devices.lofar_device import lofar_device +from tangostationcontrol.common.lofar_logging import device_logging_to_python, log_exceptions __all__ = ["Docker", "main"] @device_logging_to_python() -class Docker(hardware_device): +class Docker(lofar_device): # ----------------- # Device Properties # ----------------- @@ -131,14 +126,6 @@ class Docker(hardware_device): # ---------- # Run server # ---------- -def main(args=None, **kwargs): +def main(**kwargs): """Main function of the Docker module.""" - - from common.lofar_logging import configure_logger - configure_logger() - - return run((Docker,), args=args, **kwargs) - - -if __name__ == '__main__': - main() + return entry(Docker, **kwargs) diff --git a/devices/devices/hardware_device.py b/tangostationcontrol/tangostationcontrol/devices/lofar_device.py similarity index 94% rename from devices/devices/hardware_device.py rename to tangostationcontrol/tangostationcontrol/devices/lofar_device.py index 7c7e6663cff7a68f8b0340d59f076bb946ea9ec5..5a2cc74136514d0aa4a2f2ce16fb1609d9a219ec 100644 --- a/devices/devices/hardware_device.py +++ b/tangostationcontrol/tangostationcontrol/devices/lofar_device.py @@ -15,23 +15,25 @@ from abc import abstractmethod # PyTango imports from tango.server import Device, command, DeviceMeta, attribute -from tango import DevState, DebugIt, Attribute, DeviceProxy, AttrWriteType -# Additional import +from tango import AttrWriteType, DevState, DebugIt, Attribute, DeviceProxy -from clients.attribute_wrapper import attribute_wrapper -from common.lofar_logging import log_exceptions -from common.lofar_git import get_version -from devices.abstract_device import AbstractDeviceMetas -from devices.device_decorators import only_in_states, fault_on_error import time import math -__all__ = ["hardware_device"] +# Additional import +from tangostationcontrol.clients.attribute_wrapper import attribute_wrapper +from tangostationcontrol.common.lofar_logging import log_exceptions +from tangostationcontrol.common.lofar_version import get_version +from tangostationcontrol.devices.abstract_device import AbstractDeviceMetas +from tangostationcontrol.devices.device_decorators import only_in_states, fault_on_error + + +__all__ = ["lofar_device"] import logging logger = logging.getLogger() -class hardware_device(Device, metaclass=AbstractDeviceMetas): +class lofar_device(Device, metaclass=AbstractDeviceMetas): """ **Properties:** @@ -102,7 +104,7 @@ class hardware_device(Device, metaclass=AbstractDeviceMetas): # -------- @command() - @only_in_states([DevState.FAULT, DevState.OFF]) + @only_in_states([DevState.OFF]) @DebugIt() @fault_on_error() @log_exceptions() @@ -279,4 +281,3 @@ class hardware_device(Device, metaclass=AbstractDeviceMetas): time.sleep(pollperiod) raise Exception(f"{attr} != {value} after f{timeout} seconds still.") - diff --git a/devices/devices/observation.py b/tangostationcontrol/tangostationcontrol/devices/observation.py similarity index 88% rename from devices/devices/observation.py rename to tangostationcontrol/tangostationcontrol/devices/observation.py index 0ac9cbc1837fdd8e7ded14bb6c8459226c223866..0c38ed93c76f0e03aa71de0a0d880d8ede6d8251 100644 --- a/devices/devices/observation.py +++ b/tangostationcontrol/tangostationcontrol/devices/observation.py @@ -5,22 +5,16 @@ # Distributed under the terms of the APACHE license. # See LICENSE.txt for more info. - -# TODO(Corne): Remove sys.path.append hack once packaging is in place! -import os, sys -currentdir = os.path.dirname(os.path.realpath(__file__)) -parentdir = os.path.dirname(currentdir) -sys.path.append(parentdir) - # PyTango imports from tango import server, Except, DevState, AttrWriteType, DevString, DebugIt from tango.server import Device, run, command, attribute import numpy from time import time -from devices.device_decorators import * -from common.lofar_logging import device_logging_to_python, log_exceptions -from common.lofar_git import get_version +from tangostationcontrol.common.entrypoint import entry +from tangostationcontrol.common.lofar_logging import device_logging_to_python, log_exceptions +from tangostationcontrol.common.lofar_version import get_version +from tangostationcontrol.devices.device_decorators import * from json import loads @@ -62,7 +56,7 @@ class Observation(Device): # Lifecycle functions @command(dtype_in = DevString) - @only_in_states([DevState.FAULT, DevState.OFF]) + @only_in_states([DevState.OFF]) @log_exceptions() def Initialise(self, parameters: DevString = None): self.set_state(DevState.INIT) @@ -117,10 +111,6 @@ class Observation(Device): # ---------- # Run server # ---------- -def main(args = None, **kwargs): +def main(**kwargs): """Main function of the ObservationControl module.""" - return run((Observation,), args = args, **kwargs) - - -if __name__ == '__main__': - main() + return entry(Observation, **kwargs) diff --git a/devices/devices/observation_control.py b/tangostationcontrol/tangostationcontrol/devices/observation_control.py similarity index 97% rename from devices/devices/observation_control.py rename to tangostationcontrol/tangostationcontrol/devices/observation_control.py index 9b60f86bb983057d023483ebaa61164bdfba5bee..0383b9ab7e0b69e54feddd40af2bdc6eb4da3bb0 100644 --- a/devices/devices/observation_control.py +++ b/tangostationcontrol/tangostationcontrol/devices/observation_control.py @@ -5,13 +5,6 @@ # Distributed under the terms of the APACHE license. # See LICENSE.txt for more info. - -# TODO(Corne): Remove sys.path.append hack once packaging is in place! -import os, sys -currentdir = os.path.dirname(os.path.realpath(__file__)) -parentdir = os.path.dirname(currentdir) -sys.path.append(parentdir) - # PyTango imports from tango import Except, DevFailed, DevState, AttrWriteType, DebugIt, DeviceProxy, Util, DevBoolean, DevString from tango.server import Device, run, command, device_property, attribute @@ -21,11 +14,11 @@ import numpy import time from json import loads -from devices.device_decorators import * -from common.lofar_logging import device_logging_to_python, log_exceptions -from common.lofar_git import get_version - -from observation import Observation +from tangostationcontrol.common.entrypoint import entry +from tangostationcontrol.common.lofar_logging import device_logging_to_python, log_exceptions +from tangostationcontrol.common.lofar_version import get_version +from tangostationcontrol.devices.device_decorators import * +from tangostationcontrol.devices.observation import Observation __all__ = ["ObservationControl", "main"] @@ -123,7 +116,7 @@ class ObservationControl(Device): # Lifecycle functions @command() - @only_in_states([DevState.FAULT, DevState.OFF]) + @only_in_states([DevState.OFF]) @log_exceptions() @DebugIt() def Initialise(self): @@ -445,10 +438,6 @@ class ObservationControl(Device): # ---------- # Run server # ---------- -def main(args = None, **kwargs): +def main(**kwargs): """Main function of the ObservationControl module.""" - return run((ObservationControl, Observation), verbose = True, args = args, **kwargs) - - -if __name__ == '__main__': - main() + return entry((ObservationControl, Observation), verbose=True, **kwargs) diff --git a/devices/devices/opcua_device.py b/tangostationcontrol/tangostationcontrol/devices/opcua_device.py similarity index 92% rename from devices/devices/opcua_device.py rename to tangostationcontrol/tangostationcontrol/devices/opcua_device.py index fd49b90f122868a0741ebe91ba69d71a434143d6..c88cedfb840ad434fa80d9435b36045e0070d334 100644 --- a/devices/devices/opcua_device.py +++ b/tangostationcontrol/tangostationcontrol/devices/opcua_device.py @@ -25,15 +25,14 @@ import numpy import asyncio # Additional import -from devices.device_decorators import * - -from clients.opcua_client import OPCUAConnection -from devices.hardware_device import hardware_device -from common.lofar_logging import device_logging_to_python, log_exceptions +from tangostationcontrol.common.lofar_logging import device_logging_to_python, log_exceptions +from tangostationcontrol.clients.opcua_client import OPCUAConnection +from tangostationcontrol.devices.device_decorators import * +from tangostationcontrol.devices.lofar_device import lofar_device __all__ = ["opcua_device", "main"] -class opcua_device(hardware_device): +class opcua_device(lofar_device): """ **Properties:** diff --git a/devices/devices/recv.py b/tangostationcontrol/tangostationcontrol/devices/recv.py similarity index 78% rename from devices/devices/recv.py rename to tangostationcontrol/tangostationcontrol/devices/recv.py index d180e955a56ee583a7a2fbc1a732d933c27acced..a9eee4160f9b7a6f981119c58ad2e707df0cf717 100644 --- a/devices/devices/recv.py +++ b/tangostationcontrol/tangostationcontrol/devices/recv.py @@ -11,25 +11,19 @@ """ -# TODO(Corne): Remove sys.path.append hack once packaging is in place! -import os, sys -currentdir = os.path.dirname(os.path.realpath(__file__)) -parentdir = os.path.dirname(currentdir) -sys.path.append(parentdir) - # PyTango imports from tango import DebugIt from tango.server import run, command from tango.server import device_property, attribute from tango import AttrWriteType import numpy -# Additional import -from device_decorators import * - -from clients.attribute_wrapper import attribute_wrapper -from devices.opcua_device import opcua_device -from common.lofar_logging import device_logging_to_python, log_exceptions +# Additional import +from tangostationcontrol.common.entrypoint import entry +from tangostationcontrol.common.lofar_logging import device_logging_to_python, log_exceptions +from tangostationcontrol.clients.attribute_wrapper import attribute_wrapper +from tangostationcontrol.devices.device_decorators import * +from tangostationcontrol.devices.opcua_device import opcua_device import logging logger = logging.getLogger() @@ -63,11 +57,12 @@ class RECV(opcua_device): # ---------- # Attributes # ---------- - Ant_status_R = attribute(dtype=str, max_dim_x=3, max_dim_y=32) + ANT_status_R = attribute(dtype=str, max_dim_x=3, max_dim_y=32) + RCU_LED_colour_R = attribute(dtype=numpy.uint32, max_dim_x=32, fget=lambda self: (2 * self.RCU_LED_green_on_R + 4 * self.RCU_LED_red_on_R).astype(numpy.uint32)) ANT_mask_RW = attribute_wrapper(comms_annotation=["ANT_mask_RW" ],datatype=numpy.bool_ , dims=(3,32), access=AttrWriteType.READ_WRITE) - HBAT_beamformer_delays_R = attribute_wrapper(comms_annotation=["HBAT_beamformer_delays_R" ],datatype=numpy.int64 , dims=(32,96)) - HBAT_beamformer_delays_RW = attribute_wrapper(comms_annotation=["HBAT_beamformer_delays_RW" ],datatype=numpy.int64 , dims=(32,96), access=AttrWriteType.READ_WRITE) + HBAT_BF_delays_R = attribute_wrapper(comms_annotation=["HBAT_BF_delays_R" ],datatype=numpy.int64 , dims=(32,96)) + HBAT_BF_delays_RW = attribute_wrapper(comms_annotation=["HBAT_BF_delays_RW" ],datatype=numpy.int64 , dims=(32,96), access=AttrWriteType.READ_WRITE) HBAT_LED_on_R = attribute_wrapper(comms_annotation=["HBAT_LED_on_R" ],datatype=numpy.bool_ , dims=(32,96)) HBAT_LED_on_RW = attribute_wrapper(comms_annotation=["HBAT_LED_on_RW" ],datatype=numpy.bool_ , dims=(32,96), access=AttrWriteType.READ_WRITE) HBAT_PWR_LNA_on_R = attribute_wrapper(comms_annotation=["HBAT_PWR_LNA_on_R" ],datatype=numpy.bool_ , dims=(32,96)) @@ -82,14 +77,14 @@ class RECV(opcua_device): RCU_DTH_freq_R = attribute_wrapper(comms_annotation=["RCU_DTH_freq_R" ],datatype=numpy.int64 , dims=(3,32)) RCU_DTH_freq_RW = attribute_wrapper(comms_annotation=["RCU_DTH_freq_RW" ],datatype=numpy.int64 , dims=(3,32), access=AttrWriteType.READ_WRITE) RCU_DTH_on_R = attribute_wrapper(comms_annotation=["RCU_DTH_on_R" ],datatype=numpy.bool_ , dims=(3,32)) - RCU_DTH_shutdown_R = attribute_wrapper(comms_annotation=["RCU_DTH_shutdown_R" ],datatype=numpy.bool_ , dims=(3,32)) - RCU_I2C_error_R = attribute_wrapper(comms_annotation=["RCU_I2C_error_R" ],datatype=numpy.int64 , dims=(32,)) - RCU_ID_R = attribute_wrapper(comms_annotation=["RCU_ID_R" ],datatype=numpy.int64 , dims=(32,)) - RCU_LED_green_off_R = attribute_wrapper(comms_annotation=["RCU_LED_green_off_R" ],datatype=numpy.bool_ , dims=(32,)) - RCU_LED_green_off_RW = attribute_wrapper(comms_annotation=["RCU_LED_green_off_RW" ],datatype=numpy.bool_ , dims=(32,), access=AttrWriteType.READ_WRITE) - RCU_LED_red_off_R = attribute_wrapper(comms_annotation=["RCU_LED_red_off_R" ],datatype=numpy.bool_ , dims=(32,)) - RCU_LED_red_off_RW = attribute_wrapper(comms_annotation=["RCU_LED_red_off_RW" ],datatype=numpy.bool_ , dims=(32,), access=AttrWriteType.READ_WRITE) + RCU_LED_green_on_R = attribute_wrapper(comms_annotation=["RCU_LED_green_on_R" ],datatype=numpy.bool_ , dims=(32,)) + RCU_LED_green_on_RW = attribute_wrapper(comms_annotation=["RCU_LED_green_on_RW" ],datatype=numpy.bool_ , dims=(32,), access=AttrWriteType.READ_WRITE) + RCU_LED_red_on_R = attribute_wrapper(comms_annotation=["RCU_LED_red_on_R" ],datatype=numpy.bool_ , dims=(32,)) + RCU_LED_red_on_RW = attribute_wrapper(comms_annotation=["RCU_LED_red_on_RW" ],datatype=numpy.bool_ , dims=(32,), access=AttrWriteType.READ_WRITE) RCU_mask_RW = attribute_wrapper(comms_annotation=["RCU_mask_RW" ],datatype=numpy.bool_ , dims=(32,), access=AttrWriteType.READ_WRITE) + RCU_PCB_ID_R = attribute_wrapper(comms_annotation=["RCU_PCB_ID_R" ],datatype=numpy.int64 , dims=(32,)) + RCU_PCB_number_R = attribute_wrapper(comms_annotation=["RCU_PCB_number_R" ],datatype=numpy.str , dims=(32,)) + RCU_PCB_version_R = attribute_wrapper(comms_annotation=["RCU_PCB_version_R" ],datatype=numpy.str , dims=(32,)) RCU_PWR_1V8_R = attribute_wrapper(comms_annotation=["RCU_PWR_1V8_R" ],datatype=numpy.float64, dims=(32,)) RCU_PWR_2V5_R = attribute_wrapper(comms_annotation=["RCU_PWR_2V5_R" ],datatype=numpy.float64, dims=(32,)) RCU_PWR_3V3_R = attribute_wrapper(comms_annotation=["RCU_PWR_3V3_R" ],datatype=numpy.float64, dims=(32,)) @@ -101,8 +96,9 @@ class RECV(opcua_device): RCU_PWR_ANT_VOUT_R = attribute_wrapper(comms_annotation=["RCU_PWR_ANT_VOUT_R" ],datatype=numpy.float64, dims=(3,32)) RCU_PWR_DIGITAL_on_R = attribute_wrapper(comms_annotation=["RCU_PWR_DIGITAL_on_R" ],datatype=numpy.bool_ , dims=(32,)) RCU_PWR_good_R = attribute_wrapper(comms_annotation=["RCU_PWR_good_R" ],datatype=numpy.bool_ , dims=(32,)) - RCU_temperature_R = attribute_wrapper(comms_annotation=["RCU_temperature_R" ],datatype=numpy.float64, dims=(32,)) - RCU_version_R = attribute_wrapper(comms_annotation=["RCU_version_R" ],datatype=numpy.str , dims=(32,)) + RCU_TEMP_R = attribute_wrapper(comms_annotation=["RCU_TEMP_R" ],datatype=numpy.float64, dims=(32,)) + RECVTR_I2C_error_R = attribute_wrapper(comms_annotation=["RECVTR_I2C_error_R" ],datatype=numpy.int64 , dims=(32,)) + RECVTR_monitor_rate_RW = attribute_wrapper(comms_annotation=["RECVTR_monitor_rate_RW" ],datatype=numpy.int64 , access=AttrWriteType.READ_WRITE) RECVTR_translator_busy_R = attribute_wrapper(comms_annotation=["RECVTR_translator_busy_R" ],datatype=numpy.bool_ ) # -------- @@ -191,7 +187,7 @@ class RECV(opcua_device): return rcu_status - def read_Ant_status_R(self): + def read_ANT_status_R(self): """ Returns a set of strings denoting the status of each antenna. An empty string means no problems were detected. A non-empty @@ -199,9 +195,9 @@ class RECV(opcua_device): This function can be used as input to modify the Ant_mask_RW. """ - ant_mask = self.Ant_mask_RW + ant_mask = self.ANT_mask_RW rcu_mask = self.RCU_mask_RW - adc_lock = self.RCU_ADC_lock_R + adc_lock = self.RCU_ADC_locked_R i2c_errors = self.RCU_I2C_STATUS_R nr_rcus = len(ant_mask) @@ -232,14 +228,6 @@ class RECV(opcua_device): # ---------- # Run server # ---------- -def main(args=None, **kwargs): +def main(**kwargs): """Main function of the RECV module.""" - - from common.lofar_logging import configure_logger - configure_logger() - - return run((RECV,), args=args, **kwargs) - - -if __name__ == '__main__': - main() + return entry(RECV, **kwargs) diff --git a/devices/integration_test/__init__.py b/tangostationcontrol/tangostationcontrol/devices/sdp/__init__.py similarity index 100% rename from devices/integration_test/__init__.py rename to tangostationcontrol/tangostationcontrol/devices/sdp/__init__.py diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py b/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py new file mode 100644 index 0000000000000000000000000000000000000000..4c4b03f8a75d026f2f322ea9b301b9d2b537a6ba --- /dev/null +++ b/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py @@ -0,0 +1,177 @@ +# -*- coding: utf-8 -*- +# +# This file is part of the SDP project +# +# +# +# Distributed under the terms of the APACHE license. +# See LICENSE.txt for more info. + +""" SDP Device Server for LOFAR2.0 + +""" + +# PyTango imports +from tango.server import run +from tango.server import device_property, attribute +from tango import AttrWriteType + +# Additional import +from tangostationcontrol.clients.attribute_wrapper import attribute_wrapper +from tangostationcontrol.devices.opcua_device import opcua_device +from tangostationcontrol.common.entrypoint import entry +from tangostationcontrol.common.lofar_logging import device_logging_to_python, log_exceptions + +import numpy + +__all__ = ["SDP", "main"] + + +@device_logging_to_python() +class SDP(opcua_device): + # ----------------- + # Device Properties + # ----------------- + + TR_fpga_mask_RW_default = device_property( + dtype='DevVarBooleanArray', + mandatory=False, + default_value=[True] * 16 + ) + + 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 + ) + + # If we enable the waveform generator, we want some sane defaults. + + FPGA_wg_amplitude_RW = device_property( + dtype='DevVarDoubleArray', + mandatory=False, + default_value=[[0.1] * 12] * 16 + ) + + FPGA_wg_frequency_RW = device_property( + dtype='DevVarDoubleArray', + mandatory=False, + # Emit a signal on subband 102 + default_value=[[102 * 200e6/1024] * 12] * 16 + ) + + FPGA_wg_phase_RW = device_property( + dtype='DevVarDoubleArray', + mandatory=False, + default_value=[[0.0] * 12] * 16 + ) + + FPGA_sdp_info_station_id_RW_default = device_property( + dtype='DevVarULongArray', + mandatory=False, + default_value=[0] * 16 + ) + + FPGA_subband_weights_RW_default = device_property( + dtype='DevVarULongArray', + mandatory=False, + default_value=[[8192] * 12 * 512] * 16 + ) + + first_default_settings = [ + # set the masks first, as those filter any subsequent settings + 'TR_fpga_mask_RW' + ] + + # ---------- + # Attributes + # ---------- + + FPGA_beamlet_output_enable_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_enable_R"], datatype=numpy.bool_, dims=(16,)) + FPGA_beamlet_output_enable_RW = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_enable_RW"], datatype=numpy.bool_, dims=(16,), access=AttrWriteType.READ_WRITE) + FPGA_beamlet_output_hdr_eth_destination_mac_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_eth_destination_mac_R"], datatype=numpy.str, dims=(16,)) + FPGA_beamlet_output_hdr_eth_destination_mac_RW = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_eth_destination_mac_RW"], datatype=numpy.str, dims=(16,), access=AttrWriteType.READ_WRITE) + FPGA_beamlet_output_hdr_ip_destination_address_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_ip_destination_address_R"], datatype=numpy.str, dims=(16,)) + FPGA_beamlet_output_hdr_ip_destination_address_RW = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_ip_destination_address_RW"], datatype=numpy.str, dims=(16,), access=AttrWriteType.READ_WRITE) + FPGA_beamlet_output_hdr_udp_destination_port_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_udp_destination_port_R"], datatype=numpy.uint16, dims=(16,)) + FPGA_beamlet_output_hdr_udp_destination_port_RW = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_udp_destination_port_RW"], datatype=numpy.uint16, dims=(16,), access=AttrWriteType.READ_WRITE) + FPGA_beamlet_output_scale_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_scale_R"], datatype=numpy.uint32, dims=(16,)) + FPGA_beamlet_output_scale_RW = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_scale_RW"], datatype=numpy.uint32, dims=(16,), access=AttrWriteType.READ_WRITE) + FPGA_firmware_version_R = attribute_wrapper(comms_annotation=["FPGA_firmware_version_R"], datatype=numpy.str, dims=(16,)) + 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_processing_enable_R = attribute_wrapper(comms_annotation=["FPGA_processing_enable_R"], datatype=numpy.bool_, dims=(16,)) + FPGA_processing_enable_RW = attribute_wrapper(comms_annotation=["FPGA_processing_enable_RW"], datatype=numpy.bool_, dims=(16,), access=AttrWriteType.READ_WRITE) + FPGA_scrap_R = attribute_wrapper(comms_annotation=["FPGA_scrap_R"], datatype=numpy.int32, dims=(8192,)) + FPGA_scrap_RW = attribute_wrapper(comms_annotation=["FPGA_scrap_RW"], datatype=numpy.int32, dims=(8192,), access=AttrWriteType.READ_WRITE) + FPGA_sdp_info_antenna_band_index_R = attribute_wrapper(comms_annotation=["FPGA_sdp_info_antenna_band_index_R"], datatype=numpy.uint32, dims=(16,)) + FPGA_sdp_info_block_period_R = attribute_wrapper(comms_annotation=["FPGA_sdp_info_block_period_R"], datatype=numpy.uint32, dims=(16,)) + FPGA_sdp_info_f_adc_R = attribute_wrapper(comms_annotation=["FPGA_sdp_info_f_adc_R"], datatype=numpy.uint32, dims=(16,)) + FPGA_sdp_info_fsub_type_R = attribute_wrapper(comms_annotation=["FPGA_sdp_info_fsub_type_R"], datatype=numpy.uint32, dims=(16,)) + FPGA_sdp_info_nyquist_sampling_zone_index_R = attribute_wrapper(comms_annotation=["FPGA_sdp_info_nyquist_sampling_zone_index_R"], datatype=numpy.uint32, dims=(16,)) + FPGA_sdp_info_nyquist_sampling_zone_index_RW = attribute_wrapper(comms_annotation=["FPGA_sdp_info_nyquist_sampling_zone_index_RW"], datatype=numpy.uint32, dims=(16,), access=AttrWriteType.READ_WRITE) + FPGA_sdp_info_observation_id_R = attribute_wrapper(comms_annotation=["FPGA_sdp_info_observation_id_R"], datatype=numpy.uint32, dims=(16,)) + FPGA_sdp_info_observation_id_RW = attribute_wrapper(comms_annotation=["FPGA_sdp_info_observation_id_RW"], datatype=numpy.uint32, dims=(16,), access=AttrWriteType.READ_WRITE) + FPGA_sdp_info_station_id_R = attribute_wrapper(comms_annotation=["FPGA_sdp_info_station_id_R"], datatype=numpy.uint32, dims=(16,)) + FPGA_sdp_info_station_id_RW = attribute_wrapper(comms_annotation=["FPGA_sdp_info_station_id_RW"], datatype=numpy.uint32, dims=(16,), access=AttrWriteType.READ_WRITE) + FPGA_subband_weights_R = attribute_wrapper(comms_annotation=["FPGA_subband_weights_R"], datatype=numpy.uint32, dims=(12 * 512, 16)) + FPGA_subband_weights_RW = attribute_wrapper(comms_annotation=["FPGA_subband_weights_RW"], datatype=numpy.uint32, dims=(12 * 512, 16), access=AttrWriteType.READ_WRITE) + FPGA_temp_R = attribute_wrapper(comms_annotation=["FPGA_temp_R"], datatype=numpy.float_, dims=(16,)) + FPGA_weights_R = attribute_wrapper(comms_annotation=["FPGA_weights_R"], datatype=numpy.int16, dims=(12 * 488 * 2, 16)) + FPGA_weights_RW = attribute_wrapper(comms_annotation=["FPGA_weights_RW"], datatype=numpy.int16, dims=(12 * 488 * 2, 16), access=AttrWriteType.READ_WRITE) + FPGA_wg_amplitude_R = attribute_wrapper(comms_annotation=["FPGA_wg_amplitude_R"], datatype=numpy.float_, dims=(12, 16)) + FPGA_wg_amplitude_RW = attribute_wrapper(comms_annotation=["FPGA_wg_amplitude_RW"], datatype=numpy.float_, dims=(12, 16), access=AttrWriteType.READ_WRITE) + FPGA_wg_enable_R = attribute_wrapper(comms_annotation=["FPGA_wg_enable_R"], datatype=numpy.bool_, dims=(12, 16)) + FPGA_wg_enable_RW = attribute_wrapper(comms_annotation=["FPGA_wg_enable_RW"], datatype=numpy.bool_, dims=(12, 16), access=AttrWriteType.READ_WRITE) + FPGA_wg_frequency_R = attribute_wrapper(comms_annotation=["FPGA_wg_frequency_R"], datatype=numpy.float_, dims=(12, 16)) + FPGA_wg_frequency_RW = attribute_wrapper(comms_annotation=["FPGA_wg_frequency_RW"], datatype=numpy.float_, dims=(12, 16), access=AttrWriteType.READ_WRITE) + FPGA_wg_phase_R = attribute_wrapper(comms_annotation=["FPGA_wg_phase_R"], datatype=numpy.float_, dims=(12, 16)) + FPGA_wg_phase_RW = attribute_wrapper(comms_annotation=["FPGA_wg_phase_RW"], datatype=numpy.float_, dims=(12, 16), access=AttrWriteType.READ_WRITE) + TR_fpga_mask_R = attribute_wrapper(comms_annotation=["TR_fpga_mask_R"], datatype=numpy.bool_, dims=(16,)) + TR_fpga_mask_RW = attribute_wrapper(comms_annotation=["TR_fpga_mask_RW"], datatype=numpy.bool_, dims=(16,), access=AttrWriteType.READ_WRITE) + TR_fpga_communication_error_R = attribute_wrapper(comms_annotation=["TR_fpga_communication_error_R"], datatype=numpy.bool_, dims=(16,)) + TR_sdp_config_first_fpga_nr_R = attribute_wrapper(comms_annotation=["TR_sdp_config_first_fpga_nr_R"], datatype=numpy.uint32) + TR_sdp_config_nof_beamsets_R = attribute_wrapper(comms_annotation=["TR_sdp_config_nof_beamsets_R"], datatype=numpy.uint32) + TR_sdp_config_nof_fpgas_R = attribute_wrapper(comms_annotation=["TR_sdp_config_nof_fpgas_R"], datatype=numpy.uint32) + TR_software_version_R = attribute_wrapper(comms_annotation=["TR_software_version_R"], datatype=numpy.str) + TR_start_time_R = attribute_wrapper(comms_annotation=["TR_start_time_R"], datatype=numpy.int64) + TR_tod_R = attribute_wrapper(comms_annotation=["TR_tod_R"], datatype=numpy.int64, dims=(2,)) + TR_tod_pps_delta_R = attribute_wrapper(comms_annotation=["TR_tod_pps_delta_R"], datatype=numpy.double) + + S_pn = 12 # Number of ADC signal inputs per Processing Node (PN) FPGA. + N_pn = 16 # Number of FPGAs per antenna band that is controlled via the SC - SDP interface. + + # OPC-UA MP only points for AIT + FPGA_signal_input_mean_R = attribute_wrapper(comms_annotation=["FPGA_signal_input_mean_R"], datatype=numpy.double , dims=(S_pn, N_pn)) + FPGA_signal_input_rms_R = attribute_wrapper(comms_annotation=["FPGA_signal_input_rms_R"], datatype=numpy.double, dims=(S_pn, N_pn)) + + FPGA_jesd204b_csr_rbd_count_R = attribute_wrapper(comms_annotation=["FPGA_jesd204b_csr_rbd_count_R"], datatype=numpy.uint32, dims=(S_pn, N_pn)) + FPGA_jesd204b_csr_dev_syncn_R = attribute_wrapper(comms_annotation=["FPGA_jesd204b_csr_dev_syncn_R"], datatype=numpy.uint32, dims=(S_pn, N_pn)) + FPGA_jesd204b_rx_err0_R = attribute_wrapper(comms_annotation=["FPGA_jesd204b_rx_err0_R"], datatype=numpy.uint32, dims=(S_pn, N_pn)) + FPGA_jesd204b_rx_err1_R = attribute_wrapper(comms_annotation=["FPGA_jesd204b_rx_err1_R"], datatype=numpy.uint32, dims=(S_pn, N_pn)) + + FPGA_bsn_monitor_input_bsn_R = attribute_wrapper(comms_annotation=["FPGA_bsn_monitor_input_bsn_R"], datatype=numpy.int64, dims=(N_pn,)) + FPGA_bsn_monitor_input_nof_packets_R = attribute_wrapper(comms_annotation=["FPGA_bsn_monitor_input_nof_packets_R"], datatype=numpy.int32, dims=(N_pn,)) + FPGA_bsn_monitor_input_nof_valid_R = attribute_wrapper(comms_annotation=["FPGA_bsn_monitor_input_nof_valid_R"], datatype=numpy.int32, dims=(N_pn,)) + FPGA_bsn_monitor_input_nof_err_R = attribute_wrapper(comms_annotation=["FPGA_bsn_monitor_input_nof_err_R"], datatype=numpy.int32, dims=(N_pn,)) + + # -------- + # overloaded functions + # -------- + + # -------- + # Commands + # -------- + +# ---------- +# Run server +# ---------- +def main(**kwargs): + """Main function of the SDP module.""" + return entry(SDP, **kwargs) diff --git a/devices/devices/sdp/sst.py b/tangostationcontrol/tangostationcontrol/devices/sdp/sst.py similarity index 66% rename from devices/devices/sdp/sst.py rename to tangostationcontrol/tangostationcontrol/devices/sdp/sst.py index 277714ab0b7ada6882a5ec1086690b3c29fb2382..18f000697b5351487ce4c75c0796e2cc81c28740 100644 --- a/devices/devices/sdp/sst.py +++ b/tangostationcontrol/tangostationcontrol/devices/sdp/sst.py @@ -11,29 +11,24 @@ """ -# TODO(Corne): Remove sys.path.append hack once packaging is in place! -import os, sys -currentdir = os.path.dirname(os.path.realpath(__file__)) -parentdir = os.path.dirname(currentdir) -parentdir = os.path.dirname(parentdir) -sys.path.append(parentdir) - # PyTango imports from tango.server import run from tango.server import device_property, attribute from tango import AttrWriteType # Additional import -from clients.attribute_wrapper import attribute_wrapper -from clients.statistics_client import StatisticsClient -from clients.opcua_client import OPCUAConnection -from devices.sdp.statistics import Statistics -from devices.sdp.statistics_collector import SSTCollector +from tangostationcontrol.common.entrypoint import entry +from tangostationcontrol.clients.attribute_wrapper import attribute_wrapper +from tangostationcontrol.clients.opcua_client import OPCUAConnection +from tangostationcontrol.clients.statistics_client import StatisticsClient +from tangostationcontrol.devices.sdp.statistics import Statistics +from tangostationcontrol.devices.sdp.statistics_collector import SSTCollector import numpy __all__ = ["SST", "main"] + class SST(Statistics): STATISTICS_COLLECTOR_CLASS = SSTCollector @@ -85,16 +80,16 @@ class SST(Statistics): # ---------- # FPGA control points for SSTs - FPGA_sst_offload_enable_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_sst_offload_enable_RW"], datatype=numpy.bool_, dims=(16,), access=AttrWriteType.READ_WRITE) - FPGA_sst_offload_enable_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_sst_offload_enable_R"], datatype=numpy.bool_, dims=(16,)) - FPGA_sst_offload_hdr_eth_destination_mac_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_sst_offload_hdr_eth_destination_mac_RW"], datatype=numpy.str, dims=(16,), access=AttrWriteType.READ_WRITE) - FPGA_sst_offload_hdr_eth_destination_mac_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_sst_offload_hdr_eth_destination_mac_R"], datatype=numpy.str, dims=(16,)) - FPGA_sst_offload_hdr_ip_destination_address_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_sst_offload_hdr_ip_destination_address_RW"], datatype=numpy.str, dims=(16,), access=AttrWriteType.READ_WRITE) - FPGA_sst_offload_hdr_ip_destination_address_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_sst_offload_hdr_ip_destination_address_R"], datatype=numpy.str, dims=(16,)) - FPGA_sst_offload_hdr_udp_destination_port_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_sst_offload_hdr_udp_destination_port_RW"], datatype=numpy.uint16, dims=(16,), access=AttrWriteType.READ_WRITE) - FPGA_sst_offload_hdr_udp_destination_port_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_sst_offload_hdr_udp_destination_port_R"], datatype=numpy.uint16, dims=(16,)) - FPGA_sst_offload_weighted_subbands_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_sst_offload_weighted_subbands_RW"], datatype=numpy.bool_, dims=(16,), access=AttrWriteType.READ_WRITE) - FPGA_sst_offload_weighted_subbands_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_sst_offload_weighted_subbands_R"], datatype=numpy.bool_, dims=(16,)) + FPGA_sst_offload_enable_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_enable_RW"], datatype=numpy.bool_, dims=(16,), access=AttrWriteType.READ_WRITE) + FPGA_sst_offload_enable_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_enable_R"], datatype=numpy.bool_, dims=(16,)) + FPGA_sst_offload_hdr_eth_destination_mac_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_hdr_eth_destination_mac_RW"], datatype=numpy.str, dims=(16,), access=AttrWriteType.READ_WRITE) + FPGA_sst_offload_hdr_eth_destination_mac_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_hdr_eth_destination_mac_R"], datatype=numpy.str, dims=(16,)) + FPGA_sst_offload_hdr_ip_destination_address_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_hdr_ip_destination_address_RW"], datatype=numpy.str, dims=(16,), access=AttrWriteType.READ_WRITE) + FPGA_sst_offload_hdr_ip_destination_address_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_hdr_ip_destination_address_R"], datatype=numpy.str, dims=(16,)) + FPGA_sst_offload_hdr_udp_destination_port_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_hdr_udp_destination_port_RW"], datatype=numpy.uint16, dims=(16,), access=AttrWriteType.READ_WRITE) + FPGA_sst_offload_hdr_udp_destination_port_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_hdr_udp_destination_port_R"], datatype=numpy.uint16, dims=(16,)) + FPGA_sst_offload_weighted_subbands_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_weighted_subbands_RW"], datatype=numpy.bool_, dims=(16,), access=AttrWriteType.READ_WRITE) + FPGA_sst_offload_weighted_subbands_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_weighted_subbands_R"], datatype=numpy.bool_, dims=(16,)) # number of packets with valid payloads nof_valid_payloads_R = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "nof_valid_payloads"}, dims=(SSTCollector.MAX_FPGAS,), datatype=numpy.uint64) @@ -120,14 +115,6 @@ class SST(Statistics): # ---------- # Run server # ---------- -def main(args=None, **kwargs): +def main(**kwargs): """Main function of the SST Device module.""" - - from common.lofar_logging import configure_logger - configure_logger() - - return run((SST,), args=args, **kwargs) - - -if __name__ == '__main__': - main() + return entry(SST, **kwargs) diff --git a/devices/devices/sdp/statistics.py b/tangostationcontrol/tangostationcontrol/devices/sdp/statistics.py similarity index 92% rename from devices/devices/sdp/statistics.py rename to tangostationcontrol/tangostationcontrol/devices/sdp/statistics.py index af1cf0201fd4dc244b8495730660b7c84398a518..aa56e71f047ebd8412deb77fa315dd6e2a7d8c16 100644 --- a/devices/devices/sdp/statistics.py +++ b/tangostationcontrol/tangostationcontrol/devices/sdp/statistics.py @@ -11,27 +11,20 @@ """ -# TODO(Corne): Remove sys.path.append hack once packaging is in place! -import os, sys -currentdir = os.path.dirname(os.path.realpath(__file__)) -parentdir = os.path.dirname(currentdir) -parentdir = os.path.dirname(parentdir) -sys.path.append(parentdir) - from abc import ABCMeta, abstractmethod # PyTango imports from tango.server import device_property, attribute from tango import AttrWriteType + # Additional import import asyncio -from clients.statistics_client import StatisticsClient -from clients.attribute_wrapper import attribute_wrapper - -from devices.opcua_device import opcua_device +from tangostationcontrol.clients.statistics_client import StatisticsClient +from tangostationcontrol.clients.attribute_wrapper import attribute_wrapper +from tangostationcontrol.devices.opcua_device import opcua_device +from tangostationcontrol.common.lofar_logging import device_logging_to_python, log_exceptions -from common.lofar_logging import device_logging_to_python, log_exceptions import logging logger = logging.getLogger() diff --git a/devices/devices/sdp/statistics_collector.py b/tangostationcontrol/tangostationcontrol/devices/sdp/statistics_collector.py similarity index 98% rename from devices/devices/sdp/statistics_collector.py rename to tangostationcontrol/tangostationcontrol/devices/sdp/statistics_collector.py index d9e5668b7e9b3db288a4b2360f4fa298594bbc1c..29503ca58ef25fcd3cb0b4ced4ff09ddaa62ecc6 100644 --- a/devices/devices/sdp/statistics_collector.py +++ b/tangostationcontrol/tangostationcontrol/devices/sdp/statistics_collector.py @@ -4,8 +4,8 @@ import logging import numpy from .statistics_packet import SSTPacket, XSTPacket -from common.baselines import nr_baselines, baseline_index, baseline_from_index -from clients.statistics_client_thread import StatisticsClientThread +from tangostationcontrol.common.baselines import nr_baselines, baseline_index, baseline_from_index +from tangostationcontrol.clients.statistics_client_thread import StatisticsClientThread logger = logging.getLogger() @@ -184,6 +184,7 @@ class XSTCollector(StatisticsCollector): # process the packet self.parameters["nof_valid_payloads"][fields.gn_index] += numpy.uint64(1) + self.parameters["xst_blocks"][block_index][:fields.nof_statistics_per_packet] = fields.payload self.parameters["xst_timestamps"][block_index] = numpy.float64(fields.timestamp().timestamp()) self.parameters["xst_conjugated"][block_index] = conjugated diff --git a/devices/devices/sdp/statistics_packet.py b/tangostationcontrol/tangostationcontrol/devices/sdp/statistics_packet.py similarity index 99% rename from devices/devices/sdp/statistics_packet.py rename to tangostationcontrol/tangostationcontrol/devices/sdp/statistics_packet.py index 9bac227071dfbdec9ea0b0fd1fa63fa36176a8d9..c98ae9b5bdc604e8a55480cc5473e658b10cefa1 100644 --- a/devices/devices/sdp/statistics_packet.py +++ b/tangostationcontrol/tangostationcontrol/devices/sdp/statistics_packet.py @@ -1,6 +1,5 @@ import struct from datetime import datetime, timezone -from typing import Tuple import numpy __all__ = ["StatisticsPacket", "SSTPacket", "XSTPacket", "BSTPacket"] @@ -331,7 +330,7 @@ class BSTPacket(StatisticsPacket): return header -if __name__ == "__main__": +def main(args=None, **kwargs): # parse one packet from stdin import sys import pprint diff --git a/devices/devices/sdp/xst.py b/tangostationcontrol/tangostationcontrol/devices/sdp/xst.py similarity index 69% rename from devices/devices/sdp/xst.py rename to tangostationcontrol/tangostationcontrol/devices/sdp/xst.py index c9883303b80425f0c142181994d43e477ec5431c..dcbda73c6570f6db966eaf5518e2129ecea41187 100644 --- a/devices/devices/sdp/xst.py +++ b/tangostationcontrol/tangostationcontrol/devices/sdp/xst.py @@ -11,27 +11,19 @@ """ -# TODO(Corne): Remove sys.path.append hack once packaging is in place! -import os, sys -currentdir = os.path.dirname(os.path.realpath(__file__)) -parentdir = os.path.dirname(currentdir) -parentdir = os.path.dirname(parentdir) -sys.path.append(parentdir) - # PyTango imports from tango.server import run from tango.server import device_property, attribute from tango import AttrWriteType -# Additional import -from clients.attribute_wrapper import attribute_wrapper -from clients.statistics_client import StatisticsClient -from clients.opcua_client import OPCUAConnection - -from common.lofar_logging import device_logging_to_python, log_exceptions +# Additional import +from tangostationcontrol.common.entrypoint import entry +from tangostationcontrol.clients.attribute_wrapper import attribute_wrapper +from tangostationcontrol.clients.opcua_client import OPCUAConnection +from tangostationcontrol.clients.statistics_client import StatisticsClient -from devices.sdp.statistics import Statistics -from devices.sdp.statistics_collector import XSTCollector +from tangostationcontrol.devices.sdp.statistics import Statistics +from tangostationcontrol.devices.sdp.statistics_collector import XSTCollector import numpy @@ -101,20 +93,20 @@ class XST(Statistics): # ---------- # FPGA control points for XSTs - FPGA_xst_integration_interval_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_xst_integration_interval_RW"], datatype=numpy.double, dims=(16,), access=AttrWriteType.READ_WRITE) - FPGA_xst_integration_interval_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_xst_integration_interval_R"], datatype=numpy.double, dims=(16,)) - FPGA_xst_offload_enable_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_xst_offload_enable_RW"], datatype=numpy.bool_, dims=(16,), access=AttrWriteType.READ_WRITE) - FPGA_xst_offload_enable_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_xst_offload_enable_R"], datatype=numpy.bool_, dims=(16,)) - FPGA_xst_offload_hdr_eth_destination_mac_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_xst_offload_hdr_eth_destination_mac_RW"], datatype=numpy.str, dims=(16,), access=AttrWriteType.READ_WRITE) - FPGA_xst_offload_hdr_eth_destination_mac_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_xst_offload_hdr_eth_destination_mac_R"], datatype=numpy.str, dims=(16,)) - FPGA_xst_offload_hdr_ip_destination_address_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_xst_offload_hdr_ip_destination_address_RW"], datatype=numpy.str, dims=(16,), access=AttrWriteType.READ_WRITE) - FPGA_xst_offload_hdr_ip_destination_address_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_xst_offload_hdr_ip_destination_address_R"], datatype=numpy.str, dims=(16,)) - FPGA_xst_offload_hdr_udp_destination_port_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_xst_offload_hdr_udp_destination_port_RW"], datatype=numpy.uint16, dims=(16,), access=AttrWriteType.READ_WRITE) - FPGA_xst_offload_hdr_udp_destination_port_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_xst_offload_hdr_udp_destination_port_R"], datatype=numpy.uint16, dims=(16,)) - FPGA_xst_processing_enable_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_xst_processing_enable_RW"], datatype=numpy.bool_, dims=(16,), access=AttrWriteType.READ_WRITE) - FPGA_xst_processing_enable_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_xst_processing_enable_R"], datatype=numpy.bool_, dims=(16,)) - FPGA_xst_subband_select_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_xst_subband_select_RW"], datatype=numpy.uint32, dims=(8,16), access=AttrWriteType.READ_WRITE) - FPGA_xst_subband_select_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_xst_subband_select_R"], datatype=numpy.uint32, dims=(8,16)) + FPGA_xst_integration_interval_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_integration_interval_RW"], datatype=numpy.double, dims=(16,), access=AttrWriteType.READ_WRITE) + FPGA_xst_integration_interval_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_integration_interval_R"], datatype=numpy.double, dims=(16,)) + FPGA_xst_offload_enable_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_enable_RW"], datatype=numpy.bool_, dims=(16,), access=AttrWriteType.READ_WRITE) + FPGA_xst_offload_enable_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_enable_R"], datatype=numpy.bool_, dims=(16,)) + FPGA_xst_offload_hdr_eth_destination_mac_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_hdr_eth_destination_mac_RW"], datatype=numpy.str, dims=(16,), access=AttrWriteType.READ_WRITE) + FPGA_xst_offload_hdr_eth_destination_mac_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_hdr_eth_destination_mac_R"], datatype=numpy.str, dims=(16,)) + FPGA_xst_offload_hdr_ip_destination_address_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_hdr_ip_destination_address_RW"], datatype=numpy.str, dims=(16,), access=AttrWriteType.READ_WRITE) + FPGA_xst_offload_hdr_ip_destination_address_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_hdr_ip_destination_address_R"], datatype=numpy.str, dims=(16,)) + FPGA_xst_offload_hdr_udp_destination_port_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_hdr_udp_destination_port_RW"], datatype=numpy.uint16, dims=(16,), access=AttrWriteType.READ_WRITE) + FPGA_xst_offload_hdr_udp_destination_port_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_hdr_udp_destination_port_R"], datatype=numpy.uint16, dims=(16,)) + FPGA_xst_processing_enable_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_processing_enable_RW"], datatype=numpy.bool_, dims=(16,), access=AttrWriteType.READ_WRITE) + FPGA_xst_processing_enable_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_processing_enable_R"], datatype=numpy.bool_, dims=(16,)) + FPGA_xst_subband_select_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_subband_select_RW"], datatype=numpy.uint32, dims=(8,16), access=AttrWriteType.READ_WRITE) + FPGA_xst_subband_select_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_subband_select_R"], datatype=numpy.uint32, dims=(8,16)) # number of packets with valid payloads nof_valid_payloads_R = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "nof_valid_payloads"}, dims=(XSTCollector.MAX_FPGAS,), datatype=numpy.uint64) @@ -160,14 +152,6 @@ class XST(Statistics): # ---------- # Run server # ---------- -def main(args=None, **kwargs): +def main(**kwargs): """Main function of the XST Device module.""" - - from common.lofar_logging import configure_logger - configure_logger() - - return run((XST,), args=args, **kwargs) - - -if __name__ == '__main__': - main() + return entry(XST, **kwargs) diff --git a/devices/devices/unb2.py b/tangostationcontrol/tangostationcontrol/devices/unb2.py similarity index 75% rename from devices/devices/unb2.py rename to tangostationcontrol/tangostationcontrol/devices/unb2.py index bad1b1a324c9c838960d07cdfeb804b2789bbac6..0076a37a25c0838f8324a409f08223fab79b92f1 100644 --- a/devices/devices/unb2.py +++ b/tangostationcontrol/tangostationcontrol/devices/unb2.py @@ -11,22 +11,16 @@ """ -# TODO(Corne): Remove sys.path.append hack once packaging is in place! -import os, sys -currentdir = os.path.dirname(os.path.realpath(__file__)) -parentdir = os.path.dirname(currentdir) -sys.path.append(parentdir) - # PyTango imports from tango.server import run from tango.server import device_property, attribute from tango import AttrWriteType # Additional import -from clients.attribute_wrapper import attribute_wrapper -from devices.opcua_device import opcua_device - -from common.lofar_logging import device_logging_to_python, log_exceptions +from tangostationcontrol.common.entrypoint import entry +from tangostationcontrol.clients.attribute_wrapper import attribute_wrapper +from tangostationcontrol.devices.opcua_device import opcua_device +from tangostationcontrol.common.lofar_logging import device_logging_to_python, log_exceptions import numpy @@ -64,42 +58,44 @@ class UNB2(opcua_device): 'UNB2_mask_RW' ] + UNB2TR_I2C_bus_DDR4_error_R = attribute_wrapper(comms_annotation=["UNB2TR_I2C_bus_DDR4_error_R"],datatype=numpy.int64 , dims=(4,2)) + UNB2TR_I2C_bus_error_R = attribute_wrapper(comms_annotation=["UNB2TR_I2C_bus_error_R" ],datatype=numpy.int64 , dims=(2,)) + UNB2TR_I2C_bus_FPGA_PS_error_R = attribute_wrapper(comms_annotation=["UNB2TR_I2C_bus_FPGA_PS_error_R"],datatype=numpy.int64 , dims=(4,2)) + UNB2TR_I2C_bus_PS_error_R = attribute_wrapper(comms_annotation=["UNB2TR_I2C_bus_PS_error_R" ],datatype=numpy.int64 , dims=(2,)) + UNB2TR_I2C_bus_QSFP_error_R = attribute_wrapper(comms_annotation=["UNB2TR_I2C_bus_QSFP_error_R"],datatype=numpy.int64 , dims=(24,2)) + UNB2TR_monitor_rate_RW = attribute_wrapper(comms_annotation=["UNB2TR_monitor_rate_RW" ],datatype=numpy.int64 , access=AttrWriteType.READ_WRITE) UNB2TR_translator_busy_R = attribute_wrapper(comms_annotation=["UNB2TR_translator_busy_R" ],datatype=numpy.bool_ ) UNB2_DC_DC_48V_12V_IOUT_R = attribute_wrapper(comms_annotation=["UNB2_DC_DC_48V_12V_IOUT_R" ],datatype=numpy.float64, dims=(2,)) UNB2_DC_DC_48V_12V_TEMP_R = attribute_wrapper(comms_annotation=["UNB2_DC_DC_48V_12V_TEMP_R" ],datatype=numpy.float64, dims=(2,)) UNB2_DC_DC_48V_12V_VIN_R = attribute_wrapper(comms_annotation=["UNB2_DC_DC_48V_12V_VIN_R" ],datatype=numpy.float64, dims=(2,)) UNB2_DC_DC_48V_12V_VOUT_R = attribute_wrapper(comms_annotation=["UNB2_DC_DC_48V_12V_VOUT_R" ],datatype=numpy.float64, dims=(2,)) - UNB2_EEPROM_Serial_Number_R = attribute_wrapper(comms_annotation=["UNB2_EEPROM_Serial_Number_R"],datatype=numpy.str , dims=(2,)) - UNB2_EEPROM_Unique_ID_R = attribute_wrapper(comms_annotation=["UNB2_EEPROM_Unique_ID_R" ],datatype=numpy.int64 , dims=(2,)) - UNB2_FPGA_DDR4_SLOT_TEMP_R = attribute_wrapper(comms_annotation=["UNB2_FPGA_DDR4_SLOT_TEMP_R"],datatype=numpy.float64, dims=(16,)) - UNB2_FPGA_POL_CORE_IOUT_R = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_CORE_IOUT_R" ],datatype=numpy.float64, dims=(8,)) - UNB2_FPGA_POL_CORE_TEMP_R = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_CORE_TEMP_R" ],datatype=numpy.float64, dims=(8,)) - UNB2_FPGA_POL_CORE_VOUT_R = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_CORE_VOUT_R" ],datatype=numpy.float64, dims=(8,)) - UNB2_FPGA_POL_ERAM_IOUT_R = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_ERAM_IOUT_R" ],datatype=numpy.float64, dims=(8,)) - UNB2_FPGA_POL_ERAM_TEMP_R = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_ERAM_TEMP_R" ],datatype=numpy.float64, dims=(8,)) - UNB2_FPGA_POL_ERAM_VOUT_R = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_ERAM_VOUT_R" ],datatype=numpy.float64, dims=(8,)) - UNB2_FPGA_POL_HGXB_IOUT_R = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_HGXB_IOUT_R" ],datatype=numpy.float64, dims=(8,)) - UNB2_FPGA_POL_HGXB_TEMP_R = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_HGXB_TEMP_R" ],datatype=numpy.float64, dims=(8,)) - UNB2_FPGA_POL_HGXB_VOUT_R = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_HGXB_VOUT_R" ],datatype=numpy.float64, dims=(8,)) - UNB2_FPGA_POL_PGM_IOUT_R = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_PGM_IOUT_R" ],datatype=numpy.float64, dims=(8,)) - UNB2_FPGA_POL_PGM_TEMP_R = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_PGM_TEMP_R" ],datatype=numpy.float64, dims=(8,)) - UNB2_FPGA_POL_PGM_VOUT_R = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_PGM_VOUT_R" ],datatype=numpy.float64, dims=(8,)) - UNB2_FPGA_POL_RXGXB_IOUT_R = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_RXGXB_IOUT_R"],datatype=numpy.float64, dims=(8,)) - UNB2_FPGA_POL_RXGXB_TEMP_R = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_RXGXB_TEMP_R"],datatype=numpy.float64, dims=(8,)) - UNB2_FPGA_POL_RXGXB_VOUT_R = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_RXGXB_VOUT_R"],datatype=numpy.float64, dims=(8,)) - UNB2_FPGA_POL_TXGXB_IOUT_R = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_TXGXB_IOUT_R"],datatype=numpy.float64, dims=(8,)) - UNB2_FPGA_POL_TXGXB_TEMP_R = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_TXGXB_TEMP_R"],datatype=numpy.float64, dims=(8,)) - UNB2_FPGA_POL_TXGXB_VOUT_R = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_TXGXB_VOUT_R"],datatype=numpy.float64, dims=(8,)) - UNB2_FPGA_QSFP_CAGE_LOS_R = attribute_wrapper(comms_annotation=["UNB2_FPGA_QSFP_CAGE_LOS_R" ],datatype=numpy.int64 , dims=(48,)) - UNB2_FPGA_QSFP_CAGE_TEMP_R = attribute_wrapper(comms_annotation=["UNB2_FPGA_QSFP_CAGE_TEMP_R"],datatype=numpy.float64, dims=(48,)) - UNB2_Front_Panel_LED_R = attribute_wrapper(comms_annotation=["UNB2_Front_Panel_LED_R" ],datatype=numpy.int64 , dims=(2,)) - UNB2_Front_Panel_LED_RW = attribute_wrapper(comms_annotation=["UNB2_Front_Panel_LED_RW" ],datatype=numpy.int64 , dims=(2,), access=AttrWriteType.READ_WRITE) - UNB2_I2C_bus_DDR4_error_R = attribute_wrapper(comms_annotation=["UNB2_I2C_bus_DDR4_error_R" ],datatype=numpy.int64 , dims=(8,)) - UNB2_I2C_bus_error_R = attribute_wrapper(comms_annotation=["UNB2_I2C_bus_error_R" ],datatype=numpy.int64 , dims=(2,)) - UNB2_I2C_bus_FPGA_PS_error_R = attribute_wrapper(comms_annotation=["UNB2_I2C_bus_FPGA_PS_error_R"],datatype=numpy.int64 , dims=(8,)) - UNB2_I2C_bus_PS_error_R = attribute_wrapper(comms_annotation=["UNB2_I2C_bus_PS_error_R" ],datatype=numpy.int64 , dims=(2,)) - UNB2_I2C_bus_QSFP_error_R = attribute_wrapper(comms_annotation=["UNB2_I2C_bus_QSFP_error_R" ],datatype=numpy.int64 , dims=(48,)) + UNB2_FPGA_DDR4_SLOT_TEMP_R = attribute_wrapper(comms_annotation=["UNB2_FPGA_DDR4_SLOT_TEMP_R"],datatype=numpy.float64, dims=(8,2)) + UNB2_FPGA_POL_CORE_IOUT_R = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_CORE_IOUT_R" ],datatype=numpy.float64, dims=(4,2)) + UNB2_FPGA_POL_CORE_TEMP_R = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_CORE_TEMP_R" ],datatype=numpy.float64, dims=(4,2)) + UNB2_FPGA_POL_CORE_VOUT_R = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_CORE_VOUT_R" ],datatype=numpy.float64, dims=(4,2)) + UNB2_FPGA_POL_ERAM_IOUT_R = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_ERAM_IOUT_R" ],datatype=numpy.float64, dims=(4,2)) + UNB2_FPGA_POL_ERAM_TEMP_R = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_ERAM_TEMP_R" ],datatype=numpy.float64, dims=(4,2)) + UNB2_FPGA_POL_ERAM_VOUT_R = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_ERAM_VOUT_R" ],datatype=numpy.float64, dims=(4,2)) + UNB2_FPGA_POL_HGXB_IOUT_R = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_HGXB_IOUT_R" ],datatype=numpy.float64, dims=(4,2)) + UNB2_FPGA_POL_HGXB_TEMP_R = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_HGXB_TEMP_R" ],datatype=numpy.float64, dims=(4,2)) + UNB2_FPGA_POL_HGXB_VOUT_R = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_HGXB_VOUT_R" ],datatype=numpy.float64, dims=(4,2)) + UNB2_FPGA_POL_PGM_IOUT_R = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_PGM_IOUT_R" ],datatype=numpy.float64, dims=(4,2)) + UNB2_FPGA_POL_PGM_TEMP_R = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_PGM_TEMP_R" ],datatype=numpy.float64, dims=(4,2)) + UNB2_FPGA_POL_PGM_VOUT_R = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_PGM_VOUT_R" ],datatype=numpy.float64, dims=(4,2)) + UNB2_FPGA_POL_RXGXB_IOUT_R = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_RXGXB_IOUT_R"],datatype=numpy.float64, dims=(4,2)) + UNB2_FPGA_POL_RXGXB_TEMP_R = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_RXGXB_TEMP_R"],datatype=numpy.float64, dims=(4,2)) + UNB2_FPGA_POL_RXGXB_VOUT_R = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_RXGXB_VOUT_R"],datatype=numpy.float64, dims=(4,2)) + UNB2_FPGA_POL_TXGXB_IOUT_R = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_TXGXB_IOUT_R"],datatype=numpy.float64, dims=(4,2)) + UNB2_FPGA_POL_TXGXB_TEMP_R = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_TXGXB_TEMP_R"],datatype=numpy.float64, dims=(4,2)) + UNB2_FPGA_POL_TXGXB_VOUT_R = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_TXGXB_VOUT_R"],datatype=numpy.float64, dims=(4,2)) + UNB2_FPGA_QSFP_CAGE_LOS_R = attribute_wrapper(comms_annotation=["UNB2_FPGA_QSFP_CAGE_LOS_R" ],datatype=numpy.int64 , dims=(24,2)) + UNB2_FPGA_QSFP_CAGE_TEMP_R = attribute_wrapper(comms_annotation=["UNB2_FPGA_QSFP_CAGE_TEMP_R"],datatype=numpy.float64, dims=(24,2)) + UNB2_Front_Panel_LED_colour_R = attribute_wrapper(comms_annotation=["UNB2_Front_Panel_LED_colour_R"],datatype=numpy.int64 , dims=(2,)) + UNB2_Front_Panel_LED_colour_RW = attribute_wrapper(comms_annotation=["UNB2_Front_Panel_LED_colour_RW"],datatype=numpy.int64 , dims=(2,), access=AttrWriteType.READ_WRITE) UNB2_mask_RW = attribute_wrapper(comms_annotation=["UNB2_mask_RW" ],datatype=numpy.bool_ , dims=(2,), access=AttrWriteType.READ_WRITE) + UNB2_PCB_ID_R = attribute_wrapper(comms_annotation=["UNB2_PCB_ID_R" ],datatype=numpy.int64 , dims=(2,)) + UNB2_PCB_number_R = attribute_wrapper(comms_annotation=["UNB2_PCB_number_R" ],datatype=numpy.str , dims=(2,)) + UNB2_PCB_version_R = attribute_wrapper(comms_annotation=["UNB2_PCB_version_R" ],datatype=numpy.str , dims=(2,)) UNB2_POL_CLOCK_IOUT_R = attribute_wrapper(comms_annotation=["UNB2_POL_CLOCK_IOUT_R" ],datatype=numpy.float64, dims=(2,)) UNB2_POL_CLOCK_TEMP_R = attribute_wrapper(comms_annotation=["UNB2_POL_CLOCK_TEMP_R" ],datatype=numpy.float64, dims=(2,)) UNB2_POL_CLOCK_VOUT_R = attribute_wrapper(comms_annotation=["UNB2_POL_CLOCK_VOUT_R" ],datatype=numpy.float64, dims=(2,)) @@ -115,8 +111,7 @@ class UNB2(opcua_device): UNB2_POL_SWITCH_PHY_IOUT_R = attribute_wrapper(comms_annotation=["UNB2_POL_SWITCH_PHY_IOUT_R"],datatype=numpy.float64, dims=(2,)) UNB2_POL_SWITCH_PHY_TEMP_R = attribute_wrapper(comms_annotation=["UNB2_POL_SWITCH_PHY_TEMP_R"],datatype=numpy.float64, dims=(2,)) UNB2_POL_SWITCH_PHY_VOUT_R = attribute_wrapper(comms_annotation=["UNB2_POL_SWITCH_PHY_VOUT_R"],datatype=numpy.float64, dims=(2,)) - UNB2_PWR_off_R = attribute_wrapper(comms_annotation=["UNB2_PWR_off_R" ],datatype=numpy.bool_ , dims=(2,)) - UNB2_PWR_off_RW = attribute_wrapper(comms_annotation=["UNB2_PWR_off_RW" ],datatype=numpy.bool_ , dims=(2,), access=AttrWriteType.READ_WRITE) + UNB2_PWR_on_R = attribute_wrapper(comms_annotation=["UNB2_PWR_on_R" ],datatype=numpy.bool_ , dims=(2,)) # -------- # overloaded functions @@ -131,13 +126,4 @@ class UNB2(opcua_device): # ---------- def main(args=None, **kwargs): """Main function of the UNB2 module.""" - - from common.lofar_logging import configure_logger - configure_logger() - - return run((UNB2,), args=args, **kwargs) - - -if __name__ == '__main__': - main() - + return entry(UNB2, **kwargs) diff --git a/devices/examples/HW_device_template.py b/tangostationcontrol/tangostationcontrol/examples/HW_device_template.py similarity index 83% rename from devices/examples/HW_device_template.py rename to tangostationcontrol/tangostationcontrol/examples/HW_device_template.py index 6059733023c5ee8448369a706ea2be5c8fa6b840..abb08a06a6cdbfbef0215df1d37552ff12b11931 100644 --- a/devices/examples/HW_device_template.py +++ b/tangostationcontrol/tangostationcontrol/examples/HW_device_template.py @@ -9,27 +9,19 @@ """ -# TODO(Corne): Remove sys.path.append hack once packaging is in place! -import os, sys -currentdir = os.path.dirname(os.path.realpath(__file__)) -parentdir = os.path.dirname(currentdir) -sys.path.append(parentdir) - # PyTango imports from tango.server import run -from tango import AttrWriteType # Additional import -from clients.attribute_wrapper import attribute_wrapper -from devices.hardware_device import hardware_device +from tangostationcontrol.devices.lofar_device import lofar_device __all__ = ["HW_dev"] -class HW_dev(hardware_device): +class HW_dev(lofar_device): """ - This class is the minimal (read empty) implementation of a class using 'hardware_device' + This class is the minimal (read empty) implementation of a class using 'lofar_device' """ # ---------- @@ -90,7 +82,3 @@ class HW_dev(hardware_device): def main(args=None, **kwargs): """Main function of the hardware device module.""" return run((HW_dev,), args=args, **kwargs) - - -if __name__ == '__main__': - main() diff --git a/devices/integration_test/client/__init__.py b/tangostationcontrol/tangostationcontrol/examples/__init__.py similarity index 100% rename from devices/integration_test/client/__init__.py rename to tangostationcontrol/tangostationcontrol/examples/__init__.py diff --git a/devices/integration_test/devices/__init__.py b/tangostationcontrol/tangostationcontrol/examples/load_from_disk/__init__.py similarity index 100% rename from devices/integration_test/devices/__init__.py rename to tangostationcontrol/tangostationcontrol/examples/load_from_disk/__init__.py diff --git a/devices/examples/load_from_disk/ini_client.py b/tangostationcontrol/tangostationcontrol/examples/load_from_disk/ini_client.py similarity index 98% rename from devices/examples/load_from_disk/ini_client.py rename to tangostationcontrol/tangostationcontrol/examples/load_from_disk/ini_client.py index cd227f23458c672c08b3acf08ba65fa9a48b581d..82c57a685e105527625c7dd3c0acdb77e59e1c8c 100644 --- a/devices/examples/load_from_disk/ini_client.py +++ b/tangostationcontrol/tangostationcontrol/examples/load_from_disk/ini_client.py @@ -1,4 +1,4 @@ -from clients.comms_client import CommClient +from tangostationcontrol.clients.comms_client import CommClient import configparser import numpy diff --git a/devices/examples/load_from_disk/ini_device.py b/tangostationcontrol/tangostationcontrol/examples/load_from_disk/ini_device.py similarity index 93% rename from devices/examples/load_from_disk/ini_device.py rename to tangostationcontrol/tangostationcontrol/examples/load_from_disk/ini_device.py index 07b2f419ab6b4cd5d78eb84a66c3906e169da99d..6195ff8a51544173554da24f046945ff8c2e6917 100644 --- a/devices/examples/load_from_disk/ini_device.py +++ b/tangostationcontrol/tangostationcontrol/examples/load_from_disk/ini_device.py @@ -9,26 +9,17 @@ """ -# TODO(Corne): Remove sys.path.append hack once packaging is in place! -import os, sys -currentdir = os.path.dirname(os.path.realpath(__file__)) -parentdir = os.path.dirname(currentdir) -parentdir = os.path.dirname(parentdir) -sys.path.append(parentdir) - # PyTango imports from tango.server import run from tango import AttrWriteType -# Additional import -from clients.attribute_wrapper import attribute_wrapper -from devices.hardware_device import hardware_device - import configparser import numpy -from ini_client import * - +# Additional import +from tangostationcontrol.clients.attribute_wrapper import attribute_wrapper +from tangostationcontrol.devices.lofar_device import lofar_device +from tangostationcontrol.examples.load_from_disk.ini_client import * __all__ = ["ini_device"] @@ -59,9 +50,9 @@ def write_ini_file(filename): -class ini_device(hardware_device): +class ini_device(lofar_device): """ - This class is the minimal (read empty) implementation of a class using 'hardware_device' + This class is the minimal (read empty) implementation of a class using 'lofar_device' """ # ---------- @@ -130,10 +121,5 @@ class ini_device(hardware_device): def main(args=None, **kwargs): write_ini_file("example.ini") - """Main function of the hardware device module.""" return run((ini_device,), args=args, **kwargs) - - -if __name__ == '__main__': - main() diff --git a/devices/test/__init__.py b/tangostationcontrol/tangostationcontrol/examples/snmp/__init__.py similarity index 100% rename from devices/test/__init__.py rename to tangostationcontrol/tangostationcontrol/examples/snmp/__init__.py diff --git a/devices/examples/snmp/snmp.py b/tangostationcontrol/tangostationcontrol/examples/snmp/snmp.py similarity index 84% rename from devices/examples/snmp/snmp.py rename to tangostationcontrol/tangostationcontrol/examples/snmp/snmp.py index 2a912ce1443bbd8e83b662d4ed9764627d947943..ddcba3910b1780b040737f153bb83894be59b72c 100644 --- a/devices/examples/snmp/snmp.py +++ b/tangostationcontrol/tangostationcontrol/examples/snmp/snmp.py @@ -11,29 +11,22 @@ """ -# TODO(Corne): Remove sys.path.append hack once packaging is in place! -import os, sys -currentdir = os.path.dirname(os.path.realpath(__file__)) -parentdir = os.path.dirname(currentdir) -parentdir = os.path.dirname(parentdir) -sys.path.append(parentdir) - # PyTango imports from tango.server import run from tango.server import device_property from tango import AttrWriteType # Additional import -from examples.snmp.snmp_client import SNMP_client -from clients.attribute_wrapper import attribute_wrapper -from devices.hardware_device import hardware_device +from tangostationcontrol.examples.snmp.snmp_client import SNMP_client +from tangostationcontrol.clients.attribute_wrapper import attribute_wrapper +from tangostationcontrol.devices.lofar_device import lofar_device import numpy __all__ = ["SNMP", "main"] -class SNMP(hardware_device): +class SNMP(lofar_device): """ **Properties:** @@ -118,12 +111,7 @@ class SNMP(hardware_device): def main(args=None, **kwargs): """Main function of the module.""" - from common.lofar_logging import configure_logger - import logging - configure_logger(logging.getLogger()) + from tangostationcontrol.common.lofar_logging import configure_logger + configure_logger() return run((SNMP,), args=args, **kwargs) - - -if __name__ == '__main__': - main() diff --git a/devices/examples/snmp/snmp_client.py b/tangostationcontrol/tangostationcontrol/examples/snmp/snmp_client.py similarity index 98% rename from devices/examples/snmp/snmp_client.py rename to tangostationcontrol/tangostationcontrol/examples/snmp/snmp_client.py index 96ac67140b9bdbdba7ab4d4fb8651b5e9674c219..00464f37d92800207fec524279126e494886d01a 100644 --- a/devices/examples/snmp/snmp_client.py +++ b/tangostationcontrol/tangostationcontrol/examples/snmp/snmp_client.py @@ -1,5 +1,5 @@ -from clients.comms_client import CommClient +from tangostationcontrol.clients.comms_client import CommClient import snmp diff --git a/devices/integration_test/README.md b/tangostationcontrol/tangostationcontrol/integration_test/README.md similarity index 100% rename from devices/integration_test/README.md rename to tangostationcontrol/tangostationcontrol/integration_test/README.md diff --git a/devices/test/clients/__init__.py b/tangostationcontrol/tangostationcontrol/integration_test/__init__.py similarity index 100% rename from devices/test/clients/__init__.py rename to tangostationcontrol/tangostationcontrol/integration_test/__init__.py diff --git a/devices/integration_test/base.py b/tangostationcontrol/tangostationcontrol/integration_test/base.py similarity index 92% rename from devices/integration_test/base.py rename to tangostationcontrol/tangostationcontrol/integration_test/base.py index 241f0ecd409fd16484d81e31f1e1f83dc1b9d81b..ed1eb2239af74251e22b42adf8ea5e2596688076 100644 --- a/devices/integration_test/base.py +++ b/tangostationcontrol/tangostationcontrol/integration_test/base.py @@ -7,7 +7,7 @@ # Distributed under the terms of the APACHE license. # See LICENSE.txt for more info. -from common.lofar_logging import configure_logger +from tangostationcontrol.common.lofar_logging import configure_logger import unittest import asynctest diff --git a/devices/test/common/__init__.py b/tangostationcontrol/tangostationcontrol/integration_test/client/__init__.py similarity index 100% rename from devices/test/common/__init__.py rename to tangostationcontrol/tangostationcontrol/integration_test/client/__init__.py diff --git a/devices/integration_test/client/test_sdptr_sim.py b/tangostationcontrol/tangostationcontrol/integration_test/client/test_sdptr_sim.py similarity index 92% rename from devices/integration_test/client/test_sdptr_sim.py rename to tangostationcontrol/tangostationcontrol/integration_test/client/test_sdptr_sim.py index ab9288b727e515c19b07c99d1fe8a233d7032055..a09f407e2982d7b873021f03b1eb9e78fe336e44 100644 --- a/devices/integration_test/client/test_sdptr_sim.py +++ b/tangostationcontrol/tangostationcontrol/integration_test/client/test_sdptr_sim.py @@ -9,7 +9,7 @@ from asyncua import Client -from integration_test import base +from tangostationcontrol.integration_test import base class TestSDPTRSim(base.IntegrationAsyncTestCase): diff --git a/devices/integration_test/client/test_tcp_replicator.py b/tangostationcontrol/tangostationcontrol/integration_test/client/test_tcp_replicator.py similarity index 97% rename from devices/integration_test/client/test_tcp_replicator.py rename to tangostationcontrol/tangostationcontrol/integration_test/client/test_tcp_replicator.py index ca45c4c52ab7f5e379c484b964a05225950fc9e1..2467fd6dd8a7b24cc786c5b2cc10a25a610b88f1 100644 --- a/devices/integration_test/client/test_tcp_replicator.py +++ b/tangostationcontrol/tangostationcontrol/integration_test/client/test_tcp_replicator.py @@ -7,18 +7,16 @@ # Distributed under the terms of the APACHE license. # See LICENSE.txt for more info. -from asyncio import Queue - import logging import time import socket import sys -from clients.tcp_replicator import TCPReplicator +import timeout_decorator -from integration_test import base +from tangostationcontrol.clients.tcp_replicator import TCPReplicator -import timeout_decorator +from tangostationcontrol.integration_test import base logger = logging.getLogger() diff --git a/devices/integration_test/client/test_unb2_sim.py b/tangostationcontrol/tangostationcontrol/integration_test/client/test_unb2_sim.py similarity index 92% rename from devices/integration_test/client/test_unb2_sim.py rename to tangostationcontrol/tangostationcontrol/integration_test/client/test_unb2_sim.py index d934c06fb6dfb40dad1c8b54dc00a00715deedc8..261441901c589a26256b586dc571f7b063c08408 100644 --- a/devices/integration_test/client/test_unb2_sim.py +++ b/tangostationcontrol/tangostationcontrol/integration_test/client/test_unb2_sim.py @@ -9,7 +9,7 @@ from asyncua import Client -from integration_test import base +from tangostationcontrol.integration_test import base class TestUNB2Sim(base.IntegrationAsyncTestCase): diff --git a/tangostationcontrol/tangostationcontrol/integration_test/device_proxy.py b/tangostationcontrol/tangostationcontrol/integration_test/device_proxy.py new file mode 100644 index 0000000000000000000000000000000000000000..00ba0904c7bd01fa2ce1453a4c6701d6a4246e14 --- /dev/null +++ b/tangostationcontrol/tangostationcontrol/integration_test/device_proxy.py @@ -0,0 +1,8 @@ +from tango import DeviceProxy + + +class TestDeviceProxy(DeviceProxy): + + def __init__(self, *args, **kwargs): + super(TestDeviceProxy, self).__init__(*args, **kwargs) + self.set_timeout_millis(10000) diff --git a/devices/test/devices/__init__.py b/tangostationcontrol/tangostationcontrol/integration_test/devices/__init__.py similarity index 100% rename from devices/test/devices/__init__.py rename to tangostationcontrol/tangostationcontrol/integration_test/devices/__init__.py diff --git a/devices/integration_test/devices/test_device_recv.py b/tangostationcontrol/tangostationcontrol/integration_test/devices/test_device_recv.py similarity index 75% rename from devices/integration_test/devices/test_device_recv.py rename to tangostationcontrol/tangostationcontrol/integration_test/devices/test_device_recv.py index 3a010a000c03d3c039f8f93a68c0f6437bc30db1..6e6e8602e0662750b7b097c4e60f7fef0ce056a2 100644 --- a/devices/integration_test/devices/test_device_recv.py +++ b/tangostationcontrol/tangostationcontrol/integration_test/devices/test_device_recv.py @@ -7,12 +7,10 @@ # 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 +from tangostationcontrol.integration_test.device_proxy import TestDeviceProxy +from tangostationcontrol.integration_test import base class TestDeviceRECV(base.IntegrationTestCase): @@ -22,7 +20,7 @@ class TestDeviceRECV(base.IntegrationTestCase): def tearDown(self): """Turn device Off in teardown to prevent blocking tests""" - d = DeviceProxy("LTS/RECV/1") + d = TestDeviceProxy("LTS/RECV/1") try: d.Off() @@ -33,25 +31,25 @@ class TestDeviceRECV(base.IntegrationTestCase): def test_device_proxy_recv(self): """Test if we can successfully create a DeviceProxy and fetch state""" - d = DeviceProxy("LTS/RECV/1") + d = TestDeviceProxy("LTS/RECV/1") self.assertEqual(DevState.OFF, d.state()) def test_device_recv_initialize(self): """Test if we can transition to standby""" - d = DeviceProxy("LTS/RECV/1") + d = TestDeviceProxy("LTS/RECV/1") - d.initialise() + d.Initialise() self.assertEqual(DevState.STANDBY, d.state()) def test_device_recv_on(self): """Test if we can transition to on""" - d = DeviceProxy("LTS/RECV/1") + d = TestDeviceProxy("LTS/RECV/1") - d.initialise() + d.Initialise() d.on() diff --git a/devices/integration_test/devices/test_device_sdp.py b/tangostationcontrol/tangostationcontrol/integration_test/devices/test_device_sdp.py similarity index 71% rename from devices/integration_test/devices/test_device_sdp.py rename to tangostationcontrol/tangostationcontrol/integration_test/devices/test_device_sdp.py index 5f064128f858e0bd2c44768a4f13057e5dc20266..faf965eb00c8c57785712b6bb581d9118c4632ba 100644 --- a/devices/integration_test/devices/test_device_sdp.py +++ b/tangostationcontrol/tangostationcontrol/integration_test/devices/test_device_sdp.py @@ -7,12 +7,11 @@ # 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 +from tangostationcontrol.integration_test.device_proxy import TestDeviceProxy +from tangostationcontrol.integration_test import base class TestDeviceSDP(base.IntegrationTestCase): @@ -23,7 +22,7 @@ class TestDeviceSDP(base.IntegrationTestCase): def tearDown(self): """Turn device Off in teardown to prevent blocking tests""" - d = DeviceProxy("LTS/SDP/1") + d = TestDeviceProxy("LTS/SDP/1") try: d.Off() @@ -34,25 +33,32 @@ class TestDeviceSDP(base.IntegrationTestCase): def test_device_proxy_sdp(self): """Test if we can successfully create a DeviceProxy and fetch state""" - d = DeviceProxy("LTS/SDP/1") + d = TestDeviceProxy("LTS/SDP/1") self.assertEqual(DevState.OFF, d.state()) + def test_device_sdp_ping(self): + """Test if we can successfully ping the device server""" + + d = TestDeviceProxy("LTS/SDP/1") + + self.assertGreater(d.ping(), 0) + def test_device_sdp_initialize(self): """Test if we can transition to standby""" - d = DeviceProxy("LTS/SDP/1") + d = TestDeviceProxy("LTS/SDP/1") - d.initialise() + 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 = TestDeviceProxy("LTS/SDP/1") - d.initialise() + d.Initialise() d.on() @@ -61,7 +67,7 @@ class TestDeviceSDP(base.IntegrationTestCase): def test_device_sdp_read_attribute(self): """Test if we can read an attribute obtained over OPC-UA""" - d = DeviceProxy("LTS/SDP/1") + d = TestDeviceProxy("LTS/SDP/1") d.initialise() diff --git a/devices/integration_test/devices/test_device_sst.py b/tangostationcontrol/tangostationcontrol/integration_test/devices/test_device_sst.py similarity index 89% rename from devices/integration_test/devices/test_device_sst.py rename to tangostationcontrol/tangostationcontrol/integration_test/devices/test_device_sst.py index a6b71d328305f2dafed46f9e4f3ea9209df9601d..194313fd6708d01ab70bda04563ce038bb55086c 100644 --- a/devices/integration_test/devices/test_device_sst.py +++ b/tangostationcontrol/tangostationcontrol/integration_test/devices/test_device_sst.py @@ -10,10 +10,10 @@ import socket import sys import time -from tango import DeviceProxy from tango._tango import DevState -from integration_test import base +from tangostationcontrol.integration_test.device_proxy import TestDeviceProxy +from tangostationcontrol.integration_test import base class TestDeviceSST(base.IntegrationTestCase): @@ -24,7 +24,7 @@ class TestDeviceSST(base.IntegrationTestCase): def tearDown(self): """Turn device Off in teardown to prevent blocking tests""" - d = DeviceProxy("LTS/SST/1") + d = TestDeviceProxy("LTS/SST/1") try: d.Off() @@ -35,14 +35,14 @@ class TestDeviceSST(base.IntegrationTestCase): def test_device_proxy_sst(self): """Test if we can successfully create a DeviceProxy and fetch state""" - d = DeviceProxy("LTS/SST/1") + d = TestDeviceProxy("LTS/SST/1") self.assertEqual(DevState.OFF, d.state()) def test_device_sst_initialize(self): """Test if we can transition to standby""" - d = DeviceProxy("LTS/SST/1") + d = TestDeviceProxy("LTS/SST/1") d.initialise() @@ -53,7 +53,7 @@ class TestDeviceSST(base.IntegrationTestCase): port_property = {"Statistics_Client_TCP_Port": "4999"} - d = DeviceProxy("LTS/SST/1") + d = TestDeviceProxy("LTS/SST/1") self.assertEqual(DevState.OFF, d.state(), "Prerequisite could not be met " @@ -72,7 +72,7 @@ class TestDeviceSST(base.IntegrationTestCase): def test_device_sst_send_udp(self): port_property = {"Statistics_Client_TCP_Port": "4998"} - d = DeviceProxy("LTS/SST/1") + d = TestDeviceProxy("LTS/SST/1") self.assertEqual(DevState.OFF, d.state(), "Prerequisite could not be met " @@ -101,7 +101,7 @@ class TestDeviceSST(base.IntegrationTestCase): m_data = "Hello World!".encode("UTF-8") - d = DeviceProxy("LTS/SST/1") + d = TestDeviceProxy("LTS/SST/1") self.assertEqual(DevState.OFF, d.state(), "Prerequisite could not be met " diff --git a/devices/integration_test/devices/test_device_unb2.py b/tangostationcontrol/tangostationcontrol/integration_test/devices/test_device_unb2.py similarity index 80% rename from devices/integration_test/devices/test_device_unb2.py rename to tangostationcontrol/tangostationcontrol/integration_test/devices/test_device_unb2.py index d796e586cd5165b0e3fb7cd09c1c3acf5cdd747c..c699e225c05861f61786f332a70ccb3191f2dc5f 100644 --- a/devices/integration_test/devices/test_device_unb2.py +++ b/tangostationcontrol/tangostationcontrol/integration_test/devices/test_device_unb2.py @@ -7,12 +7,10 @@ # 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 +from tangostationcontrol.integration_test.device_proxy import TestDeviceProxy +from tangostationcontrol.integration_test import base class TestDeviceUNB2(base.IntegrationTestCase): @@ -23,7 +21,7 @@ class TestDeviceUNB2(base.IntegrationTestCase): def tearDown(self): """Turn device Off in teardown to prevent blocking tests""" - d = DeviceProxy("LTS/UNB2/1") + d = TestDeviceProxy("LTS/UNB2/1") try: d.Off() @@ -34,14 +32,14 @@ class TestDeviceUNB2(base.IntegrationTestCase): def test_device_proxy_unb2(self): """Test if we can successfully create a DeviceProxy and fetch state""" - d = DeviceProxy("LTS/UNB2/1") + d = TestDeviceProxy("LTS/UNB2/1") self.assertEqual(DevState.OFF, d.state()) def test_device_unb2_initialize(self): """Test if we can transition to standby""" - d = DeviceProxy("LTS/UNB2/1") + d = TestDeviceProxy("LTS/UNB2/1") d.initialise() @@ -50,7 +48,7 @@ class TestDeviceUNB2(base.IntegrationTestCase): def test_device_unb2_on(self): """Test if we can transition to on""" - d = DeviceProxy("LTS/UNB2/1") + d = TestDeviceProxy("LTS/UNB2/1") d.initialise() diff --git a/tangostationcontrol/tangostationcontrol/integration_test/devices/test_tango_database.py b/tangostationcontrol/tangostationcontrol/integration_test/devices/test_tango_database.py new file mode 100644 index 0000000000000000000000000000000000000000..b14cc363f24b3ea8e77ecd59e1184500fe40e0d4 --- /dev/null +++ b/tangostationcontrol/tangostationcontrol/integration_test/devices/test_tango_database.py @@ -0,0 +1,34 @@ +# -*- 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 Database +from tango._tango import DevState + +from tangostationcontrol.integration_test import base + + +class TestTangoDatabase(base.IntegrationTestCase): + + def setUp(self): + """Intentionally recreate the device object in each test""" + super(TestTangoDatabase, self).setUp() + + def test_database_servers(self): + """Connect to the database and find at least 3 servers + + One for SDP, RECV and the databaseds itself. + """ + + d = Database() + + # Ensure this value is close to actual amount of servers defined by + # integration_ConfigDb.json + self.assertGreater(len(d.get_server_list()), 16, msg=f"Servers: {d.get_server_list()}") diff --git a/devices/statistics_writer/README.md b/tangostationcontrol/tangostationcontrol/statistics_writer/README.md similarity index 100% rename from devices/statistics_writer/README.md rename to tangostationcontrol/tangostationcontrol/statistics_writer/README.md diff --git a/devices/statistics_writer/SST_2021-10-04-07-36-52.h5 b/tangostationcontrol/tangostationcontrol/statistics_writer/SST_2021-10-04-07-36-52.h5 similarity index 100% rename from devices/statistics_writer/SST_2021-10-04-07-36-52.h5 rename to tangostationcontrol/tangostationcontrol/statistics_writer/SST_2021-10-04-07-36-52.h5 diff --git a/tangostationcontrol/tangostationcontrol/statistics_writer/__init__.py b/tangostationcontrol/tangostationcontrol/statistics_writer/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/devices/statistics_writer/hdf5_writer.py b/tangostationcontrol/tangostationcontrol/statistics_writer/hdf5_writer.py similarity index 98% rename from devices/statistics_writer/hdf5_writer.py rename to tangostationcontrol/tangostationcontrol/statistics_writer/hdf5_writer.py index 6715dd870608a0202610ea52c417695844f0d1c9..eb7fa643bd9c8d74b1e946f468532c4852ecaba5 100644 --- a/devices/statistics_writer/hdf5_writer.py +++ b/tangostationcontrol/tangostationcontrol/statistics_writer/hdf5_writer.py @@ -11,8 +11,8 @@ import logging # import statistics classes with workaround import sys sys.path.append("..") -from devices.sdp.statistics_packet import SSTPacket, XSTPacket, BSTPacket, StatisticsPacket -import devices.sdp.statistics_collector as statistics_collector +from tangostationcontrol.devices.sdp.statistics_packet import SSTPacket, XSTPacket, BSTPacket, StatisticsPacket +import tangostationcontrol.devices.sdp.statistics_collector as statistics_collector logger = logging.getLogger("statistics_writer") diff --git a/devices/statistics_writer/receiver.py b/tangostationcontrol/tangostationcontrol/statistics_writer/receiver.py similarity index 96% rename from devices/statistics_writer/receiver.py rename to tangostationcontrol/tangostationcontrol/statistics_writer/receiver.py index 92d0d6d34bfc69f8f89f306c86b906c68956e47b..cd6c0af4cd5d4a1f8cdc3c2e37d86f6bd655db53 100644 --- a/devices/statistics_writer/receiver.py +++ b/tangostationcontrol/tangostationcontrol/statistics_writer/receiver.py @@ -2,7 +2,7 @@ import socket import sys sys.path.append("..") -from devices.sdp.statistics_packet import StatisticsPacket +from tangostationcontrol.devices.sdp.statistics_packet import StatisticsPacket import os class receiver: diff --git a/devices/statistics_writer/statistics_reader.py b/tangostationcontrol/tangostationcontrol/statistics_writer/statistics_reader.py similarity index 93% rename from devices/statistics_writer/statistics_reader.py rename to tangostationcontrol/tangostationcontrol/statistics_writer/statistics_reader.py index f0906e7d4122b2f1d0d8d864d8c6a47ad793c0f4..67ff6377cdf90326d7a9fa33a015c1ac5861064d 100644 --- a/devices/statistics_writer/statistics_reader.py +++ b/tangostationcontrol/tangostationcontrol/statistics_writer/statistics_reader.py @@ -5,16 +5,9 @@ import argparse import os import psutil import pytz -import time process = psutil.Process(os.getpid()) -parser = argparse.ArgumentParser(description='Select a file to explore') -parser.add_argument('--files', type=str, nargs="+", help='the name and path of the files, takes one or more files') -parser.add_argument('--start_time', type=str, help='lowest timestamp to process (uses isoformat, ex: 2021-10-04T07:50:08.937+00:00)') -parser.add_argument('--end_time', type=str, help='highest timestamp to process (uses isoformat, ex: 2021-10-04T07:50:08.937+00:00)') - - import logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger("hdf5_explorer") @@ -219,7 +212,20 @@ class statistics_data: self.values = numpy.array(file.get(f"{group_key}/values")) -if __name__ == "__main__": +def main(): + parser = argparse.ArgumentParser(description='Select a file to explore') + parser.add_argument( + '--files', type=str, nargs="+", required=True, + help='the name and path of the files, takes one or more files') + parser.add_argument( + '--start_time', type=str, required=True, + help='lowest timestamp to process (uses isoformat, ex: 2021-10-04T07:50' + ':08.937+00:00)') + parser.add_argument( + '--end_time', type=str, required=True, + help='highest timestamp to process (usesisoformat, ex: 2021-10-04T07:50' + ':08.937+00:00)') + args = parser.parse_args() files = args.files end_time = args.end_time diff --git a/devices/statistics_writer/statistics_writer.py b/tangostationcontrol/tangostationcontrol/statistics_writer/statistics_writer.py similarity index 56% rename from devices/statistics_writer/statistics_writer.py rename to tangostationcontrol/tangostationcontrol/statistics_writer/statistics_writer.py index 8bf8fa64fbba9626f60abec0bb6cacb7e7288c51..1a1ecb671159e1b3ca143ecbf860000d6cdbe0c5 100644 --- a/devices/statistics_writer/statistics_writer.py +++ b/tangostationcontrol/tangostationcontrol/statistics_writer/statistics_writer.py @@ -1,32 +1,49 @@ import argparse -from receiver import tcp_receiver, file_receiver -from hdf5_writer import hdf5_writer - import time -from datetime import datetime - import sys -import signal + +from tangostationcontrol.statistics_writer.receiver import tcp_receiver, file_receiver +from tangostationcontrol.statistics_writer.hdf5_writer import hdf5_writer import logging logging.basicConfig(level=logging.INFO, format = '%(asctime)s:%(levelname)s: %(message)s') logger = logging.getLogger("statistics_writer") +def main(): + parser = argparse.ArgumentParser( + description='Converts a stream of statistics packets into HDF5 files.') + parser.add_argument( + '-a', '--host', type=str, required=True, help='the host to connect to') + parser.add_argument( + '-p', '--port', type=int, default=0, + help='the port to connect to, or 0 to use default port for the ' + 'selected mode (default: %(default)s)') + parser.add_argument( + '-f', '--file', type=str, required=True, help='the file to read from') + parser.add_argument( + '-m', '--mode', type=str, choices=['SST', 'XST', 'BST'], default='SST', + help='sets the statistics type to be decoded options (default: ' + '%(default)s)') + parser.add_argument( + '-i', '--interval', type=float, default=3600, nargs="?", + help='The time between creating new files in seconds (default: ' + '%(default)s)') + parser.add_argument( + '-o', '--output_dir', type=str, default=".", nargs="?", + help='specifies the folder to write all the files (default: ' + '%(default)s)') + parser.add_argument( + '-v', '--debug', dest='debug', action='store_true', default=False, + help='increase log output') + parser.add_argument( + '-d', '--decimation', type=int, default=1, + help='Configure the writer to only store one every n samples. Saves ' + 'storage space') + parser.add_argument( + '-r', '--reconnect', dest='reconnect', action='store_true', default=False, + help='Set the writer to keep trying to reconnect whenever connection ' + 'is lost. (default: %(default)s)') -parser = argparse.ArgumentParser(description='Converts a stream of statistics packets into HDF5 files.') -parser.add_argument('-a', '--host', type=str, help='The host to connect to.') -parser.add_argument('-p', '--port', type=int, default=0, help='The port to connect to, or 0 to use default port for the selected mode. (default: %(default)s)') -parser.add_argument('-f', '--file', type=str, help='The file to read from. (will ignore --host and --port)') - -parser.add_argument('-m', '--mode', type=str, choices=['SST', 'XST', 'BST'], default='SST', help='Sets the statistics type to be decoded options. (default: %(default)s)') -parser.add_argument('-i', '--interval', type=float, default=3600, nargs="?", help='The time between creating new files in seconds. (default: %(default)s)') -parser.add_argument('-o', '--output_dir', type=str, default=".", nargs="?", help='Specifies the folder to write all the files. (default: %(default)s)') -parser.add_argument('-d', '--decimation', type=int, default=1, help='Configure the writer to only store one every n samples. Saves storage space.') -parser.add_argument('-v', '--debug', dest='debug', action='store_true', default=False, help='Increase log output.') -parser.add_argument('-r', '--reconnect', dest='reconnect', action='store_true', default=False, help='Set the writer to keep trying to reconnect whenever connection is lost. (default: %(default)s)') - - -if __name__ == "__main__": args = parser.parse_args() # argparse arguments diff --git a/devices/statistics_writer/test/SST_10m_test_1.h5 b/tangostationcontrol/tangostationcontrol/statistics_writer/test/SST_10m_test_1.h5 similarity index 100% rename from devices/statistics_writer/test/SST_10m_test_1.h5 rename to tangostationcontrol/tangostationcontrol/statistics_writer/test/SST_10m_test_1.h5 diff --git a/devices/statistics_writer/test/SST_10m_test_2.h5 b/tangostationcontrol/tangostationcontrol/statistics_writer/test/SST_10m_test_2.h5 similarity index 100% rename from devices/statistics_writer/test/SST_10m_test_2.h5 rename to tangostationcontrol/tangostationcontrol/statistics_writer/test/SST_10m_test_2.h5 diff --git a/devices/statistics_writer/test/SST_10m_test_3.h5 b/tangostationcontrol/tangostationcontrol/statistics_writer/test/SST_10m_test_3.h5 similarity index 100% rename from devices/statistics_writer/test/SST_10m_test_3.h5 rename to tangostationcontrol/tangostationcontrol/statistics_writer/test/SST_10m_test_3.h5 diff --git a/tangostationcontrol/tangostationcontrol/statistics_writer/test/__init__.py b/tangostationcontrol/tangostationcontrol/statistics_writer/test/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/devices/statistics_writer/test/devices_test_SDP_SST_statistics_packets.bin b/tangostationcontrol/tangostationcontrol/statistics_writer/test/devices_test_SDP_SST_statistics_packets.bin similarity index 100% rename from devices/statistics_writer/test/devices_test_SDP_SST_statistics_packets.bin rename to tangostationcontrol/tangostationcontrol/statistics_writer/test/devices_test_SDP_SST_statistics_packets.bin diff --git a/devices/statistics_writer/test/test_server.py b/tangostationcontrol/tangostationcontrol/statistics_writer/test/test_server.py similarity index 100% rename from devices/statistics_writer/test/test_server.py rename to tangostationcontrol/tangostationcontrol/statistics_writer/test/test_server.py diff --git a/tangostationcontrol/tangostationcontrol/statistics_writer/udp_dev/__init__.py b/tangostationcontrol/tangostationcontrol/statistics_writer/udp_dev/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/devices/statistics_writer/udp_dev/udp_client.py b/tangostationcontrol/tangostationcontrol/statistics_writer/udp_dev/udp_client.py similarity index 100% rename from devices/statistics_writer/udp_dev/udp_client.py rename to tangostationcontrol/tangostationcontrol/statistics_writer/udp_dev/udp_client.py diff --git a/devices/statistics_writer/udp_dev/udp_server.py b/tangostationcontrol/tangostationcontrol/statistics_writer/udp_dev/udp_server.py similarity index 100% rename from devices/statistics_writer/udp_dev/udp_server.py rename to tangostationcontrol/tangostationcontrol/statistics_writer/udp_dev/udp_server.py diff --git a/devices/statistics_writer/udp_dev/udp_write_manager.py b/tangostationcontrol/tangostationcontrol/statistics_writer/udp_dev/udp_write_manager.py similarity index 100% rename from devices/statistics_writer/udp_dev/udp_write_manager.py rename to tangostationcontrol/tangostationcontrol/statistics_writer/udp_dev/udp_write_manager.py diff --git a/devices/test/README.md b/tangostationcontrol/tangostationcontrol/test/README.md similarity index 100% rename from devices/test/README.md rename to tangostationcontrol/tangostationcontrol/test/README.md diff --git a/devices/test/SDP_SST_statistics_packet.bin b/tangostationcontrol/tangostationcontrol/test/SDP_SST_statistics_packet.bin similarity index 100% rename from devices/test/SDP_SST_statistics_packet.bin rename to tangostationcontrol/tangostationcontrol/test/SDP_SST_statistics_packet.bin diff --git a/devices/test/SDP_SST_statistics_packets.bin b/tangostationcontrol/tangostationcontrol/test/SDP_SST_statistics_packets.bin similarity index 100% rename from devices/test/SDP_SST_statistics_packets.bin rename to tangostationcontrol/tangostationcontrol/test/SDP_SST_statistics_packets.bin diff --git a/devices/test/SDP_XST_statistics_packets.bin b/tangostationcontrol/tangostationcontrol/test/SDP_XST_statistics_packets.bin similarity index 100% rename from devices/test/SDP_XST_statistics_packets.bin rename to tangostationcontrol/tangostationcontrol/test/SDP_XST_statistics_packets.bin diff --git a/tangostationcontrol/tangostationcontrol/test/__init__.py b/tangostationcontrol/tangostationcontrol/test/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/devices/test/base.py b/tangostationcontrol/tangostationcontrol/test/base.py similarity index 91% rename from devices/test/base.py rename to tangostationcontrol/tangostationcontrol/test/base.py index 1c2eff09be8e6a4034a476173944c8ec2a1fe61c..7cf3af7f8becb1f92cde139290394ea540f5d8d6 100644 --- a/devices/test/base.py +++ b/tangostationcontrol/tangostationcontrol/test/base.py @@ -7,7 +7,7 @@ # Distributed under the terms of the APACHE license. # See LICENSE.txt for more info. -from common.lofar_logging import configure_logger +from tangostationcontrol.common.lofar_logging import configure_logger import unittest import testscenarios diff --git a/tangostationcontrol/tangostationcontrol/test/clients/__init__.py b/tangostationcontrol/tangostationcontrol/test/clients/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/devices/test/clients/test_attr_wrapper.py b/tangostationcontrol/tangostationcontrol/test/clients/test_attr_wrapper.py similarity index 93% rename from devices/test/clients/test_attr_wrapper.py rename to tangostationcontrol/tangostationcontrol/test/clients/test_attr_wrapper.py index 8711d989a67730667c10aed91de7c9929c500fcb..38ad2cce666f5bb435d8f58e2810cf3d62ad7475 100644 --- a/devices/test/clients/test_attr_wrapper.py +++ b/tangostationcontrol/tangostationcontrol/test/clients/test_attr_wrapper.py @@ -10,13 +10,13 @@ from tango import DevState # Internal imports -from test.clients.test_client import test_client -from clients.attribute_wrapper import * -from devices.hardware_device import * +from tangostationcontrol.test.clients.test_client import test_client +from tangostationcontrol.clients.attribute_wrapper import * +from tangostationcontrol.devices.lofar_device import * # Test imports from tango.test_context import DeviceTestContext -from test import base +from tangostationcontrol.test import base import asyncio @@ -39,252 +39,252 @@ def dev_init(device): class TestAttributeTypes(base.TestCase): - class str_scalar_device(hardware_device): + class str_scalar_device(lofar_device): scalar_R = attribute_wrapper(comms_annotation="str_scalar_R", datatype=numpy.str) scalar_RW = attribute_wrapper(comms_annotation="str_scalar_RW", datatype=numpy.str, access=AttrWriteType.READ_WRITE) def configure_for_initialise(self): dev_init(self) - class bool_scalar_device(hardware_device): + class bool_scalar_device(lofar_device): scalar_R = attribute_wrapper(comms_annotation="bool_scalar_R", datatype=numpy.bool_) scalar_RW = attribute_wrapper(comms_annotation="bool_scalar_RW", datatype=numpy.bool_, access=AttrWriteType.READ_WRITE) def configure_for_initialise(self): dev_init(self) - class float32_scalar_device(hardware_device): + class float32_scalar_device(lofar_device): scalar_R = attribute_wrapper(comms_annotation="float32_scalar_R", datatype=numpy.float32) scalar_RW = attribute_wrapper(comms_annotation="float32_scalar_RW", datatype=numpy.float32, access=AttrWriteType.READ_WRITE) def configure_for_initialise(self): dev_init(self) - class float64_scalar_device(hardware_device): + class float64_scalar_device(lofar_device): scalar_R = attribute_wrapper(comms_annotation="float64_scalar_R", datatype=numpy.float64) scalar_RW = attribute_wrapper(comms_annotation="float64_scalar_RW", datatype=numpy.float64, access=AttrWriteType.READ_WRITE) def configure_for_initialise(self): dev_init(self) - class double_scalar_device(hardware_device): + class double_scalar_device(lofar_device): scalar_R = attribute_wrapper(comms_annotation="double_scalar_R", datatype=numpy.double) scalar_RW = attribute_wrapper(comms_annotation="double_scalar_RW", datatype=numpy.double, access=AttrWriteType.READ_WRITE) def configure_for_initialise(self): dev_init(self) - class uint8_scalar_device(hardware_device): + class uint8_scalar_device(lofar_device): scalar_R = attribute_wrapper(comms_annotation="uint8_scalar_R", datatype=numpy.uint8) scalar_RW = attribute_wrapper(comms_annotation="uint8_scalar_RW", datatype=numpy.uint8, access=AttrWriteType.READ_WRITE) def configure_for_initialise(self): dev_init(self) - class uint16_scalar_device(hardware_device): + class uint16_scalar_device(lofar_device): scalar_R = attribute_wrapper(comms_annotation="uint16_scalar_R", datatype=numpy.uint16) scalar_RW = attribute_wrapper(comms_annotation="uint16_scalar_RW", datatype=numpy.uint16, access=AttrWriteType.READ_WRITE) def configure_for_initialise(self): dev_init(self) - class uint32_scalar_device(hardware_device): + class uint32_scalar_device(lofar_device): scalar_R = attribute_wrapper(comms_annotation="uint32_scalar_R", datatype=numpy.uint32) scalar_RW = attribute_wrapper(comms_annotation="uint32_scalar_RW", datatype=numpy.uint32, access=AttrWriteType.READ_WRITE) def configure_for_initialise(self): dev_init(self) - class uint64_scalar_device(hardware_device): + class uint64_scalar_device(lofar_device): scalar_R = attribute_wrapper(comms_annotation="uint64_scalar_R", datatype=numpy.uint64) scalar_RW = attribute_wrapper(comms_annotation="uint64_scalar_RW", datatype=numpy.uint64, access=AttrWriteType.READ_WRITE) def configure_for_initialise(self): dev_init(self) - class int16_scalar_device(hardware_device): + class int16_scalar_device(lofar_device): scalar_R = attribute_wrapper(comms_annotation="int16_scalar_R", datatype=numpy.int16) scalar_RW = attribute_wrapper(comms_annotation="int16_scalar_RW", datatype=numpy.int16, access=AttrWriteType.READ_WRITE) def configure_for_initialise(self): dev_init(self) - class int32_scalar_device(hardware_device): + class int32_scalar_device(lofar_device): scalar_R = attribute_wrapper(comms_annotation="int32_scalar_R", datatype=numpy.int32) scalar_RW = attribute_wrapper(comms_annotation="int32_scalar_RW", datatype=numpy.int32, access=AttrWriteType.READ_WRITE) def configure_for_initialise(self): dev_init(self) - class int64_scalar_device(hardware_device): + class int64_scalar_device(lofar_device): scalar_R = attribute_wrapper(comms_annotation="int64_scalar_R", datatype=numpy.int64) scalar_RW = attribute_wrapper(comms_annotation="int64_scalar_RW", datatype=numpy.int64, access=AttrWriteType.READ_WRITE) def configure_for_initialise(self): dev_init(self) - class str_spectrum_device(hardware_device): + class str_spectrum_device(lofar_device): spectrum_R = attribute_wrapper(comms_annotation="str_spectrum_R", datatype=numpy.str, dims=spectrum_dims) spectrum_RW = attribute_wrapper(comms_annotation="str_spectrum_RW", datatype=numpy.str, access=AttrWriteType.READ_WRITE, dims=spectrum_dims) def configure_for_initialise(self): dev_init(self) - class bool_spectrum_device(hardware_device): + class bool_spectrum_device(lofar_device): spectrum_R = attribute_wrapper(comms_annotation="bool_spectrum_R", datatype=numpy.bool_, dims=spectrum_dims) spectrum_RW = attribute_wrapper(comms_annotation="bool_spectrum_RW", datatype=numpy.bool_, access=AttrWriteType.READ_WRITE, dims=spectrum_dims) def configure_for_initialise(self): dev_init(self) - class float32_spectrum_device(hardware_device): + class float32_spectrum_device(lofar_device): spectrum_R = attribute_wrapper(comms_annotation="float32_spectrum_R", datatype=numpy.float32, dims=spectrum_dims) spectrum_RW = attribute_wrapper(comms_annotation="float32_spectrum_RW", datatype=numpy.float32, access=AttrWriteType.READ_WRITE, dims=spectrum_dims) def configure_for_initialise(self): dev_init(self) - class float64_spectrum_device(hardware_device): + class float64_spectrum_device(lofar_device): spectrum_R = attribute_wrapper(comms_annotation="float64_spectrum_R", datatype=numpy.float64, dims=spectrum_dims) spectrum_RW = attribute_wrapper(comms_annotation="float64_spectrum_RW", datatype=numpy.float64, access=AttrWriteType.READ_WRITE, dims=spectrum_dims) def configure_for_initialise(self): dev_init(self) - class double_spectrum_device(hardware_device): + class double_spectrum_device(lofar_device): spectrum_R = attribute_wrapper(comms_annotation="double_spectrum_R", datatype=numpy.double, dims=spectrum_dims) spectrum_RW = attribute_wrapper(comms_annotation="double_spectrum_RW", datatype=numpy.double, access=AttrWriteType.READ_WRITE, dims=spectrum_dims) def configure_for_initialise(self): dev_init(self) - class uint8_spectrum_device(hardware_device): + class uint8_spectrum_device(lofar_device): spectrum_R = attribute_wrapper(comms_annotation="uint8_spectrum_R", datatype=numpy.uint8, dims=spectrum_dims) spectrum_RW = attribute_wrapper(comms_annotation="uint8_spectrum_RW", datatype=numpy.uint8, access=AttrWriteType.READ_WRITE, dims=spectrum_dims) def configure_for_initialise(self): dev_init(self) - class uint16_spectrum_device(hardware_device): + class uint16_spectrum_device(lofar_device): spectrum_R = attribute_wrapper(comms_annotation="uint16_spectrum_R", datatype=numpy.uint16, dims=spectrum_dims) spectrum_RW = attribute_wrapper(comms_annotation="uint16_spectrum_RW", datatype=numpy.uint16, access=AttrWriteType.READ_WRITE, dims=spectrum_dims) def configure_for_initialise(self): dev_init(self) - class uint32_spectrum_device(hardware_device): + class uint32_spectrum_device(lofar_device): spectrum_R = attribute_wrapper(comms_annotation="uint32_spectrum_R", datatype=numpy.uint32, dims=spectrum_dims) spectrum_RW = attribute_wrapper(comms_annotation="uint32_spectrum_RW", datatype=numpy.uint32, access=AttrWriteType.READ_WRITE, dims=spectrum_dims) def configure_for_initialise(self): dev_init(self) - class uint64_spectrum_device(hardware_device): + class uint64_spectrum_device(lofar_device): spectrum_R = attribute_wrapper(comms_annotation="uint64_spectrum_R", datatype=numpy.uint64, dims=spectrum_dims) spectrum_RW = attribute_wrapper(comms_annotation="uint64_spectrum_RW", datatype=numpy.uint64, access=AttrWriteType.READ_WRITE, dims=spectrum_dims) def configure_for_initialise(self): dev_init(self) - class int16_spectrum_device(hardware_device): + class int16_spectrum_device(lofar_device): spectrum_R = attribute_wrapper(comms_annotation="int16_spectrum_R", datatype=numpy.int16, dims=spectrum_dims) spectrum_RW = attribute_wrapper(comms_annotation="int16_spectrum_RW", datatype=numpy.int16, access=AttrWriteType.READ_WRITE, dims=spectrum_dims) def configure_for_initialise(self): dev_init(self) - class int32_spectrum_device(hardware_device): + class int32_spectrum_device(lofar_device): spectrum_R = attribute_wrapper(comms_annotation="int32_spectrum_R", datatype=numpy.int32, dims=spectrum_dims) spectrum_RW = attribute_wrapper(comms_annotation="int32_spectrum_RW", datatype=numpy.int32, access=AttrWriteType.READ_WRITE, dims=spectrum_dims) def configure_for_initialise(self): dev_init(self) - class int64_spectrum_device(hardware_device): + class int64_spectrum_device(lofar_device): spectrum_R = attribute_wrapper(comms_annotation="int64_spectrum_R", datatype=numpy.int64, dims=spectrum_dims) spectrum_RW = attribute_wrapper(comms_annotation="int64_spectrum_RW", datatype=numpy.int64, access=AttrWriteType.READ_WRITE, dims=spectrum_dims) def configure_for_initialise(self): dev_init(self) - class str_image_device(hardware_device): + class str_image_device(lofar_device): image_R = attribute_wrapper(comms_annotation="str_image_R", datatype=numpy.str, dims=(2,3)) image_RW = attribute_wrapper(comms_annotation="str_image_RW", datatype=numpy.str, access=AttrWriteType.READ_WRITE, dims=(2,3)) def configure_for_initialise(self): dev_init(self) - class bool_image_device(hardware_device): + class bool_image_device(lofar_device): image_R = attribute_wrapper(comms_annotation="bool_image_R", datatype=numpy.bool_, dims=(2,3)) image_RW = attribute_wrapper(comms_annotation="bool_image_RW", datatype=numpy.bool_, access=AttrWriteType.READ_WRITE, dims=(2,3)) def configure_for_initialise(self): dev_init(self) - class float32_image_device(hardware_device): + class float32_image_device(lofar_device): image_R = attribute_wrapper(comms_annotation="float32_image_R", datatype=numpy.float32, dims=(2,3)) image_RW = attribute_wrapper(comms_annotation="float32_image_RW", datatype=numpy.float32, access=AttrWriteType.READ_WRITE, dims=(2,3)) def configure_for_initialise(self): dev_init(self) - class float64_image_device(hardware_device): + class float64_image_device(lofar_device): image_R = attribute_wrapper(comms_annotation="float64_image_R", datatype=numpy.float64, dims=(2,3)) image_RW = attribute_wrapper(comms_annotation="float64_image_RW", datatype=numpy.float64, access=AttrWriteType.READ_WRITE, dims=(2,3)) def configure_for_initialise(self): dev_init(self) - class double_image_device(hardware_device): + class double_image_device(lofar_device): image_R = attribute_wrapper(comms_annotation="double_image_R", datatype=numpy.double, dims=(2,3)) image_RW = attribute_wrapper(comms_annotation="double_image_RW", datatype=numpy.double, access=AttrWriteType.READ_WRITE, dims=(2,3)) def configure_for_initialise(self): dev_init(self) - class uint8_image_device(hardware_device): + class uint8_image_device(lofar_device): image_R = attribute_wrapper(comms_annotation="uint8_image_R", datatype=numpy.uint8, dims=(2,3)) image_RW = attribute_wrapper(comms_annotation="uint8_image_RW", datatype=numpy.uint8, access=AttrWriteType.READ_WRITE, dims=(2,3)) def configure_for_initialise(self): dev_init(self) - class uint16_image_device(hardware_device): + class uint16_image_device(lofar_device): image_R = attribute_wrapper(comms_annotation="uint16_image_R", datatype=numpy.uint16, dims=(2,3)) image_RW = attribute_wrapper(comms_annotation="uint16_image_RW", datatype=numpy.uint16, access=AttrWriteType.READ_WRITE, dims=(2,3)) def configure_for_initialise(self): dev_init(self) - class uint32_image_device(hardware_device): + class uint32_image_device(lofar_device): image_R = attribute_wrapper(comms_annotation="uint32_image_R", datatype=numpy.uint32, dims=(2,3)) image_RW = attribute_wrapper(comms_annotation="uint32_image_RW", datatype=numpy.uint32, access=AttrWriteType.READ_WRITE, dims=(2,3)) def configure_for_initialise(self): dev_init(self) - class uint64_image_device(hardware_device): + class uint64_image_device(lofar_device): image_R = attribute_wrapper(comms_annotation="uint64_image_R", datatype=numpy.uint64, dims=(2,3)) image_RW = attribute_wrapper(comms_annotation="uint64_image_RW", datatype=numpy.uint64, access=AttrWriteType.READ_WRITE, dims=(2,3)) def configure_for_initialise(self): dev_init(self) - class int16_image_device(hardware_device): + class int16_image_device(lofar_device): image_R = attribute_wrapper(comms_annotation="int16_image_R", datatype=numpy.int16, dims=(2,3)) image_RW = attribute_wrapper(comms_annotation="int16_image_RW", datatype=numpy.int16, access=AttrWriteType.READ_WRITE, dims=(2,3)) def configure_for_initialise(self): dev_init(self) - class int32_image_device(hardware_device): + class int32_image_device(lofar_device): image_R = attribute_wrapper(comms_annotation="int32_image_R", datatype=numpy.int32, dims=(2,3)) image_RW = attribute_wrapper(comms_annotation="int32_image_RW", datatype=numpy.int32, access=AttrWriteType.READ_WRITE, dims=(2,3)) def configure_for_initialise(self): dev_init(self) - class int64_image_device(hardware_device): + class int64_image_device(lofar_device): image_R = attribute_wrapper(comms_annotation="int64_image_R", datatype=numpy.int64, dims=(2,3)) image_RW = attribute_wrapper(comms_annotation="int64_image_RW", datatype=numpy.int64, access=AttrWriteType.READ_WRITE, dims=(2,3)) diff --git a/devices/test/clients/test_client.py b/tangostationcontrol/tangostationcontrol/test/clients/test_client.py similarity index 98% rename from devices/test/clients/test_client.py rename to tangostationcontrol/tangostationcontrol/test/clients/test_client.py index 7e002c3ad28a531b0ba16f12a22e782d4ba3bb01..ee3e0faf62b780dfb83a252dcf99897690090a35 100644 --- a/devices/test/clients/test_client.py +++ b/tangostationcontrol/tangostationcontrol/test/clients/test_client.py @@ -3,7 +3,7 @@ import numpy # Test imports -from clients.comms_client import CommClient +from tangostationcontrol.clients.comms_client import CommClient class test_client(CommClient): diff --git a/devices/test/clients/test_opcua_client.py b/tangostationcontrol/tangostationcontrol/test/clients/test_opcua_client.py similarity index 98% rename from devices/test/clients/test_opcua_client.py rename to tangostationcontrol/tangostationcontrol/test/clients/test_opcua_client.py index bc13dc5e1d1d04c800e35f113825015b38779cd9..c1c29ee04279bab3c943ccc35d4e3a5071345607 100644 --- a/devices/test/clients/test_opcua_client.py +++ b/tangostationcontrol/tangostationcontrol/test/clients/test_opcua_client.py @@ -1,16 +1,15 @@ import numpy -from clients.opcua_client import OPCUAConnection -from clients import opcua_client - import asyncua import io -import asyncio +import asynctest from unittest import mock -import unittest -from test import base -import asynctest + +from tangostationcontrol.clients.opcua_client import OPCUAConnection +from tangostationcontrol.clients import opcua_client + +from tangostationcontrol.test import base class attr_props: diff --git a/devices/test/clients/test_statistics_client_thread.py b/tangostationcontrol/tangostationcontrol/test/clients/test_statistics_client_thread.py similarity index 86% rename from devices/test/clients/test_statistics_client_thread.py rename to tangostationcontrol/tangostationcontrol/test/clients/test_statistics_client_thread.py index fd7ce0701f9d792863909b9f8ee4a9d39a2b1fd1..17f866871bd682b3f289364c16a55e5ee2010a7c 100644 --- a/devices/test/clients/test_statistics_client_thread.py +++ b/tangostationcontrol/tangostationcontrol/test/clients/test_statistics_client_thread.py @@ -10,9 +10,10 @@ import logging from unittest import mock -from clients.statistics_client_thread import StatisticsClientThread +from tangostationcontrol.clients.statistics_client_thread import \ + StatisticsClientThread -from test import base +from tangostationcontrol.test import base logger = logging.getLogger() diff --git a/devices/test/clients/test_tcp_replicator.py b/tangostationcontrol/tangostationcontrol/test/clients/test_tcp_replicator.py similarity index 97% rename from devices/test/clients/test_tcp_replicator.py rename to tangostationcontrol/tangostationcontrol/test/clients/test_tcp_replicator.py index a9babed0eb7af7a58544b3ff7535c3113ed12ca3..04c87f1d5a15705f7d0b8ce1460141255cb02b27 100644 --- a/devices/test/clients/test_tcp_replicator.py +++ b/tangostationcontrol/tangostationcontrol/test/clients/test_tcp_replicator.py @@ -9,15 +9,14 @@ import logging import time -from queue import Queue from unittest import mock -from clients.tcp_replicator import TCPReplicator -from clients import tcp_replicator +import timeout_decorator -from test import base +from tangostationcontrol.clients.tcp_replicator import TCPReplicator +from tangostationcontrol.clients import tcp_replicator -import timeout_decorator +from tangostationcontrol.test import base logger = logging.getLogger() diff --git a/tangostationcontrol/tangostationcontrol/test/common/__init__.py b/tangostationcontrol/tangostationcontrol/test/common/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/devices/test/common/test_baselines.py b/tangostationcontrol/tangostationcontrol/test/common/test_baselines.py similarity index 91% rename from devices/test/common/test_baselines.py rename to tangostationcontrol/tangostationcontrol/test/common/test_baselines.py index 206b4ca0eccefe1012519c8236d158e52f1cdc38..25eb5d1dfffa2fca8748d74020893edfb17c2037 100644 --- a/devices/test/common/test_baselines.py +++ b/tangostationcontrol/tangostationcontrol/test/common/test_baselines.py @@ -7,9 +7,9 @@ # Distributed under the terms of the APACHE license. # See LICENSE.txt for more info. -from common import baselines +from tangostationcontrol.common import baselines -from test import base +from tangostationcontrol.test import base class TestBaselines(base.TestCase): diff --git a/devices/test/common/test_lofar_logging.py b/tangostationcontrol/tangostationcontrol/test/common/test_lofar_logging.py similarity index 97% rename from devices/test/common/test_lofar_logging.py rename to tangostationcontrol/tangostationcontrol/test/common/test_lofar_logging.py index c1030b28f3b9b7861e6eec9d25b4ca6ef22a0c22..5140d05e58ca370509a080211ca96f2df21fe399 100644 --- a/devices/test/common/test_lofar_logging.py +++ b/tangostationcontrol/tangostationcontrol/test/common/test_lofar_logging.py @@ -7,16 +7,16 @@ # Distributed under the terms of the APACHE license. # See LICENSE.txt for more info. -import git from unittest import mock - -from common import lofar_logging import logging + from tango.server import Device from tango import device_server from tango.test_context import DeviceTestContext -from test import base +from tangostationcontrol.common import lofar_logging + +from tangostationcontrol.test import base class TestLofarLogging(base.TestCase): diff --git a/tangostationcontrol/tangostationcontrol/test/common/test_lofar_version.py b/tangostationcontrol/tangostationcontrol/test/common/test_lofar_version.py new file mode 100644 index 0000000000000000000000000000000000000000..89ac894d9388d3939671c43239033ce1147fef30 --- /dev/null +++ b/tangostationcontrol/tangostationcontrol/test/common/test_lofar_version.py @@ -0,0 +1,107 @@ +# -*- 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 git +from unittest import mock + +from tangostationcontrol.common import lofar_version + +from tangostationcontrol.test import base + + +class TestLofarVersion(base.TestCase): + + def setUp(self): + super(TestLofarVersion, self).setUp() + + # Clear the cache as this function of lofar_version uses LRU decorator + # This is a good demonstration of how unit tests in Python can have + # permanent effects, typically fixtures are needed to restore these. + lofar_version.get_version.cache_clear() + + def test_get_version(self): + """Test if attributes of get_repo are correctly used by get_version""" + + with mock.patch.object(lofar_version, 'get_repo') as m_get_repo: + m_commit = mock.Mock() + m_commit.return_value.__str__ = mock.Mock(return_value="123456") + m_commit.return_value.iter_items.return_value = [] + + m_is_dirty = mock.Mock() + m_is_dirty.return_value = False + + m_head = mock.Mock(is_detached=False) + + m_get_repo.return_value = mock.Mock( + active_branch="main", commit=m_commit, tags=[], + is_dirty=m_is_dirty, head=m_head) + + # No need for special string equal in Python + self.assertEqual("0.0.0.main.123456", lofar_version.get_version()) + + def test_get_version_tag(self): + """Test if get_version determines production_ready for tagged commit""" + + with mock.patch.object(lofar_version, 'get_repo') as m_get_repo: + m_commit = mock.Mock() + m_commit.return_value.__str__ = mock.Mock(return_value="123456") + m_commit.return_value.iter_items.return_value = [] + + m_is_dirty = mock.Mock() + m_is_dirty.return_value = False + + m_head = mock.Mock(is_detached=False) + + m_tag_commit = mock.Mock(type="commit") + m_tag_commit.__str__ = mock.Mock(return_value="123456") + + m_tag = mock.Mock(commit=m_tag_commit) + m_tag.name = "v0.0.3" + m_tag.__str__ = mock.Mock(return_value= "v0.0.3") + + m_commit.return_value = m_tag_commit + m_commit.return_value.iter_items.return_value = [m_tag_commit] + + m_get_repo.return_value = mock.Mock( + active_branch="main", commit=m_commit, + tags=[m_tag], is_dirty=m_is_dirty, head=m_head) + + self.assertEqual("0.0.3", lofar_version.get_version()) + + @mock.patch.object(lofar_version, 'get_repo') + def test_get_version_tag_dirty(self, m_get_repo): + + """Test if get_version determines dirty tagged commit""" + m_commit = mock.Mock() + m_commit.return_value.__str__ = mock.Mock(return_value="123456") + m_commit.return_value.iter_items.return_value = [] + + m_is_dirty = mock.Mock() + m_is_dirty.return_value = True + + m_head = mock.Mock(is_detached=False) + + m_get_repo.return_value = mock.Mock( + active_branch="main", commit=m_commit, tags=[], + is_dirty=m_is_dirty, head=m_head) + + # No need for special string equal in Python + self.assertEqual("0.0.0.main.123456.dirty", lofar_version.get_version()) + + def test_catch_repo_error(self): + """Test if invalid git directories will raise error""" + + with mock.patch.object(lofar_version, 'get_repo') as m_get_repo: + + # Configure lofar_version.get_repo to raise InvalidGitRepositoryError + m_get_repo.side_effect = git.InvalidGitRepositoryError + + # Test that error is raised by get_version + self.assertRaises( + git.InvalidGitRepositoryError, lofar_version.get_version) diff --git a/tangostationcontrol/tangostationcontrol/test/devices/__init__.py b/tangostationcontrol/tangostationcontrol/test/devices/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/devices/test/devices/random_data.py b/tangostationcontrol/tangostationcontrol/test/devices/random_data.py similarity index 97% rename from devices/test/devices/random_data.py rename to tangostationcontrol/tangostationcontrol/test/devices/random_data.py index 43e1a037624a516f88d05d644fd86e23fab6baa8..51d7b269f99c814cb340dc9f0e8feb44f3393f94 100644 --- a/devices/test/devices/random_data.py +++ b/tangostationcontrol/tangostationcontrol/test/devices/random_data.py @@ -7,13 +7,6 @@ # Distributed under the terms of the APACHE license. # See LICENSE.txt for more info. -# TODO(Corne): Remove sys.path.append hack once packaging is in place! -import os, sys -currentdir = os.path.dirname(os.path.realpath(__file__)) -parentdir = os.path.dirname(currentdir) -parentdir = os.path.dirname(parentdir) -sys.path.append(parentdir) - # PyTango imports from tango import DevState from tango.server import run, Device, attribute, command @@ -497,6 +490,3 @@ def main(args = None, **kwargs): Main function of the RandomData module. """ return run((Random_Data,), args = args, **kwargs) - -if __name__ == '__main__': - main() diff --git a/devices/test/devices/test_abstract_device.py b/tangostationcontrol/tangostationcontrol/test/devices/test_abstract_device.py similarity index 95% rename from devices/test/devices/test_abstract_device.py rename to tangostationcontrol/tangostationcontrol/test/devices/test_abstract_device.py index f54383c9a1b85f5c9e442f51d7f04d061951f772..469ea19fa970cf48c2de9c4c6b5648bd7b756040 100644 --- a/devices/test/devices/test_abstract_device.py +++ b/tangostationcontrol/tangostationcontrol/test/devices/test_abstract_device.py @@ -16,9 +16,9 @@ from tango.server import attribute from tango.test_context import DeviceTestContext -from devices.abstract_device import AbstractDeviceMetas +from tangostationcontrol.devices.abstract_device import AbstractDeviceMetas -from test import base +from tangostationcontrol.test import base class TestAbstractDevice(base.TestCase): diff --git a/devices/test/devices/test_statistics_collector.py b/tangostationcontrol/tangostationcontrol/test/devices/test_statistics_collector.py similarity index 96% rename from devices/test/devices/test_statistics_collector.py rename to tangostationcontrol/tangostationcontrol/test/devices/test_statistics_collector.py index 5fe4e24dabbf169664b19250cba13f19b8020327..4b58141c06d9b09d68dba295b007b41081ca3618 100644 --- a/devices/test/devices/test_statistics_collector.py +++ b/tangostationcontrol/tangostationcontrol/test/devices/test_statistics_collector.py @@ -1,7 +1,7 @@ -from devices.sdp.statistics_collector import XSTCollector -from devices.sdp.statistics_packet import XSTPacket +from tangostationcontrol.devices.sdp.statistics_collector import XSTCollector +from tangostationcontrol.devices.sdp.statistics_packet import XSTPacket -from test import base +from tangostationcontrol.test import base class TestXSTCollector(base.TestCase): def test_valid_packet(self): diff --git a/devices/toolkit/README.md b/tangostationcontrol/tangostationcontrol/toolkit/README.md similarity index 100% rename from devices/toolkit/README.md rename to tangostationcontrol/tangostationcontrol/toolkit/README.md diff --git a/tangostationcontrol/tangostationcontrol/toolkit/__init__.py b/tangostationcontrol/tangostationcontrol/toolkit/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/devices/toolkit/archiver.py b/tangostationcontrol/tangostationcontrol/toolkit/archiver.py similarity index 99% rename from devices/toolkit/archiver.py rename to tangostationcontrol/tangostationcontrol/toolkit/archiver.py index 35012767add234b2b0421b359bfacf19ca6b9155..f4a0974f82a18b213746264be133911893ab54ee 100644 --- a/devices/toolkit/archiver.py +++ b/tangostationcontrol/tangostationcontrol/toolkit/archiver.py @@ -3,7 +3,9 @@ #from logging import raiseExceptions import logging import traceback -from clients.attribute_wrapper import attribute_wrapper + +from tangostationcontrol.clients.attribute_wrapper import attribute_wrapper + from tango import DeviceProxy, AttributeProxy from datetime import datetime, timedelta diff --git a/devices/toolkit/archiver_base.py b/tangostationcontrol/tangostationcontrol/toolkit/archiver_base.py similarity index 100% rename from devices/toolkit/archiver_base.py rename to tangostationcontrol/tangostationcontrol/toolkit/archiver_base.py diff --git a/devices/toolkit/archiver_config/lofar2.json b/tangostationcontrol/tangostationcontrol/toolkit/archiver_config/lofar2.json similarity index 100% rename from devices/toolkit/archiver_config/lofar2.json rename to tangostationcontrol/tangostationcontrol/toolkit/archiver_config/lofar2.json diff --git a/devices/toolkit/get_internal_attribute_history.py b/tangostationcontrol/tangostationcontrol/toolkit/get_internal_attribute_history.py similarity index 99% rename from devices/toolkit/get_internal_attribute_history.py rename to tangostationcontrol/tangostationcontrol/toolkit/get_internal_attribute_history.py index 735be01613611d73f39678f6b0ed5fb1f1c56a70..8b6b4254f6c10dc8207232b16fd5e22d44e7c556 100644 --- a/devices/toolkit/get_internal_attribute_history.py +++ b/tangostationcontrol/tangostationcontrol/toolkit/get_internal_attribute_history.py @@ -1,10 +1,8 @@ #! /usr/bin/env python3 - from tango import DeviceProxy from numpy import array, transpose - def get_internal_attribute_history(device: DeviceProxy, attribute_name: str, depth: int = 10): try: history = array(device.attribute_history(attr_name = attribute_name, depth = depth)) diff --git a/devices/toolkit/lofar2_config.py b/tangostationcontrol/tangostationcontrol/toolkit/lofar2_config.py similarity index 99% rename from devices/toolkit/lofar2_config.py rename to tangostationcontrol/tangostationcontrol/toolkit/lofar2_config.py index 581eea4f73a4d276613123ec9bf86bdb7e97a0ea..811f4f27abbbac832c6de6811a223a27229e9032 100644 --- a/devices/toolkit/lofar2_config.py +++ b/tangostationcontrol/tangostationcontrol/toolkit/lofar2_config.py @@ -2,7 +2,6 @@ import logging - def configure_logging(): # Always also log the hostname because it makes the origin of the log clear. import socket diff --git a/devices/toolkit/udp_simulator.py b/tangostationcontrol/tangostationcontrol/toolkit/udp_simulator.py similarity index 100% rename from devices/toolkit/udp_simulator.py rename to tangostationcontrol/tangostationcontrol/toolkit/udp_simulator.py diff --git a/devices/test-requirements.txt b/tangostationcontrol/test-requirements.txt similarity index 100% rename from devices/test-requirements.txt rename to tangostationcontrol/test-requirements.txt diff --git a/devices/tox.ini b/tangostationcontrol/tox.ini similarity index 95% rename from devices/tox.ini rename to tangostationcontrol/tox.ini index 59d2347f3ff42ccb084033aea67d478fd63513cb..69782d5e33c1ab14ce9abcd50253e0db9eabdf9a 100644 --- a/devices/tox.ini +++ b/tangostationcontrol/tox.ini @@ -22,7 +22,7 @@ commands = stestr run {posargs} ; 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 +setenv = TESTS_DIR=./tangostationcontrol/integration_test commands = stestr run --serial {posargs}