134 lines
4.7 KiB
Python
134 lines
4.7 KiB
Python
import re
|
|
from pathlib import Path
|
|
from .base import MarcheControl, Logger, ArgError
|
|
|
|
|
|
WRAPPER_CFG = """interface = '{port}'
|
|
include({cfg!r})
|
|
overrideNode(interface=interface)
|
|
"""
|
|
WRAPPER_PAT = re.compile(r"interface\s=\s*'(\d*)'\s*\n")
|
|
|
|
|
|
class FrappyMarche(MarcheControl):
|
|
services = 'main', 'stick', 'addons'
|
|
|
|
def __init__(self, instance, host='localhost', port=None, user=None):
|
|
super().__init__(host, port, user, instance)
|
|
superconfig = self.config.sections['superfrappy']
|
|
self.instance = instance
|
|
|
|
self.wrapperdir = superconfig.pop('wrapperdir')
|
|
self.cfgdirs = superconfig.pop('cfgdirs')
|
|
frappy_ports = self.ins_config.get('frappy_ports')
|
|
ports = frappy_ports.split('-')
|
|
self.frappy_ports = list(range(int(ports[0]), int(ports[-1])))
|
|
self.frappy_servers = [f'{host}:{p}' for p in self.frappy_ports]
|
|
|
|
if not Path(self.wrapperdir).is_dir():
|
|
raise ValueError(f'{self.wrapperdir} does not exist')
|
|
self.get_cfg_info() # do we need to update this from time to time?
|
|
self.argmap.update((k, 'service') for k in self.services)
|
|
|
|
def get_service(self, instance):
|
|
return f'frappy.{instance}' if self.instance == 'this' else f'frappy.{self.instrument}-{instance}'
|
|
|
|
def wrapper_file(self, cfg):
|
|
return Path(self.wrapperdir) / f'{cfg}_cfg.py'
|
|
|
|
def cfg_file(self, cfgdirs, service, cfg):
|
|
if '/' in cfg:
|
|
return Path(cfg)
|
|
cfgpy = f'{cfg}_cfg.py'
|
|
tries = []
|
|
|
|
services = [service] if service else list(self.services)
|
|
services.append('')
|
|
|
|
for servicedir in services:
|
|
for cfgdir in cfgdirs.split(':'):
|
|
cfgfile = Path(cfgdir) / servicedir / cfgpy
|
|
tries.append(cfgfile)
|
|
if cfgfile.is_file():
|
|
return servicedir, cfgfile
|
|
else:
|
|
raise FileNotFoundError(f'can not find {cfgpy} in {tries}')
|
|
|
|
def get_std_port(self, service):
|
|
if service == 'main':
|
|
return self.frappy_ports[0]
|
|
if service == 'stick':
|
|
return self.frappy_ports[1]
|
|
return self.frappy_ports[2:]
|
|
|
|
def get_local_ports(self):
|
|
self.get_cfg_info()
|
|
run_state = self.status('frappy')
|
|
result = {}
|
|
for host_port, cfg in self.cfg_info.items():
|
|
host, port = host_port.split(':')
|
|
if host == 'localhost':
|
|
busy, on, _ = run_state.get(cfg, (0,0,0))
|
|
if on or busy:
|
|
result.setdefault(port, []).append((on, busy, cfg))
|
|
return {sorted(v)[-1][-1]: k for k, v in result.items()}
|
|
|
|
def get_port(self, service):
|
|
if service not in {'main', 'stick', 'addons', 'addon'}:
|
|
raise ArgError('illegal service argument')
|
|
ports = self.get_std_port(service)
|
|
if isinstance(ports, int):
|
|
return ports
|
|
self.get_cfg_info()
|
|
used_ports = self.get_local_ports()
|
|
for port in ports:
|
|
if port not in used_ports:
|
|
return port
|
|
raise ValueError('too many frappy servers')
|
|
|
|
def add_frappy_service(self, service, cfg, port, log=None):
|
|
if log is None:
|
|
log = Logger('info')
|
|
log.info('add %r port=%r', cfg, port)
|
|
service, cfgfile = self.cfg_file(self.cfgdirs, service, cfg)
|
|
if not port:
|
|
if not service:
|
|
raise ArgError('service is not given and can not be determined from cfg file location')
|
|
port = self.get_port(service)
|
|
wrapper_content = WRAPPER_CFG.format(cfg=str(cfgfile), port=port)
|
|
cfgname = cfgfile.stem.removesuffix('_cfg')
|
|
self.wrapper_file(cfgname).write_text(wrapper_content)
|
|
self.get_cfg_info()
|
|
log.info('wrapper %r %r', self.wrapper_file(cfgname), wrapper_content)
|
|
self.reload()
|
|
log.info('registered %r', cfgname)
|
|
|
|
def get_cfg_info(self):
|
|
"""get info from wrapper dir"""
|
|
result = {}
|
|
for cfgfile in Path(self.wrapperdir).glob('*_cfg.py'):
|
|
cfg = cfgfile.stem[:-4]
|
|
match = WRAPPER_PAT.match(cfgfile.read_text())
|
|
if match:
|
|
result[f'localhost:{match.group(1)}'] = cfg
|
|
self.cfg_info = result
|
|
|
|
def delete_frappy_service(self, cfg):
|
|
try:
|
|
self.wrapper_file(cfg).unlink()
|
|
self.reload()
|
|
except FileNotFoundError:
|
|
pass
|
|
|
|
def _run(self, action, service=None, other=None):
|
|
cfg= other
|
|
if action == 'start':
|
|
self.add_frappy_service(service, cfg, None)
|
|
self.start(cfg)
|
|
elif action == 'restart':
|
|
self.restart(cfg)
|
|
elif action == 'stop':
|
|
self.stop(cfg)
|
|
else:
|
|
raise ArgError(f'unknown action {action!r}')
|