better systemd service support
This commit is contained in:
parent
20f329d433
commit
9c1589ca53
45 changed files with 496 additions and 120 deletions
|
@ -28,15 +28,13 @@ from os.path import basename
|
||||||
from typing import Tuple
|
from typing import Tuple
|
||||||
|
|
||||||
from rougail.i18n import _
|
from rougail.i18n import _
|
||||||
from rougail.utils import normalize_family
|
from rougail.utils import normalize_family, valid_variable_family_name
|
||||||
from rougail.error import DictConsistencyError
|
from rougail.error import DictConsistencyError
|
||||||
# a object's attribute has some annotations
|
# a object's attribute has some annotations
|
||||||
# that shall not be present in the exported (flatened) XML
|
# that shall not be present in the exported (flatened) XML
|
||||||
ERASED_ATTRIBUTES = ('redefine', 'exists', 'optional', 'remove_check', 'namespace',
|
ERASED_ATTRIBUTES = ('redefine', 'namespace', 'xmlfiles', 'disabled', 'name', 'manage')
|
||||||
'remove_condition', 'path', 'instance_mode', 'index',
|
ERASED_ATTRIBUTES2 = ('redefine', 'namespace', 'xmlfiles')
|
||||||
'level', 'remove_fill', 'xmlfiles', 'type', 'reflector_name',
|
ALLOW_ATTRIBUT_NOT_MANAGE = ['file', 'engine', 'target']
|
||||||
'reflector_object',)
|
|
||||||
ALLOW_ATTRIBUT_NOT_MANAGE = ['file']
|
|
||||||
|
|
||||||
|
|
||||||
class Annotator:
|
class Annotator:
|
||||||
|
@ -72,6 +70,7 @@ class Annotator:
|
||||||
self.objectspace.space.services.doc = 'services'
|
self.objectspace.space.services.doc = 'services'
|
||||||
self.objectspace.space.services.path = 'services'
|
self.objectspace.space.services.path = 'services'
|
||||||
for service_name, service in self.objectspace.space.services.service.items():
|
for service_name, service in self.objectspace.space.services.service.items():
|
||||||
|
valid_variable_family_name(service_name, service.xmlfiles)
|
||||||
activate_obj = self._generate_element('boolean',
|
activate_obj = self._generate_element('boolean',
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
|
@ -88,11 +87,12 @@ class Annotator:
|
||||||
values,
|
values,
|
||||||
[]).append(activate_obj)
|
[]).append(activate_obj)
|
||||||
continue
|
continue
|
||||||
if not isinstance(values, (dict, list)) or elttype in ERASED_ATTRIBUTES:
|
if elttype in ERASED_ATTRIBUTES:
|
||||||
continue
|
continue
|
||||||
if not service.manage and elttype not in ALLOW_ATTRIBUT_NOT_MANAGE:
|
if not service.manage and elttype not in ALLOW_ATTRIBUT_NOT_MANAGE:
|
||||||
msg = _(f'unmanage service cannot have "{elttype}"')
|
msg = _(f'unmanage service cannot have "{elttype}"')
|
||||||
raise DictConsistencyError(msg, 66, service.xmlfiles)
|
raise DictConsistencyError(msg, 66, service.xmlfiles)
|
||||||
|
if isinstance(values, (dict, list)):
|
||||||
if elttype != 'ip':
|
if elttype != 'ip':
|
||||||
eltname = elttype + 's'
|
eltname = elttype + 's'
|
||||||
else:
|
else:
|
||||||
|
@ -111,6 +111,10 @@ class Annotator:
|
||||||
path,
|
path,
|
||||||
)
|
)
|
||||||
setattr(service, elttype, family)
|
setattr(service, elttype, family)
|
||||||
|
else:
|
||||||
|
if not hasattr(service, 'information'):
|
||||||
|
service.information = self.objectspace.information(service.xmlfiles)
|
||||||
|
setattr(service.information, elttype, values)
|
||||||
manage = self._generate_element('boolean',
|
manage = self._generate_element('boolean',
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
|
@ -157,7 +161,7 @@ class Annotator:
|
||||||
'.'.join([subpath, 'activate']),
|
'.'.join([subpath, 'activate']),
|
||||||
)
|
)
|
||||||
for key in dir(elt):
|
for key in dir(elt):
|
||||||
if key.startswith('_') or key.endswith('_type') or key in ERASED_ATTRIBUTES:
|
if key.startswith('_') or key.endswith('_type') or key in ERASED_ATTRIBUTES2:
|
||||||
continue
|
continue
|
||||||
value = getattr(elt, key)
|
value = getattr(elt, key)
|
||||||
if key == listname:
|
if key == listname:
|
||||||
|
|
|
@ -51,6 +51,9 @@
|
||||||
<!ATTLIST service manage (True|False) "True">
|
<!ATTLIST service manage (True|False) "True">
|
||||||
<!ATTLIST service servicelist CDATA #IMPLIED>
|
<!ATTLIST service servicelist CDATA #IMPLIED>
|
||||||
<!ATTLIST service disabled (True|False) "False">
|
<!ATTLIST service disabled (True|False) "False">
|
||||||
|
<!ATTLIST service engine (none|creole|jinja2) #IMPLIED>
|
||||||
|
<!ATTLIST service target CDATA #IMPLIED>
|
||||||
|
<!ATTLIST service type (service|mount) "service">
|
||||||
|
|
||||||
<!ELEMENT ip (#PCDATA)>
|
<!ELEMENT ip (#PCDATA)>
|
||||||
<!ATTLIST ip iplist CDATA #IMPLIED>
|
<!ATTLIST ip iplist CDATA #IMPLIED>
|
||||||
|
|
|
@ -255,6 +255,7 @@ class RougailBaseTemplate:
|
||||||
filevar: Dict,
|
filevar: Dict,
|
||||||
type_: str,
|
type_: str,
|
||||||
service_name: str,
|
service_name: str,
|
||||||
|
service_type: str,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Run templatisation on one file
|
"""Run templatisation on one file
|
||||||
"""
|
"""
|
||||||
|
@ -275,10 +276,11 @@ class RougailBaseTemplate:
|
||||||
var = variable[idx]
|
var = variable[idx]
|
||||||
else:
|
else:
|
||||||
var = None
|
var = None
|
||||||
func = f'_instance_{type_}'
|
func = f'get_data_{type_}'
|
||||||
data = getattr(self, func)(filevar,
|
data = getattr(self, func)(filevar,
|
||||||
filename,
|
filename,
|
||||||
service_name,
|
service_name,
|
||||||
|
service_type,
|
||||||
variable,
|
variable,
|
||||||
idx,
|
idx,
|
||||||
)
|
)
|
||||||
|
@ -319,10 +321,26 @@ class RougailBaseTemplate:
|
||||||
for included in (True, False):
|
for included in (True, False):
|
||||||
for service_obj in await self.config.option('services').list('all'):
|
for service_obj in await self.config.option('services').list('all'):
|
||||||
service_name = await service_obj.option.name()
|
service_name = await service_obj.option.name()
|
||||||
|
service_type = await service_obj.information.get('type', 'service')
|
||||||
if await service_obj.option('activate').value.get() is False:
|
if await service_obj.option('activate').value.get() is False:
|
||||||
if included is False:
|
if included is False:
|
||||||
self.desactive_service(service_name)
|
self.desactive_service(service_name, service_type)
|
||||||
continue
|
continue
|
||||||
|
if not included:
|
||||||
|
engine = await service_obj.information.get('engine', None)
|
||||||
|
if engine:
|
||||||
|
self.instance_file({'engine': engine},
|
||||||
|
'service',
|
||||||
|
service_name,
|
||||||
|
service_type,
|
||||||
|
)
|
||||||
|
target_name = await service_obj.information.get('target', None)
|
||||||
|
if target_name:
|
||||||
|
self.target_service(service_name,
|
||||||
|
target_name,
|
||||||
|
service_type,
|
||||||
|
engine is None,
|
||||||
|
)
|
||||||
for fills in await service_obj.list('optiondescription'):
|
for fills in await service_obj.list('optiondescription'):
|
||||||
type_ = await fills.option.name()
|
type_ = await fills.option.name()
|
||||||
for fill_obj in await fills.list('all'):
|
for fill_obj in await fills.list('all'):
|
||||||
|
@ -335,10 +353,14 @@ class RougailBaseTemplate:
|
||||||
elif included is True:
|
elif included is True:
|
||||||
continue
|
continue
|
||||||
if fill['activate']:
|
if fill['activate']:
|
||||||
self.instance_file(fill, type_, service_name)
|
self.instance_file(fill,
|
||||||
|
type_,
|
||||||
|
service_name,
|
||||||
|
service_type,
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
self.log.debug(_("Instantiation of file '{filename}' disabled"))
|
self.log.debug(_("Instantiation of file '{filename}' disabled"))
|
||||||
self.post_instance_service(service_name)
|
self.post_instance_service(service_name, service_type)
|
||||||
self.post_instance()
|
self.post_instance()
|
||||||
chdir(ori_dir)
|
chdir(ori_dir)
|
||||||
|
|
||||||
|
@ -356,27 +378,40 @@ class RougailBaseTemplate:
|
||||||
dico[key] = await obj.information.get(key, default_value)
|
dico[key] = await obj.information.get(key, default_value)
|
||||||
|
|
||||||
def desactive_service(self,
|
def desactive_service(self,
|
||||||
service_name: str,
|
*args,
|
||||||
):
|
):
|
||||||
raise NotImplementedError(_('cannot desactivate a service'))
|
raise NotImplementedError(_('cannot desactivate a service'))
|
||||||
|
|
||||||
def post_instance_service(self, service_name): # pragma: no cover
|
def target_service(self,
|
||||||
|
service_name: str,
|
||||||
|
*args,
|
||||||
|
):
|
||||||
|
raise NotImplementedError(_('cannot use target for the service {service_name}'))
|
||||||
|
|
||||||
|
def post_instance_service(self,
|
||||||
|
*args,
|
||||||
|
): # pragma: no cover
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def post_instance(self): # pragma: no cover
|
def post_instance(self): # pragma: no cover
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def _instance_ip(self,
|
def get_data_ip(self,
|
||||||
*args,
|
*args,
|
||||||
) -> None: # pragma: no cover
|
) -> None: # pragma: no cover
|
||||||
raise NotImplementedError(_('cannot instanciate this service type ip'))
|
raise NotImplementedError(_('cannot instanciate this service type ip'))
|
||||||
|
|
||||||
def _instance_files(self,
|
def get_data_files(self,
|
||||||
*args,
|
*args,
|
||||||
) -> None: # pragma: no cover
|
) -> None: # pragma: no cover
|
||||||
raise NotImplementedError(_('cannot instanciate this service type file'))
|
raise NotImplementedError(_('cannot instanciate this service type file'))
|
||||||
|
|
||||||
def _instance_overrides(self,
|
def get_data_service(self,
|
||||||
|
*args,
|
||||||
|
) -> None: # pragma: no cover
|
||||||
|
raise NotImplementedError(_('cannot instanciate this service'))
|
||||||
|
|
||||||
|
def get_data_overrides(self,
|
||||||
*args,
|
*args,
|
||||||
) -> None: # pragma: no cover
|
) -> None: # pragma: no cover
|
||||||
raise NotImplementedError(_('cannot instanciate this service type override'))
|
raise NotImplementedError(_('cannot instanciate this service type override'))
|
||||||
|
|
|
@ -38,9 +38,13 @@ IPAddressDeny=any
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
ROUGAIL_TMPL_TEMPLATE = """%def display(%%file, %%filename)
|
ROUGAIL_DEST = '/usr/local/lib'
|
||||||
|
ROUGAIL_GLOBAL_SYSTEMD_FILE = '/usr/lib/systemd/system'
|
||||||
|
|
||||||
|
|
||||||
|
ROUGAIL_TMPL_TEMPLATE = f"""%def display(%%file, %%filename)
|
||||||
%if %%filename.startswith('/etc/') or %%filename.startswith('/var/') or %%filename.startswith('/srv/')
|
%if %%filename.startswith('/etc/') or %%filename.startswith('/var/') or %%filename.startswith('/srv/')
|
||||||
C %%filename %%file.mode %%file.owner %%file.group - /usr/local/lib%%filename
|
C %%filename %%file.mode %%file.owner %%file.group - {ROUGAIL_DEST}%%filename
|
||||||
z %%filename - - - - -
|
z %%filename - - - - -
|
||||||
%end if
|
%end if
|
||||||
%end def
|
%end def
|
||||||
|
@ -70,10 +74,11 @@ class RougailSystemdTemplate(RougailBaseTemplate):
|
||||||
self.ip_per_service = None
|
self.ip_per_service = None
|
||||||
super().__init__(config, rougailconfig)
|
super().__init__(config, rougailconfig)
|
||||||
|
|
||||||
def _instance_files(self,
|
def get_data_files(self,
|
||||||
filevar: Dict,
|
filevar: Dict,
|
||||||
destfile: str,
|
destfile: str,
|
||||||
service_name: str,
|
service_name: str,
|
||||||
|
service_type: str,
|
||||||
variable,
|
variable,
|
||||||
idx: int,
|
idx: int,
|
||||||
) -> tuple:
|
) -> tuple:
|
||||||
|
@ -88,10 +93,11 @@ class RougailSystemdTemplate(RougailBaseTemplate):
|
||||||
var = None
|
var = None
|
||||||
return tmp_file, None, destfile, var
|
return tmp_file, None, destfile, var
|
||||||
|
|
||||||
def _instance_overrides(self,
|
def get_data_overrides(self,
|
||||||
filevar: Dict,
|
filevar: Dict,
|
||||||
destfile,
|
destfile,
|
||||||
service_name: str,
|
service_name: str,
|
||||||
|
service_type: str,
|
||||||
*args,
|
*args,
|
||||||
) -> tuple:
|
) -> tuple:
|
||||||
source = filevar['source']
|
source = filevar['source']
|
||||||
|
@ -99,12 +105,14 @@ class RougailSystemdTemplate(RougailBaseTemplate):
|
||||||
raise FileNotFound(_(f"File {source} does not exist."))
|
raise FileNotFound(_(f"File {source} does not exist."))
|
||||||
tmp_file = join(self.tmp_dir, source)
|
tmp_file = join(self.tmp_dir, source)
|
||||||
service_name = filevar['name']
|
service_name = filevar['name']
|
||||||
return tmp_file, None, f'/systemd/system/{service_name}.service.d/rougail.conf', None
|
destfile = f'/systemd/system/{service_name}.{service_type}.d/rougail.conf'
|
||||||
|
return tmp_file, None, destfile, None
|
||||||
|
|
||||||
def _instance_ip(self,
|
def get_data_ip(self,
|
||||||
filevar: Dict,
|
filevar: Dict,
|
||||||
ip,
|
ip,
|
||||||
service_name: str,
|
service_name: str,
|
||||||
|
service_type: str,
|
||||||
var: Any,
|
var: Any,
|
||||||
idx: int,
|
idx: int,
|
||||||
*args,
|
*args,
|
||||||
|
@ -120,19 +128,49 @@ class RougailSystemdTemplate(RougailBaseTemplate):
|
||||||
elif ip:
|
elif ip:
|
||||||
self.ip_per_service.append(ip)
|
self.ip_per_service.append(ip)
|
||||||
|
|
||||||
|
def get_data_service(self,
|
||||||
|
servicevar: Dict,
|
||||||
|
info,
|
||||||
|
service_name: str,
|
||||||
|
service_type: str,
|
||||||
|
*args,
|
||||||
|
):
|
||||||
|
filename = f'{service_name}.{service_type}'
|
||||||
|
tmp_file = join(self.tmp_dir, filename)
|
||||||
|
var = None
|
||||||
|
destfile = f'/systemd/system/{filename}'
|
||||||
|
return tmp_file, None, destfile, var
|
||||||
|
|
||||||
|
|
||||||
def desactive_service(self,
|
def desactive_service(self,
|
||||||
service_name: str,
|
service_name: str,
|
||||||
|
service_type: str,
|
||||||
):
|
):
|
||||||
filename = f'{self.destinations_dir}/systemd/system/{service_name}.service'
|
filename = f'{self.destinations_dir}/systemd/system/{service_name}.{service_type}'
|
||||||
makedirs(dirname(filename), exist_ok=True)
|
makedirs(dirname(filename), exist_ok=True)
|
||||||
symlink('/dev/null', filename)
|
symlink('/dev/null', filename)
|
||||||
|
|
||||||
|
def target_service(self,
|
||||||
|
service_name: str,
|
||||||
|
target_name: str,
|
||||||
|
service_type: str,
|
||||||
|
global_service: str,
|
||||||
|
):
|
||||||
|
filename = f'{self.destinations_dir}/systemd/system/{target_name}.target.wants/{service_name}.{service_type}'
|
||||||
|
makedirs(dirname(filename), exist_ok=True)
|
||||||
|
if global_service:
|
||||||
|
source_filename = f'{ROUGAIL_GLOBAL_SYSTEMD_FILE}/{service_name}.{service_type}'
|
||||||
|
else:
|
||||||
|
source_filename = f'{ROUGAIL_DEST}/systemd/system/{service_name}.{service_type}'
|
||||||
|
symlink(source_filename, filename)
|
||||||
|
|
||||||
def post_instance_service(self,
|
def post_instance_service(self,
|
||||||
service_name: str,
|
service_name: str,
|
||||||
|
service_type: str,
|
||||||
) -> None: # pragma: no cover
|
) -> None: # pragma: no cover
|
||||||
if self.ip_per_service is None:
|
if self.ip_per_service is None:
|
||||||
return
|
return
|
||||||
destfile = f'/systemd/system/{service_name}.service.d/rougail_ip.conf'
|
destfile = f'/systemd/system/{service_name}.{service_type}.d/rougail_ip.conf'
|
||||||
destfilename = join(self.destinations_dir, destfile[1:])
|
destfilename = join(self.destinations_dir, destfile[1:])
|
||||||
makedirs(dirname(destfilename), exist_ok=True)
|
makedirs(dirname(destfilename), exist_ok=True)
|
||||||
self.log.info(_(f"creole processing: '{destfilename}'"))
|
self.log.info(_(f"creole processing: '{destfilename}'"))
|
||||||
|
|
|
@ -144,6 +144,63 @@ class RougailUpgrade:
|
||||||
value.text = choices[0]
|
value.text = choices[0]
|
||||||
variable.attrib['mandatory'] = 'True'
|
variable.attrib['mandatory'] = 'True'
|
||||||
|
|
||||||
|
# convert group to leadership
|
||||||
|
groups = []
|
||||||
|
if constraints is not None:
|
||||||
|
for constraint in constraints:
|
||||||
|
if constraint.tag == 'group':
|
||||||
|
constraints.remove(constraint)
|
||||||
|
groups.append(constraint)
|
||||||
|
for group in groups:
|
||||||
|
if group.attrib['leader'] in paths:
|
||||||
|
leader_obj = paths[group.attrib['leader']]
|
||||||
|
#FIXME name peut avoir "." il faut le virer
|
||||||
|
#FIXME si extra c'est un follower !
|
||||||
|
if 'name' in group.attrib:
|
||||||
|
grpname = group.attrib['name']
|
||||||
|
if 'description' in group.attrib:
|
||||||
|
description = group.attrib['description']
|
||||||
|
else:
|
||||||
|
description = grpname
|
||||||
|
else:
|
||||||
|
grpname = leader_obj['variable'].attrib['name']
|
||||||
|
if '.' in grpname:
|
||||||
|
grpname = grpname.rsplit('.', 1)[-1]
|
||||||
|
if 'description' in group.attrib:
|
||||||
|
description = group.attrib['description']
|
||||||
|
elif 'description' in leader_obj['variable'].attrib:
|
||||||
|
description = leader_obj['variable'].attrib['description']
|
||||||
|
else:
|
||||||
|
description = grpname
|
||||||
|
family = SubElement(leader_obj['parent'], 'family', name=grpname, description=description, leadership="True")
|
||||||
|
leader_obj['parent'].remove(leader_obj['variable'])
|
||||||
|
family.append(leader_obj['variable'])
|
||||||
|
else:
|
||||||
|
# append in group
|
||||||
|
follower = next(iter(group))
|
||||||
|
leader_name = group.attrib['leader']
|
||||||
|
if '.' in leader_name:
|
||||||
|
leader_path = leader_name.rsplit('.', 1)[0]
|
||||||
|
follower_path = leader_path + '.' + follower.text
|
||||||
|
else:
|
||||||
|
follower_path = follower.text
|
||||||
|
obj = paths[follower_path]
|
||||||
|
family = SubElement(obj['parent'], 'family', name=leader_name, leadership="True")
|
||||||
|
grpname = leader_name
|
||||||
|
for follower in group:
|
||||||
|
leader_name = group.attrib['leader']
|
||||||
|
if '.' in leader_name:
|
||||||
|
leader_path = leader_name.rsplit('.', 1)[0]
|
||||||
|
follower_path = leader_path + '.' + follower.text
|
||||||
|
else:
|
||||||
|
follower_path = follower.text
|
||||||
|
follower_obj = paths[follower_path]
|
||||||
|
follower_obj['parent'].remove(follower_obj['variable'])
|
||||||
|
family.append(follower_obj['variable'])
|
||||||
|
if '.' in follower_path:
|
||||||
|
new_path = follower_path.rsplit('.', 1)[0] + '.' + grpname + '.' + follower_path.rsplit('.', 1)[1]
|
||||||
|
paths[new_path] = paths[follower_path]
|
||||||
|
|
||||||
# convert choice option
|
# convert choice option
|
||||||
valid_enums = []
|
valid_enums = []
|
||||||
if constraints is not None:
|
if constraints is not None:
|
||||||
|
@ -207,58 +264,6 @@ class RougailUpgrade:
|
||||||
for target in targets:
|
for target in targets:
|
||||||
if 'remove_choice' not in target.attrib or target.attrib['remove_choice'] != 'True':
|
if 'remove_choice' not in target.attrib or target.attrib['remove_choice'] != 'True':
|
||||||
target.attrib['type'] = 'choice'
|
target.attrib['type'] = 'choice'
|
||||||
# convert group to leadership
|
|
||||||
groups = []
|
|
||||||
if constraints is not None:
|
|
||||||
for constraint in constraints:
|
|
||||||
if constraint.tag == 'group':
|
|
||||||
constraints.remove(constraint)
|
|
||||||
groups.append(constraint)
|
|
||||||
for group in groups:
|
|
||||||
if group.attrib['leader'] in paths:
|
|
||||||
leader_obj = paths[group.attrib['leader']]
|
|
||||||
#FIXME name peut avoir "." il faut le virer
|
|
||||||
#FIXME si extra c'est un follower !
|
|
||||||
if 'name' in group.attrib:
|
|
||||||
name = group.attrib['name']
|
|
||||||
if 'description' in group.attrib:
|
|
||||||
description = group.attrib['description']
|
|
||||||
else:
|
|
||||||
description = name
|
|
||||||
else:
|
|
||||||
name = leader_obj['variable'].attrib['name']
|
|
||||||
if '.' in name:
|
|
||||||
name = name.rsplit('.', 1)[-1]
|
|
||||||
if 'description' in group.attrib:
|
|
||||||
description = group.attrib['description']
|
|
||||||
elif 'description' in leader_obj['variable'].attrib:
|
|
||||||
description = leader_obj['variable'].attrib['description']
|
|
||||||
else:
|
|
||||||
description = name
|
|
||||||
family = SubElement(leader_obj['parent'], 'family', name=name, description=description, leadership="True")
|
|
||||||
leader_obj['parent'].remove(leader_obj['variable'])
|
|
||||||
family.append(leader_obj['variable'])
|
|
||||||
else:
|
|
||||||
# append in group
|
|
||||||
follower = next(iter(group))
|
|
||||||
leader_name = group.attrib['leader']
|
|
||||||
if '.' in leader_name:
|
|
||||||
leader_path = leader_name.rsplit('.', 1)[0]
|
|
||||||
follower_path = leader_path + '.' + follower.text
|
|
||||||
else:
|
|
||||||
follower_path = follower.text
|
|
||||||
obj = paths[follower_path]
|
|
||||||
family = SubElement(obj['parent'], 'family', name=leader_name, leadership="True")
|
|
||||||
for follower in group:
|
|
||||||
leader_name = group.attrib['leader']
|
|
||||||
if '.' in leader_name:
|
|
||||||
leader_path = leader_name.rsplit('.', 1)[0]
|
|
||||||
follower_path = leader_path + '.' + follower.text
|
|
||||||
else:
|
|
||||||
follower_path = follower.text
|
|
||||||
follower_obj = paths[follower_path]
|
|
||||||
follower_obj['parent'].remove(follower_obj['variable'])
|
|
||||||
family.append(follower_obj['variable'])
|
|
||||||
return root
|
return root
|
||||||
|
|
||||||
def _get_path_variables(self, variables, is_variable_namespace, path, dico=None):
|
def _get_path_variables(self, variables, is_variable_namespace, path, dico=None):
|
||||||
|
|
14
tests/dictionaries/70service_engine/00-base.xml
Normal file
14
tests/dictionaries/70service_engine/00-base.xml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
|
<rougail version="0.10">
|
||||||
|
<services>
|
||||||
|
<service name="testsrv" engine="creole">
|
||||||
|
</service>
|
||||||
|
</services>
|
||||||
|
<variables>
|
||||||
|
<family name="general" description="général">
|
||||||
|
<variable name="mode_conteneur_actif" type="string" description="No change" hidden="True">
|
||||||
|
<value>oui</value>
|
||||||
|
</variable>
|
||||||
|
</family>
|
||||||
|
</variables>
|
||||||
|
</rougail>
|
0
tests/dictionaries/70service_engine/__init__.py
Normal file
0
tests/dictionaries/70service_engine/__init__.py
Normal file
14
tests/dictionaries/70service_engine/makedict/after.json
Normal file
14
tests/dictionaries/70service_engine/makedict/after.json
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"rougail.general.mode_conteneur_actif": {
|
||||||
|
"owner": "default",
|
||||||
|
"value": "oui"
|
||||||
|
},
|
||||||
|
"services.testsrv.activate": {
|
||||||
|
"owner": "default",
|
||||||
|
"value": true
|
||||||
|
},
|
||||||
|
"services.testsrv.manage": {
|
||||||
|
"owner": "default",
|
||||||
|
"value": true
|
||||||
|
}
|
||||||
|
}
|
5
tests/dictionaries/70service_engine/makedict/base.json
Normal file
5
tests/dictionaries/70service_engine/makedict/base.json
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"rougail.general.mode_conteneur_actif": "oui",
|
||||||
|
"services.testsrv.activate": true,
|
||||||
|
"services.testsrv.manage": true
|
||||||
|
}
|
14
tests/dictionaries/70service_engine/makedict/before.json
Normal file
14
tests/dictionaries/70service_engine/makedict/before.json
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"rougail.general.mode_conteneur_actif": {
|
||||||
|
"owner": "default",
|
||||||
|
"value": "oui"
|
||||||
|
},
|
||||||
|
"services.testsrv.activate": {
|
||||||
|
"owner": "default",
|
||||||
|
"value": true
|
||||||
|
},
|
||||||
|
"services.testsrv.manage": {
|
||||||
|
"owner": "default",
|
||||||
|
"value": true
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
oui
|
22
tests/dictionaries/70service_engine/tiramisu/base.py
Normal file
22
tests/dictionaries/70service_engine/tiramisu/base.py
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
from importlib.machinery import SourceFileLoader
|
||||||
|
from importlib.util import spec_from_loader, module_from_spec
|
||||||
|
loader = SourceFileLoader('func', 'tests/dictionaries/../eosfunc/test.py')
|
||||||
|
spec = spec_from_loader(loader.name, loader)
|
||||||
|
func = module_from_spec(spec)
|
||||||
|
loader.exec_module(func)
|
||||||
|
for key, value in dict(locals()).items():
|
||||||
|
if key != ['SourceFileLoader', 'func']:
|
||||||
|
setattr(func, key, value)
|
||||||
|
try:
|
||||||
|
from tiramisu3 import *
|
||||||
|
except:
|
||||||
|
from tiramisu import *
|
||||||
|
option_3 = StrOption(name="mode_conteneur_actif", doc="No change", default="oui", properties=frozenset({"force_default_on_freeze", "frozen", "hidden", "mandatory", "normal"}))
|
||||||
|
option_2 = OptionDescription(name="general", doc="général", children=[option_3], properties=frozenset({"normal"}))
|
||||||
|
option_1 = OptionDescription(name="rougail", doc="rougail", children=[option_2])
|
||||||
|
option_6 = BoolOption(name="activate", doc="activate", default=True)
|
||||||
|
option_7 = BoolOption(name="manage", doc="manage", default=True)
|
||||||
|
option_5 = OptionDescription(name="testsrv", doc="testsrv", children=[option_6, option_7])
|
||||||
|
option_5.impl_set_information('engine', "creole")
|
||||||
|
option_4 = OptionDescription(name="services", doc="services", children=[option_5], properties=frozenset({"hidden"}))
|
||||||
|
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[option_1, option_4])
|
1
tests/dictionaries/70service_engine/tmpl/testsrv.service
Normal file
1
tests/dictionaries/70service_engine/tmpl/testsrv.service
Normal file
|
@ -0,0 +1 @@
|
||||||
|
%%mode_conteneur_actif
|
13
tests/dictionaries/70service_mount/00-base.xml
Normal file
13
tests/dictionaries/70service_mount/00-base.xml
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
|
<rougail version="0.10">
|
||||||
|
<services>
|
||||||
|
<service name="testsrv" type="mount" engine="creole"/>
|
||||||
|
</services>
|
||||||
|
<variables>
|
||||||
|
<family name="general" description="général">
|
||||||
|
<variable name="mode_conteneur_actif" type="string" description="No change" hidden="True">
|
||||||
|
<value>oui</value>
|
||||||
|
</variable>
|
||||||
|
</family>
|
||||||
|
</variables>
|
||||||
|
</rougail>
|
0
tests/dictionaries/70service_mount/__init__.py
Normal file
0
tests/dictionaries/70service_mount/__init__.py
Normal file
14
tests/dictionaries/70service_mount/makedict/after.json
Normal file
14
tests/dictionaries/70service_mount/makedict/after.json
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"rougail.general.mode_conteneur_actif": {
|
||||||
|
"owner": "default",
|
||||||
|
"value": "oui"
|
||||||
|
},
|
||||||
|
"services.testsrv.activate": {
|
||||||
|
"owner": "default",
|
||||||
|
"value": true
|
||||||
|
},
|
||||||
|
"services.testsrv.manage": {
|
||||||
|
"owner": "default",
|
||||||
|
"value": true
|
||||||
|
}
|
||||||
|
}
|
5
tests/dictionaries/70service_mount/makedict/base.json
Normal file
5
tests/dictionaries/70service_mount/makedict/base.json
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"rougail.general.mode_conteneur_actif": "oui",
|
||||||
|
"services.testsrv.activate": true,
|
||||||
|
"services.testsrv.manage": true
|
||||||
|
}
|
14
tests/dictionaries/70service_mount/makedict/before.json
Normal file
14
tests/dictionaries/70service_mount/makedict/before.json
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"rougail.general.mode_conteneur_actif": {
|
||||||
|
"owner": "default",
|
||||||
|
"value": "oui"
|
||||||
|
},
|
||||||
|
"services.testsrv.activate": {
|
||||||
|
"owner": "default",
|
||||||
|
"value": true
|
||||||
|
},
|
||||||
|
"services.testsrv.manage": {
|
||||||
|
"owner": "default",
|
||||||
|
"value": true
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
oui
|
23
tests/dictionaries/70service_mount/tiramisu/base.py
Normal file
23
tests/dictionaries/70service_mount/tiramisu/base.py
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
from importlib.machinery import SourceFileLoader
|
||||||
|
from importlib.util import spec_from_loader, module_from_spec
|
||||||
|
loader = SourceFileLoader('func', 'tests/dictionaries/../eosfunc/test.py')
|
||||||
|
spec = spec_from_loader(loader.name, loader)
|
||||||
|
func = module_from_spec(spec)
|
||||||
|
loader.exec_module(func)
|
||||||
|
for key, value in dict(locals()).items():
|
||||||
|
if key != ['SourceFileLoader', 'func']:
|
||||||
|
setattr(func, key, value)
|
||||||
|
try:
|
||||||
|
from tiramisu3 import *
|
||||||
|
except:
|
||||||
|
from tiramisu import *
|
||||||
|
option_3 = StrOption(name="mode_conteneur_actif", doc="No change", default="oui", properties=frozenset({"force_default_on_freeze", "frozen", "hidden", "mandatory", "normal"}))
|
||||||
|
option_2 = OptionDescription(name="general", doc="général", children=[option_3], properties=frozenset({"normal"}))
|
||||||
|
option_1 = OptionDescription(name="rougail", doc="rougail", children=[option_2])
|
||||||
|
option_6 = BoolOption(name="activate", doc="activate", default=True)
|
||||||
|
option_7 = BoolOption(name="manage", doc="manage", default=True)
|
||||||
|
option_5 = OptionDescription(name="testsrv", doc="testsrv", children=[option_6, option_7])
|
||||||
|
option_5.impl_set_information('type', "mount")
|
||||||
|
option_5.impl_set_information('engine', "creole")
|
||||||
|
option_4 = OptionDescription(name="services", doc="services", children=[option_5], properties=frozenset({"hidden"}))
|
||||||
|
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[option_1, option_4])
|
1
tests/dictionaries/70service_mount/tmpl/testsrv.mount
Normal file
1
tests/dictionaries/70service_mount/tmpl/testsrv.mount
Normal file
|
@ -0,0 +1 @@
|
||||||
|
%%mode_conteneur_actif
|
13
tests/dictionaries/70service_target/00-base.xml
Normal file
13
tests/dictionaries/70service_target/00-base.xml
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
|
<rougail version="0.10">
|
||||||
|
<services>
|
||||||
|
<service name="testsrv" target="test"/>
|
||||||
|
</services>
|
||||||
|
<variables>
|
||||||
|
<family name="general" description="général">
|
||||||
|
<variable name="mode_conteneur_actif" type="string" description="No change" hidden="True">
|
||||||
|
<value>oui</value>
|
||||||
|
</variable>
|
||||||
|
</family>
|
||||||
|
</variables>
|
||||||
|
</rougail>
|
0
tests/dictionaries/70service_target/__init__.py
Normal file
0
tests/dictionaries/70service_target/__init__.py
Normal file
14
tests/dictionaries/70service_target/makedict/after.json
Normal file
14
tests/dictionaries/70service_target/makedict/after.json
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"rougail.general.mode_conteneur_actif": {
|
||||||
|
"owner": "default",
|
||||||
|
"value": "oui"
|
||||||
|
},
|
||||||
|
"services.testsrv.activate": {
|
||||||
|
"owner": "default",
|
||||||
|
"value": true
|
||||||
|
},
|
||||||
|
"services.testsrv.manage": {
|
||||||
|
"owner": "default",
|
||||||
|
"value": true
|
||||||
|
}
|
||||||
|
}
|
5
tests/dictionaries/70service_target/makedict/base.json
Normal file
5
tests/dictionaries/70service_target/makedict/base.json
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"rougail.general.mode_conteneur_actif": "oui",
|
||||||
|
"services.testsrv.activate": true,
|
||||||
|
"services.testsrv.manage": true
|
||||||
|
}
|
14
tests/dictionaries/70service_target/makedict/before.json
Normal file
14
tests/dictionaries/70service_target/makedict/before.json
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"rougail.general.mode_conteneur_actif": {
|
||||||
|
"owner": "default",
|
||||||
|
"value": "oui"
|
||||||
|
},
|
||||||
|
"services.testsrv.activate": {
|
||||||
|
"owner": "default",
|
||||||
|
"value": true
|
||||||
|
},
|
||||||
|
"services.testsrv.manage": {
|
||||||
|
"owner": "default",
|
||||||
|
"value": true
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
/usr/lib/systemd/system/testsrv.service
|
22
tests/dictionaries/70service_target/tiramisu/base.py
Normal file
22
tests/dictionaries/70service_target/tiramisu/base.py
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
from importlib.machinery import SourceFileLoader
|
||||||
|
from importlib.util import spec_from_loader, module_from_spec
|
||||||
|
loader = SourceFileLoader('func', 'tests/dictionaries/../eosfunc/test.py')
|
||||||
|
spec = spec_from_loader(loader.name, loader)
|
||||||
|
func = module_from_spec(spec)
|
||||||
|
loader.exec_module(func)
|
||||||
|
for key, value in dict(locals()).items():
|
||||||
|
if key != ['SourceFileLoader', 'func']:
|
||||||
|
setattr(func, key, value)
|
||||||
|
try:
|
||||||
|
from tiramisu3 import *
|
||||||
|
except:
|
||||||
|
from tiramisu import *
|
||||||
|
option_3 = StrOption(name="mode_conteneur_actif", doc="No change", default="oui", properties=frozenset({"force_default_on_freeze", "frozen", "hidden", "mandatory", "normal"}))
|
||||||
|
option_2 = OptionDescription(name="general", doc="général", children=[option_3], properties=frozenset({"normal"}))
|
||||||
|
option_1 = OptionDescription(name="rougail", doc="rougail", children=[option_2])
|
||||||
|
option_6 = BoolOption(name="activate", doc="activate", default=True)
|
||||||
|
option_7 = BoolOption(name="manage", doc="manage", default=True)
|
||||||
|
option_5 = OptionDescription(name="testsrv", doc="testsrv", children=[option_6, option_7])
|
||||||
|
option_5.impl_set_information('target', "test")
|
||||||
|
option_4 = OptionDescription(name="services", doc="services", children=[option_5], properties=frozenset({"hidden"}))
|
||||||
|
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[option_1, option_4])
|
13
tests/dictionaries/70service_target_engine/00-base.xml
Normal file
13
tests/dictionaries/70service_target_engine/00-base.xml
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
|
<rougail version="0.10">
|
||||||
|
<services>
|
||||||
|
<service name="testsrv" target="test" engine="none"/>
|
||||||
|
</services>
|
||||||
|
<variables>
|
||||||
|
<family name="general" description="général">
|
||||||
|
<variable name="mode_conteneur_actif" type="string" description="No change" hidden="True">
|
||||||
|
<value>oui</value>
|
||||||
|
</variable>
|
||||||
|
</family>
|
||||||
|
</variables>
|
||||||
|
</rougail>
|
0
tests/dictionaries/70service_target_engine/__init__.py
Normal file
0
tests/dictionaries/70service_target_engine/__init__.py
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"rougail.general.mode_conteneur_actif": {
|
||||||
|
"owner": "default",
|
||||||
|
"value": "oui"
|
||||||
|
},
|
||||||
|
"services.testsrv.activate": {
|
||||||
|
"owner": "default",
|
||||||
|
"value": true
|
||||||
|
},
|
||||||
|
"services.testsrv.manage": {
|
||||||
|
"owner": "default",
|
||||||
|
"value": true
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"rougail.general.mode_conteneur_actif": "oui",
|
||||||
|
"services.testsrv.activate": true,
|
||||||
|
"services.testsrv.manage": true
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"rougail.general.mode_conteneur_actif": {
|
||||||
|
"owner": "default",
|
||||||
|
"value": "oui"
|
||||||
|
},
|
||||||
|
"services.testsrv.activate": {
|
||||||
|
"owner": "default",
|
||||||
|
"value": true
|
||||||
|
},
|
||||||
|
"services.testsrv.manage": {
|
||||||
|
"owner": "default",
|
||||||
|
"value": true
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
/usr/local/lib/systemd/system/testsrv.service
|
|
@ -0,0 +1 @@
|
||||||
|
%%mode_conteneur_actif
|
23
tests/dictionaries/70service_target_engine/tiramisu/base.py
Normal file
23
tests/dictionaries/70service_target_engine/tiramisu/base.py
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
from importlib.machinery import SourceFileLoader
|
||||||
|
from importlib.util import spec_from_loader, module_from_spec
|
||||||
|
loader = SourceFileLoader('func', 'tests/dictionaries/../eosfunc/test.py')
|
||||||
|
spec = spec_from_loader(loader.name, loader)
|
||||||
|
func = module_from_spec(spec)
|
||||||
|
loader.exec_module(func)
|
||||||
|
for key, value in dict(locals()).items():
|
||||||
|
if key != ['SourceFileLoader', 'func']:
|
||||||
|
setattr(func, key, value)
|
||||||
|
try:
|
||||||
|
from tiramisu3 import *
|
||||||
|
except:
|
||||||
|
from tiramisu import *
|
||||||
|
option_3 = StrOption(name="mode_conteneur_actif", doc="No change", default="oui", properties=frozenset({"force_default_on_freeze", "frozen", "hidden", "mandatory", "normal"}))
|
||||||
|
option_2 = OptionDescription(name="general", doc="général", children=[option_3], properties=frozenset({"normal"}))
|
||||||
|
option_1 = OptionDescription(name="rougail", doc="rougail", children=[option_2])
|
||||||
|
option_6 = BoolOption(name="activate", doc="activate", default=True)
|
||||||
|
option_7 = BoolOption(name="manage", doc="manage", default=True)
|
||||||
|
option_5 = OptionDescription(name="testsrv", doc="testsrv", children=[option_6, option_7])
|
||||||
|
option_5.impl_set_information('target', "test")
|
||||||
|
option_5.impl_set_information('engine', "none")
|
||||||
|
option_4 = OptionDescription(name="services", doc="services", children=[option_5], properties=frozenset({"hidden"}))
|
||||||
|
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[option_1, option_4])
|
|
@ -0,0 +1 @@
|
||||||
|
%%mode_conteneur_actif
|
6
tests/dictionaries/80wrong_service_name/00-base.xml
Normal file
6
tests/dictionaries/80wrong_service_name/00-base.xml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
|
<rougail version="0.10">
|
||||||
|
<services>
|
||||||
|
<service name="testsrv.mount"/>
|
||||||
|
</services>
|
||||||
|
</rougail>
|
0
tests/dictionaries/80wrong_service_name/__init__.py
Normal file
0
tests/dictionaries/80wrong_service_name/__init__.py
Normal file
0
tests/dictionaries/80wrong_service_name/errno_76
Normal file
0
tests/dictionaries/80wrong_service_name/errno_76
Normal file
|
@ -1,4 +1,4 @@
|
||||||
from os import listdir, mkdir
|
from os import listdir, mkdir, readlink
|
||||||
from os.path import join, isdir, isfile, islink
|
from os.path import join, isdir, isfile, islink
|
||||||
from shutil import rmtree
|
from shutil import rmtree
|
||||||
from pytest import fixture, mark
|
from pytest import fixture, mark
|
||||||
|
@ -82,7 +82,9 @@ async def test_dictionary(test_dir):
|
||||||
assert list_templates == list_results
|
assert list_templates == list_results
|
||||||
for result in list_results:
|
for result in list_results:
|
||||||
template_file = join(dest_dir, result)
|
template_file = join(dest_dir, result)
|
||||||
if islink(template_file) and islink(join(test_dir, 'result', result)):
|
assert islink(template_file) == islink(join(test_dir, 'result', result))
|
||||||
|
if islink(template_file):
|
||||||
|
assert readlink(template_file) == readlink(join(test_dir, 'result', result))
|
||||||
continue
|
continue
|
||||||
if not isfile(template_file):
|
if not isfile(template_file):
|
||||||
raise Exception(f'{template_file} is not generated')
|
raise Exception(f'{template_file} is not generated')
|
||||||
|
|
Loading…
Reference in a new issue