rework guess_cfg to get_server_state
This commit is contained in:
parent
fc364f0fc6
commit
2d3394e205
181
frappyman.py
181
frappyman.py
@ -25,13 +25,17 @@ import os
|
|||||||
import re
|
import re
|
||||||
import builtins
|
import builtins
|
||||||
from glob import glob
|
from glob import glob
|
||||||
from collections import defaultdict
|
from itertools import zip_longest
|
||||||
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
|
||||||
from .base import ServiceManager, ServiceDown, UsageError
|
from .base import ServiceManager, ServiceDown, UsageError
|
||||||
from .seaman import SeaManager
|
from .seaman import SeaManager
|
||||||
|
|
||||||
|
|
||||||
|
MAIN = 1
|
||||||
|
STICK = 2
|
||||||
|
|
||||||
|
|
||||||
class Namespace(dict):
|
class Namespace(dict):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self['Node'] = self.node
|
self['Node'] = self.node
|
||||||
@ -58,6 +62,117 @@ class Namespace(dict):
|
|||||||
__builtins__ = builtins
|
__builtins__ = builtins
|
||||||
|
|
||||||
|
|
||||||
|
SEAEXT = {'main': '.config', 'stick': '.stick'}
|
||||||
|
|
||||||
|
|
||||||
|
def summarize_server_state(givencfgs, ourcfgs, sealist, sea_info, strict=False):
|
||||||
|
"""get a guess for the configuration from information about running services
|
||||||
|
|
||||||
|
:param givencfgs: dict <service> of given configuration (from nicos cache)
|
||||||
|
:param outcfgs: dict <service> of running configuration (frappy)
|
||||||
|
:param sealist: list of running sea configuration
|
||||||
|
:param sea_info: dict <frappycfg> of <seacfg> with info about sea configs
|
||||||
|
:param strict: when True return empty cfg result on error
|
||||||
|
:return: tuple (<error>, <proposed>, (<frappyitems>, <seaitems>), <remarks> where:
|
||||||
|
<error>: proposed config not sure
|
||||||
|
<proposed>: dict <service> of proposed cfg
|
||||||
|
<frappyitems>: dict of items runnning in frappy servers (addons are separated)
|
||||||
|
<seaitems>: dict of items running on the sea server
|
||||||
|
<remarks>: dict of actions / remarks
|
||||||
|
"""
|
||||||
|
givencfgs = dict(givencfgs)
|
||||||
|
addons = givencfgs.pop('addons', '')
|
||||||
|
for addon in addons.split(','):
|
||||||
|
addon = addon.strip()
|
||||||
|
if addon:
|
||||||
|
givencfgs[addon] = addon
|
||||||
|
frappycfgs = dict(ourcfgs)
|
||||||
|
addons = frappycfgs.pop('addons', '')
|
||||||
|
for addon in addons.split(','):
|
||||||
|
addon = addon.strip()
|
||||||
|
if addon:
|
||||||
|
frappycfgs[addon] = addon
|
||||||
|
|
||||||
|
seacfgfiles = [(c or '') + SEAEXT.get(s, '.addon')
|
||||||
|
for c, s in zip_longest(sealist, FrappyManager.services)]
|
||||||
|
seacfgset = set(seacfgfiles)
|
||||||
|
inverted_sea_info = {k: [] for k in seacfgfiles}
|
||||||
|
for cfg, seacfg in sea_info.items():
|
||||||
|
if seacfg in seacfgset:
|
||||||
|
inverted_sea_info[seacfg].append(cfg)
|
||||||
|
error = False
|
||||||
|
result = {}
|
||||||
|
addons = set()
|
||||||
|
seacfgs = {}
|
||||||
|
remarks = {}
|
||||||
|
for seacfg, seacfgfile, key in zip_longest(sealist, seacfgfiles, ('main', 'stick')):
|
||||||
|
if not seacfg:
|
||||||
|
continue
|
||||||
|
available = inverted_sea_info[seacfgfile]
|
||||||
|
if available:
|
||||||
|
proposed = available[0] if len(available) == 1 else None
|
||||||
|
if not proposed:
|
||||||
|
running = None
|
||||||
|
for item in available:
|
||||||
|
if item == givencfgs.get(key or item):
|
||||||
|
proposed = item
|
||||||
|
if item == frappycfgs.get(key or item):
|
||||||
|
running = item
|
||||||
|
if running and not proposed:
|
||||||
|
proposed = running
|
||||||
|
if proposed:
|
||||||
|
pkey = key or proposed
|
||||||
|
given = givencfgs.get(pkey)
|
||||||
|
running = frappycfgs.get(pkey)
|
||||||
|
if running == proposed:
|
||||||
|
remarks[pkey] = '' if given == running else 'reconnect'
|
||||||
|
elif running:
|
||||||
|
remarks[pkey] = 'frappy restart needed'
|
||||||
|
else:
|
||||||
|
remarks[pkey] = 'frappy start needed'
|
||||||
|
|
||||||
|
seacfgs[pkey] = seacfg
|
||||||
|
if key:
|
||||||
|
result[key] = proposed
|
||||||
|
else:
|
||||||
|
addons.add(proposed)
|
||||||
|
else:
|
||||||
|
for item in available:
|
||||||
|
remarks[item] = 'ambiguous'
|
||||||
|
seacfgs[item] = seacfg
|
||||||
|
error = True
|
||||||
|
else:
|
||||||
|
pkey = key or seacfg
|
||||||
|
seacfgs[pkey] = seacfg
|
||||||
|
remarks[pkey] = 'missing frappy config'
|
||||||
|
error = True
|
||||||
|
restart = set()
|
||||||
|
for key, running in frappycfgs.items():
|
||||||
|
if running:
|
||||||
|
if key in ('main', 'stick'):
|
||||||
|
service = key
|
||||||
|
else:
|
||||||
|
service = 'addons'
|
||||||
|
addons.add(running)
|
||||||
|
if not seacfgs.get(key):
|
||||||
|
if sea_info.get(running):
|
||||||
|
restart.add(service)
|
||||||
|
remarks[key] = 'restart to start sea'
|
||||||
|
elif givencfgs.get(key) != running:
|
||||||
|
remarks[key] = 'reconnect'
|
||||||
|
elif remarks.get(key) is None:
|
||||||
|
remarks[key] = ''
|
||||||
|
if addons:
|
||||||
|
result['addons'] = ','.join(addons)
|
||||||
|
|
||||||
|
for service, cfg in ourcfgs.items():
|
||||||
|
if cfg:
|
||||||
|
prop = result.get(service, '')
|
||||||
|
if prop == cfg and service not in restart:
|
||||||
|
result[service] = True
|
||||||
|
return error, result, (frappycfgs, seacfgs), remarks
|
||||||
|
|
||||||
|
|
||||||
class FrappyManager(ServiceManager):
|
class FrappyManager(ServiceManager):
|
||||||
group = 'frappy'
|
group = 'frappy'
|
||||||
services = ('main', 'stick', 'addons')
|
services = ('main', 'stick', 'addons')
|
||||||
@ -203,7 +318,8 @@ class FrappyManager(ServiceManager):
|
|||||||
:param service: service nor None for all services
|
:param service: service nor None for all services
|
||||||
:param list_info: None or a dict to collect info in the form
|
:param list_info: None or a dict to collect info in the form
|
||||||
dict <cfgdir> of <cfg> of <description>
|
dict <cfgdir> of <cfg> of <description>
|
||||||
:param sea_info: None or a dict <sea config> of set() to be populated
|
:param sea_info: None or a dict <frappycfg> of <seacfg> with info about sea configs
|
||||||
|
in frappy cfgs to be populated
|
||||||
:return: set of available config
|
:return: set of available config
|
||||||
"""
|
"""
|
||||||
all_cfg = set()
|
all_cfg = set()
|
||||||
@ -224,6 +340,7 @@ class FrappyManager(ServiceManager):
|
|||||||
if cfg not in all_cfg:
|
if cfg not in all_cfg:
|
||||||
if sea_cfg and sea_info is not None:
|
if sea_cfg and sea_info is not None:
|
||||||
sea_info.setdefault(sea_cfg, set()).add(cfg)
|
sea_info.setdefault(sea_cfg, set()).add(cfg)
|
||||||
|
sea_info[cfg] = sea_cfg
|
||||||
all_cfg.add(cfg)
|
all_cfg.add(cfg)
|
||||||
if list_info is not None:
|
if list_info is not None:
|
||||||
list_info.setdefault(cfgdir, {})[cfg] = desc.split('\n', 1)[0]
|
list_info.setdefault(cfgdir, {})[cfg] = desc.split('\n', 1)[0]
|
||||||
@ -239,11 +356,10 @@ class FrappyManager(ServiceManager):
|
|||||||
else:
|
else:
|
||||||
for service in self.services:
|
for service in self.services:
|
||||||
self.all_cfg(ins, service, list_info, sea_info)
|
self.all_cfg(ins, service, list_info, sea_info)
|
||||||
sea_ambig = {} # collect info about ambiguous sea info
|
|
||||||
seacfgpat = re.compile(r'(.*)(\.config|\.stick|\.addon)')
|
seacfgpat = re.compile(r'(.*)(\.config|\.stick|\.addon)')
|
||||||
for seacfg, cfgset in sea_info.items():
|
sea_ambig = {} # collect info about ambiguous sea info
|
||||||
name, ext = seacfgpat.match(seacfg).groups()
|
for cfg, seacfg in sea_info.items():
|
||||||
sea_ambig.update({k: (name, ext, len(cfgset)) for k in cfgset})
|
sea_ambig.setdefault(seacfg, set()).add(cfg)
|
||||||
ambiguous = 0
|
ambiguous = 0
|
||||||
keylen = max(max(len(k) for k in cfgs) for cfgs in list_info.values())
|
keylen = max(max(len(k) for k in cfgs) for cfgs in list_info.values())
|
||||||
for cfgdir, cfgs in list_info.items():
|
for cfgdir, cfgs in list_info.items():
|
||||||
@ -251,12 +367,14 @@ class FrappyManager(ServiceManager):
|
|||||||
prt('')
|
prt('')
|
||||||
prt('--- %s:' % cfgdir)
|
prt('--- %s:' % cfgdir)
|
||||||
for cfg, desc in cfgs.items():
|
for cfg, desc in cfgs.items():
|
||||||
if cfg in sea_ambig:
|
seacfg = sea_info.get(cfg)
|
||||||
name, ext, n = sea_ambig[cfg]
|
if seacfg:
|
||||||
|
name, ext = seacfgpat.match(seacfg).groups()
|
||||||
if name == cfg or name + 'stick' == cfg:
|
if name == cfg or name + 'stick' == cfg:
|
||||||
prefix = '* '
|
prefix = '* '
|
||||||
else:
|
else:
|
||||||
prefix = f'* ({name}{ext}) '
|
prefix = f'* ({name}{ext}) '
|
||||||
|
n = len(sea_ambig.get(seacfg))
|
||||||
if n > 1:
|
if n > 1:
|
||||||
prefix = '!' + prefix[1:]
|
prefix = '!' + prefix[1:]
|
||||||
ambiguous += 1
|
ambiguous += 1
|
||||||
@ -290,40 +408,25 @@ class FrappyManager(ServiceManager):
|
|||||||
except Exception:
|
except Exception:
|
||||||
return cfg + '?'
|
return cfg + '?'
|
||||||
|
|
||||||
def guess_cfgs(self, ins, cfgs):
|
def get_server_state(self, ins, givencfgs):
|
||||||
|
"""get proposed configuration and an overview of the running servers
|
||||||
|
|
||||||
|
:param ins: the instance to be checked for
|
||||||
|
:param givencfgs: a dict <service> of cfg given by the ECS
|
||||||
|
|
||||||
|
:return: tuple (<error>, <proposed>, (<frappyitems>, <seaitems>), <remarks> where:
|
||||||
|
<error>: proposed config not sure
|
||||||
|
<proposed>: dict <service> of proposed cfg
|
||||||
|
<frappyitems>: dict of items runnning in frappy servers (addons are separated)
|
||||||
|
<seaitems>: dict of items running on the sea server
|
||||||
|
<remarks>: dict of actions to do / remarks
|
||||||
|
"""
|
||||||
|
ourcfgs = self.get_cfg(ins, None)
|
||||||
sea = SeaManager()
|
sea = SeaManager()
|
||||||
seacfgs = sea.get_cfg(ins, 'sea').split('/')
|
seacfgs = sea.get_cfg(ins, 'sea').split('/')
|
||||||
sea_info = {}
|
|
||||||
if len(seacfgs) < 2:
|
if len(seacfgs) < 2:
|
||||||
seacfgs.append('')
|
seacfgs.append('')
|
||||||
|
sea_info = {}
|
||||||
self.all_cfg(ins, None, sea_info=sea_info)
|
self.all_cfg(ins, None, sea_info=sea_info)
|
||||||
|
return summarize_server_state(givencfgs, ourcfgs, seacfgs, sea_info)
|
||||||
|
|
||||||
guess = defaultdict(lambda: defaultdict(list))
|
|
||||||
|
|
||||||
def check_cfg(service, ext, frappyset, seacfgs):
|
|
||||||
for seacfg in seacfgs:
|
|
||||||
available = sea_info.get(seacfg + ext, ())
|
|
||||||
if available:
|
|
||||||
for a in available:
|
|
||||||
if a in frappyset:
|
|
||||||
guess[service]['ok'].append(a)
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
if len(available) == 1:
|
|
||||||
available = next(iter(available))
|
|
||||||
# available is either a string or a set of strings
|
|
||||||
guess[service]['proposed'].append(available)
|
|
||||||
else:
|
|
||||||
guess[service]['missing'].append(seacfg)
|
|
||||||
|
|
||||||
main = cfgs.get('main')
|
|
||||||
check_cfg('main', '.config', set() if main is None else {main}, {seacfgs[0]})
|
|
||||||
|
|
||||||
if len(seacfgs) > 1:
|
|
||||||
stick = cfgs.get('stick')
|
|
||||||
check_cfg('stick', '.stick', set() if stick is None else {stick}, {seacfgs[1]})
|
|
||||||
|
|
||||||
if len(seacfgs) > 2:
|
|
||||||
addons = set(cfgs.get('addons').split(','))
|
|
||||||
check_cfg('addons', '.addons', set(addons), set(seacfgs[2:]))
|
|
||||||
return guess
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user