Files
sics/site_ansto/instrument/runsics.py
Ferdi Franceschini 40ecb8478d The env var field in the default SICS start string should be blank.
By default SICS is launched with no environment variables and sudo
doesn't allow 'None' on the ICS computers.
2013-06-16 10:54:19 +10:00

243 lines
9.3 KiB
Python
Executable File

#!/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
import time
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 = {
'echidna' : 0,
'wombat' : 100,
'kowari' : 200,
'dingo' : 300,
'quokka' : 400,
'platypus' : 500,
'pelican' : 600,
'taipan' : 700,
'lyrebird' : 800,
'kookaburra' : 900,
'bilby' : 1000,
'emu' : 1100
}
deflt_dir = '/usr/local/sics/server'
deflt_sockoffset = 'none'
deflt_user = inst_user
sics_killer = inst_user
sics_checker = 'root'
if os.environ.has_key('TEST_SICS'):
deflt_test = os.environ['TEST_SICS']
else:
deflt_test = 'none'
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_fn(server, args) != (0,0):
print '%s is already running. Cowardly refusing to launch it twice' % server
return
if (args.sockoffset != 'none'):
soffset = ':' + str(inst_test_sockoffset[args.sockoffset])
else:
soffset = ''
sicsenv = {
'none': '',
'fullsim': 'SICS_SIMULATION=full%s' % soffset,
'fakedev': 'SICS_SIMULATION=fakedev%s' % soffset,
'scriptval': 'SICS_SIMULATION=script_validator%s' % soffset
}
# Set SICS_SIMULATION environment variable
if (server == 'scriptval'):
SIMENV = sicsenv['scriptval']
else:
SIMENV = sicsenv[args.test]
start_str = 'sudo -u %s %s %s/SICServer -d %s' % (args.user, SIMENV,
args.dir, args.config)
# print "DEBUG: start_str:%s" % (start_str)
# 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,
cwd=args.dir, stderr=fp, stdout=fp)
else:
subprocess.call(shlex.split(start_str), preexec_fn=sics_preexec,
cwd=args.dir)
status_cmd(server, args)
def stop_cmd(server, args):
INTMSG = 'SICSINT 6'
(serv_port, pid) = status_cmd(server, args)
if pid:
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) by sending '%s' to socket %d" % (server, pid,
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) != (0,0):
sys.stdout.write('Waiting ')
for n in range(3):
sys.stdout.write('.')
time.sleep(1)
if status_fn(server, args) != (0,0):
continue
else:
break
print ''
else:
return
if status_fn(server, args) != (0,0):
print 'Failed to stop %s' % server
print "Fragging PID %d with default KILL" % (pid)
subprocess.call(shlex.split('sudo -u %s /bin/kill %d' %
(sics_killer, pid)))
else:
return
if status_fn(server, args) != (0,0):
print 'Failed again!'
print "Terminating PID %d with EXTREME PREJUDICE (-15)" % (pid)
subprocess.call(shlex.split('sudo -u %s /bin/kill -15 %d' %
sics_killer, (pid)))
else:
return
if status_cmd(server, args) != (0,0):
print 'Why wont you die, Powers!!??'
print 'I give up. Try calling a SICS programmer or sysadmin'
def status_fn(server, args):
if (args.sockoffset == 'none'):
sock = server_port[server]['server']
else:
sock = server_port[server]['server'] + inst_test_sockoffset[args.sockoffset]
status_str = 'sudo -u %s netstat -nltp' % sics_checker
netstat_str, err = subprocess.Popen(shlex.split(status_str),
stdout=subprocess.PIPE,
stderr=subprocess.PIPE).communicate()
# ffr: We can replace the previous Popen().communicate() line with the following two lines if Python is upgraded to V2.7
# with open(os.devnull) as fp:
# netstat_str = subprocess.check_output(shlex.split(status_str), 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))
return (sock, pid)
else:
return (0,0)
def status_cmd(server, args):
(sock,pid) = status_fn(server, args)
if pid:
print '%s listening on port %d, PID=%d' % (server, sock, pid)
else:
print '%s not running' % server
return (sock, pid)
args_adv_grp_help = """
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.
"""
args_config_help = 'Run SICS with the given configuration file. Default=%s'
args_dir_help = 'Run SICS from the given directory. Default=%s'
args_test_help = 'Run SICS in the given mode. Default=%s'
args_user_help = 'Run SICS as the given user. Default=%s'
args_sockoffset_help = """
Offset the sockets to allow multiple SICS instances on a single
host. Default=%s
"""
args_sicsonly_help = 'Just run SICS without the script validator'
args_scriptval_help = """
Launch script validator as well as SICServer. Use this to
override the default action when the TEST_SICS environmant
variable is set.
"""
args_dev_help = """
Launch SICS only in current directory listening on socket %s
and with simulation = fullsim
"""
def main(**kwargs):
global sics_killer, sics_checker
runsics_cmd = {'start': start_cmd, 'stop': stop_cmd, 'status': status_cmd}
# Setup defaults. Use nice defaults in test environments.
# 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', args_adv_grp_help)
# Mandatory arguments
cmd_grp.add_argument('cmd', choices=['start', 'stop', 'status'])
# Advanced arguments
adv_grp.add_argument('-c', '--config', help= args_config_help % inst_config,
default = inst_config )
adv_grp.add_argument('-d', '--dir', help=args_dir_help % deflt_dir,
default = deflt_dir)
adv_grp.add_argument('-t', '--test',
choices=['fullsim', 'fakedev', 'scriptval'],
help=args_dir_help % deflt_test, default=deflt_test)
adv_grp.add_argument('-u', '--user', help= args_user_help % deflt_user,
default = deflt_user )
adv_grp.add_argument('--sockoffset',
help= args_sockoffset_help % deflt_sockoffset,
choices=inst_test_sockoffset.keys(),
default = deflt_sockoffset )
exc_grp = parser.add_mutually_exclusive_group()
exc_grp.add_argument('--sicsonly', help= args_sicsonly_help,
action='store_true', default=False)
exc_grp.add_argument('--scriptval', help= args_scriptval_help,
action='store_true', default=False)
exc_grp.add_argument('--dev',
help= args_dir_help % (server_port['sics']['server'] +
inst_test_sockoffset[inst_name]),
action='store_true')
args = parser.parse_args()
# By default don't launch script validator in development environments.
if args.dev:
if args.scriptval:
args.sicsonly = False
else:
args.sicsonly = True
args.sockoffset = inst_name
args.user = getpass.getuser()
sics_killer = getpass.getuser()
sics_checker = getpass.getuser()
if (args.test == 'none'):
args.test = 'fullsim'
if (args.dir == deflt_dir):
args.dir = './'
# Launch SICS
if (args.sicsonly):
runsics_cmd[args.cmd]('sics', args)
else:
runsics_cmd[args.cmd]('sics', args)
runsics_cmd[args.cmd]('scriptval', args)
if __name__ == '__main__':
main()