From babc5fe17efce0df9cf331d45e5a6983ed9f78dc Mon Sep 17 00:00:00 2001 From: Ferdi Franceschini Date: Mon, 13 May 2013 23:11:15 +1000 Subject: [PATCH] A new runsics script has been implemented in python (runsics.py). It supports the new "fakedev" simulation mode which runs SICS with real drivers for devices which have simulated controllers. There are advance options which allow multiple instances of SICS to be launched on development and test environments. Also we no longer depend on having serverport numbers in /etc/services. --- site_ansto/instrument/MANIFEST.TXT | 1 + site_ansto/instrument/dingo/MANIFEST.TXT | 1 + site_ansto/instrument/dingo/runsics_def.py | 3 + site_ansto/instrument/hipd/MANIFEST.TXT | 1 + site_ansto/instrument/hipd/runsics_def.py | 3 + site_ansto/instrument/hrpd/MANIFEST.TXT | 1 + site_ansto/instrument/hrpd/runsics_def.py | 3 + site_ansto/instrument/kookaburra/MANIFEST.TXT | 1 + .../instrument/kookaburra/runsics_def.py | 3 + site_ansto/instrument/lyrebird/MANIFEST.TXT | 1 + site_ansto/instrument/lyrebird/runsics_def.py | 3 + site_ansto/instrument/pelican/MANIFEST.TXT | 1 + site_ansto/instrument/pelican/runsics_def.py | 3 + .../instrument/reflectometer/MANIFEST.TXT | 1 + .../instrument/reflectometer/runsics_def.py | 3 + site_ansto/instrument/rsd/MANIFEST.TXT | 1 + site_ansto/instrument/rsd/runsics_def.py | 3 + site_ansto/instrument/runsics.py | 162 ++++++++++++++++++ site_ansto/instrument/sans/MANIFEST.TXT | 1 + site_ansto/instrument/sans/runsics_def.py | 3 + site_ansto/instrument/server_config.tcl | 19 +- site_ansto/instrument/tas/MANIFEST.TXT | 1 + site_ansto/instrument/tas/runsics_def.py | 3 + 23 files changed, 218 insertions(+), 4 deletions(-) create mode 100644 site_ansto/instrument/dingo/runsics_def.py create mode 100644 site_ansto/instrument/hipd/runsics_def.py create mode 100644 site_ansto/instrument/hrpd/runsics_def.py create mode 100644 site_ansto/instrument/kookaburra/runsics_def.py create mode 100644 site_ansto/instrument/lyrebird/runsics_def.py create mode 100644 site_ansto/instrument/pelican/runsics_def.py create mode 100644 site_ansto/instrument/reflectometer/runsics_def.py create mode 100644 site_ansto/instrument/rsd/runsics_def.py create mode 100755 site_ansto/instrument/runsics.py create mode 100644 site_ansto/instrument/sans/runsics_def.py create mode 100644 site_ansto/instrument/tas/runsics_def.py diff --git a/site_ansto/instrument/MANIFEST.TXT b/site_ansto/instrument/MANIFEST.TXT index 7521efaa..89c8a5e2 100644 --- a/site_ansto/instrument/MANIFEST.TXT +++ b/site_ansto/instrument/MANIFEST.TXT @@ -1,3 +1,4 @@ +runsics.py server_config.tcl barebones.tcl util diff --git a/site_ansto/instrument/dingo/MANIFEST.TXT b/site_ansto/instrument/dingo/MANIFEST.TXT index e8de9be2..6ca7ab23 100644 --- a/site_ansto/instrument/dingo/MANIFEST.TXT +++ b/site_ansto/instrument/dingo/MANIFEST.TXT @@ -1,3 +1,4 @@ +runsics_def.py dingo_configuration.tcl sics_ports.tcl script_validator_ports.tcl diff --git a/site_ansto/instrument/dingo/runsics_def.py b/site_ansto/instrument/dingo/runsics_def.py new file mode 100644 index 00000000..ced76c70 --- /dev/null +++ b/site_ansto/instrument/dingo/runsics_def.py @@ -0,0 +1,3 @@ +inst_user = 'dingo_sics' +inst_name = 'dingo' +inst_config = 'dingo_configuration.tcl' diff --git a/site_ansto/instrument/hipd/MANIFEST.TXT b/site_ansto/instrument/hipd/MANIFEST.TXT index c058f196..0ab31880 100644 --- a/site_ansto/instrument/hipd/MANIFEST.TXT +++ b/site_ansto/instrument/hipd/MANIFEST.TXT @@ -1,3 +1,4 @@ +runsics_def.py sics_ports.tcl script_validator_ports.tcl instrument_vars.tcl diff --git a/site_ansto/instrument/hipd/runsics_def.py b/site_ansto/instrument/hipd/runsics_def.py new file mode 100644 index 00000000..f2a6af78 --- /dev/null +++ b/site_ansto/instrument/hipd/runsics_def.py @@ -0,0 +1,3 @@ +inst_user = 'wombat_sics' +inst_name = 'wombat' +inst_config = 'wombat_configuration.tcl' diff --git a/site_ansto/instrument/hrpd/MANIFEST.TXT b/site_ansto/instrument/hrpd/MANIFEST.TXT index e770e1f6..de1b6bd1 100644 --- a/site_ansto/instrument/hrpd/MANIFEST.TXT +++ b/site_ansto/instrument/hrpd/MANIFEST.TXT @@ -1,3 +1,4 @@ +runsics_def.py sics_ports.tcl script_validator_ports.tcl instrument_vars.tcl diff --git a/site_ansto/instrument/hrpd/runsics_def.py b/site_ansto/instrument/hrpd/runsics_def.py new file mode 100644 index 00000000..321d54a2 --- /dev/null +++ b/site_ansto/instrument/hrpd/runsics_def.py @@ -0,0 +1,3 @@ +inst_user = 'echidna_sics' +inst_name = 'echidna' +inst_config = 'echidna_configuration.tcl' diff --git a/site_ansto/instrument/kookaburra/MANIFEST.TXT b/site_ansto/instrument/kookaburra/MANIFEST.TXT index 89fa2dfa..4e62d61e 100644 --- a/site_ansto/instrument/kookaburra/MANIFEST.TXT +++ b/site_ansto/instrument/kookaburra/MANIFEST.TXT @@ -1,3 +1,4 @@ +runsics_def.py kookaburra_configuration.tcl sics_ports.tcl script_validator_ports.tcl diff --git a/site_ansto/instrument/kookaburra/runsics_def.py b/site_ansto/instrument/kookaburra/runsics_def.py new file mode 100644 index 00000000..d976d11d --- /dev/null +++ b/site_ansto/instrument/kookaburra/runsics_def.py @@ -0,0 +1,3 @@ +inst_user = 'kookaburra_sics' +inst_name = 'kookaburra' +inst_config = 'kookaburra_configuration.tcl' diff --git a/site_ansto/instrument/lyrebird/MANIFEST.TXT b/site_ansto/instrument/lyrebird/MANIFEST.TXT index 75371c6c..1ddf45f1 100644 --- a/site_ansto/instrument/lyrebird/MANIFEST.TXT +++ b/site_ansto/instrument/lyrebird/MANIFEST.TXT @@ -1,3 +1,4 @@ +runsics_def.py lyrebird_configuration.tcl sics_ports.tcl script_validator_ports.tcl diff --git a/site_ansto/instrument/lyrebird/runsics_def.py b/site_ansto/instrument/lyrebird/runsics_def.py new file mode 100644 index 00000000..6ddd852f --- /dev/null +++ b/site_ansto/instrument/lyrebird/runsics_def.py @@ -0,0 +1,3 @@ +inst_user = 'lyrebird_sics' +inst_name = 'lyrebird' +inst_config = 'lyrebird_configuration.tcl' diff --git a/site_ansto/instrument/pelican/MANIFEST.TXT b/site_ansto/instrument/pelican/MANIFEST.TXT index bc3a006e..f5807a59 100644 --- a/site_ansto/instrument/pelican/MANIFEST.TXT +++ b/site_ansto/instrument/pelican/MANIFEST.TXT @@ -1,3 +1,4 @@ +runsics_def.py pelican_configuration.tcl sics_ports.tcl script_validator_ports.tcl diff --git a/site_ansto/instrument/pelican/runsics_def.py b/site_ansto/instrument/pelican/runsics_def.py new file mode 100644 index 00000000..d72c5850 --- /dev/null +++ b/site_ansto/instrument/pelican/runsics_def.py @@ -0,0 +1,3 @@ +inst_user = 'pelican_sics' +inst_name = 'pelican' +inst_config = 'pelican_configuration.tcl' diff --git a/site_ansto/instrument/reflectometer/MANIFEST.TXT b/site_ansto/instrument/reflectometer/MANIFEST.TXT index 15faf1c1..c48c7d9a 100644 --- a/site_ansto/instrument/reflectometer/MANIFEST.TXT +++ b/site_ansto/instrument/reflectometer/MANIFEST.TXT @@ -1,3 +1,4 @@ +runsics_def.py platypus_configuration.tcl sics_ports.tcl script_validator_ports.tcl diff --git a/site_ansto/instrument/reflectometer/runsics_def.py b/site_ansto/instrument/reflectometer/runsics_def.py new file mode 100644 index 00000000..6d44a3b9 --- /dev/null +++ b/site_ansto/instrument/reflectometer/runsics_def.py @@ -0,0 +1,3 @@ +inst_user = 'platypus_sics' +inst_name = 'platypus' +inst_config = 'platypus_configuration.tcl' diff --git a/site_ansto/instrument/rsd/MANIFEST.TXT b/site_ansto/instrument/rsd/MANIFEST.TXT index 3adb26a4..afc3c3c1 100644 --- a/site_ansto/instrument/rsd/MANIFEST.TXT +++ b/site_ansto/instrument/rsd/MANIFEST.TXT @@ -1,3 +1,4 @@ +runsics_def.py sics_ports.tcl script_validator_ports.tcl kowari_configuration.tcl diff --git a/site_ansto/instrument/rsd/runsics_def.py b/site_ansto/instrument/rsd/runsics_def.py new file mode 100644 index 00000000..6e5a95b0 --- /dev/null +++ b/site_ansto/instrument/rsd/runsics_def.py @@ -0,0 +1,3 @@ +inst_user = 'kowari_sics' +inst_name = 'kowari' +inst_config = 'kowari_configuration.tcl' diff --git a/site_ansto/instrument/runsics.py b/site_ansto/instrument/runsics.py new file mode 100755 index 00000000..82b940de --- /dev/null +++ b/site_ansto/instrument/runsics.py @@ -0,0 +1,162 @@ +#!/usr/bin/env python +# vim: ts=8 sts=4 sw=4 expandtab +import sys +import os +import getpass +import resource +import subprocess +import shlex +import argparse +import re +import socket +from runsics_def import * + +# Re-open stdout unbuffered because we want to see feedback live as it happens. +sys.stdout = os.fdopen(sys.stdout.fileno(), 'w',0) + +# TODO These numbers should be available on the system to any application +server_port = { + 'sics': {'telnet': 60001, 'interrupt': 60002, 'server': 60003, 'quieck': 60004}, + 'scriptval': {'telnet': 60011, 'interrupt': 60012, 'server': 60013, 'quieck': 60014} +} +inst_test_sockoffset = { + 'wombat': 0, + 'echidna': 100, + 'kowari': 200, + 'quokka': 300, + 'platypus': 400, + 'taipan': 500, + 'pelican': 600, + 'dingo': 700, + 'emu': 800, + 'kookaburra': 900, + 'bilby': 1000 +} + +def sics_preexec(): + resource.setrlimit(resource.RLIMIT_CORE, (resource.RLIM_INFINITY, resource.RLIM_INFINITY)) + os.umask(0022) + +# TODO Launch simulated devices if TEST_SICS=fakedev. Must write launch script first. +def start_cmd(server, args): + if status_cmd(server, args): + print '%s is already running. Cowardly refusing to launch it twice' % server + return + sicsenv = { + 'none': None, + 'fullsim': {'SICS_SIMULATION': 'full'}, + 'fakedev': {'SICS_SIMULATION': 'fakedev'}, + 'scriptval': {'SICS_SIMULATION': 'script_validator'} + } + execenv = os.environ + if (args.sockoffset != 'none'): + execenv['SOCKOFFSET'] = str(inst_test_sockoffset[args.sockoffset]) + # Set SICS_SIMULATION environment variable + if (server == 'scriptval'): + execenv.update(sicsenv['scriptval']) + else: + execenv.update(sicsenv[args.test]) + start_str = 'sudo -Eu %s %s/SICServer -d %s' % (args.user, args.dir, args.config) + # Suppress output if launching the script validator + if (server == 'scriptval'): + with open(os.devnull) as fp: + subprocess.call(shlex.split(start_str), preexec_fn=sics_preexec, env=execenv, cwd=args.dir, stderr=fp, stdout=fp) + else: + subprocess.call(shlex.split(start_str), preexec_fn=sics_preexec, env=execenv, cwd=args.dir) + status_cmd(server, args) + +def stop_cmd(server, args): + INTMSG = 'SICSINT 6' + ret = status_cmd(server, args) + if ret: + (serv_port, pid) = ret + if (args.sockoffset == 'none'): + int_port = server_port[server]['interrupt'] + else: + int_port = server_port[server]['interrupt'] + inst_test_sockoffset[args.sockoffset] + print 'STOP %s(%d) listening on %d' % (server, pid, serv_port) + print "Sending '%s' to %d" % (INTMSG, int_port) + sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + sock.sendto( INTMSG + '\n\r', ('localhost', int_port) ) + sock.close() + if status_cmd(server, args): + print 'Failed to stop %s' % server + print 'Try harder dammit!' + subprocess.call(shlex.split('sudo -Eu root killall SICServer')) + else: + return + if status_cmd(server, args): + print 'Failed again!' + print 'Die damn you! DIE!!' + subprocess.call(shlex.split('sudo -Eu root killall -s15 SICServer')) + else: + return + if status_cmd(server, args): + print 'Why wont you die!!??' + print 'I give up. Try calling a SICS programmer or sysadmin' + + +def status_cmd(server, args): + if (args.sockoffset == 'none'): + sock = server_port[server]['server'] + else: + sock = server_port[server]['server'] + inst_test_sockoffset[args.sockoffset] + status_cmd = 'sudo -Eu %s netstat -nltp' % args.user + with open(os.devnull) as fp: + netstat_str = subprocess.check_output(shlex.split(status_cmd), stderr=fp) + #Find PID of SICServer listening on server port + m = re.search(':%d .* (\d+)\/SICServer' % sock, netstat_str) + if m: + pid = int(m.group(1)) + print '%s listening on port %d, PID=%d' % (server, sock, pid) + return (sock, pid) + else: + print '%s not running' % server + return '' + +def main(**kwargs): + runsics_cmd = {'start': start_cmd, 'stop': stop_cmd, 'status': status_cmd} + # Setup defaults. Use nice defaults in test environments. + if os.environ.has_key('TEST_SICS'): + deflt_user = getpass.getuser() + deflt_test = os.environ['TEST_SICS'] + deflt_dir = './' + deflt_sockoffset = inst_name + else: + deflt_user = inst_user + deflt_test = 'none' + deflt_dir = '/usr/local/sics/server' + deflt_sockoffset = 'none' + # Parse arguments + parser = argparse.ArgumentParser( description='SICS Server startup script.' ) + cmd_grp = parser.add_argument_group('Commands', 'Runsics commands') + adv_grp = parser.add_argument_group('Advanced', 'Options providing more control. Usually only useful for SICS developers and testers. If you are running multiple instances of SICS on a single host you can set the TEST_SICS environment variable to one of the --test values to get nice defaults.') + # Mandatory arguments + cmd_grp.add_argument('cmd', choices=['start', 'stop', 'status']) + # Advanced arguments + adv_grp.add_argument('-c', '--config', help='Run SICS with the given configuration file. Default=%s' % inst_config, default = inst_config ) + adv_grp.add_argument('-d', '--dir', help='Run SICS from the given directory. Default=%s' % deflt_dir, default = deflt_dir) + adv_grp.add_argument('-t', '--test', choices=['fullsim', 'fakedev', 'scriptval'], help='Run SICS in the given mode. Default=%s' % deflt_test, default=deflt_test) + adv_grp.add_argument('-u', '--user', help='Run SICS as the given user. Default=%s' % deflt_user, default = deflt_user ) + adv_grp.add_argument('--sockoffset', help='Offset the sockets to allow multiple SICS instances on a single host. Default=%s' % deflt_sockoffset, choices=inst_test_sockoffset.keys(), default = deflt_sockoffset ) + exc_grp = parser.add_mutually_exclusive_group() + exc_grp.add_argument('--sicsonly', help='Just run SICS without the script validator', action='store_true', default=False) + exc_grp.add_argument('--scriptval', help='Launch script validator as well as SICServer. Use this to override the default action when the TEST_SICS environmant variable is set.', action='store_true', default=False) + args = parser.parse_args() + # Don't launch script validator in development environments. + if args.scriptval: + deflt_sicsonly = False + elif os.environ.has_key('TEST_SICS'): + deflt_sicsonly = True + else: + deflt_sicsonly = args.sicsonly + # Launch SICS + if (deflt_sicsonly): + runsics_cmd[args.cmd]('sics', args) + else: + runsics_cmd[args.cmd]('sics', args) + runsics_cmd[args.cmd]('scriptval', args) + + +if __name__ == '__main__': + main() diff --git a/site_ansto/instrument/sans/MANIFEST.TXT b/site_ansto/instrument/sans/MANIFEST.TXT index 2a8bd319..92a3f6d5 100644 --- a/site_ansto/instrument/sans/MANIFEST.TXT +++ b/site_ansto/instrument/sans/MANIFEST.TXT @@ -1,3 +1,4 @@ +runsics_def.py quokka_configuration.tcl sics_ports.tcl script_validator_ports.tcl diff --git a/site_ansto/instrument/sans/runsics_def.py b/site_ansto/instrument/sans/runsics_def.py new file mode 100644 index 00000000..2a4a613f --- /dev/null +++ b/site_ansto/instrument/sans/runsics_def.py @@ -0,0 +1,3 @@ +inst_user = 'quokka_sics' +inst_name = 'quokka' +inst_config = 'quokka_configuration.tcl' diff --git a/site_ansto/instrument/server_config.tcl b/site_ansto/instrument/server_config.tcl index b708853a..aab91abe 100644 --- a/site_ansto/instrument/server_config.tcl +++ b/site_ansto/instrument/server_config.tcl @@ -5,6 +5,10 @@ #set sicsroot /usr/local/sics VarMake sicsdebug Int Mugger sicsdebug 0 +set telnetport 60001 +set interruptport 60002 +set serverport 60003 +set quieckport 60004 # Simulation flags, possible values = true or false # true: The simulated driver will be used. @@ -41,6 +45,12 @@ proc syncbackup {file} { backup motorSave } publish syncbackup Spy +if [info exists env(SOCKOFFSET)] { + set telnetport [expr {$telnetport + $env(SOCKOFFSET)}] + set interruptport [expr {$interruptport + $env(SOCKOFFSET)}] + set serverport [expr {$serverport + $env(SOCKOFFSET)}] + set quieckport [expr {$quieckport + $env(SOCKOFFSET)}] +} if {[info exists env(SICS_SIMULATION)] != 1} { set sicsroot ../ source sics_ports.tcl @@ -66,21 +76,22 @@ if {[info exists env(SICS_SIMULATION)] != 1} { switch $env(SICS_SIMULATION) { "full" { set sicsroot ../ - source sics_ports.tcl sics_simulation true } "fakedev" { set sicsroot ../ - source sics_ports.tcl sics_simulation fakedev } "script_validator" { VarMake sics_script_validator Text internal sics_script_validator true set sicsroot ../script_validator/ - source script_validator_ports.tcl + set telnetport [expr {$telnetport + 10}] + set interruptport [expr {$interruptport + 10}] + set serverport [expr {$serverport + 10}] + set quieckport [expr {$quieckport + 10}] sics_simulation true - MakeSync localhost [expr [get_portnum $serverport ]-10] spy 007 ../log/syncfile.tcl + MakeSync localhost $serverport spy 007 ../log/syncfile.tcl } default { error "ERROR: SICS_SIMULATION must be full, script_validator, or fakedev, not $env(SICS_SIMULATION)" diff --git a/site_ansto/instrument/tas/MANIFEST.TXT b/site_ansto/instrument/tas/MANIFEST.TXT index 2871a006..d223330f 100644 --- a/site_ansto/instrument/tas/MANIFEST.TXT +++ b/site_ansto/instrument/tas/MANIFEST.TXT @@ -1,3 +1,4 @@ +runsics_def.py sics_ports.tcl script_validator_ports.tcl taipan_configuration.tcl diff --git a/site_ansto/instrument/tas/runsics_def.py b/site_ansto/instrument/tas/runsics_def.py new file mode 100644 index 00000000..432a2caa --- /dev/null +++ b/site_ansto/instrument/tas/runsics_def.py @@ -0,0 +1,3 @@ +inst_user = 'taipan_sics' +inst_name = 'taipan' +inst_config = 'taipan_configuration.tcl'