170 lines
7.3 KiB
Python
Executable File
170 lines
7.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
|
|
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
|
|
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'
|
|
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 "Fragging PID %d with default KILL" % (pid)
|
|
subprocess.call(shlex.split('sudo -u root /bin/kill %d' % (pid)))
|
|
else:
|
|
return
|
|
if status_cmd(server, args):
|
|
print 'Failed again!'
|
|
print "Terminating PID %d with EXTREME PREJUDICE (-15)" % (pid)
|
|
subprocess.call(shlex.split('sudo -u root /bin/kill -15 %d' % (pid)))
|
|
else:
|
|
return
|
|
if status_cmd(server, args):
|
|
print 'Why wont you die, Powers!!??'
|
|
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 -u %s netstat -nltp' % 'root'
|
|
netstat_str, err = subprocess.Popen(shlex.split(status_cmd), 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_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.
|
|
deflt_dir = '/usr/local/sics/server'
|
|
deflt_sockoffset = 'none'
|
|
deflt_user = inst_user
|
|
if os.environ.has_key('TEST_SICS'):
|
|
deflt_test = os.environ['TEST_SICS']
|
|
else:
|
|
deflt_test = '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)
|
|
exc_grp.add_argument('--dev', help='Launch SICS only in current directory listening on socket %s and with simulation = fullsim' % (server_port['sics']['server'] + inst_test_sockoffset[inst_name]), action='store_true')
|
|
args = parser.parse_args()
|
|
# Don't launch script validator in development environments.
|
|
if args.scriptval:
|
|
args.sicsonly = False
|
|
elif args.dev:
|
|
args.sicsonly = True
|
|
args.sockoffset = inst_name
|
|
if (args.test == 'none'):
|
|
args.test = 'fullsim'
|
|
if (args.dir == deflt_dir):
|
|
args.dir = './'
|
|
args.user = getpass.getuser()
|
|
# 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()
|