From ff71f10ce5ffbf1ffe85af8116feab3a9db0b75e Mon Sep 17 00:00:00 2001 From: Markus Zolliker Date: Fri, 26 Feb 2021 14:48:15 +0100 Subject: [PATCH] renamed to 'servicemanager' the PYTHONPATH should be set to the directory above servicemanager --- README.md | 4 +-- __init__.py | 66 ++++++++++++++++++++++++++++++++++++--- base.py | 59 ++++++++++++++++++---------------- bin/frappy | 30 +++--------------- bin/nicos | 41 +++--------------------- bin/sea | 32 ++----------------- frappyman.py => bin/seweb | 12 ++++--- nicosman.py | 23 +++++++++++++- seaman.py | 25 +++++++++++---- 9 files changed, 158 insertions(+), 134 deletions(-) rename frappyman.py => bin/seweb (79%) mode change 100644 => 100755 diff --git a/README.md b/README.md index 0ffd06a..391e366 100644 --- a/README.md +++ b/README.md @@ -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. diff --git a/__init__.py b/__init__.py index d5eaa81..20d3dc8 100644 --- a/__init__.py +++ b/__init__.py @@ -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 [] + frappy start + frappy restart [] [] + frappy stop [] + + is one of main, stick, addons + is one of %s + """ + + +class SewebManager(ServiceManager): + group = 'seweb' + services = ('',) + USAGE = """ + Usage: + + seaweb list [] + seaweb start + seaweb restart + seaweb stop + + 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()) + + diff --git a/base.py b/base.py index dd974f6..ef43ed9 100644 --- a/base.py +++ b/base.py @@ -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 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)) + diff --git a/bin/frappy b/bin/frappy index 34ea398..eed63fd 100755 --- a/bin/frappy +++ b/bin/frappy @@ -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 [] - frappy start - frappy restart [] [] - frappy stop [] - - is one of main, stick, addons - 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:]) diff --git a/bin/nicos b/bin/nicos index c94a174..aa88f44 100755 --- a/bin/nicos +++ b/bin/nicos @@ -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 - nicos (the same as above) - nicos list [] - nicos start [] - nicos restart [] - nicos stop [] - nicos create - nicos create all - nicos link (create links to nicos data and scripts) - - is one of main, stick, addons - is one of %s - -to be done after the experiment: - nicos copy (copy data and scripts from link) - nicos copy [ [/]] (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:]) diff --git a/bin/sea b/bin/sea index f4e1dc0..afe60d5 100755 --- a/bin/sea +++ b/bin/sea @@ -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 - sea # the same as sea gui - sea cli (the same as old seacmd) - sea start - sea restart [] - sea stop [] - sea list [] - - is one of main, stick, addons - 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:]) diff --git a/frappyman.py b/bin/seweb old mode 100644 new mode 100755 similarity index 79% rename from frappyman.py rename to bin/seweb index 14ec5d8..d1639d6 --- a/frappyman.py +++ b/bin/seweb @@ -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:]) diff --git a/nicosman.py b/nicosman.py index ab0c03d..8af4094 100644 --- a/nicosman.py +++ b/nicosman.py @@ -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 + nicos (the same as above) + nicos list [] + nicos start [] + nicos restart [] + nicos stop [] + nicos create + nicos create all + nicos link (create links to nicos data and scripts) + + is one of main, stick, addons + is one of %s + + to be done after the experiment: + nicos copy (copy data and scripts from link) + nicos copy [ [/]] (copy specific data) + + """ def do_create(self, ins, *args): self.get_info() diff --git a/seaman.py b/seaman.py index f29fa48..be7233e 100644 --- a/seaman.py +++ b/seaman.py @@ -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 + sea # the same as sea gui + sea cli (the same as old seacmd) + sea start + sea restart [] + sea stop [] + sea list [] + + is one of main, stick, addons + 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