Compare commits

2 Commits
master ... tmp

Author SHA1 Message Date
ec52f6f858 add getsestuff related stuff 2025-04-29 11:16:42 +02:00
d9877c1712 keep gesestuff in servicemanager
- still need to copy to
  /afs/psi.ch/project/sinq/common/stow/markus/bin/
2025-04-29 09:28:36 +02:00
17 changed files with 173 additions and 490 deletions

View File

@@ -3,5 +3,3 @@
A manager for starting, stopping and listing services/servers like frappy, nicos and sea. A manager for starting, stopping and listing services/servers like frappy, nicos and sea.
Several instances of nicos, frappy, sea and seweb might run on the same machine. Several instances of nicos, frappy, sea and seweb might run on the same machine.
contains also getsestuff, the script to manage the repos on all instruments

View File

@@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# ***************************************************************************** # *****************************************************************************
# #
# This program is free software; you can redistribute it and/or modify it under # This program is free software; you can redistribute it and/or modify it under
@@ -26,19 +27,28 @@ this code is currently used:
- from a script allowing to start/stop/list (and more) multiple frappy and nicos servers - from a script allowing to start/stop/list (and more) multiple frappy and nicos servers
""" """
import sys
from servicemanager.base import ServiceManager, ServiceDown, UsageError, get_config from servicemanager.base import ServiceManager, ServiceDown, UsageError, get_config
from servicemanager.nicosman import NicosManager from servicemanager.nicosman import NicosManager
from servicemanager.seaman import SeaManager from servicemanager.seaman import SeaManager
from servicemanager.frappyman import FrappyManager, Reconnect, Keep from servicemanager.frappyman import FrappyManager, Reconnect, Keep
from servicemanager.single import SewebManager, FeederManager
#from servicemanager.racks import RackConfig
#rack = RackConfig() class SewebManager(ServiceManager):
group = 'seweb'
services = ('',)
USAGE = """
Usage:
all = NicosManager, FrappyManager, SeaManager, SewebManager, FeederManager seaweb list [instance]
KINDS = 'action', 'ins', 'service' seaweb start <instance>
seaweb restart <instance>
seaweb stop <instance>
%s
"""
all = NicosManager, FrappyManager, SeaManager, SewebManager
def run(group, arglist): def run(group, arglist):
@@ -54,11 +64,11 @@ def run(group, arglist):
arg_is = { arg_is = {
'action': lambda arg: hasattr(serv, 'do_' + arg), 'action': lambda arg: hasattr(serv, 'do_' + arg),
'ins': lambda arg: arg in serv.info or arg in ('all', 'check') or serv.wildcard(arg), 'ins': lambda arg: arg in serv.info or arg == 'all' or serv.wildcard(arg),
'service': lambda arg: arg in serv.services, 'service': lambda arg: arg in serv.services,
} }
for kind in KINDS: for kind in 'action', 'ins', 'service':
if arglist and arg_is[kind](arglist[0]): # arg is of expected kind if arglist and arg_is[kind](arglist[0]): # arg is of expected kind
args[kind] = arglist.pop(0) args[kind] = arglist.pop(0)
continue continue
@@ -81,11 +91,8 @@ def run(group, arglist):
args.setdefault('ins', serv.main_ins) args.setdefault('ins', serv.main_ins)
if guessed_args: if guessed_args:
args.setdefault('action', 'gui') args.setdefault('action', 'gui')
guessed = [group] + [args.get(k, '') for k in KINDS] + extra print('do you mean:\n %s %s %s %s %s' %
while not guessed[-1]: (group, args.get('action', ''), args.get('ins', ''), args.get('service', ''), ' '.join(extra)))
guessed.pop()
guessed = ' '.join(a or '?' for a in guessed)
print(f'do you mean:\n {guessed}')
else: else:
try: try:
serv.action(args['action'], *serv.treat_args(args, extra + arglist)) serv.action(args['action'], *serv.treat_args(args, extra + arglist))
@@ -94,4 +101,5 @@ def run(group, arglist):
except UsageError as e: except UsageError as e:
serv.do_help() serv.do_help()
print('ERROR:', str(e)) print('ERROR:', str(e))
sys.exit(1)

View File

@@ -1,12 +0,0 @@
import os
instruments = ['amor', 'camea', 'dmc', 'eiger', 'focus', 'hrpt', 'boa', 'sans', 'tasp', 'zebra'] # morpheus
def influx_setup(instrument=None):
ins_list = instruments if instrument is None else [instrument]
for ins in ins_list:
print(ins)
os.system(f'ssh {ins} influx setup --username l_samenv --password LIN3601se '
'--token lZpLL_FrPw3cgkeuOWo_DcwjFZerrVTa1QQk6bcjSOYgjQ8W0eyvsp4Z4FULvsz2XEWTZZ8OPengYfLaWU-gdA== '
f'--org linse --bucket sehistory --force --name {ins}')

63
base.py
View File

@@ -24,7 +24,7 @@
import sys import sys
import json import json
import os import os
from os.path import expanduser, basename, exists from os.path import expanduser, basename
import subprocess import subprocess
import time import time
import re import re
@@ -84,7 +84,6 @@ class ServiceManager:
revcmd = {} revcmd = {}
USAGE = None USAGE = None
main_ins = None main_ins = None
single_ins = None
def __init__(self): def __init__(self):
self.env = {} self.env = {}
@@ -147,18 +146,12 @@ class ServiceManager:
nr = section.get(self.group) nr = section.get(self.group)
if nr is not None: if nr is not None:
nr = '%02d' % int(nr) nr = '%02d' % int(nr)
self.commands[ins] = command.replace('~', expanduser('~'))
services = self.get_services(section) services = self.get_services(section)
env = {k: get_subs(section, k, ins, nr) for k in section if k.isupper()} env = {k: get_subs(section, k, ins, nr) for k in section if k.isupper()}
result[ins] = services result[ins] = services
self.env[ins] = env self.env[ins] = env
cmd = command.replace('~', expanduser('~'))
if cmd.startswith('PY '):
cmd = env.get('PY', 'python3') + cmd[2:]
self.commands[ins] = cmd
self.info = result self.info = result
if len(self.info) == 1:
self.single_ins = list(self.info)[0]
return result
#def get_cmdpats(self, groups): #def get_cmdpats(self, groups):
# return self.cmdpats # return self.cmdpats
@@ -214,7 +207,7 @@ class ServiceManager:
match = cmdpat.match(cmd) match = cmdpat.match(cmd)
if match: if match:
gdict = match.groupdict() gdict = match.groupdict()
ins = gdict.get('ins', self.main_ins) or self.single_ins ins = gdict.get('ins', self.main_ins)
serv = gdict.get('serv', '') serv = gdict.get('serv', '')
if cfginfo is not None and 'cfg' in gdict: if cfginfo is not None and 'cfg' in gdict:
cfginfo[ins, serv] = gdict['cfg'] cfginfo[ins, serv] = gdict['cfg']
@@ -226,7 +219,7 @@ class ServiceManager:
or None, when no wildcard character in ins or None, when no wildcard character in ins
""" """
if not ins or ins == 'all': if ins is None or ins == 'all':
return list(self.info) return list(self.info)
pat = re.sub(r'(\.|\*)', '.*', ins) pat = re.sub(r'(\.|\*)', '.*', ins)
if pat == ins: if pat == ins:
@@ -286,9 +279,9 @@ class ServiceManager:
return done return done
def do_stop(self, ins, service=None, *args): def do_stop(self, ins, service=None, *args):
if not ins:
raise UsageError(f'need instrument or "all" to stop all')
self.get_info() self.get_info()
if ins is None:
raise ValueError('use stop all if you really want to stop all')
ins_list = self.wildcard(ins) ins_list = self.wildcard(ins)
if ins_list is not None: if ins_list is not None:
return ins_list return ins_list
@@ -302,42 +295,31 @@ class ServiceManager:
if not ins: if not ins:
raise UsageError('need instance') raise UsageError('need instance')
env = self.env[ins] env = self.env[ins]
startdir = env.get('%s_ROOT' % gr, '') return env.get('%s_ROOT' % gr, ''), env
if startdir not in sys.path:
sys.path.insert(0, startdir)
return startdir, env
def do_start(self, ins, service=None, cfg='', restart=False, wait=False, logger=None, opts=''): def do_start(self, ins, service=None, cfg='', restart=False, wait=False, logger=None, opts=''):
if not ins:
raise UsageError(f'need instrument or "all" to start all')
ins_list = self.wildcard(ins) ins_list = self.wildcard(ins)
if ins_list is not None: if ins_list is not None:
return ins_list return ins_list
if not logger: if logger is None:
if logger is False: class logger:
def info(fmt, *args): @staticmethod
pass
else:
def info(fmt, *args): def info(fmt, *args):
print(fmt % args) print(fmt % args)
def error(fmt, *args): @staticmethod
print(('ERROR: ' + fmt) % args) def error(fmt, *args):
print(('ERROR: ' + fmt) % args)
logger = type('Logger', (), {})
logger.info = info
logger.error = error
if ins is None: if ins is None:
logger.info('nothing to start') logger.info('nothing to start')
return return
try: try:
service_ports = self.get_ins_info(ins) service_ports = self.get_ins_info(ins)
except (KeyError, ValueError): except ValueError:
raise UsageError('do not know %r' % ins) raise ValueError('do not know %r' % ins)
if ins in self.remote_hosts: if ins in self.remote_hosts:
raise UsageError('can not start, %s is running on a remote host' % self.group) raise ValueError('can not start, %s is running on a remote host' % self.group)
services = list(service_ports) if service is None else [service] services = list(service_ports) if service is None else [service]
if restart: if restart:
self.stop(ins, service) self.stop(ins, service)
@@ -354,7 +336,6 @@ class ServiceManager:
services = to_start services = to_start
for service_i in services: for service_i in services:
port = service_ports[service_i] port = service_ports[service_i]
# TODO: remove unused pkg
cmd = self.commands[ins] % dict(ins=ins, serv=service_i, port=port, cfg=cfg, pkg=self.pkg or ins) cmd = self.commands[ins] % dict(ins=ins, serv=service_i, port=port, cfg=cfg, pkg=self.pkg or ins)
if opts: if opts:
cmd = f'{cmd} {opts}' cmd = f'{cmd} {opts}'
@@ -370,9 +351,8 @@ class ServiceManager:
start_dir, env = self.prepare_start(ins, service_i, cfg) start_dir, env = self.prepare_start(ins, service_i, cfg)
env = dict(os.environ, **env, Instrument=ins) env = dict(os.environ, **env, Instrument=ins)
os.chdir(start_dir) os.chdir(start_dir)
nicosenv = '/home/nicos/nicos/nicosenv/bin/' if start_dir not in sys.path:
if exists(nicosenv): sys.path.insert(0, start_dir)
env['PATH'] = f"{nicosenv}:{env['PATH']}"
if wait: if wait:
proc = subprocess.Popen(cmd.split(), env=env) proc = subprocess.Popen(cmd.split(), env=env)
for _ in range(3): for _ in range(3):
@@ -419,8 +399,8 @@ class ServiceManager:
os.chdir(wd) os.chdir(wd)
def do_restart(self, ins, service=None, cfg=None, logger=None): def do_restart(self, ins, service=None, cfg=None, logger=None):
if not ins: if ins is None:
raise UsageError("need instrument or 'all' or wildcard") raise UsageError("need instance or 'all' or wildcard")
ins_list = self.wildcard(ins) ins_list = self.wildcard(ins)
if ins_list is not None: if ins_list is not None:
if cfg is not None: if cfg is not None:
@@ -431,7 +411,7 @@ class ServiceManager:
def do_run(self, ins, service=None, cfg=None, opts=''): def do_run(self, ins, service=None, cfg=None, opts=''):
"""for tests: run and wait""" """for tests: run and wait"""
if self.wildcard(ins) is not None: if self.wildcard(ins) is not None:
raise UsageError('need instrument and service for "%s run"' % self.group) raise UsageError('no wildcards allowed with %s run' % self.group)
if not service: if not service:
try: try:
service, = self.services service, = self.services
@@ -441,7 +421,6 @@ class ServiceManager:
def do_list(self, ins=None, *args): def do_list(self, ins=None, *args):
"""info about running services""" """info about running services"""
self.get_info()
show_unused = ins == 'all' show_unused = ins == 'all'
if show_unused: if show_unused:
ins = None ins = None

View File

@@ -1,8 +0,0 @@
#!/usr/bin/env python3
import sys
from os.path import expanduser
sys.path.append(expanduser('~'))
from servicemanager import run
run('feeder', sys.argv[1:])

View File

@@ -1,4 +1,4 @@
#!/home/software/virtualenv/nicosenv/bin/python3 #!/home/nicos/nicos/nicosenv/bin/python3
import sys import sys
import time import time
from os import path from os import path
@@ -10,18 +10,18 @@ usage = """
Usage: Usage:
nicos-gui start nicos gui nicos-gui start nicos gui
nicos_gui start nicos gui and connect without asking for password nicos gui start nicos gui and connect without asking for password
nicos-client start nicos command line client nicos-client start nicos command line client
nicos_cli start nicos command line client and connect without asking for password nicos cli start nicos command line client and connect without asking for password
""" """
# yr = time.strftime('%y') yr = time.strftime('%y')
connect = f'user:sinq@localhost' connect = f'user:{yr}lns1@localhost'
if sys.argv[-1] == 'cli' or sys.argv[0].endswith('cli'): if sys.argv[-1] == 'cli':
from nicos.clients.cli import main from nicos.clients.cli import main
sys.exit(main([connect])) sys.exit(main([connect]))
elif sys.argv[-1] == 'gui' or sys.argv[0].endswith('gui'): elif sys.argv[-1] == 'gui':
from nicos.clients.gui.main import main from nicos.clients.gui.main import main
instrument = gethostname().split('.')[0] instrument = gethostname().split('.')[0]
guiconfig = f'{nicosroot}/nicos_sinq/{instrument}/guiconfig.py' guiconfig = f'{nicosroot}/nicos_sinq/{instrument}/guiconfig.py'

View File

@@ -1,11 +0,0 @@
[Unit]
Description=sehistory feeder process
[Service]
Type=simple
WorkingDirectory=%h/sehistory
ExecStart=%h/sevenv/bin/python feeder.py -d %i
Restart=always
[Install]
WantedBy=default.target

View File

@@ -1,7 +1,7 @@
[hrpt2] [hrpt2]
SEA_SEA_PORT = 8652 SEA_SEA_PORT = 8642
SEA_GRAPH_PORT = 8752 SEA_GRAPH_PORT = 8742
sea_command = ./SeaServer %(serv)s_%(ins)s.tcl sea_command = ./SeaServer %(serv)s_%(ins)s.tcl
sea = 2 sea = 2

View File

@@ -1,11 +0,0 @@
[local]
uri=http://localhost:8086
bucket=sehistory
org=linse
token=lZpLL_FrPw3cgkeuOWo_DcwjFZerrVTa1QQk6bcjSOYgjQ8W0eyvsp4Z4FULvsz2XEWTZZ8OPengYfLaWU-gdA==
[central]
uri=http://linse-c:8086
bucket=sehistory
org=linse
token=ggo2cRoCIkgniXdUGi-s6oxXJPPDzgKEFHh6PXuBg1QQa3aBo36tGFP_6cf50FRNoDQgGcelh3xBM5QsVw4rHA==

View File

@@ -1,4 +1,5 @@
[DEFAULT] [DEFAULT]
VENV = /home/nicos/nicos/nicosenv/bin/
FRAPPY_MAIN_PORT = 151nr FRAPPY_MAIN_PORT = 151nr
FRAPPY_STICK_PORT = 152nr FRAPPY_STICK_PORT = 152nr
FRAPPY_ADDONS_PORT = 153nr FRAPPY_ADDONS_PORT = 153nr
@@ -9,7 +10,7 @@ FRAPPY_LOGDIR = ~/frappylog
FRAPPY_PIDDIR = ~/frappylog/pid FRAPPY_PIDDIR = ~/frappylog/pid
FRAPPY_SEA_DIR = ~/frappy/cfg/sea FRAPPY_SEA_DIR = ~/frappy/cfg/sea
FRAPPY_CALIB_PATH = ~/calcurves FRAPPY_CALIB_PATH = ~/calcurves
frappy_command = ~/sevenv/bin/python bin/frappy-server %(ins)s_%(serv)s -p=%(port)s -c=%(cfg)s frappy_command = bin/frappy-server %(ins)s_%(serv)s -p=%(port)s -c=%(cfg)s
SEA_SEA_PORT = 8641 SEA_SEA_PORT = 8641
SEA_GRAPH_PORT = 8741 SEA_GRAPH_PORT = 8741
@@ -17,17 +18,12 @@ SEA_ROOT = ~/sea
sea_command = ./SeaServer %(serv)s.tcl sea_command = ./SeaServer %(serv)s.tcl
SEWEB_ROOT = ~/seweb SEWEB_ROOT = ~/seweb
SEWEB_PORT = 8642 SEWEB_PORT = 8941
seweb_command = ~/sevenv/bin/python secop-webserver %(port)s -i %(ins)s SEWEB_HISTORY = ~/seweb/history
seweb_command = python3 seweb.py frappy ins=%(ins)s port=%(port)s
FEEDER_ROOT = ~/sehistory PYTHONPATH = ~
FEEDER_PORT = 0
feeder_command = ~/sevenv/bin/python feeder.py -d %(serv)s
PYTHONPATH = ~:~/frappy
[MAIN] [MAIN]
frappy = 1 frappy = 1
sea = 1 sea = 1
seweb = 1
feeder = 1

View File

@@ -1,11 +0,0 @@
[Unit]
Description=SE web server
[Service]
Type=simple
WorkingDirectory=%h/seweb
ExecStart=%h/sevenv/bin/python secop-webserver 8642 -i %i
Restart=always
[Install]
WantedBy=default.target

View File

@@ -1,7 +1,7 @@
[zebra2] [zebra2]
SEA_SEA_PORT = 8652 SEA_SEA_PORT = 8642
SEA_GRAPH_PORT = 8752 SEA_GRAPH_PORT = 8742
sea_command = ./SeaServer %(serv)s_%(ins)s.tcl sea_command = ./SeaServer %(serv)s_%(ins)s.tcl
sea = 2 sea = 2

View File

@@ -24,9 +24,7 @@ import os
import re import re
import builtins import builtins
from glob import glob from glob import glob
from socket import gethostbyname, gethostname
from itertools import zip_longest from itertools import zip_longest
from pathlib import Path
from collections import defaultdict from collections import defaultdict
from os.path import join, isdir, basename, expanduser, exists from os.path import join, isdir, basename, expanduser, exists
from configparser import ConfigParser from configparser import ConfigParser
@@ -38,24 +36,30 @@ MAIN = 1
STICK = 2 STICK = 2
class Config: class Namespace(dict):
log = None def __init__(self):
process_file = None self['Node'] = self.node
self['Mod'] = self.mod
for fun in 'Param', 'Command', 'Group':
self[fun] = self.dummy
self.init()
@classmethod def init(self):
def get(cls, cfgfile): self.description = ''
if not cls.process_file: self.sea_cfg = None
import logging
try: def node(self, equipment_id, description, *args, **kwds):
from frappy.config import process_file self.description = description
except Exception as e:
print(sys.path) def mod(self, name, cls, description, config=None, **kwds):
raise cls = getattr(cls, '__name__', cls)
from frappy.lib import generalConfig if cls.endswith('SeaClient'):
generalConfig.init() self.sea_cfg = config
cls.log = logging.getLogger('frappyman')
cls.process_file = process_file def dummy(self, *args, **kwds):
return cls.process_file(Path(cfgfile), cls.log) return None
__builtins__ = builtins
SEAEXT = {'main': '.config', 'stick': '.stick'} SEAEXT = {'main': '.config', 'stick': '.stick'}
@@ -110,19 +114,16 @@ class FrappyManager(ServiceManager):
cfgpaths = [] cfgpaths = []
cfgparser = ConfigParser() cfgparser = ConfigParser()
cfgparser.optionxform = str cfgparser.optionxform = str
env = self.env.get(ins, {}) cfgfile = self.env[ins].get('FRAPPY_CONFIG_FILE')
cfgfile = env.get('FRAPPY_CONFIG_FILE') confdir = self.env[ins].get('FRAPPY_CONFDIR')
confdir = env.get('FRAPPY_CONFDIR')
if cfgfile: if cfgfile:
cfgfile = cfgfile.replace('<SERV>', service) cfgfile = self.env[ins]['FRAPPY_CONFIG_FILE'].replace('<SERV>', service)
cfgparser.read(cfgfile) cfgparser.read(cfgfile)
try: try:
section = cfgparser['FRAPPY'] section = cfgparser['FRAPPY']
except KeyError: except KeyError:
raise ValueError('%s does not exist or has no FRAPPY section' % cfgfile) raise ValueError('%s does not exist or has no FRAPPY section' % cfgfile)
confdir = section.get('confdir', confdir) confdir = section.get('confdir', confdir)
if not confdir:
return []
for cfgpath in confdir.split(os.pathsep): for cfgpath in confdir.split(os.pathsep):
if cfgpath.endswith('<SERV>'): if cfgpath.endswith('<SERV>'):
cfgpaths.append(expanduser(cfgpath[:-6] + service)) cfgpaths.append(expanduser(cfgpath[:-6] + service))
@@ -137,9 +138,9 @@ class FrappyManager(ServiceManager):
start_dir, env = super().prepare_start(ins, service) start_dir, env = super().prepare_start(ins, service)
env_update = {} env_update = {}
for key, value in env.items(): for key, value in env.items():
if '<SERV>' in value: if '<SERV>' in value:
env_update[key] = value.replace('<SERV>', service) env_update[key] = value.replace('<SERV>', service)
os.environ[key] = env[key] os.environ[key] = env[key]
cfgpaths = self.config_dirs(ins, service) cfgpaths = self.config_dirs(ins, service)
if cfgpaths: if cfgpaths:
env_update['FRAPPY_CONFDIR'] = os.pathsep.join(cfgpaths) env_update['FRAPPY_CONFDIR'] = os.pathsep.join(cfgpaths)
@@ -169,7 +170,9 @@ class FrappyManager(ServiceManager):
return [i for i in ins_list if i in cfgs] return [i for i in ins_list if i in cfgs]
def get_nodes(self, ins='', service=None): def get_nodes(self, ins='', service=None):
ServiceManager.prepare_start(self, ins, None) start_dir = ServiceManager.prepare_start(self, ins, None)[0]
if start_dir not in sys.path:
sys.path.insert(0, start_dir)
nodes = [] nodes = []
services = self.services if service is None else [service] services = self.services if service is None else [service]
for service in services: for service in services:
@@ -196,66 +199,39 @@ class FrappyManager(ServiceManager):
from frappy.gui.mainwindow import MainWindow from frappy.gui.mainwindow import MainWindow
app = QApplication([]) app = QApplication([])
args = type('args', (), dict(detailed=True, node=nodes)) win = MainWindow(nodes, logging.getLogger('gui'))
win = MainWindow(args, logging.getLogger('gui'))
win.show() win.show()
return app.exec_() return app.exec_()
def do_cli(self, ins='', service=None): def do_cli(self, ins='', service=None):
nodes = self.get_nodes(ins, service) nodes = self.get_nodes(ins, service)
from frappy.client.interactive import init, interact from frappy.client.interactive import init, interact
from frappy.protocol.discovery import scan
if ins == self.single_ins:
all_nodes = {}
for node in nodes:
host, port = node.split(':')
if host == 'localhost':
host = gethostname()
all_nodes[gethostbyname(host), int(port)] = node
for a in scan():
all_nodes.setdefault((a.address, a.port), f'{a.hostname}:{a.port}')
nodes = list(all_nodes.values())
init(*nodes) init(*nodes)
try: interact()
interact(appname=ins)
except TypeError: # older frappy client
interact()
@staticmethod @staticmethod
def get_cfg_details(cfgfile): def get_cfg_details(namespace, cfgfile):
mods = Config.get(cfgfile) # get sea_cfg option from frappy cfg file
node = mods.pop('node') or {} namespace.init()
sea_cfg = None local = {}
for mod, config in mods.items(): with open(cfgfile, encoding='utf-8') as f:
cls = config['cls'] exec(f.read(), namespace, local)
cls = getattr(cls, '__name__', cls) return namespace.description, local.get('sea_cfg', namespace.sea_cfg)
if cls.endswith('SeaClient'):
try:
sea_cfg = config['config']['value']
except KeyError:
sea_cfg = None
return node.get('description', '').strip(), sea_cfg
def cfg_details(self, ins, service, cfgfile): def cfg_details(self, ins, service, cfg):
if cfgfile: namespace = Namespace()
return self.get_cfg_details(cfgfile)
raise FileNotFoundError(f'{cfgfile} not found')
def get_cfg_file(self, ins, service, cfg, lazy=False):
if service is None:
return None
filenames = [f'{cfg}_cfg.py']
if lazy:
filenames.extend([f'{cfg}.py', cfg])
for cfgdir in self.config_dirs(ins, service): for cfgdir in self.config_dirs(ins, service):
for filename in filenames: cfgfile = join(cfgdir, f'{cfg}_cfg.py')
cfgfile = join(cfgdir, filename) if exists(cfgfile):
if exists(cfgfile): return self.get_cfg_details(namespace, cfgfile)
return cfgfile raise FileNotFoundError(f'{cfg} not found')
return None
def is_cfg(self, ins, service, cfg): def is_cfg(self, ins, service, cfg):
return bool(self.get_cfg_file(ins, service, cfg)) try:
self.cfg_details(ins, service, cfg)
return True
except Exception:
return False
def all_cfg(self, ins, service, details=False): def all_cfg(self, ins, service, details=False):
"""get available cfg files """get available cfg files
@@ -273,6 +249,7 @@ class FrappyManager(ServiceManager):
all_cfg = set() all_cfg = set()
if not ins: if not ins:
return {} return {}
namespace = Namespace()
if details: if details:
self.frappy2sea = f2s = {} self.frappy2sea = f2s = {}
self.sea2frappy = s2f = {} self.sea2frappy = s2f = {}
@@ -283,9 +260,7 @@ class FrappyManager(ServiceManager):
cfg = basename(cfgfile)[:-7] cfg = basename(cfgfile)[:-7]
if details: if details:
try: try:
desc, sea_cfg = self.get_cfg_details(cfgfile) desc, sea_cfg = self.get_cfg_details(namespace, cfgfile)
except TypeError:
raise
except Exception as e: except Exception as e:
sea_cfg = None sea_cfg = None
desc = repr(e) desc = repr(e)
@@ -303,7 +278,6 @@ class FrappyManager(ServiceManager):
def do_listcfg(self, ins='', service='', prt=print): def do_listcfg(self, ins='', service='', prt=print):
if not ins: if not ins:
raise UsageError('missing instance') raise UsageError('missing instance')
ServiceManager.prepare_start(self, ins, service)
self.all_cfg(ins, service, True) self.all_cfg(ins, service, True)
seacfgpat = re.compile(r'(.*)(\.config|\.stick|\.addon)') seacfgpat = re.compile(r'(.*)(\.config|\.stick|\.addon)')
keylen = max((max(len(k) for k in cfgs) for cfgs in self.list_info.values()), default=1) keylen = max((max(len(k) for k in cfgs) for cfgs in self.list_info.values()), default=1)
@@ -346,7 +320,7 @@ class FrappyManager(ServiceManager):
argdict['service'] = cfg argdict['service'] = cfg
return super().treat_args(argdict, (), extra) return super().treat_args(argdict, (), extra)
if (',' in cfg or cfg.endswith('.cfg') or if (',' in cfg or cfg.endswith('.cfg') or
self.get_cfg_file(argdict.get('ins'), argdict.get('service'), cfg, True)): self.is_cfg(argdict.get('ins'), argdict.get('service'), cfg)):
return super().treat_args(argdict, (), [cfg] + extra) return super().treat_args(argdict, (), [cfg] + extra)
return super().treat_args(argdict, unknown, extra) return super().treat_args(argdict, unknown, extra)
@@ -430,6 +404,7 @@ class FrappyManager(ServiceManager):
if proposed_addons: # and set(proposed_addons) != set(running_addons): if proposed_addons: # and set(proposed_addons) != set(running_addons):
proposed_cfg['addons'] = {','.join(proposed_addons)} proposed_cfg['addons'] = {','.join(proposed_addons)}
self._debug = {}
for service in FrappyManager.services: for service in FrappyManager.services:
given = givencfgs.get(service) given = givencfgs.get(service)
running = self.frappy_cfgs.get(service) running = self.frappy_cfgs.get(service)
@@ -438,6 +413,8 @@ class FrappyManager(ServiceManager):
if running: if running:
self.state[f'frappy {service}'] = running self.state[f'frappy {service}'] = running
self._debug[service] = (seaconfig, available, running, running in self.frappy2sea)
if seaconfig and (available or running in self.frappy2sea): if seaconfig and (available or running in self.frappy2sea):
# we get here when the sea server is running and either at least one of: # we get here when the sea server is running and either at least one of:
# - the sea config is matching any frappy cfg # - the sea config is matching any frappy cfg

View File

@@ -10,7 +10,7 @@ from subprocess import Popen, PIPE, check_output
from glob import glob from glob import glob
from socket import gethostname from socket import gethostname
instruments = ['camea', 'dmc', 'eiger', 'focus', 'hrpt', 'sans', 'tasp', 'zebra', 'boa', 'amor'] instruments = ['amor', 'camea', 'dmc', 'eiger', 'focus', 'hrpt', 'morpheus', 'sans', 'tasp', 'zebra'] # boa
stuffsrc = '/afs/psi.ch/project/sinq/common/lib/servicemanager/' stuffsrc = '/afs/psi.ch/project/sinq/common/lib/servicemanager/'
@@ -41,7 +41,6 @@ if home.endswith('zolliker'):
if remote: if remote:
instrument = '' instrument = ''
nicosroot = '' nicosroot = ''
nicosenv = ''
else: else:
nicosroot = '/home/nicos/nicos' nicosroot = '/home/nicos/nicos'
if not exists(f'{nicosroot}/.git/config'): if not exists(f'{nicosroot}/.git/config'):
@@ -93,15 +92,13 @@ def do(cmd):
def docopy(src, dst): def docopy(src, dst):
if not os.system(f'diff {dst} {src}'): if os.system(f'diff {dst} {src}'):
return False if doit:
if doit: if not do(f'cp {src} {dst}'):
if not do(f'cp {src} {dst}'): do(f'mv {dst} {dst}0')
do(f'mv {dst} {dst}0') do(f'cp {src} {dst}')
do(f'cp {src} {dst}') else:
else: todo.add(action)
todo.add(action)
return True
def dolink(dst, src): def dolink(dst, src):
@@ -155,14 +152,23 @@ def check_repo(root, repo, url=None, branch=None):
print(gitconfig.get('remote.origin.url'), 'does not match', url) print(gitconfig.get('remote.origin.url'), 'does not match', url)
print(f'{join(root, repo)} exists already') print(f'{join(root, repo)} exists already')
return False return False
# if repo == 'sea':
# do('mkdir seagit')
# if sim:
# print('> cd seagit')
# else:
# chdir('seagit')
# do('git clone %s' % url)
# do(f'mv sea/.git ../sea/.git')
# if sim:
# print('> cd ..')
# else:
# chdir('..')
# do(f'rm -rf seagit')
else: else:
do('git clone %s' % url) do('git clone %s' % url)
pull = True pull = True
created = doit created = doit
if 'gitea' in url:
hooksrc = '/afs/psi.ch/project/sinq/common/stow/markus/lib/gitea'
docopy(f'{hooksrc}/get_gitea_token', '.git/hooks/')
docopy(f'{hooksrc}/pre-commit', '.git/hooks/')
if created: if created:
chdir(join(root, repo)) chdir(join(root, repo))
docmd('git remote update') docmd('git remote update')
@@ -177,9 +183,9 @@ def check_repo(root, repo, url=None, branch=None):
gitconfig['pull.rebase'] = 'True' gitconfig['pull.rebase'] = 'True'
gitconfig['remote.origin.url'] = url gitconfig['remote.origin.url'] = url
if 'gitea' in url: if 'gitea' in url:
# hooksrc = '/afs/psi.ch/project/sinq/common/stow/markus/lib/gitea' hooksrc = '/afs/psi.ch/project/sinq/common/stow/markus/lib/gitea'
# docopy(f'{hooksrc}/get_gitea_token', '.git/hooks/') docopy(f'{hooksrc}/get_gitea_token', '.git/hooks/')
# docopy(f'{hooksrc}/pre-commit', '.git/hooks/') docopy(f'{hooksrc}/pre-commit', '.git/hooks/')
gitconfig['credential.helper'] = f'{getcwd()}/.git/hooks/get_gitea_token' gitconfig['credential.helper'] = f'{getcwd()}/.git/hooks/get_gitea_token'
diff = {k: v for k, v in gitconfig.items() if v != prev.get(k) and v != prev.get(k.replace('branch.', ''))} diff = {k: v for k, v in gitconfig.items() if v != prev.get(k) and v != prev.get(k.replace('branch.', ''))}
if doit: if doit:
@@ -274,35 +280,12 @@ def do_sshnicos():
do_ssh() do_ssh()
def do_sevenv():
"""install python packages needed for seweb etc."""
sevenv = join(home, 'sevenv')
if not exists(join(sevenv, 'bin')):
if exists(nicosenv):
# start from nicos env if possible
py = join(nicosenv, 'bin/python')
else:
py = 'python3'
do(f'{py} -m venv {sevenv}')
if exists(join(sevenv, 'bin')):
upgrade = True
for pkg in ['mlzlog', 'scipy', 'psutil', 'flask', 'gevent', 'influxdb_client']:
if not glob(f'{sevenv}/lib/python3*/site-packages/{pkg}'):
if doit:
if upgrade:
do(f'{sevenv}/bin/python3 -m pip install --upgrade pip')
upgrade = False
do(f'{sevenv}/bin/python3 -m pip install {pkg}')
else:
print(f'missing {pkg} in sevenv')
def do_frappy(): def do_frappy():
"""Frappy framework""" """Frappy framework"""
frappydir = join(home, 'frappy') frappydir = join(home, 'frappy')
if exists(frappydir) and not exists(join(frappydir, '.git')): if exists(frappydir) and not exists(join(frappydir, '.git')):
do('rm -rf %s' % frappydir) do('rm -rf %s' % frappydir)
if check_repo(home, 'frappy'): if check_repo(home, 'frappy', 'gitlab'):
do('git pull') do('git pull')
if exists(join(frappydir, '.git')): if exists(join(frappydir, '.git')):
sys.path.extend(glob(f'{nicosenv}/lib/*/site-packages')) sys.path.extend(glob(f'{nicosenv}/lib/*/site-packages'))
@@ -327,35 +310,15 @@ def do_servicemanager():
do('git pull') do('git pull')
def do_feeder(): def do_sehistory():
"""history feeder""" """history feeder"""
if check_repo(home, 'sehistory', None, 'master'): if check_repo(home, 'sehistory', None, 'master'):
do('git pull') do('git pull')
configdir = join(home, '.config')
systemddir = join(configdir, 'systemd/user')
if not exists(systemddir):
do(f'mkdir -p {systemddir}')
docopy(join(home, 'servicemanager/cfg/sehistory'), join(configdir, 'sehistory'))
if docopy(join(home, 'servicemanager/cfg/feeder@.service'),
join(systemddir, 'feeder@.service')):
do('systemctl --user daemon-reload')
def do_seweb():
"""SE web client"""
if check_repo(home, 'seweb', None, 'master'):
do('git pull')
systemddir = join(home, '.config/systemd/user')
if not exists(systemddir):
do(f'mkdir -p {systemddir}')
if docopy(join(home, 'servicemanager/cfg/seweb@.service'),
join(systemddir, 'seweb@.service')):
do('systemctl --user daemon-reload')
def do_sea(): def do_sea():
"""SEA server scripts""" """SEA server scripts"""
if check_repo(home, 'sea'): if check_repo(home, 'sea', 'gitlab'):
do('git pull') do('git pull')
# do('git checkout master -- .gitignore') # do not know why this is needed # do('git checkout master -- .gitignore') # do not know why this is needed
# do('chmod -x tcl/config/json_racklist tcl/*.* tcl/*.tcl tcl/*/*.tcl') # do('chmod -x tcl/config/json_racklist tcl/*.* tcl/*.tcl tcl/*/*.tcl')
@@ -367,12 +330,11 @@ def do_sea():
do('rm -rf tcl/calcurves') do('rm -rf tcl/calcurves')
do_calcurves() do_calcurves()
docopy('/afs/psi.ch/user/z/zolliker/public/git.rhel7/sics/SeaServer', join(home, 'sea', 'SeaServer')) docopy('/afs/psi.ch/user/z/zolliker/public/git.rhel7/sics/SeaServer', join(home, 'sea', 'SeaServer'))
dolink('/afs/psi.ch/project/sinq/rhel7/bin/SeaClient', join(home, 'bin', 'SeaClient'))
def do_calcurves(): def do_calcurves():
"""calibration curves""" """calibration curves"""
if check_repo(home, 'calcurves'): if check_repo(home, 'calcurves', 'gitlab'):
do('git pull') do('git pull')
dolink('~/calcurves', '~/sea/tcl/calcurves') dolink('~/calcurves', '~/sea/tcl/calcurves')
@@ -380,7 +342,7 @@ def do_calcurves():
def do_frappysinq(): def do_frappysinq():
"""nicos_sinq/frappy_sinq setups and extensions""" """nicos_sinq/frappy_sinq setups and extensions"""
if exists(nicosroot): if exists(nicosroot):
if check_repo(join(nicosroot, 'nicos_sinq'), 'frappy_sinq'): if check_repo(join(nicosroot, 'nicos_sinq'), 'frappy_sinq', 'gitlab'):
do('git pull') do('git pull')
@@ -497,7 +459,7 @@ def do_bin():
chdir(home) chdir(home)
if not exists('bin'): if not exists('bin'):
do('mkdir -p bin') do('mkdir -p bin')
pgms = ['frappy', 'sea', 'seweb', 'feeder'] pgms = ['frappy', 'sea']
if nicosroot: if nicosroot:
executable = f'{nicosenv}/bin/python3' executable = f'{nicosenv}/bin/python3'
else: else:
@@ -547,6 +509,11 @@ def remove_line(file, content):
todo.add(action) todo.add(action)
print('remove above') print('remove above')
#def do_monit():
# """remove monit support for sea / graph"""
# remove_line('%s/monitconfig' % home, 'sea')
# remove_line('%s/monitconfig' % home, 'graph')
selected_instruments = None selected_instruments = None
action_arg = '' action_arg = ''
@@ -571,7 +538,7 @@ for arg in sys.argv[1:]:
action_arg = arg action_arg = arg
nc_actions = ['frappysinq', 'nicosconf', 'nicosenv'] # 'sshnicos', 'nicos_pick' nc_actions = ['sshnicos', 'frappysinq', 'nicosconf', 'nicosenv'] # 'nicos_pick'
ncactionfuncs = {} ncactionfuncs = {}
with_su = False with_su = False
@@ -583,8 +550,8 @@ else:
with_su = action_arg in nc_actions with_su = action_arg in nc_actions
for a in nc_actions: for a in nc_actions:
ncactionfuncs[a] = locals()['do_%s' % a] ncactionfuncs[a] = locals()['do_%s' % a]
actions = ['bin', 'scfg', 'frappy', 'servicemanager', 'sea', actions = ['ssh', 'bin', 'scfg', 'frappy', 'servicemanager', 'sea',
'calcurves', 'feeder', 'seweb', 'sevenv'] # 'ssh' 'calcurves', 'sehistory']
actionfuncs = {} actionfuncs = {}
for a in actions: for a in actions:
@@ -595,8 +562,6 @@ for a in actions:
def print_help(): def print_help():
if not help:
return
if remote: if remote:
inst = "<instrument> " inst = "<instrument> "
else: else:
@@ -616,29 +581,22 @@ def print_help():
print(" replace <instrument> by allin for applying to all instruments") print(" replace <instrument> by allin for applying to all instruments")
def remote_cmd(command, instlist=None):
# to be used with "python -i getsestuff"
for inst in instlist or instruments:
print(f'===== {inst} ' + '=' * (70-len(inst)))
os.environ['SSHPASS'] = inst.upper()+'LNS'
docmd(f'sshpass -e ssh {inst}@{inst} {command}')
if remote: if remote:
if not doit: if not doit:
action_arg = 'check ' + action_arg action_arg = 'check ' + action_arg
if selected_instruments is None: if selected_instruments is None:
print_help() print_help()
else: else:
remote_cmd(f'getsestuff {action_arg} nohelp', selected_instruments) for inst in selected_instruments:
print(f'===== {inst} ' + '=' * (70-len(inst)))
os.environ['SSHPASS'] = inst.upper()+'LNS'
docmd(f'sshpass -e ssh {inst}@{inst} getsestuff {action_arg} nohelp')
sys.exit(0) sys.exit(0)
def su_action(action): def su_action(action):
os.environ['SSHPASS'] = scramble('P[d20+2:1eh') os.environ['SSHPASS'] = scramble('P[d20+2:1eh')
docmd(f'sshpass -e ssh nicos@localhost {sys.argv[0]} {action} nohelp') docmd(f'sshpass -e ssh nicos@localhost {sys.argv[0]} {action} nohelp')
if with_su: if with_su:
su_action(action_arg) su_action(action_arg)
sys.exit(0) sys.exit(0)
@@ -667,7 +625,8 @@ if action_arg in ('', 'all', 'sim') and nc_actions:
print_help() print_help()
sys.exit(0) sys.exit(0)
print_help() if help:
if sim or not action_arg and todo: print_help()
print('needs updates: %s' % ' '.join(todo)) if sim or not action_arg and todo:
print('needs updates: %s' % ' '.join(todo))

View File

@@ -84,7 +84,6 @@ class NicosManager(ServiceManager):
print('ambiguos package: %s' % ', '.join(instdir)) print('ambiguos package: %s' % ', '.join(instdir))
else: else:
env['NICOS_PACKAGE'] = basename(dirname(instdir[0])) env['NICOS_PACKAGE'] = basename(dirname(instdir[0]))
return self.info
def do_create(self, ins, *args): def do_create(self, ins, *args):
if ins == 'check': if ins == 'check':
@@ -96,13 +95,13 @@ class NicosManager(ServiceManager):
self.get_info() self.get_info()
for ins_i in ins_list: for ins_i in ins_list:
env = self.env[ins_i] env = self.env[ins_i]
base = join(env['NICOS_ROOT'], env['NICOS_PACKAGE'], ins_i) base = join(env['NICOS_ROOT'], env['NICOS_PACKAGE'], ins)
nicos_conf = join(base, 'nicos.conf') nicos_conf = join(base, 'nicos.conf')
content = { content = {
'nicos': { 'nicos': {
'setup_subdirs': '["%s", "linse_nicos", "frappy_sinq"]' % ins_i, 'setup_subdirs': '["%s", "common", "frappy_sinq"]' % ins,
'logging_path': '"%s/%s"' % (env['NICOS_LOG'], ins_i), 'logging_path': '"%s/%s"' % (env['NICOS_LOG'], ins),
'pid_path': '"%s/%s"' % (env['NICOS_LOG'], ins_i), 'pid_path': '"%s/%s"' % (env['NICOS_LOG'], ins),
}, },
# 'environment': { # 'environment': {
# key: f'"{env[key]}"' for key in env if key in ENV_KEYS # key: f'"{env[key]}"' for key in env if key in ENV_KEYS

View File

@@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# ***************************************************************************** # *****************************************************************************
# #
# This program is free software; you can redistribute it and/or modify it under # This program is free software; you can redistribute it and/or modify it under
@@ -26,24 +27,13 @@ import subprocess
import psutil import psutil
import os import os
import re import re
import socket from os.path import join, exists
from os.path import join, exists, expanduser
from servicemanager.base import ServiceManager, ServiceDown, UsageError from servicemanager.base import ServiceManager, ServiceDown, UsageError
CFGLINE = re.compile(r'(?:device makeitem (name|stick_name|confirmed) "(.*)" ""' CFGLINE = re.compile(r'(?:device makeitem (name|stick_name|confirmed) "(.*)" ""'
r'|addon_list makeitem (.*) (?:"permanent"|"volatile"))') r'|addon_list makeitem (.*) (?:"permanent"|"volatile"))')
INIFILE_CONTENT = """
set instrument {ins_i}
set serverport {port}
set logbase {insdir}
{extraline}cd {seadir}tcl
exe echo 1
exe {service}init.tcl
"""
def run_command(cmd, wait=False): def run_command(cmd, wait=False):
if wait: if wait:
old = termios.tcgetattr(sys.stdin) old = termios.tcgetattr(sys.stdin)
@@ -78,49 +68,7 @@ class SeaManager(ServiceManager):
%(legend)s %(legend)s
""" """
def do_create(self, ins, *args): def do_cli(self, ins):
if ins == 'check':
ins_list = self.wildcard(None)
else:
ins_list = self.wildcard(ins)
if ins_list is None:
ins_list = [ins]
self.get_info()
for ins_i in ins_list:
seadir = f"{expanduser('~')}/sea/"
if not exists(seadir):
print(f'get {seadir} from git first')
return
insdir = seadir if ins_i == self.main_ins else f'{seadir}{ins_i}/'
if ins != 'check':
os.makedirs(f'{insdir}/logger', exist_ok=True)
os.makedirs(f'{insdir}/log', exist_ok=True)
os.makedirs(f'{insdir}/status', exist_ok=True)
extraline = 'set connect_sea_to_sics 0\n'
for service in 'sea', 'graph':
port = self.info[ins_i][service]
if not port:
continue
sea_init = INIFILE_CONTENT.format(**locals()).strip()
extraline = ''
filename = f'{seadir}{service}_{ins_i}.tcl'
try:
with open(filename) as f:
content = f.read().strip()
except FileNotFoundError:
content = ''
if sea_init != content:
if ins == 'check':
if content:
print(filename, 'does not match')
else:
print(filename, 'does not exist')
else:
with open(filename, 'w') as f:
f.write(sea_init)
f.write('\n')
def do_cli(self, ins, service=None):
if self.wildcard(ins): if self.wildcard(ins):
raise UsageError('wildcards not allowed in sea cli') raise UsageError('wildcards not allowed in sea cli')
try: try:
@@ -130,8 +78,7 @@ class SeaManager(ServiceManager):
print(str(e)) print(str(e))
except KeyError: # running on an other machine? except KeyError: # running on an other machine?
self.do_help() self.do_help()
service = service or 'sea' run_command('six -sea %s' % ins, wait=True)
run_command(f'six -{service} {ins}', wait=True)
def do_gui(self, ins='', *args): def do_gui(self, ins='', *args):
if ins and self.wildcard(ins): if ins and self.wildcard(ins):
@@ -170,7 +117,7 @@ class SeaManager(ServiceManager):
seastatus = self.get_status_filename(ins) seastatus = self.get_status_filename(ins)
if seastatus: if seastatus:
boot_time = time.strftime("%Y-%m-%dT%H-%M-%S", time.localtime(psutil.boot_time())) boot_time = time.strftime("%Y-%m-%dT%H-%M-%S", time.localtime(psutil.boot_time()))
dst = seastatus.replace('.tcl', '') + '.before_boot_at' + boot_time dst = seastatus.replace('.tcl', '') + '.' + boot_time
if not exists(dst): if not exists(dst):
os.system(f'cp {seastatus} {dst}') os.system(f'cp {seastatus} {dst}')
return start_dir, env return start_dir, env
@@ -249,28 +196,8 @@ class SeaManager(ServiceManager):
argdict['ins'] = arg argdict['ins'] = arg
else: else:
raise UsageError('unknown argument: %s' % arg) raise UsageError('unknown argument: %s' % arg)
else:
print('env variable "InstrumentHostList" is not defined')
result = [argdict.pop('ins', '')] result = [argdict.pop('ins', '')]
service = argdict.pop('service', '') service = argdict.pop('service', '')
if service: if service:
result.append(service) result.append(service)
return result + extra return result + extra
def sea_recorder(self, ins, recorders):
self.do_start(ins, None, logger=False)
port = self.info[ins]['sea']
try:
conn = socket.create_connection(('localhost', port))
args = ' '.join(recorders.get(k, '0') for k in ('main', 'stick', 'addons'))
conn.send(f'seauser seaser\nconfig listen 1\nsea_recorder {args}\n'.encode())
conn.settimeout(2)
if args != '0 0 0':
prev = b''
while True:
lines = (prev + conn.recv(999)).split(b'\n')
prev = lines.pop()
if b'ACTIVE' in lines:
break
finally:
conn.close()

107
single.py
View File

@@ -1,107 +0,0 @@
# *****************************************************************************
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation; either version 2 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# Module authors:
# Markus Zolliker <markus.zolliker@psi.ch>
#
# *****************************************************************************
import os
from os.path import expanduser
from configparser import ConfigParser
from servicemanager.base import ServiceManager
class SingleManager(ServiceManager):
"""service to be started with systemd, only one per computer
running as systemd (user level)
"""
def systemd_service(self, service):
"""return the name of the systemd service"""
raise NotImplementedError
def treat_args(self, argdict, unknown=(), extra=()):
if not argdict.get('ins'):
argdict['ins'] = self.single_ins
return super().treat_args(argdict, unknown, extra)
def systemd_action(self, service, action):
service_ports = self.get_ins_info(self.single_ins)
services = list(service_ports) if service is None else [service]
for service in services:
print(f'systemctl --user {action} {self.systemd_service(service)}')
os.system(f'systemctl --user {action} {self.systemd_service(service)}')
def do_start(self, ins, service=None, cfg='', restart=False, wait=False, logger=None, opts=''):
if wait:
super().do_start(ins, service, cfg, False, True, logger, opts)
return
if restart:
action = 'restart'
else:
action = 'start'
os.system('loginctl enable-linger')
self.systemd_action(service, action)
self.systemd_action(service, 'enable')
def do_stop(self, ins, service=None, *args):
self.systemd_action(service, 'stop')
self.systemd_action(service, 'disable')
class FeederManager(SingleManager):
group = 'feeder'
services = ('central', 'local')
USAGE = """
Usage:
feeder start <instance> <service>
feeder restart <instance> <service>
feeder stop <instance> <service>
feeder list [<instance>]
%s
"""
def __init__(self):
parser = ConfigParser()
parser.read(expanduser('~/.config/sehistory'))
services = tuple(s for s in self.services if s in parser.sections())
self.services = services
super().__init__()
def systemd_service(self, service):
return f'{self.group}@{service}'
class SewebManager(SingleManager):
group = 'seweb'
services = ('',)
USAGE = """
Usage:
seweb start <instance>
seweb restart <instance>
seweb stop <instance>
seweb list [<instance>]
%s
"""
def systemd_service(self, service):
return f'{self.group}@{self.single_ins}'