renamed to 'servicemanager'

the PYTHONPATH should be set to the directory above servicemanager
This commit is contained in:
zolliker 2021-02-26 14:48:15 +01:00
parent 632beda430
commit ff71f10ce5
9 changed files with 158 additions and 134 deletions

View File

@ -1,5 +1,5 @@
# servman
# servicemanager
A manager for starting, stopping and listing services/servers like frappy, nicos and sea.
Several instances of nicos, frappy and sea might run on the same machine.
Several instances of nicos, frappy, sea and seweb might run on the same machine.

View File

@ -27,7 +27,65 @@ this code is currently used:
- from a script allowing to start/stop/list (and more) multiple frappy and nicos servers
"""
from servman.base import ServiceManager, ServiceDown, run, UsageError
from servman.frappyman import FrappyManager
from servman.nicosman import NicosManager
from servman.seaman import SeaManager
from servicemanager.base import ServiceManager, ServiceDown, UsageError, get_config
from servicemanager.nicosman import NicosManager
from servicemanager.seaman import SeaManager
class FrappyManager(ServiceManager):
group = 'frappy'
services = ('main', 'stick', 'addons')
USAGE = """
Usage:
frappy list [<instance>]
frappy start <instance> <service> <cfgfiles>
frappy restart <instance> [<service>] [<cfgfiles>]
frappy stop <instance> [<service>]
<service> is one of main, stick, addons
<instance> is one of %s
"""
class SewebManager(ServiceManager):
group = 'seweb'
services = ('',)
USAGE = """
Usage:
seaweb list [<instance>]
seaweb start <instance>
seaweb restart <instance>
seaweb stop <instance>
<instance> is one of %s
"""
all = NicosManager, FrappyManager, SeaManager, SewebManager
def run(group, arglist):
try:
parser = get_config()
defaults = parser['DEFAULT']
managers = {cls.group: cls() for cls in all if cls.group + '_command' in defaults}
serv = managers[group]
arglist = arglist + [''] # add dummy argument
action = arglist.pop(0) if hasattr(serv, 'do_' + arglist[0]) else 'gui'
instance = arglist.pop(0) if arglist[0] and arglist[0] not in serv.services else None
if instance is None and len(serv.info) == 1:
instance = list(serv.info)[0]
if instance is not None:
arglist.insert(0, instance)
arglist.pop() # remove dummy argument
try:
serv.action(action, *arglist)
except AttributeError:
raise UsageError("do not know '%s'" % ' '.join([serv.group, action] + arglist))
except UsageError as e:
print(repr(e))
print(serv.usage())

59
base.py
View File

@ -21,6 +21,7 @@
# *****************************************************************************
import sys
import json
import os
from os.path import expanduser
@ -65,25 +66,15 @@ def printTable(headers, items, printfunc, minlen=0, rjust=False):
printfunc((rfmtstr if rjust else lfmtstr) % (tuple(row) + ('',) * (ncolumns - len(row))))
def run(serv, arglist):
arglist = arglist + [''] # add dummy argument
action = arglist.pop(0) if hasattr(serv, 'do_' + arglist[0]) else 'gui'
instance = arglist.pop(0) if arglist[0] and arglist[0] not in serv.services else None
if instance is None and len(serv.info) == 1:
instance = list(serv.info)[0]
if instance is not None:
arglist.insert(0, instance)
arglist.pop() # remove dummy argument
try:
serv.action(action, *arglist)
except AttributeError as e:
raise
print(repr(e))
raise ValueError("do not know '%s'" % ' '.join([serv.group, action] + arglist))
def get_config():
parser = ConfigParser(interpolation=None)
parser.optionxform = str
parser.read(expanduser('~/servicemanager.cfg'))
return parser
class ServiceManager:
services = None
services = ['SINGLE']
need_cfg = False
start_dir = None
group = None
@ -91,6 +82,7 @@ class ServiceManager:
virtualenv = None
pkg = ''
revcmd = {}
USAGE = None
def __init__(self):
self.env = {}
@ -109,10 +101,11 @@ class ServiceManager:
ports = {}
nr = '%02d' % int(section[self.group])
gr = self.group.upper()
singlekey = gr + '_PORT'
for service in self.services:
sv = '%s_%s' % (gr, service.upper())
sv = gr + '_' + service.upper()
key = '%s_PORT' % sv
port = section.get(key)
port = section.get(key) or section.get(singlekey)
if port or json.loads(section.get(sv, '0').lower()):
# e.g. NICOS_POLLER = True leads to port = 0
port = (port or '0').replace('nr', nr)
@ -128,24 +121,28 @@ class ServiceManager:
if ins is omitted, return a list of above for all ins
"""
result = OrderedDict()
parser = ConfigParser(interpolation=None)
parser.optionxform = str
parser.read(expanduser('~/servman.cfg'))
parser = get_config()
defaults = parser['DEFAULT']
self.commands = {}
# self.revcmd = {}
def expand_path(pathlist, ins):
return ':'.join(expanduser(p % dict(ins=ins)) for p in pathlist.split(':'))
def get_subs(section, key, ins, nr):
"""get item <key> from section and substitute nr or expand filename"""
value = section.get(key)
if key.endswith('_PORT'):
return value.replace('nr', nr)
return ':'.join(expanduser(p % dict(ins=ins)) for p in value.split(':'))
for ins in parser.sections():
section = dict(parser[ins])
command = section.get('%s_command' % self.group)
self.revcmd[command] = self.group
if self.group in section:
nr = section.get(self.group)
if nr is not None:
nr = '%02d' % int(nr)
self.commands[ins] = command
services = self.get_services(section)
env = {k: expand_path(section.get(k), ins) for k in defaults if k.isupper()}
env = {k: get_subs(section, k, ins, nr) for k in defaults if k.isupper()}
result[ins] = services
self.env[ins] = env
self.info = result
@ -194,7 +191,7 @@ class ServiceManager:
if match:
gdict = match.groupdict()
ins = gdict['ins']
serv = gdict['serv']
serv = gdict.get('serv', '')
if cfginfo is not None and 'cfg' in gdict:
cfginfo[ins, serv] = gdict['cfg']
result.setdefault(ins, {}).setdefault(serv, []).append(p)
@ -264,6 +261,7 @@ class ServiceManager:
except ValueError:
raise ValueError('do not know %r' % ins)
services = list(service_ports) if service is None else [service]
print('start', services, service_ports)
if restart:
self.stop(ins, service)
else:
@ -280,6 +278,7 @@ class ServiceManager:
for service_i in services:
port = service_ports[service_i]
cmd = self.commands[ins] % dict(ins=ins, serv=service_i, port=port, cfg=cfg, pkg=self.pkg)
print('COMMAND', cmd)
if '%(cfg)s' in self.commands[ins] and not cfg:
cmd = self.stopped[ins].get(service_i)
if not cmd:
@ -338,8 +337,10 @@ class ServiceManager:
def do_restart(self, ins, service=None, cfg=None):
self.do_start(ins, service, cfg, True)
def do_run(self, ins, service, cfg=None):
def do_run(self, ins, service=None, cfg=None):
"""for tests: run and wait"""
if not service:
service, = self.services
self.do_start(ins, service, cfg, wait=True)
def do_list(self, ins=None, *args):
@ -403,3 +404,7 @@ class ServiceManager:
if ' do_%s(' % action in errtxt and 'argument' in errtxt:
raise UsageError(errtxt)
raise
def usage(self):
print(self.USAGE % ', '.join(self.info))

View File

@ -24,31 +24,11 @@
import sys
from os.path import join, abspath, dirname
# above packages: servman, nicos, frappy, history
# for packages: servicemanager, frappyhistory
sys.path.insert(0, abspath(join(dirname(__file__), '../..')))
# for frappy:
sys.path.insert(0, abspath(join(dirname(__file__), '../../frappy')))
from servman import run, FrappyManager, NicosManager, SeaManager, UsageError
from servicemanager import run
NicosManager()
serv = FrappyManager()
SeaManager()
USAGE = """
Usage:
frappy list [<instance>]
frappy start <instance> <service> <cfgfiles>
frappy restart <instance> [<service>] [<cfgfiles>]
frappy stop <instance> [<service>]
<service> is one of main, stick, addons
<instance> is one of %s
""" % ', '.join(serv.info)
try:
run(serv, sys.argv[1:])
except Exception as e: # TODO: change to UsageError
print(repr(e))
print(''.join(USAGE))
run('frappy', sys.argv[1:])

View File

@ -24,42 +24,11 @@
import sys
from os.path import join, abspath, dirname
# above packages: servman, nicos, frappy, history
# for packages: servicemanager, frappyhistory
sys.path.insert(0, abspath(join(dirname(__file__), '../..')))
# for nicos:
sys.path.insert(0, abspath(join(dirname(__file__), '../../nicos')))
from servman import run, FrappyManager, NicosManager, SeaManager, UsageError
from servicemanager import run
serv = NicosManager()
FrappyManager()
SeaManager()
USAGE = """
Usage:
nicos gui <instance>
nicos <instance> (the same as above)
nicos list [<instance>]
nicos start <instance> [<service>]
nicos restart <instance> [<service>]
nicos stop <instance> [<service>]
nicos create <instance> <nr>
nicos create all
nicos link <instance> (create links to nicos data and scripts)
<service> is one of main, stick, addons
<instance> is one of %s
to be done after the experiment:
nicos copy (copy data and scripts from link)
nicos copy [<instance> [<year>/<proposal>]] (copy specific data)
""" % ', '.join(serv.info)
try:
run(serv, sys.argv[1:])
except UsageError as e:
print(repr(e))
print(''.join(USAGE))
run('nicos', sys.argv[1:])

32
bin/sea
View File

@ -24,35 +24,9 @@
import sys
from os.path import join, abspath, dirname
# above packages: servman, nicos, frappy, history
# for packages: servicemanager, frappyhistory
sys.path.insert(0, abspath(join(dirname(__file__), '../..')))
from servman import run, FrappyManager, NicosManager, SeaManager, UsageError
from servicemanager import run
NicosManager()
FrappyManager()
serv = SeaManager()
USAGE = """
Usage:
sea gui <instance>
sea <instance> # the same as sea gui <instance>
sea cli <instance> (the same as old seacmd)
sea start <instance> <service>
sea restart <instance> [<service>]
sea stop <instance> [<service>]
sea list [<instance>]
<service> is one of main, stick, addons
<instance> is one of %s
""" % ', '.join(serv.info)
try:
run(serv, sys.argv[1:])
except Exception as e: # TODO: change to UsageError
raise
print(repr(e))
print(''.join(USAGE))
run('sea', sys.argv[1:])

12
frappyman.py → bin/seweb Normal file → Executable file
View File

@ -1,3 +1,4 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# *****************************************************************************
#
@ -20,9 +21,12 @@
#
# *****************************************************************************
from servman.base import ServiceManager
import sys
from os.path import join, abspath, dirname
# for packages: servicemanager, frappyhistory
sys.path.insert(0, abspath(join(dirname(__file__), '../..')))
class FrappyManager(ServiceManager):
group = 'frappy'
services = ('main', 'stick', 'addons')
from servicemanager import run
run('seweb', sys.argv[1:])

View File

@ -26,7 +26,7 @@ import shutil
from glob import glob
from os.path import join, abspath, dirname, expanduser, exists, islink
from configparser import ConfigParser
from servman.base import ServiceManager
from servicsmanager.base import ServiceManager
ENV_KEYS = {
@ -50,6 +50,27 @@ def copy_all(srcdir, dstdir):
class NicosManager(ServiceManager):
group = 'nicos'
services = ('cache', 'daemon', 'poller')
USAGE = """
Usage:
nicos gui <instance>
nicos <instance> (the same as above)
nicos list [<instance>]
nicos start <instance> [<service>]
nicos restart <instance> [<service>]
nicos stop <instance> [<service>]
nicos create <instance> <nr>
nicos create all
nicos link <instance> (create links to nicos data and scripts)
<service> is one of main, stick, addons
<instance> is one of %s
to be done after the experiment:
nicos copy (copy data and scripts from link)
nicos copy [<instance> [<year>/<proposal>]] (copy specific data)
"""
def do_create(self, ins, *args):
self.get_info()

View File

@ -24,15 +24,15 @@ import sys
import time
import termios
import subprocess
from servman.base import ServiceManager
from servman.sicsclient import sics_client
from servicemanager.base import ServiceManager, ServiceDown
from servicemanager.sicsclient import sics_client
def run_command(cmd, wait=False):
if wait:
old = termios.tcgetattr(sys.stdin)
proc = subprocess.Popen(cmd.split())
try:
proc = subprocess.Popen(cmd.split())
proc.wait()
except KeyboardInterrupt:
proc.terminate()
@ -47,6 +47,20 @@ def run_command(cmd, wait=False):
class SeaManager(ServiceManager):
group = 'sea'
services = ('sea', 'graph')
USAGE = """
Usage:
sea gui <instance>
sea <instance> # the same as sea gui <instance>
sea cli <instance> (the same as old seacmd)
sea start <instance> <service>
sea restart <instance> [<service>]
sea stop <instance> [<service>]
sea list [<instance>]
<service> is one of main, stick, addons
<instance> is one of %s
"""
def do_cli(self, ins):
try:
@ -55,7 +69,7 @@ class SeaManager(ServiceManager):
print('%s, try to start...' % e)
self.do_start(ins)
time.sleep(1) # make sure caller did read the message
except KeyError as e: # running on an other machine?
except KeyError: # running on an other machine?
pass
run_command('six -sea %s' % ins, wait=True)
@ -66,13 +80,12 @@ class SeaManager(ServiceManager):
print('%s, try to start...' % e)
self.do_start(ins)
time.sleep(1) # make sure caller did read the message
except KeyError as e: # running on an other machine?
except KeyError: # running on an other machine?
pass
run_command('SeaClient %s' % ins)
print('starting sea gui %s' % ins)
time.sleep(5)
def get_cfg(self, ins, service):
"""return cfg info about running programs, if relevant