Skip to content
This repository was archived by the owner on Apr 13, 2022. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.gitignore
.git/
LICENSE.txt
README.md
docker-compose.yml
10 changes: 10 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
FROM alpine:3

# TODO: determine and pin versions
RUN apk update \
&& apk add --no-cache py3-zmq \
&& pip3 install -U --no-cache \
aiozmq==0.7.1 \
&& adduser -D runner

USER runner
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,25 @@ optional arguments:
Tango host (default is given by PyTango)
```

Local testing
-------------

Developer can test this project locally by using minimal control system set up with ``docker-compose``

Requirements:

- docker
- docker-compose

To set up testing environment, run `docker-compose up -d` in project root directory.

To see logs from Tango Gateway in real time, run `docker-compose logs -f gateway`.

Test environment is separated in two netwroks: `net-int` and `net-ext`. `net-int` is internal network for Tango Control System.
It consists of all services needed by Tango Control System like DatabaseDs, Jive, etc.
Other network, `net-ext`, is separated from control system. Only joint point is `gateway` container. It has access to both networks.
There are to client services, `pytango-in` and `pytango-ext`, both placed in different networks. They can be used for
connectivity tests.

Contact
-------
Expand Down
96 changes: 96 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
version: "3"

networks:
net-int:
driver: bridge
net-ext:
driver: bridge

services:

database:
image: tangocs/mysql:latest
environment:
- MYSQL_ALLOW_EMPTY_PASSWORD=1
networks:
- net-int

control-system:
image: tangocs/tango-cs:latest
environment:
- ORB_PORT=10000
- TANGO_HOST=127.0.0.1:10000
- MYSQL_HOST=database:3306
- MYSQL_USER=tango
- MYSQL_PASSWORD=tango
- MYSQL_DATABASE=tango
networks:
- net-int

tango-test:
image: tangocs/tango-test:latest
environment:
- TANGO_HOST=control-system:10000
depends_on:
- control-system
networks:
- net-int
command: ["test", "-v4"]

jive:
image: tangocs/tango-jive
networks:
- net-int
depends_on:
- control-system
environment:
TANGO_HOST: control-system:10000
DISPLAY: :0
_JAVA_OPTIONS: '-Dawt.useSystemAAFontSettings=lcd'
volumes:
- /tmp/.X11-unix:/tmp/.X11-unix

pytango-in :
image: tangocs/tango-pytango
networks:
- net-int
depends_on:
- control-system
environment:
TANGO_HOST: control-system:10000
command: ["sleep", "infinity"]
working_dir: /mnt
volumes:
- ./sub:/mnt/

pytango-ext :
image: tangocs/tango-pytango
networks:
- net-ext
depends_on:
- gateway
environment:
TANGO_HOST: tango-gateway_gateway_1.tango-gateway_net-ext:10000 # if you change docker-compose project name (i.e. change parent folder name) you have to modify it accordingly
command: ["sleep", "infinity"]
working_dir: /mnt
volumes:
- ./sub:/mnt/

gateway:
build:
context: .
hostname: gateway
networks:
net-ext:
priority: 1000 # this makes this interface first - make CORBA working
restart: on-failure
depends_on:
- control-system
working_dir: /mnt
environment:
TANGO_GATEWAY_BIND: 0.0.0.0
TANGO_GATEWAY_PORT: 10000
TANGO_GATEWAY_HOST: tango-gateway_control-system_1.tango-gateway_net-in:10000 # if you change docker-compose project name (i.e. change parent folder name) you have to modify it accordingly
command: ["python3", "-m", "tangogateway", "--verbose"]
volumes:
- ./tangogateway:/mnt/tangogateway
91 changes: 91 additions & 0 deletions sub/sub.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
#!/usr/bin/env python3

import tango
import datetime
import argparse
import time


EVENT_TYPES = {"periodic": tango.EventType.PERIODIC_EVENT,
"change": tango.EventType.CHANGE_EVENT,
"archive": tango.EventType.ARCHIVE_EVENT,
"data_ready": tango.EventType.DATA_READY_EVENT}

# PIPE_EVENT
# ATTR_CONF_EVENT
# QUALITY_EVENT
# USER_EVENT
# INTERFACE_CHANGE_EVENT


def echo(event):
"""
Event subscribtion callabck, print all relevant info
:param event:
:return:
"""

print(datetime.datetime.now())
print(event)
print("To exit use Ctrl+C!")


def sub_pull(attr, evt_type, sleep):
ap = tango.AttributeProxy(attr)

evt_id = ap.subscribe_event(EVENT_TYPES[evt_type], 1)

try:
while True:
if not ap.is_event_queue_empty(evt_id):
print("Extracting event")
print("Processing event: " + str(datetime.datetime.now()))
print("Event time: " + str(ap.get_last_event_date(evt_id)))
events = ap.get_events(event_id=evt_id)
print(events[0].attr_value.value)
else:
print("No event")
print(datetime.datetime.now())
time.sleep(sleep)

except KeyboardInterrupt:
ap.unsubscribe_event(evt_id)
print("Unbsubscribing for %s event on attribute %s" % (evt_type, attr))


def sub_push(attr, evt_type):
ap = tango.AttributeProxy(attr)

evt_id = ap.subscribe_event(EVENT_TYPES[evt_type], echo)

try:
while True:
pass

except KeyboardInterrupt:
ap.unsubscribe_event(evt_id)
print("Unbsubscribing for %s event on attribute %s" % (evt_type, attr))


def main(attr, evt_type, push, pull):
try:
if push:
sub_push(attr, evt_type)
else:
sub_pull(attr, evt_type, pull)

except TypeError:
print("Error with parsing attribute!")


if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Simple script for testing Tango events")
parser.add_argument('attribute', help='device attribute name to test')
parser.add_argument('event_type', choices=['periodic', 'change', 'archive'], help='type of event')
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument("--push", action="store_true", help="Subscribe in push mode")
group.add_argument("--pull", type=float, help="Subscribe in pull mode. Provide value of loop time")

args = parser.parse_args()
main(args.attribute, args.event_type, args.push, args.pull)