diff --git a/src/risotto/services/servermodel/servermodel.py b/src/risotto/services/servermodel/servermodel.py index 64c93ce..fbf3f09 100644 --- a/src/risotto/services/servermodel/servermodel.py +++ b/src/risotto/services/servermodel/servermodel.py @@ -2,6 +2,7 @@ from os import listdir from os.path import join from yaml import load, SafeLoader from traceback import print_exc +from typing import Dict, List from ...controller import Controller from ...register import register from ...utils import _ @@ -11,15 +12,63 @@ from ...error import ExecutionError class Risotto(Controller): + async def _servermodel_create(self, + risotto_context: Context, + servermodel_name: str, + servermodel_description: str, + servermodel_parents_id, + release_id): + servermodel_update = """INSERT INTO Servermodel(ServermodelName, ServermodelDescription, ServermodelParentsId, ServermodelReleaseId, ServermodelApplicationServiceId) VALUES ($1,$2,$3,$4,$5) + RETURNING ServermodelId + """ + as_name = f"local_{servermodel_name}" + as_description = f'local application service for {servermodel_name}' + applicationservice = await self.call('v1.applicationservice.create', + risotto_context, + applicationservice_name=as_name, + applicationservice_description=as_description, + release_id=release_id) + servermodel = await risotto_context.connection.fetchval(servermodel_update, + sm_name, + sm_description, + sm_parentsid, + release_id, + applicationservice['applicationservice_id']) + return {'servermodel_name': servermodel_name, + 'servermodel_description': servermodel_description, + 'servermodel_parents_id': servermodel_parents_id, + 'release_id': release_id, + 'servermodel_id': servermodel['servermodel_id']} + + def parse_parents(self, + servermodels: Dict, + servermodel: Dist, + parents: List=None) -> List: + if parents is None: + parents = [servermodel] + parent = servermodels[servermodel]['parent'] + if parent in servermodels: + parents.append(parent) + self.parse_parents(servermodels, parent, parents) + return parents + + async def get_servermodel_id_by_name(self, + risotto_context: Context, + servermodel_name: str, + release_id: int): + sql = 'SELECT ServermodelId as servermodel_id FROM Servermodel WHERE ServermodelName = $1 AND ServermodelReleaseId = $2', + return await risotto_context.connection.fetchval(sql, + servermodel_name, + release_id)['servermodel_id'] + @register('v1.servermodel.dataset.updated', None, database=True) async def servermodel_update(self, risotto_context: Context, release_path: str, release_id: int): - servermodel_update = """INSERT INTO Servermodel(ServermodelName, ServermodelDescription, ServermodelParentsId, ServermodelReleaseId, ServermodelApplicationServiceId) VALUES ($1,$2,$3,$4,$5) - RETURNING ServermodelId - """ servermodel_path = join(release_path, 'servermodel') + servermodels = {} + # for dependencies reason load all servermodels for servermodel in listdir(servermodel_path): if not servermodel.endswith('.yml'): continue @@ -32,31 +81,38 @@ class Risotto(Controller): if get_config().get('global').get('debug'): print_exc() raise ExecutionError(_(f'Error while reading {servermodel_description_path}: {err}')) - sm_name = servermodel_description['name'] - sm_description = servermodel_description['description'] - sm_parentsid = servermodel_description['parent'] - if sm_parentsid is None: - sm_parentsid = [] - else: - sm_parentsid = [sm_parentsid] - as_name = f"local_{sm_name}" - as_description = f'local application service for {sm_name}' - applicationservice = await self.call('v1.applicationservice.create', - risotto_context, - applicationservice_name=as_name, - applicationservice_description=as_description, - release_id=release_id) - try: - await risotto_context.connection.fetch(servermodel_update, - sm_name, - sm_description, - sm_parentsid, - release_id, - applicationservice['applicationservice_id']) - except Exception as err: - if get_config().get('global').get('debug'): - print_exc() - raise ExecutionError(_(f"Error while injecting servermodel {servermodel_description['name']} in database: {err}")) + servermodels[servermodel_yml['name']] = servermodel_description + servermodels[servermodel_yml['name']]['done'] = False + + for servermodel in servermodels: + if not servermodel['done']: + # parent needs to create before child, so retrieve all parents + parents = self.parse_parents(servermodels, + servermodel) + parents.reverse() + servermodelparent_id = [] + for new_servermodel in parents: + if not servermodels[new_servermodel]['done']: + servermodel_description = servermodels[new_servermodel] + parent = servermodel_description['parent'] + if not servermodelparent_id and parent None: + # parent is a str, so get ID + servermodelparent_id = [await self.get_servermodel_id_by_name(risotto_context, + parent, + release_id)] + sm_name = servermodel_description['name'] + sm_description = servermodel_description['description'] + try: + servermodel_id = await self._servermodel_create(sm_name, + sm_description, + servermodelparent_id, + release_id)['servermodel_id'] + except Exception as err: + if get_config().get('global').get('debug'): + print_exc() + raise ExecutionError(_(f"Error while injecting servermodel {sm_name} in database: {err}")) + servermodelparent_id = [servermodel_id] + servermodel_description['done'] = True return {'retcode': 0, 'returns': _('Servermodels successfully loaded')} @register('v1.servermodel.list', None, database=True)