diff --git a/messages/v1/messages/old/server.describe.yml b/messages/v1/messages/old/server.describe.yml deleted file mode 100644 index b976339..0000000 --- a/messages/v1/messages/old/server.describe.yml +++ /dev/null @@ -1,49 +0,0 @@ ---- -uri: server.describe - -description: | - Retourne les attributs détaillés d’un serveur. - -sampleuse: | - zephir-client server.describe -s 1 - -pattern: rpc - -public: true - -domain: server-domain - -parameters: - serverid: - type: Number - ref: Server.ServerId - description: Identifiant du serveur. - shortarg: s - configuration: - type: Boolean - description: Inclure les valeurs de configuration. - default: false - environment: - type: Boolean - description: Inclure les variables d'environement. - default: false - peering: - type: Boolean - description: Inclure la clé d'appairage. - default: false - -response: - type: ServerDescribe - description: Description du serveur. - -errors: - - uri: server.error.database-not-available - - uri: server.error.db-connection - - uri: server.error.invalid-server-id - - uri: server.error.unknown-server-id - -related: - - server.list - - server.create - - server.update - - server.delete diff --git a/messages/v1/messages/server.describe.yml b/messages/v1/messages/server.describe.yml new file mode 100644 index 0000000..cb703c1 --- /dev/null +++ b/messages/v1/messages/server.describe.yml @@ -0,0 +1,18 @@ +--- +uri: server.describe + +description: Retourne les attributs détaillés d’un serveur. + +pattern: rpc + +public: true + +parameters: + server_name: + type: String + ref: Server.ServerName + description: Nom du serveur. + +response: + type: Server + description: Description du serveur. diff --git a/messages/v1/messages/template.generate.yml b/messages/v1/messages/template.generate.yml index 0d9b21c..8a97141 100644 --- a/messages/v1/messages/template.generate.yml +++ b/messages/v1/messages/template.generate.yml @@ -9,12 +9,12 @@ pattern: rpc public: true parameters: - server_id: - type: Number - ref: Server.ServerId + server_name: + type: String + ref: Server.ServerName shortarg: s description: | - Identifiant du serveur. + Nom du serveur. response: type: Template diff --git a/messages/v1/types/server.describe.yml b/messages/v1/types/server.describe.yml deleted file mode 100644 index 2eba51e..0000000 --- a/messages/v1/types/server.describe.yml +++ /dev/null @@ -1,44 +0,0 @@ ---- -title: ServerDescribe -type: object -description: Description du serveur. -properties: - serverid: - type: number - description: Identifiant du serveur. - ref: Server.ServerId - servername: - type: string - description: Nom du serveur. - serverdescription: - type: string - description: Description du serveur. - servermodelid: - type: number - description: Identifiant du modèle de serveur. - ref: Servermodel.ServermodelId - zoneid: - type: number - description: Identifiant de la zone. - ref: Zone.ZoneId - machineid: - type: number - description: Identifiant de la machine. - ref: Zone.MachineId - configuration: - type: file - description: Valeurs de configuration. - serverenvironment: - type: object - description: Variables d'environnement du serveur. - peering: - type: object - description: Clé d'appairage. - lastpeerconnection: - type: string - description: Timestamp de la dernière connexion avec le serveur. -required: - - serverid - - servername - - serverdescription - - servermodelid diff --git a/script/database_manager.py b/script/database_manager.py index 3914f22..8fa8db9 100644 --- a/script/database_manager.py +++ b/script/database_manager.py @@ -47,7 +47,7 @@ CREATE TABLE ApplicationService ( -- Server table creation CREATE TABLE Server ( ServerId SERIAL PRIMARY KEY, - ServerName VARCHAR(255) NOT NULL, + ServerName VARCHAR(255) NOT NULL UNIQUE, ServerDescription VARCHAR(255) NOT NULL, ServerServermodelId INTEGER NOT NULL ); diff --git a/src/risotto/services/config/config.py b/src/risotto/services/config/config.py index be4f99d..aa13575 100644 --- a/src/risotto/services/config/config.py +++ b/src/risotto/services/config/config.py @@ -66,9 +66,7 @@ class Risotto(Controller): def get_funcs_filename(self, servermodel_id: int): - return join(self.cache_root_path, str(servermodel_id)+".creolefuncs") - - + return join(self.cache_root_path, str(servermodel_id), "funcs.py") async def load_servermodel(self, risotto_context: Context, @@ -76,7 +74,7 @@ class Risotto(Controller): servermodel_name: str) -> None: """ Loads a servermodel """ - cache_file = join(self.cache_root_path, str(servermodel_id)+".xml") + cache_file = join(self.cache_root_path, str(servermodel_id), "dictionaries.xml") funcs_file = self.get_funcs_filename(servermodel_id) log.info_msg(risotto_context, None, diff --git a/src/risotto/services/server/server.py b/src/risotto/services/server/server.py index 7381a24..1fa2c50 100644 --- a/src/risotto/services/server/server.py +++ b/src/risotto/services/server/server.py @@ -3,6 +3,7 @@ from typing import Dict from ...controller import Controller from ...register import register from ...context import Context +from ...utils import _ class Risotto(Controller): @@ -10,7 +11,8 @@ class Risotto(Controller): async def server_list(self, risotto_context: Context) -> Dict: sql = ''' - SELECT ServerId as server_id, ServerName as server_name, ServerDescription as server_description, ServerServermodelId as server_servermodel_id FROM Server + SELECT ServerId as server_id, ServerName as server_name, ServerDescription as server_description, ServerServermodelId as server_servermodel_id + FROM Server ''' servers = await risotto_context.connection.fetch(sql) return [dict(r) for r in servers] @@ -18,9 +20,9 @@ class Risotto(Controller): @register('v1.server.create', 'v1.server.created', database=True) async def server_create(self, risotto_context: Context, - server_name, - server_description, - server_servermodel_id) -> Dict: + server_name: str, + server_description: str, + server_servermodel_id: int) -> Dict: await self.call('v1.servermodel.get_by_id', risotto_context, @@ -37,3 +39,18 @@ class Risotto(Controller): 'server_name': server_name, 'server_description': server_description, 'server_servermodel_id': server_servermodel_id} + + @register('v1.server.describe', None, database=True) + async def server_create(self, + risotto_context: Context, + server_name: str) -> Dict: + sql = ''' + SELECT ServerId as server_id, ServerName as server_name, ServerDescription as server_description, ServerServermodelId as server_servermodel_id + FROM Server + WHERE ServerName = $1 + ''' + server = await risotto_context.connection.fetchrow(sql, + server_name) + if not server: + raise Exception(_(f'unable to find server with name {server_name}')) + return dict(server) diff --git a/src/risotto/services/servermodel/servermodel.py b/src/risotto/services/servermodel/servermodel.py index ea78b22..fe3b7cd 100644 --- a/src/risotto/services/servermodel/servermodel.py +++ b/src/risotto/services/servermodel/servermodel.py @@ -1,8 +1,9 @@ +from shutil import rmtree, copyfile from os import listdir, makedirs -from os.path import join, isdir +from os.path import join, isdir, isfile from yaml import load, SafeLoader from traceback import print_exc -from typing import Dict, List +from typing import Dict, List, Optional from rougail import CreoleObjSpace from rougail.config import dtdfilename from ...controller import Controller @@ -34,40 +35,94 @@ class Risotto(Controller): release_distribution='stable') self.internal_release_id = internal_release['release_id'] - async def servermodel_gen_schema(self, - risotto_context: Context, - servermodel_name: str, - servermodel_id: int, - applicationservice_id: int, - release_cache: Dict) -> None: - dependencies = await self.get_applicationservices(risotto_context, - applicationservice_id) - if release_cache is None: - release_cache = {} - dict_paths = [] + def servermodel_gen_funcs(self, + servermodel_name: str, + servermodel_id: int, + dependencies: Dict, + release_cache: Dict) -> None: + as_names = [] + dest_file = self.get_servermodel_cache(servermodel_id, 'funcs.py') + with open(dest_file, 'w') as funcs: + for applicationservice_id, applicationservice_infos in dependencies.items(): + applicationservice_name, as_release_id = applicationservice_infos + path = join(self.source_root_path, + release_cache[as_release_id]['source_name'], + release_cache[as_release_id]['release_name'], + 'applicationservice', + applicationservice_name, + 'funcs') + if isdir(path): + as_names.append(applicationservice_name) + for fil in listdir(path): + with open(join(path, fil), 'r') as fh: + funcs.write('# {}\n'.format(join(path, fil))) + funcs.write(fh.read() + '\n') + + as_names_str = '", "'.join(as_names) + log.info(_(f'gen funcs for "{servermodel_name}" with application services "{as_names_str}"')) + eolobj = CreoleObjSpace(dtdfilename) + + def servermodel_gen_schema(self, + servermodel_name: str, + servermodel_id: int, + dependencies: Dict, + release_cache: Dict) -> None: + paths = [] as_names = [] for applicationservice_id, applicationservice_infos in dependencies.items(): applicationservice_name, as_release_id = applicationservice_infos - as_names.append(applicationservice_name) - if as_release_id not in release_cache: - release_cache[as_release_id] = await self.call('v1.source.release.get_by_id', - risotto_context, - release_id=as_release_id) - dict_paths.append(join(self.source_root_path, - release_cache[as_release_id]['source_name'], - release_cache[as_release_id]['release_name'], - 'applicationservice', - applicationservice_name, - 'dictionaries')) + path = join(self.source_root_path, + release_cache[as_release_id]['source_name'], + release_cache[as_release_id]['release_name'], + 'applicationservice', + applicationservice_name, + 'dictionaries') + if isdir(path): + as_names.append(applicationservice_name) + paths.append(path) eolobj = CreoleObjSpace(dtdfilename) as_names_str = '", "'.join(as_names) log.info(_(f'gen schema for "{servermodel_name}" with application services "{as_names_str}"')) - eolobj.create_or_populate_from_xml('creole', dict_paths) + eolobj.create_or_populate_from_xml('creole', paths) # FIXME extra - # FIXME eosfunc - eosfunc = '/eosfunc.py' - eolobj.space_visitor(eosfunc) - eolobj.save(join(self.cache_root_path, f'{servermodel_id}.xml')) + funcs_file = self.get_servermodel_cache(servermodel_id, 'funcs.py') + eolobj.space_visitor(funcs_file) + dest_dir = self.get_servermodel_cache(servermodel_id, 'dictionaries.xml') + eolobj.save(dest_dir) + + def get_servermodel_cache(self, + servermodel_id: int, + subdir: Optional[str]=None) -> str: + if subdir: + return join(self.cache_root_path, str(servermodel_id), subdir) + return join(self.cache_root_path, str(servermodel_id)) + + def servermodel_copy_templates(self, + servermodel_name: str, + servermodel_id: int, + dependencies: Dict, + release_cache: Dict) -> None: + as_names = [] + dest_dir = self.get_servermodel_cache(servermodel_id, 'templates') + makedirs(dest_dir) + for applicationservice_id, applicationservice_infos in dependencies.items(): + applicationservice_name, as_release_id = applicationservice_infos + path = join(self.source_root_path, + release_cache[as_release_id]['source_name'], + release_cache[as_release_id]['release_name'], + 'applicationservice', + applicationservice_name, + 'templates') + if isdir(path): + for template in listdir(path): + template_path = join(dest_dir, template) + if isfile(template_path): + as_names_str = '", "'.join(as_names) + raise Exception(_(f'duplicate "{template}" when copying template from "{applicationservice_name}" to "{dest_dir}" for servermodel "{servermodel_name}" (previous application services was "{as_names_str}"')) + copyfile(join(path, template), template_path) + as_names.append(applicationservice_name) + as_names_str = '", "'.join(as_names) + log.info(_(f'copy templates for "{servermodel_name}" with application services "{as_names_str}"')) async def _servermodel_create(self, risotto_context: Context, @@ -96,11 +151,35 @@ class Risotto(Controller): servermodel_parents_id, release_id, applicationservice_id) - await self.servermodel_gen_schema(risotto_context, - servermodel_name, - servermodel_id, - applicationservice_id, - release_cache) + dest_dir = self.get_servermodel_cache(servermodel_id) + if isdir(dest_dir): + rmtree(dest_dir) + makedirs(dest_dir) + # get all dependencies for this application service + dependencies = await self.get_applicationservices(risotto_context, + applicationservice_id) + # build cache to have all release informations + if release_cache is None: + release_cache = {} + for applicationservice_id, applicationservice_infos in dependencies.items(): + applicationservice_name, as_release_id = applicationservice_infos + if as_release_id not in release_cache: + release_cache[as_release_id] = await self.call('v1.source.release.get_by_id', + risotto_context, + release_id=as_release_id) + + self.servermodel_gen_funcs(servermodel_name, + servermodel_id, + dependencies, + release_cache) + self.servermodel_gen_schema(servermodel_name, + servermodel_id, + dependencies, + release_cache) + self.servermodel_copy_templates(servermodel_name, + servermodel_id, + dependencies, + release_cache) sm_dict = {'servermodel_name': servermodel_name, 'servermodel_description': servermodel_description, 'servermodel_parents_id': servermodel_parents_id, diff --git a/src/risotto/services/template/template.py b/src/risotto/services/template/template.py index 41cae22..3c61c26 100644 --- a/src/risotto/services/template/template.py +++ b/src/risotto/services/template/template.py @@ -1,21 +1,30 @@ from os import mkdir from os.path import isdir, join from shutil import rmtree +from typing import Dict from rougail.template import generate from tiramisu import Storage -from ...config import CONFIGURATION_DIR, TEMPLATE_DIR, TMP_DIR +from ...config import CONFIGURATION_DIR, TMP_DIR, get_config from ...controller import Controller from ...register import register from ...dispatcher import dispatcher +from ...utils import _ class Risotto(Controller): def __init__(self): self.storage = Storage(engine='dictionary') + self.cache_root_path = join(get_config().get('cache').get('root_path'), 'servermodel') @register('v1.template.generate', None) async def template_get(self, - server_id: int): + risotto_context, + server_name: str) -> Dict: + server = await self.call('v1.server.describe', + risotto_context, + server_name=server_name) + server_id = server['server_id'] + servermodel_id = server['server_servermodel_id'] config_module = dispatcher.get_service('config') server = config_module.server[server_id] config = meta = server['server'].config.deepcopy(storage=self.storage) @@ -28,7 +37,6 @@ class Risotto(Controller): config = children[0] else: break - print(config.value.dict()) configurations_dir = join(CONFIGURATION_DIR, str(server_id)) if isdir(configurations_dir): @@ -38,7 +46,7 @@ class Risotto(Controller): if isdir(tmp_dir): rmtree(tmp_dir) mkdir(tmp_dir) - templates_dir = join(TEMPLATE_DIR, str(server_id)) + templates_dir = join(self.cache_root_path, str(servermodel_id), 'templates') generate(config, server['funcs_file'], templates_dir,