diff --git a/script/database_manager.py b/script/database_manager.py index 9de09ca..4847dff 100644 --- a/script/database_manager.py +++ b/script/database_manager.py @@ -1,110 +1,24 @@ import asyncpg import asyncio +from os.path import isfile +from sys import init + + from risotto.config import get_config -VERSION_INIT = """ --- Source -CREATE TABLE Source ( - SourceId SERIAL PRIMARY KEY, - SourceName VARCHAR(255) NOT NULL UNIQUE, - SourceURL TEXT -); - --- Release -CREATE TABLE Release ( - ReleaseId SERIAL PRIMARY KEY, - ReleaseName VARCHAR(255) NOT NULL, - ReleaseSourceId INTEGER NOT NULL, - ReleaseDistribution VARCHAR(20) CONSTRAINT releasedistribution_choice CHECK (ReleaseDistribution IN ('last', 'n-1', 'n-2')), - UNIQUE (ReleaseName, ReleaseSourceId), - UNIQUE (ReleaseDistribution, ReleaseSourceId), - FOREIGN KEY (ReleaseSourceId) REFERENCES Source(SourceId) -); - --- Servermodel -CREATE TABLE Servermodel ( - ServermodelId SERIAL PRIMARY KEY, - ServermodelName VARCHAR(255) NOT NULL, - ServermodelDescription VARCHAR(255) NOT NULL, - ServermodelParentsId INTEGER [] DEFAULT '{}', - ServermodelReleaseId INTEGER NOT NULL, - ServermodelApplicationserviceId INTEGER NOT NULL, - UNIQUE (ServermodelName, ServermodelReleaseId) -); -CREATE INDEX ServermodelApplicationserviceId_index ON Servermodel (ServermodelApplicationserviceId); - --- Applicationservice -CREATE TABLE Applicationservice ( - ApplicationserviceId SERIAL PRIMARY KEY, - ApplicationserviceName VARCHAR(255) NOT NULL, - ApplicationserviceDescription VARCHAR(255) NOT NULL, - ApplicationserviceReleaseId INTEGER NOT NULL, - UNIQUE (ApplicationserviceName, ApplicationserviceReleaseId) -); -CREATE TABLE ApplicationserviceDependency ( - ApplicationserviceId INTEGER NOT NULL, - ApplicationserviceDependencyId INTEGER NOT NULL, - UNIQUE(ApplicationserviceId, ApplicationserviceDependencyId), - FOREIGN KEY (ApplicationserviceId) REFERENCES Applicationservice(ApplicationserviceId), - FOREIGN KEY (ApplicationserviceDependencyId) REFERENCES Applicationservice(ApplicationserviceId) -); - --- Server -CREATE TABLE Server ( - ServerId SERIAL PRIMARY KEY, - ServerName VARCHAR(255) NOT NULL UNIQUE, - ServerDescription VARCHAR(255) NOT NULL, - ServerServermodelId INTEGER NOT NULL -); - --- User, Role and ACL -CREATE TABLE RisottoUser ( - UserId SERIAL PRIMARY KEY, - UserLogin VARCHAR(100) NOT NULL UNIQUE, - UserName VARCHAR(100) NOT NULL, - UserSurname VARCHAR(100) NOT NULL -); - -CREATE TABLE UserRole ( - RoleId SERIAL PRIMARY KEY, - RoleUserId INTEGER NOT NULL, - RoleName VARCHAR(255) NOT NULL, - RoleAttribute VARCHAR(255), - RoleAttributeValue VARCHAR(255), - FOREIGN KEY (RoleUserId) REFERENCES RisottoUser(UserId) -); - -CREATE TABLE URI ( - URIId SERIAL PRIMARY KEY, - URIName VARCHAR(255) NOT NULL UNIQUE -); - -CREATE TABLE RoleURI ( - RoleName VARCHAR(255) NOT NULL, - URIId INTEGER NOT NULL, - FOREIGN KEY (URIId) REFERENCES URI(URIId), - PRIMARY KEY (RoleName, URIId) -); - --- Log -CREATE TABLE log( - Msg VARCHAR(255) NOT NULL, - Level VARCHAR(10) NOT NULL, - Path VARCHAR(255), - Username VARCHAR(100) NOT NULL, - Data JSON, - Date timestamp DEFAULT current_timestamp -); -""" async def main(): + sql_filename = get_config()['global']['sql_filename'] + if not isfile(sql_filename): + print('no sql file to import') + exit() db_conf = get_config()['database']['dsn'] pool = await asyncpg.create_pool(db_conf) async with pool.acquire() as connection: async with connection.transaction(): - returns = await connection.execute(VERSION_INIT) + with open(sql_filename, 'r') as sql: + await connection.execute(sql.read().decode()) if __name__ == '__main__': loop = asyncio.get_event_loop() loop.run_until_complete(main()) - # asyncio.run(main()) diff --git a/src/risotto/config.py b/src/risotto/config.py index 2543020..f7375a9 100644 --- a/src/risotto/config.py +++ b/src/risotto/config.py @@ -8,6 +8,7 @@ DEFAULT_DSN = environ.get('RISOTTO_DSN', 'postgres:///risotto?host=/var/run/post DEFAULT_TIRAMISU_DSN = environ.get('DEFAULT_TIRAMISU_DSN', 'postgres:///tiramisu?host=/var/run/postgresql/&user=tiramisu') MESSAGE_PATH = environ.get('MESSAGE_PATH', '/root/risotto-message/messages') MODULE_NAME = environ.get('MODULE_NAME', 'test') +SQL_FILENAME = f'/root/risotto-{MODULE_NAME}/sql/init.sql' def get_config(): @@ -22,6 +23,7 @@ def get_config(): 'check_role': True, 'admin_user': DEFAULT_USER, 'module_name': MODULE_NAME, + 'sql_filename': SQL_FILENAME, 'version': 'v1'}, 'source': {'root_path': '/srv/seed'}, 'cache': {'root_path': '/var/cache/risotto'}, diff --git a/src/risotto/services/__init__.py b/src/risotto/services/__init__.py deleted file mode 100644 index e83d35b..0000000 --- a/src/risotto/services/__init__.py +++ /dev/null @@ -1,20 +0,0 @@ -from os import listdir -from os.path import isdir, isfile, dirname, abspath, basename, join -from importlib import import_module -from ..dispatcher import dispatcher - - -def load_services(modules=None, - validate: bool=True, - test: bool=False): - abs_here = dirname(abspath(__file__)) - here = basename(abs_here) - module = basename(dirname(abs_here)) - if not modules: - modules = listdir(abs_here) - for filename in modules: - absfilename = join(abs_here, filename) - if isdir(absfilename) and isfile(join(absfilename, '__init__.py')): - dispatcher.set_module(filename, import_module(f'.{here}.{filename}', module), test) - if validate: - dispatcher.validate() diff --git a/src/risotto/services/applicationservice/__init__.py b/src/risotto/services/applicationservice/__init__.py deleted file mode 100644 index 735209d..0000000 --- a/src/risotto/services/applicationservice/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .applicationservice import Risotto diff --git a/src/risotto/services/applicationservice/applicationservice.py b/src/risotto/services/applicationservice/applicationservice.py deleted file mode 100644 index 97490aa..0000000 --- a/src/risotto/services/applicationservice/applicationservice.py +++ /dev/null @@ -1,248 +0,0 @@ -from os import listdir -from os.path import join -from traceback import print_exc -from yaml import load, SafeLoader -from typing import Dict, List, Set - -from ...controller import Controller -from ...register import register -from ...config import get_config -from ...error import ExecutionError -from ...context import Context -from ...utils import _ - -class Risotto(Controller): - def __init__(self, - test: bool) -> None: - self.source_root_path = get_config().get('source').get('root_path') - self.internal_source_name = get_config()['servermodel']['internal_source'] - self.internal_distribution_name = get_config()['servermodel']['internal_distribution'] - self.internal_release_name = get_config()['servermodel']['internal_release_name'] - super().__init__(test) - - async def on_join(self, - risotto_context: Context) -> None: - internal_source = await self.call('v1.setting.source.create', - risotto_context, - source_name=self.internal_source_name, - source_url='none') - internal_release = await self.call('v1.setting.source.release.create', - risotto_context, - source_name=self.internal_source_name, - release_name=self.internal_release_name, - release_distribution=self.internal_distribution_name) - self.internal_release_id = internal_release['release_id'] - - async def _applicationservice_create(self, - risotto_context: Context, - applicationservice_name: str, - applicationservice_description: str, - applicationservice_dependencies: List[int], - release_id: int) -> Dict: - applicationservice_update_query = '''INSERT INTO Applicationservice(ApplicationserviceName, ApplicationserviceDescription, ApplicationserviceReleaseId) - VALUES ($1,$2,$3) - RETURNING ApplicationserviceId - ''' - applicationservice_id = await risotto_context.connection.fetchval(applicationservice_update_query, - applicationservice_name, - applicationservice_description, - release_id) - await self.insert_dependency(risotto_context, - applicationservice_id, - applicationservice_dependencies) - return {'applicationservice_name': applicationservice_name, - 'applicationservice_description': applicationservice_description, - 'applicationservice_release_id': release_id, - 'applicationservice_id': applicationservice_id} - - async def insert_dependency(self, - risotto_context: Context, - applicationservice_id: int, - dependencies: list) -> None: - sql = '''INSERT INTO ApplicationserviceDependency(ApplicationserviceId, ApplicationserviceDependencyId) - VALUES ($1, $2)''' - for dependency in dependencies: - await risotto_context.connection.execute(sql, - applicationservice_id, - dependency) - - @register('v1.setting.applicationservice.dependency.add') - async def applicationservice_dependency_add(self, - risotto_context: Context, - applicationservice_name: str, - applicationservice_dependency: str, - source_name: str, - release_distribution: str) -> Dict: - release = await self.call('v1.setting.source.release.describe', - risotto_context, - source_name=source_name, - release_distribution=release_distribution) - as_descr = await self._applicationservice_describe(risotto_context, - applicationservice_name, - self.internal_release_id) - dependency_descr = await self._applicationservice_describe(risotto_context, - applicationservice_dependency, - release['release_id']) - sql = '''SELECT ApplicationserviceDependencyId - FROM ApplicationserviceDependency - WHERE ApplicationserviceId = $1 AND ApplicationserviceDependencyId = $2''' - if await risotto_context.connection.fetchrow(sql, - as_descr['applicationservice_id'], - dependency_descr['applicationservice_id']): - raise Exception(_(f'{applicationservice_name} has already a dependency to {applicationservice_dependency}')) - await self.insert_dependency(risotto_context, - as_descr['applicationservice_id'], - [dependency_descr['applicationservice_id']]) - await self.publish('v1.setting.applicationservice.updated', - risotto_context, - **as_descr) - await self.updated_related_applicationservice(risotto_context, - as_descr['applicationservice_id']) - return as_descr - - async def updated_related_applicationservice(self, - risotto_context: Context, - applicationservice_id: int) -> None: - sql = """ - SELECT ApplicationserviceId as applicationservice_id - FROM ApplicationserviceDependency - WHERE ApplicationserviceDependencyId = $1""" - for dependency in await risotto_context.connection.fetch(sql, - applicationservice_id): - dependency_id = dependency['applicationservice_id'] - applicationservice = await self._applicationservice_get_by_id(risotto_context, - dependency_id) - await self.publish('v1.setting.applicationservice.updated', - risotto_context, - **applicationservice) - await self.updated_related_applicationservice(risotto_context, - dependency_id) - - async def get_dependencies(self, - risotto_context: Context, - applicationservice_id: int) -> List[int]: - dependencies = set() - sql = """ - SELECT ApplicationserviceDependencyId as applicationservice_dependency_id - FROM ApplicationserviceDependency - WHERE ApplicationserviceId = $1""" - for dependency in await risotto_context.connection.fetch(sql, - applicationservice_id): - dependencies.add(dependency['applicationservice_dependency_id']) - for dependency in dependencies.copy(): - dependencies |= await self.get_dependencies(risotto_context, - dependency) - return dependencies - - @register('v1.setting.applicationservice.create') - async def applicationservice_create(self, - risotto_context: Context, - applicationservice_name: str, - applicationservice_description: str, - applicationservice_dependencies: List[int]) -> Dict: - applicationservice = await self._applicationservice_create(risotto_context, - applicationservice_name, - applicationservice_description, - applicationservice_dependencies, - self.internal_release_id) - dependencies = list(await self.get_dependencies(risotto_context, - applicationservice['applicationservice_id'])) - applicationservice['applicationservice_dependencies'] = dependencies - return applicationservice - - @register('v1.setting.applicationservice.dataset.updated') - async def applicationservice_update(self, - risotto_context: Context, - source_name: str, - release_distribution: str) -> Dict: - release = await self.call('v1.setting.source.release.describe', - risotto_context, - source_name=source_name, - release_distribution=release_distribution) - applicationservice_path = join(self.source_root_path, - source_name, - release['release_name'], - 'applicationservice') - release_id = release['release_id'] - for service in listdir(applicationservice_path): - try: - applicationservice_description_path = join(applicationservice_path, - service, - 'applicationservice.yml') - with open(applicationservice_description_path, 'r') as applicationservice_yml: - applicationservice_description = load(applicationservice_yml, - Loader=SafeLoader) - except Exception as err: - if get_config().get('global').get('debug'): - print_exc() - raise ExecutionError(_(f'Error while reading {applicationservice_description_path}: {err}')) - try: - await self._applicationservice_create(risotto_context, - applicationservice_description['name'], - applicationservice_description['description'], - [], - release_id) - except Exception as err: - if get_config().get('global').get('debug'): - print_exc() - raise ExecutionError(_(f"Error while injecting application service {applicationservice_description['name']} in database: {err}")) - return {'retcode': 0, - 'returns': _('Application Services successfully loaded')} - - @register('v1.setting.applicationservice.get_by_id') - async def applicationservice_get_by_id(self, - risotto_context: Context, - applicationservice_id: int) -> Dict: - return await self._applicationservice_get_by_id(risotto_context, - applicationservice_id) - - async def _applicationservice_get_by_id(self, - risotto_context: Context, - applicationservice_id: int) -> Dict: - applicationservice_query = """ - SELECT ApplicationserviceId as applicationservice_id, ApplicationserviceName as applicationservice_name, ApplicationserviceReleaseId as applicationservice_release_id - FROM applicationservice - WHERE ApplicationserviceId=$1""" - applicationservice = await risotto_context.connection.fetchrow(applicationservice_query, - applicationservice_id) - if applicationservice is None: - raise Exception(_(f'unknown service with ID {applicationservice_id}')) - dependencies = list(await self.get_dependencies(risotto_context, - applicationservice['applicationservice_id'])) - applicationservice = dict(applicationservice) - applicationservice['applicationservice_dependencies'] = dependencies - return applicationservice - - async def _applicationservice_describe(self, - risotto_context: Context, - applicationservice_name, - release_id): - applicationservice_query = """ - SELECT ApplicationserviceId as applicationservice_id, ApplicationserviceName as applicationservice_name, ApplicationserviceReleaseId as applicationservice_release_id - FROM Applicationservice - WHERE ApplicationserviceName=$1 AND ApplicationserviceReleaseId=$2""" - applicationservice = await risotto_context.connection.fetchrow(applicationservice_query, - applicationservice_name, - release_id) - if applicationservice is None: - raise Exception(_(f'unknown service {applicationservice_name} in release ID {release_id}')) - return dict(applicationservice) - - - @register('v1.setting.applicationservice.describe') - async def applicationservice_describe(self, - risotto_context: Context, - applicationservice_name, - source_name, - release_distribution): - release = await self.call('v1.setting.source.release.describe', - risotto_context, - source_name=source_name, - release_distribution=release_distribution) - applicationservice = await self._applicationservice_describe(risotto_context, - applicationservice_name, - release['release_id']) - dependencies = list(await self.get_dependencies(risotto_context, - applicationservice['applicationservice_id'])) - applicationservice['applicationservice_dependencies'] = dependencies - return applicationservice diff --git a/src/risotto/services/config/__init__.py b/src/risotto/services/config/__init__.py deleted file mode 100644 index 39ba47e..0000000 --- a/src/risotto/services/config/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .config import Risotto diff --git a/src/risotto/services/config/config.py b/src/risotto/services/config/config.py deleted file mode 100644 index e620768..0000000 --- a/src/risotto/services/config/config.py +++ /dev/null @@ -1,428 +0,0 @@ -from lxml.etree import parse -from io import BytesIO -from os import unlink -from os.path import isdir, isfile, join -from traceback import print_exc -from typing import Dict, List - -from tiramisu import Storage, MixConfig -from tiramisu.error import PropertiesOptionError -from rougail import load as rougail_load -from rougail.config import dtdfilename - -from ...controller import Controller -from ...register import register -from ...config import get_config -from ...context import Context -from ...utils import _ -from ...error import CallError, RegistrationError -from ...logger import log - - -class Risotto(Controller): - - def __init__(self, - test) -> None: - global conf_storage - self.cache_root_path = join(get_config().get('cache').get('root_path'), 'servermodel') - if not isdir(self.cache_root_path): - raise RegistrationError(_(f'unable to find the cache dir "{self.cache_root_path}"')) - if not test: - db_conf = get_config()['database']['tiramisu_dsn'] - self.save_storage = Storage(engine='postgres') - self.save_storage.setting(dsn=db_conf) - self.servermodel = {} - self.server = {} - super().__init__(test) - - async def on_join(self, - risotto_context: Context) -> None: - """ pre-load servermodel and server - """ - await self.load_servermodels(risotto_context) - await self.load_servers(risotto_context) - - async def load_servermodels(self, - risotto_context: Context) -> None: - """ load all available servermodels - """ - await log.info_msg(risotto_context, - None, - 'Load servermodels') - servermodels = await self.call('v1.setting.servermodel.list', - risotto_context) - - # load each servermodels - for servermodel in servermodels: - try: - await self.load_servermodel(risotto_context, - servermodel['servermodel_id'], - servermodel['servermodel_name']) - except CallError as err: - pass - - # do link to this servermodel - for servermodel in servermodels: - if 'servermodel_parents_id' in servermodel: - for servermodelparentid in servermodel['servermodel_parents_id']: - await self.servermodel_legacy(risotto_context, - servermodel['servermodel_name'], - servermodel['servermodel_id'], - servermodelparentid) - - def get_funcs_filename(self, - servermodel_id: int): - return join(self.cache_root_path, str(servermodel_id), "funcs.py") - - async def load_servermodel(self, - risotto_context: Context, - servermodel_id: int, - servermodel_name: str) -> None: - """ Loads a servermodel - """ - cache_file = join(self.cache_root_path, str(servermodel_id), "dictionaries.xml") - funcs_file = self.get_funcs_filename(servermodel_id) - await log.info_msg(risotto_context, - None, - f'Load servermodel {servermodel_name} ({servermodel_id})') - - # use file in cache - with open(cache_file) as fileio: - xmlroot = parse(fileio).getroot() - try: - self.servermodel[servermodel_id] = await self.build_mixconfig(servermodel_id, - servermodel_name, - xmlroot, - funcs_file) - except Exception as err: - if get_config().get('global').get('debug'): - print_exc() - msg = _(f'unable to load {servermodel_name}: {err}') - await log.error_msg(risotto_context, - None, - msg) - - async def build_mixconfig(self, - servermodel_id: int, - servermodel_name: str, - xmlroot: str, - funcs_file: str) -> MixConfig: - """ Build mixconfig for a servermodel - """ - # build tiramisu's session ID - session_id = f'v_{servermodel_id}' - optiondescription = rougail_load(xmlroot, - dtdfilename, - funcs_file) - - # build servermodel mixconfig (v_xxx) - mixconfig = await MixConfig(children=[], - optiondescription=optiondescription, - session_id=session_id, - storage=self.save_storage) - # change default rights - ro_origin = await mixconfig.property.getdefault('read_only', 'append') - ro_append = frozenset(ro_origin - {'force_store_value'}) - rw_origin = await mixconfig.property.getdefault('read_write', 'append') - rw_append = frozenset(rw_origin - {'force_store_value'}) - await mixconfig.property.setdefault(ro_append, 'read_only', 'append') - await mixconfig.property.setdefault(rw_append, 'read_write', 'append') - - await mixconfig.property.read_only() - await mixconfig.permissive.add('basic') - await mixconfig.permissive.add('normal') - await mixconfig.permissive.add('expert') - - # set informtion and owner - await mixconfig.owner.set('v_{}'.format(servermodel_name)) - await mixconfig.information.set('servermodel_id', servermodel_id) - await mixconfig.information.set('servermodel_name', servermodel_name) - - # return configuration - return mixconfig - - async def servermodel_legacy(self, - risotto_context: Context, - servermodel_name: str, - servermodel_id: int, - servermodel_parent_id: int) -> None: - """ Make link between parent and children - """ - if servermodel_parent_id is None: - return - if not self.servermodel.get(servermodel_parent_id): - msg = _(f'Servermodel with id {servermodel_parent_id} not loaded, skipping legacy for servermodel {servermodel_name} ({servermodel_id})') - await log.error_msg(risotto_context, - None, - msg) - return - servermodel_parent = self.servermodel[servermodel_parent_id] - servermodel_parent_name = await servermodel_parent.information.get('servermodel_name') - msg = _(f'Create legacy of servermodel {servermodel_name} ({servermodel_id}) with parent {servermodel_parent_name} ({servermodel_parent_id})') - await log.info_msg(risotto_context, - None, - msg) - - # do link - try: - await servermodel_parent.config.add(self.servermodel[servermodel_id]) - except Exception as err: - await log.error_msg(risotto_context, - None, - str(err)) - - async def load_servers(self, - risotto_context: Context) -> None: - """ load all available servers - """ - await log.info_msg(risotto_context, - None, - f'Load servers') - # get all servers - servers = await self.call('v1.setting.server.list', - risotto_context) - # loads servers - for server in servers: - try: - if server['server_id'] in self.server: - return - await self.load_server(risotto_context, - server['server_id'], - server['server_name'], - server['server_servermodel_id']) - except Exception as err: - if get_config().get('global').get('debug'): - print_exc() - server_name = server['server_name'] - server_id = server['server_id'] - msg = _(f'unable to load server {server_name} ({server_id}): {err}') - await log.error_msg(risotto_context, - None, - msg) - - async def load_server(self, - risotto_context: Context, - server_id: int, - server_name: str, - server_servermodel_id: int) -> None: - """ Loads a server - """ - await log.info_msg(risotto_context, - None, - f'Load server {server_name} ({server_id})') - if not server_servermodel_id in self.servermodel: - msg = f'unable to find servermodel with id {server_servermodel_id}' - await log.error_msg(risotto_context, - None, - msg) - raise CallError(msg) - - # check if server was already created - session_id = f's_{server_id}' - - # get the servermodel's mixconfig - mixconfig = self.servermodel[server_servermodel_id] - - # create server configuration and store it - self.server[server_id] = {'server': await self.build_config(session_id, - server_id, - server_name, - mixconfig), - 'server_to_deploy': await self.build_config(f'std_{server_id}', - server_id, - server_name, - mixconfig, - std=True), - 'funcs_file': self.get_funcs_filename(server_servermodel_id)} - - async def build_config(self, - session_id: str, - server_id: int, - server_name: str, - mixconfig: MixConfig, - std: bool=False) -> None: - """ build server's config - """ - config = await mixconfig.config.new(session_id, - storage=self.save_storage) - await config.information.set('server_id', server_id) - await config.information.set('server_name', server_name) - option_value = config.option('creole.interface_0.domain_name_eth0').value - if std: - try: - await option_value.get() - except PropertiesOptionError: - await config.owner.set(server_name) - await config.property.read_write() - await config.option('creole.interface_0.domain_name_eth0').value.set(server_name) - await config.property.read_only() - return config - - @register('v1.setting.server.created') - async def server_created(self, - risotto_context: Context, - server_id: int, - server_name: str, - server_servermodel_id: int) -> None: - """ Loads server's configuration when a new server is created - """ - if server_id in self.server: - return - await self.load_server(risotto_context, - server_id, - server_name, - server_servermodel_id) - - @register('v1.setting.server.deleted') - async def server_deleted(self, - server_id: int) -> None: - for server_type in ['server', 'server_to_deploy']: - config = self.server[server_id]['server'] - for parent in await config.config.parents(): - await parent.config.pop(await config.config.name()) - await config.session.reset() - del self.server[server_id] - - @register('v1.setting.servermodel.created') - async def servermodel_created(self, - risotto_context: Context, - servermodel_id: int, - servermodel_name: str, - servermodel_parents_id: List[int]) -> None: - """ when servermodels are created, load it and do link - """ - await self.load_and_link_servermodel(risotto_context, - servermodel_id, - servermodel_name, - servermodel_parents_id) - - - async def load_and_link_servermodel(self, - risotto_context: Context, - servermodel_id: int, - servermodel_name: str, - servermodel_parents_id: List[int]) -> None: - await self.load_servermodel(risotto_context, - servermodel_id, - servermodel_name) - if servermodel_parents_id is not None: - for servermodelparentid in servermodel_parents_id: - await self.servermodel_legacy(risotto_context, - servermodel_name, - servermodel_id, - servermodelparentid) - - async def servermodel_delete(self, - servermodel_id: int) -> List[MixConfig]: - mixconfig = self.servermodel.pop(servermodel_id) - children = [] - for child in await mixconfig.config.list(): - if not (await child.session.id()).startswith('std_'): - children.append(child) - await mixconfig.config.pop(await child.session.id()) - for parent in await mixconfig.config.parents(): - await parent.config.pop(await mixconfig.session.id()) - return children - - @register('v1.setting.servermodel.updated') - async def servermodel_updated(self, - risotto_context: Context, - servermodel_id: int, - servermodel_name: str, - servermodel_parents_id: List[int]) -> None: - await log.info_msg(risotto_context, - None, - f'Reload servermodel {servermodel_name} ({servermodel_id})') - # store all informations - if servermodel_id in self.servermodel: - children = await self.servermodel_delete(servermodel_id) - else: - children = [] - - # create new one - await self.load_and_link_servermodel(risotto_context, - servermodel_id, - servermodel_name, - servermodel_parents_id) - # recreate link to children - for child in children: - if await child.config.type() == 'config': - server_id = await child.information.get('server_id') - server_name = await child.information.get('server_name') - await self.load_server(risotto_context, - server_id, - server_name, - servermodel_id) - else: - await self.servermodel[servermodel_id].config.add(child) - - @register('v1.setting.config.configuration.server.get') - async def get_configuration(self, - risotto_context: Context, - server_name: str, - deployed: bool) -> dict: - server = await self.call('v1.setting.server.describe', - risotto_context, - server_name=server_name) - server_id = server['server_id'] - if server_id not in self.server: - msg = _(f'cannot find server with id {server_id}') - await log.error_msg(risotto_context, - None, - msg) - raise CallError(msg) - - if deployed: - server = self.server[server_id]['server'] - else: - server = self.server[server_id]['server_to_deploy'] - - await server.property.read_only() - try: - configuration = await server.value.dict(fullpath=True, - leader_to_list=True) - except: - if deployed: - msg = _(f'No configuration available for server {server_id}') - else: - msg = _(f'No undeployed configuration available for server {server_id}') - await log.error_msg(risotto_context, - None, - msg) - raise CallError(msg) - return {'server_name': server_name, - 'deployed': deployed, - 'configuration': configuration} - - @register('v1.setting.config.configuration.server.deploy') - async def deploy_configuration(self, - risotto_context: Context, - server_name: str) -> Dict: - """Copy values, permissions, permissives from config 'to deploy' to active config - """ - server = await self.call('v1.setting.server.describe', - risotto_context, - server_name=server_name) - server_id = server['server_id'] - # FIXME is server_to_deploy working? - config = self.server[server_id]['server'] - config_std = self.server[server_id]['server_to_deploy'] - - # when deploy, calculate force_store_value - ro = await config_std.property.getdefault('read_only', 'append') - if 'force_store_value' not in ro: - ro = frozenset(list(ro) + ['force_store_value']) - await config_std.property.setdefault(ro, 'read_only', 'append') - rw = await config_std.property.getdefault('read_write', 'append') - rw = frozenset(list(rw) + ['force_store_value']) - await config_std.property.setdefault(rw, 'read_write', 'append') - await config_std.property.add('force_store_value') - - # copy informations from server 'to deploy' configuration to server configuration - await config.value.importation(await config_std.value.exportation()) - await config.permissive.importation(await config_std.permissive.exportation()) - await config.property.importation(await config_std.property.exportation()) - - return {'server_id': server_id, - 'server_name': server_name, - 'deployed': True} diff --git a/src/risotto/services/server/__init__.py b/src/risotto/services/server/__init__.py deleted file mode 100644 index 3e60340..0000000 --- a/src/risotto/services/server/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .server import Risotto diff --git a/src/risotto/services/server/server.py b/src/risotto/services/server/server.py deleted file mode 100644 index 5249655..0000000 --- a/src/risotto/services/server/server.py +++ /dev/null @@ -1,71 +0,0 @@ -from typing import Dict -from tiramisu import DomainnameOption - -from ...controller import Controller -from ...register import register -from ...context import Context -from ...config import get_config -from ...utils import _ - - -class Risotto(Controller): - def __init__(self, - test: bool) -> None: - self.internal_source_name = get_config()['servermodel']['internal_source'] - - @register('v1.setting.server.list') - 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 - ''' - servers = await risotto_context.connection.fetch(sql) - return [dict(r) for r in servers] - - @register('v1.setting.server.create', 'v1.setting.server.created') - async def server_create(self, - risotto_context: Context, - server_name: str, - server_description: str, - servermodel_name: str, - release_distribution: str) -> Dict: - DomainnameOption('server_name', _('Server name'), server_name) - servermodel = await self.call('v1.setting.servermodel.describe', - risotto_context, - servermodel_name=servermodel_name, - source_name=self.internal_source_name, - release_distribution=release_distribution) - server_insert = """INSERT INTO Server(ServerName, ServerDescription, ServerServermodelId) - VALUES ($1,$2,$3) - RETURNING ServerId - """ - server_id = await risotto_context.connection.fetchval(server_insert, - server_name, - server_description, - servermodel['servermodel_id']) - await self.call('v1.setting.user.role.create', - risotto_context, - user_login=risotto_context.username, - role_name='server_rw', - role_attribute='Server.ServerName', - role_attribute_value=server_name) - return {'server_id': server_id, - 'server_name': server_name, - 'server_description': server_description, - 'server_servermodel_id': servermodel['servermodel_id']} - - @register('v1.setting.server.describe') - async def server_describe(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/__init__.py b/src/risotto/services/servermodel/__init__.py deleted file mode 100644 index 058fd52..0000000 --- a/src/risotto/services/servermodel/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .servermodel import Risotto diff --git a/src/risotto/services/servermodel/generator.py b/src/risotto/services/servermodel/generator.py deleted file mode 100644 index 14880a1..0000000 --- a/src/risotto/services/servermodel/generator.py +++ /dev/null @@ -1,172 +0,0 @@ -from os.path import join, isdir, isfile -from os import listdir, makedirs -from shutil import rmtree, copyfile -from typing import Dict, List, Optional -from rougail import CreoleObjSpace -from rougail.config import dtdfilename -from ...controller import Controller -from ...context import Context -from ...logger import log -from ...utils import _ - - -class Generator(Controller): - async def generate(self, - risotto_context: Context, - servermodel_name: str, - servermodel_id: int, - dependencies: List[int], - generate_cache: Optional[Dict]=None) -> None: - if generate_cache is None: - generate_cache = {'applicationservice': {}, - 'release_id': {}} - await self.servermodel_gen_funcs(servermodel_name, - servermodel_id, - dependencies, - generate_cache, - risotto_context) - await self.servermodel_gen_schema(servermodel_name, - servermodel_id, - dependencies, - generate_cache, - risotto_context) - await self.servermodel_copy_templates(servermodel_name, - servermodel_id, - dependencies, - generate_cache, - risotto_context) - - async def servermodel_gen_funcs(self, - servermodel_name: str, - servermodel_id: int, - dependencies: Dict, - generate_cache: Dict, - risotto_context: Context) -> None: - as_names = [] - dest_file = self.get_servermodel_cache(servermodel_id, 'funcs.py') - with open(dest_file, 'wb') as funcs: - funcs.write(b'from tiramisu import valid_network_netmask, valid_ip_netmask, valid_broadcast, valid_in_network, valid_not_equal as valid_differ, valid_not_equal, calc_value\n\n') - for dependency in dependencies: - if dependency not in generate_cache['applicationservice']: - applicationservice = await self.call('v1.setting.applicationservice.get_by_id', - risotto_context, - applicationservice_id=dependency) - generate_cache['applicationservice'][dependency] = (applicationservice['applicationservice_name'], - applicationservice['applicationservice_release_id']) - applicationservice_name, release_id = generate_cache['applicationservice'][dependency] - if release_id not in generate_cache['release_id']: - release = await self.call('v1.setting.source.release.get_by_id', - risotto_context, - release_id=release_id) - generate_cache['release_id'][release_id] = (release['source_name'], - release['release_name']) - source_name, release_name = generate_cache['release_id'][release_id] - path = join(self.source_root_path, - source_name, - release_name, - 'applicationservice', - applicationservice_name, - 'funcs') - if isdir(path): - as_names.append(applicationservice_name) - for fil in listdir(path): - if not fil.endswith('.py'): - continue - fil_path = join(path, fil) - with open(fil_path, 'rb') as fh: - funcs.write(f'# {fil_path}\n'.encode()) - funcs.write(fh.read()) - funcs.write(b'\n') - - as_names_str = '", "'.join(as_names) - await log.info(risotto_context, - _(f'gen funcs for "{servermodel_name}" with application services "{as_names_str}"')) - - async def servermodel_gen_schema(self, - servermodel_name: str, - servermodel_id: int, - dependencies: Dict, - generate_cache: Dict, - risotto_context: Context) -> None: - paths = [] - extras = [] - as_names = set() - for dependency in dependencies: - applicationservice_name, release_id = generate_cache['applicationservice'][dependency] - source_name, release_name = generate_cache['release_id'][release_id] - # load creole dictionaries - path = join(self.source_root_path, - source_name, - release_name, - 'applicationservice', - applicationservice_name, - 'dictionaries') - if isdir(path): - as_names.add(applicationservice_name) - paths.append(path) - - # load extra dictionaries - path = join(self.source_root_path, - source_name, - release_name, - 'applicationservice', - applicationservice_name, - 'extras') - if isdir(path): - for namespace in listdir(path): - extra_dir = join(path, namespace) - if not isdir(extra_dir): - continue - as_names.add(applicationservice_name) - extras.append((namespace, [extra_dir])) - eolobj = CreoleObjSpace(dtdfilename) - as_names_str = '", "'.join(as_names) - await log.info(risotto_context, - _(f'gen schema for "{servermodel_name}" with application services "{as_names_str}"')) - eolobj.create_or_populate_from_xml('creole', paths) - for extra in extras: - eolobj.create_or_populate_from_xml(extra[0], extra[1]) - # FIXME extra - 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)) - - async def servermodel_copy_templates(self, - servermodel_name: str, - servermodel_id: int, - dependencies: Dict, - generate_cache: Dict, - risotto_context: Context) -> None: - as_names = [] - dest_dir = self.get_servermodel_cache(servermodel_id, 'templates') - if isdir(dest_dir): - rmtree(dest_dir) - makedirs(dest_dir) - for dependency in dependencies: - applicationservice_name, release_id = generate_cache['applicationservice'][dependency] - source_name, release_name = generate_cache['release_id'][release_id] - path = join(self.source_root_path, - source_name, - 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) - await log.info(risotto_context, - _(f'copy templates for "{servermodel_name}" with application services "{as_names_str}"')) diff --git a/src/risotto/services/servermodel/servermodel.py b/src/risotto/services/servermodel/servermodel.py deleted file mode 100644 index 9876c31..0000000 --- a/src/risotto/services/servermodel/servermodel.py +++ /dev/null @@ -1,292 +0,0 @@ -from shutil import rmtree -from os import listdir, makedirs -from os.path import join, isdir -from yaml import load, SafeLoader -from traceback import print_exc -from typing import Dict, List, Optional -from .generator import Generator -from ...register import register -from ...utils import _ -from ...context import Context -from ...config import get_config -from ...error import ExecutionError -from ...logger import log - - -class Risotto(Generator): - def __init__(self, - test: bool) -> None: - self.source_root_path = get_config()['source']['root_path'] - self.cache_root_path = join(get_config()['cache']['root_path'], 'servermodel') - self.internal_source_name = get_config()['servermodel']['internal_source'] - self.internal_distribution_name = get_config()['servermodel']['internal_distribution'] - self.internal_release_name = get_config()['servermodel']['internal_release_name'] - if not isdir(self.cache_root_path): - makedirs(join(self.cache_root_path)) - super().__init__(test) - - async def on_join(self, - risotto_context: Context) -> None: - print('===', await self.call('v1.pki.openssh.get', risotto_context)) - internal_release = await self.call('v1.setting.source.release.describe', - risotto_context, - source_name=self.internal_source_name, - release_distribution=self.internal_distribution_name) - self.internal_release_id = internal_release['release_id'] - - async def _servermodel_create(self, - risotto_context: Context, - servermodel_name: str, - servermodel_description: str, - servermodel_parents: List[Dict], - dependencies: List[int], - release_id: int, - generate_cache: Dict=None) -> Dict: - if generate_cache is None: - generate_cache = {'applicationservice': {}, - 'release_id': {}} - servermodel_insert = """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}' - servermodel_parents_id = [] - for servermodel_parent in servermodel_parents: - servermodel_parents_id.append(servermodel_parent['servermodel_id']) - dependencies.append(servermodel_parent['servermodel_applicationservice_id']) - applicationservice = await self.call('v1.setting.applicationservice.create', - risotto_context, - applicationservice_name=as_name, - applicationservice_description=as_description, - applicationservice_dependencies=dependencies) - applicationservice_id = applicationservice['applicationservice_id'] - generate_cache['applicationservice'][applicationservice_id] = (as_name, - self.internal_release_id) - if self.internal_release_id not in generate_cache['release_id']: - generate_cache['release_id'][self.internal_release_id] = (self.internal_source_name, - self.internal_release_name) - - servermodel_id = await risotto_context.connection.fetchval(servermodel_insert, - servermodel_name, - servermodel_description, - servermodel_parents_id, - release_id, - applicationservice_id) - dest_dir = self.get_servermodel_cache(servermodel_id) - if isdir(dest_dir): - rmtree(dest_dir) - makedirs(dest_dir) - dependencies = applicationservice['applicationservice_dependencies'] - # for as_release_id in dependencies.values(): - # applicationservice_name, as_release_id = applicationservice_infos - # if as_release_id not in release_cache: - # release_cache[as_release_id] = await self.call('v1.setting.source.release.get_by_id', - # risotto_context, - # release_id=as_release_id) - await self.generate(risotto_context, - servermodel_name, - servermodel_id, - dependencies, - generate_cache) - sm_dict = {'servermodel_name': servermodel_name, - 'servermodel_description': servermodel_description, - 'servermodel_parents_id': servermodel_parents_id, - 'servermodel_applicationservice_id': applicationservice_id, - 'release_id': release_id, - 'servermodel_id': servermodel_id} - return sm_dict - - def parse_parents(self, - servermodels: Dict, - servermodel: Dict, - parents: List=None) -> List: - if parents is None: - parents = [servermodel['name']] - parent = servermodel['parent'] - if parent in servermodels: - parents.append(parent) - self.parse_parents(servermodels, servermodels[parent], parents) - return parents - - @register('v1.setting.applicationservice.updated') - async def applicationservice_updated(self, - risotto_context: Context, - applicationservice_id): - # FIXME applicationservices qui depend de ce services => updated - sql = ''' - SELECT ServermodelId as servermodel_id, ServermodelName as servermodel_name, ServermodelDescription as servermodel_description, ServermodelParentsId as servermodel_parents_id, ServermodelReleaseId as release_id, ServermodelApplicationServiceId as servermodel_applicationservice_id - FROM Servermodel - WHERE ServermodelApplicationServiceId = $1 - ''' - servermodel = await risotto_context.connection.fetchrow(sql, - applicationservice_id) - if servermodel is not None: - servermodel_name = servermodel['servermodel_name'] - servermodel_id = servermodel['servermodel_id'] - release_id = servermodel['release_id'] - applicationservice = await self.call('v1.setting.applicationservice.get_by_id', - risotto_context, - applicationservice_id=applicationservice_id) - dependencies = applicationservice['applicationservice_dependencies'] - await self.generate(risotto_context, - servermodel_name, - servermodel_id, - dependencies, - None) - await self.publish('v1.setting.servermodel.updated', - risotto_context, - **servermodel) - - @register('v1.setting.servermodel.dataset.updated') - async def servermodel_dataset_updated(self, - risotto_context: Context, - source_name: str, - release_distribution: int): - release = await self.call('v1.setting.source.release.describe', - risotto_context, - source_name=source_name, - release_distribution=release_distribution) - release_id = release['release_id'] - generate_cache = {'applicationservice': {}, - 'release_id': {release['release_id']: (release['source_name'], - release['release_name'])}} - servermodel_path = join(self.source_root_path, - source_name, - release['release_name'], - 'servermodel') - servermodels = {} - for servermodel in listdir(servermodel_path): - if not servermodel.endswith('.yml'): - continue - servermodel_description_path = join(servermodel_path, servermodel) - try: - with open(servermodel_description_path, 'r') as servermodel_yml: - servermodel_description = load(servermodel_yml, - Loader=SafeLoader) - except Exception as err: - if get_config().get('global').get('debug'): - print_exc() - raise ExecutionError(_(f'Error while reading {servermodel_description_path}: {err}')) - servermodels[servermodel_description['name']] = servermodel_description - servermodels[servermodel_description['name']]['done'] = False - - for servermodel in servermodels.values(): - if not servermodel['done']: - # parent needs to create before child, so retrieve all parents - parents = self.parse_parents(servermodels, - servermodel) - parents.reverse() - servermodel_parent = [] - for new_servermodel in parents: - if not servermodels[new_servermodel]['done']: - servermodel_description = servermodels[new_servermodel] - parent = servermodel_description['parent'] - if not servermodel_parent and parent is not None: - servermodel_parent = [await self._servermodel_describe(risotto_context, - parent, - release_id, - source_name, - release_distribution)] - # link application service with this servermodel - dependencies = [] - for depend in servermodels[new_servermodel]['applicationservices']: - applicationservice = await self.call('v1.setting.applicationservice.describe', - risotto_context, - applicationservice_name=depend, - source_name=source_name, - release_distribution=release_distribution) - dependencies.append(applicationservice['applicationservice_id']) - sm_name = servermodel_description['name'] - sm_description = servermodel_description['description'] - try: - servermodel_ob = await self._servermodel_create(risotto_context, - sm_name, - sm_description, - servermodel_parent, - dependencies, - release_id, - generate_cache) - await self.publish('v1.setting.servermodel.created', - risotto_context, - **servermodel_ob) - 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}")) - servermodel_parent = [servermodel_ob] - servermodel_description['done'] = True - return {'retcode': 0, 'returns': _('Servermodels successfully loaded')} - - @register('v1.setting.servermodel.list') - async def servermodel_list(self, - risotto_context: Context, - source_id: int): - sql = ''' - SELECT ServermodelId as servermodel_id, ServermodelName as servermodel_name, ServermodelDescription as servermodel_description, ServermodelParentsId as servermodel_parents_id, ServermodelReleaseId as release_id, ServermodelApplicationServiceId as servermodel_applicationservice_id - FROM Servermodel - ''' - servermodels = await risotto_context.connection.fetch(sql) - return [dict(r) for r in servermodels] - - @register('v1.setting.servermodel.describe') - async def servermodel_describe(self, - risotto_context: Context, - servermodel_name, - source_name, - release_distribution) -> Dict: - release = await self.call('v1.setting.source.release.describe', - risotto_context, - source_name=source_name, - release_distribution=release_distribution) - return await self._servermodel_describe(risotto_context, - servermodel_name, - release['release_id'], - source_name, - release_distribution) - - async def _servermodel_describe(self, - risotto_context, - servermodel_name, - release_id, - source_name, - release_distribution): - sql = ''' - SELECT ServermodelId as servermodel_id, ServermodelName as servermodel_name, ServermodelDescription as servermodel_description, ServermodelParentsId as servermodel_parents_id, ServermodelReleaseId as release_id, ServermodelApplicationServiceId as servermodel_applicationservice_id - FROM Servermodel - WHERE ServermodelName=$1 AND ServermodelReleaseId=$2 - ''' - servermodel = await risotto_context.connection.fetchrow(sql, - servermodel_name, - release_id) - if not servermodel: - raise Exception(_(f'"{servermodel_name}" is not a valid name for a servermodel in source "{source_name}" and release "{release_distribution}"')) - return dict(servermodel) - - @register('v1.setting.servermodel.create', notification='v1.setting.servermodel.created') - async def create_servermodel(self, - risotto_context: Context, - servermodel_name: str, - servermodel_description: str, - servermodel_parents_name: List[int], - servermodel_parents_source_name: str, - servermodel_parents_release_distribution: str) -> Dict: - release = await self.call('v1.setting.source.release.describe', - risotto_context, - source_name=servermodel_parents_source_name, - release_distribution=servermodel_parents_release_distribution) - release_id = release['release_id'] - servermodel_parents = [] - for servermodel_parent_name in servermodel_parents_name: - servermodel_parents.append(await self._servermodel_describe(risotto_context, - servermodel_parent_name, - release_id, - servermodel_parents_source_name, - servermodel_parents_release_distribution)) - return await self._servermodel_create(risotto_context, - servermodel_name, - servermodel_description, - servermodel_parents, - [], - self.internal_release_id, - None) diff --git a/src/risotto/services/session/__init__.py b/src/risotto/services/session/__init__.py deleted file mode 100644 index c9d4b3d..0000000 --- a/src/risotto/services/session/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .session import Risotto diff --git a/src/risotto/services/session/session.py b/src/risotto/services/session/session.py deleted file mode 100644 index 788591f..0000000 --- a/src/risotto/services/session/session.py +++ /dev/null @@ -1,316 +0,0 @@ -from os import urandom # , unlink -from binascii import hexlify -from traceback import print_exc -from typing import Dict, List, Optional, Any -from tiramisu import Storage - - -from ...http import register as register_http -from ...context import Context -from ...utils import _ -from .storage import storage_server, storage_servermodel -from ...controller import Controller -from ...register import register -from ...dispatcher import dispatcher -from ...config import get_config - - -class Risotto(Controller): - def __init__(self, - test): - self.modify_storage = Storage(engine='dictionary') - self.internal_source_name = get_config()['servermodel']['internal_source'] - self.internal_distribution_name = get_config()['servermodel']['internal_distribution'] - - def get_storage(self, - type: str): - if type == 'server': - return storage_server - return storage_servermodel - - def get_session(self, - risotto_context: Context, - session_id: str, - type: str) -> Dict: - """ Get session information from storage - """ - if type == 'server': - storage = storage_server - else: - storage = storage_servermodel - return storage.get_session(session_id, - risotto_context.username) - - def get_session_informations(self, - risotto_context: Context, - session_id: str, - type: str) -> Dict: - """ format session with a session ID name - """ - session = self.get_session(risotto_context, - session_id, - type) - return self.format_session(session_id, - session) - - def format_session(self, - session_name: str, - session: Dict) -> Dict: - """ format session - """ - return {'session_id': session_name, - 'id': session['id'], - 'username': session['username'], - 'timestamp': session['timestamp'], - 'namespace': session['namespace'], - 'mode': session['mode'], - 'debug': session['debug']} - - @register('v1.setting.session.server.start') - async def start_session_server(self, - risotto_context: Context, - server_name: str) -> Dict: - """ start a new config session for a server - """ - config_module = dispatcher.get_service('config') - server = await self.call('v1.setting.server.describe', - risotto_context, - server_name=server_name) - if not server or server['server_id'] not in config_module.server: - raise Exception(_(f'cannot find server with name {server_name}')) - id = server['server_id'] - config = config_module.server[id]['server_to_deploy'] - - storage = self.get_storage('server') - - # check if a session already exists - sessions = storage.get_sessions() - for sess_id, session in sessions.items(): - if session['id'] == id: - if session['username'] == risotto_context.username: - # same user so returns it - return self.format_session(sess_id, - session) - else: - raise Exception(_(f'{username} already edits this configuration')) - - # create a new session - while True: - session_id = 'z' + hexlify(urandom(23)).decode() - if not session_id in sessions: - break - await storage.add_session(session_id, - config, - id, - risotto_context.username, - self.modify_storage) - - # return session's information - return self.get_session_informations(risotto_context, - session_id, - 'server') - - @register('v1.setting.session.servermodel.start') - async def start_session_servermodel(self, - risotto_context: Context, - servermodel_name: str) -> Dict: - """ start a new config session for a server or a servermodel - """ - config_module = dispatcher.get_service('config') - servermodel = await self.call('v1.setting.servermodel.describe', - risotto_context, - servermodel_name=servermodel_name, - source_name=self.internal_source_name, - release_distribution=self.internal_distribution_name) - if not servermodel or servermodel['servermodel_id'] not in config_module.servermodel: - raise Exception(_(f'cannot find servermodel with name {servermodel_name}')) - id = servermodel['servermodel_id'] - config = config_module.servermodel[id] - - storage = self.get_storage('servermodel') - - # check if a session already exists - sessions = storage.get_sessions() - for sess_id, session in sessions.items(): - if session['id'] == id: - if session['username'] == risotto_context.username: - # same user so returns it - return self.format_session(sess_id, - session) - else: - raise Exception(_(f'{username} already edits this configuration')) - - # create a new session - while True: - session_id = 'z' + hexlify(urandom(23)).decode() - if not session_id in sessions: - break - await storage.add_session(session_id, - config, - id, - risotto_context.username, - self.modify_storage) - - # return session's information - return self.get_session_informations(risotto_context, - session_id, - 'servermodel') - - @register(['v1.setting.session.server.list', 'v1.setting.session.servermodel.list']) - async def list_session_server(self, - risotto_context: Context) -> Dict: - type = risotto_context.message.rsplit('.', 2)[-2] - storage = self.get_storage(type) - return [self.format_session(session_id, session) for session_id, session in storage.get_sessions().items()] - - - @register(['v1.setting.session.server.filter', 'v1.setting.session.servermodel.filter']) - async def filter_session(self, - risotto_context: Context, - session_id: str, - namespace: str, - mode: str, - debug: Optional[bool]): - type = risotto_context.message.rsplit('.', 2)[-2] - storage = self.get_storage(type) - # to validate the session right - storage.get_session(session_id, - risotto_context.username) - if namespace is not None: - storage.set_namespace(session_id, - namespace) - if mode is not None: - if mode not in ('basic', 'normal', 'expert'): - raise Exception(f'unknown mode {mode}') - await storage.set_config_mode(session_id, - mode) - if debug is not None: - await storage.set_config_debug(session_id, - debug) - return self.get_session_informations(risotto_context, - session_id, - type) - - @register(['v1.setting.session.server.configure', 'v1.setting.session.servermodel.configure']) - async def configure_session(self, - risotto_context: Context, - session_id: str, - action: str, - name: str, - index: int, - value: Any, - value_multi: Optional[List]) -> Dict: - type = risotto_context.message.rsplit('.', 2)[-2] - session = self.get_session(risotto_context, - session_id, - type) - # if multi and not follower the value is in fact in value_multi - # FIXME option = session['option'].option(name).option - option = session['config'].option(name).option - if await option.ismulti() and not await option.isfollower(): - value = value_multi - #FIXME namespace = session['namespace'] - #FIXME update = {'name': f'{namespace}.{name}', - update = {'name': name, - 'action': action, - 'value': value} - if index is not None: - update['index'] = index - updates = {'updates': [update]} - ret = await session['option'].updates(updates) - if update['name'] in ret: - for val in ret[update['name']][index]: - if isinstance(val, ValueError): - raise Exception(val) - ret = {'session_id': session_id, - 'name': name} - if index is not None: - ret['index'] = index - return ret - - @register(['v1.setting.session.server.validate', 'v1.setting.session.servermodel.validate']) - async def validate_session(self, - risotto_context: Context, - session_id: str) -> Dict: - type = risotto_context.message.rsplit('.', 2)[-2] - session = self.get_session(risotto_context, - session_id, - type) - try: - await session['config'].forcepermissive.option(session['namespace']).value.dict() - except Exception as err: - raise Exception(str(err)) - if type == 'server': - config = session['config'] - await config.property.read_only() - mandatories = list(await config.value.mandatory()) - await config.property.read_write() - if mandatories: - # FIXME mandatories = [mandatory.split('.', 1)[1] for mandatory in mandatories] - if len(mandatories) == 1: - mandatories = mandatories[0] - msg = _(f'the parameter "--{mandatories}" is mandatory') - else: - mandatories = '", "--'.join(mandatories) - msg = _(f'parameters "--{mandatories}" are mandatories') - raise Exception(msg) - return self.format_session(session_id, - session) - - @register(['v1.setting.session.server.get', 'v1.setting.session.servermodel.get']) - async def get_session_server(self, - risotto_context: Context, - session_id: str, - name: Optional[str]) -> Dict: - type = risotto_context.message.rsplit('.', 2)[-2] - session = self.get_session(risotto_context, - session_id, - type) - info = self.format_session(session_id, session) - if name is not None: - content = {name: await session['config'].option(name).value.get()} - else: - content = await session['option'].value.dict(fullpath=True, - leader_to_list=True) - info['content'] = content - return info - - @register(['v1.setting.session.server.stop', 'v1.setting.session.servermodel.stop']) - async def stop_session(self, - risotto_context: Context, - session_id: str, - save: bool) -> Dict: - type = risotto_context.message.rsplit('.', 2)[-2] - storage = self.get_storage(type) - session = storage.get_session(session_id, - risotto_context.username) - id_ = session['id'] - config_module = dispatcher.get_service('config') - if type == 'server': - config = config_module.server[id_]['server_to_deploy'] - else: - config = config_module.servermodel[id_] - if save: - modif_config = session['config'] - await config.value.importation(await modif_config.value.exportation()) - await config.permissive.importation(await modif_config.permissive.exportation()) - await storage.del_session(session_id) - return self.format_session(session_id, session) - - @register_http('v1', '/config/server/{session_id}') - async def get_server_api(self, - request, - risotto_context: Context, - session_id: str) -> Dict: - session = storage_server.get_session(session_id, - risotto_context.username) - return await session['option'].dict(remotable='all') - - @register_http('v1', '/config/servermodel/{session_id}') - async def get_servermodel_api(self, - request, - risotto_context: Context, - session_id: str) -> Dict: - session = storage_servermodel.get_session(session_id, - risotto_context.username) - return await session['option'].dict(remotable='all') diff --git a/src/risotto/services/session/storage.py b/src/risotto/services/session/storage.py deleted file mode 100644 index fe71432..0000000 --- a/src/risotto/services/session/storage.py +++ /dev/null @@ -1,147 +0,0 @@ -import time -from typing import Dict -from tiramisu import Config -from rougail import modes -from ...error import CallError, NotAllowedError - - -class StorageError(Exception): - pass - - -class Storage(object): - __slots__ = ('sessions',) - - def __init__(self): - self.sessions = {} - - async def add_session(self, - session_id: int, - orig_config: Config, - server_id: int, - username: str, - config_storage): - prefix_id = f'{session_id}_' - config_name = self.get_config_name(server_id) - config_id = f'{prefix_id}{config_name}' - - # copy Config and all it's parents - meta = await orig_config.config.deepcopy(session_id=config_id, - storage=config_storage, - metaconfig_prefix=prefix_id) - - # retrieve the copied config (not metaconfig) - config = meta - while True: - try: - children = list(await config.config.list()) - if not children: - # it's an empty metaconfig - break - config = children[0] - except: - # it's a config, so no "list" method - break - await config.property.read_write() - # set the default owner - await self.set_owner(config, - username) - - # store it - self.sessions[session_id] = {'config': config, - # do not delete meta, so keep it! - 'meta': meta, - 'id': server_id, - 'timestamp': int(time.time()), - 'username': username} - await self.set_config_mode(session_id, - 'normal') - await self.set_config_debug(session_id, - False) - self.set_namespace(session_id, - 'creole') - - async def set_config_mode(self, - id: int, - mode: str): - """ Define which edition mode to select - """ - config = self.sessions[id]['config'] - for mode_level in modes.values(): - if modes[mode] < mode_level: - await config.property.add(mode_level.name) - else: - await config.property.pop(mode_level.name) - self.sessions[id]['mode'] = mode - - async def set_config_debug(self, id_, is_debug): - """ Enable/Disable debug mode - """ - config = self.sessions[id_]['config'] - if is_debug: - await config.property.pop('hidden') - else: - await config.property.add('hidden') - self.sessions[id_]['debug'] = is_debug - - def set_namespace(self, - session_id: int, - namespace: str): - self.sessions[session_id]['option'] = self.sessions[session_id]['config'].option(namespace) - self.sessions[session_id]['namespace'] = namespace - - def get_sessions(self): - return self.sessions; - - def get_session(self, - session_id: int, - username: str) -> Dict: - if session_id not in self.sessions: - raise Exception(f'the session "{session_id}" not exists') - session = self.sessions[session_id] - if username != session['username']: - raise NotAllowedError() - return session - - async def del_session(self, - id: int): - config = self.sessions[id]['meta'] - while True: - try: - children = list(await config.config.list()) - if not children: - # it's an empty metaconfig - break - config = children[0] - await config.session.reset() - except: - # it's a config, so no "list" method - break - await self.sessions[id]['meta'].session.reset() - del self.sessions[id] - - -class StorageServer(Storage): - def get_config_name(self, - server_id: int): - return f'std_{server_id}' - - async def set_owner(self, - config: Config, - username: str): - await config.owner.set(username) - - -class StorageServermodel(Storage): - def get_config_name(self, - server_id: int): - return f'v_{server_id}' - - async def set_owner(self, - config: Config, - username: str): - await config.owner.set('servermodel_' + username) - - -storage_server = StorageServer() -storage_servermodel = StorageServermodel() diff --git a/src/risotto/services/source/__init__.py b/src/risotto/services/source/__init__.py deleted file mode 100644 index b72dc1c..0000000 --- a/src/risotto/services/source/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .source import Risotto diff --git a/src/risotto/services/source/source.py b/src/risotto/services/source/source.py deleted file mode 100644 index b1ae261..0000000 --- a/src/risotto/services/source/source.py +++ /dev/null @@ -1,150 +0,0 @@ -from typing import Dict, List -from ...controller import Controller -from ...register import register -from ...context import Context -import requests -import yaml -import os -from ...utils import _ -from ...config import get_config - - -class Risotto(Controller): - @register('v1.setting.source.create') - async def source_create(self, - risotto_context: Context, - source_name: str, - source_url: str) -> Dict: - source_upsert = """INSERT INTO Source(SourceName, SourceURL) VALUES ($1, $2) - ON CONFLICT (SourceName) DO UPDATE SET SourceURL = $2 - RETURNING SourceId - """ - # If given url is not 'none' (a.k.a internal source) - # Look for file releases.yml at given url - # If such a file exists, consider source a valid one and create source in database. - if source_url != 'none': - try: - releases = yaml.load(requests.get(source_url.rstrip('/') + '/releases.yml').content, Loader=yaml.SafeLoader) - except requests.exceptions.ConnectionError as err: - raise Exception(_('Invalid URL')) - except yaml.scanner.ScannerError as err: - raise Exception(_('Invalid releases.yml file')) - except: - raise Exception(_('Invalid source')) - else: - releases = {'1.0.0': {'distribution': 'last'}} - os.makedirs(os.path.join(get_config().get('source').get('root_path'), source_name), exist_ok=True) - with open(os.path.join(get_config().get('source').get('root_path'), source_name, 'releases.yml'), 'w') as release_file: - yaml.dump(releases, release_file) - source_id = await risotto_context.connection.fetchval(source_upsert, - source_name, - source_url) - return {'source_name': source_name, - 'source_url': source_url, - 'source_id': source_id} - - @register('v1.setting.source.describe') - async def source_describe(self, - risotto_context: Context, - source_name: str) -> Dict: - source_get = """SELECT SourceId as source_id, SourceName as source_name, SourceURL as source_url - FROM Source - WHERE SourceName = $1 - """ - source = await risotto_context.connection.fetchrow(source_get, - source_name) - if not source: - raise Exception(_(f'unknown source with name {source_name}')) - return dict(source) - - @register('v1.setting.source.list') - async def source_list(self, - risotto_context: Context) -> List[Dict]: - source_list = """SELECT SourceId as source_id, SourceName as source_name, SourceURL as source_url - FROM Source - """ - result = await risotto_context.connection.fetch(source_list) - return [dict(r) for r in result] - - @register('v1.setting.source.dataset.update') - async def version_update(self, - risotto_context: Context, - source_id: int, - release_name: str): - # source.release.create is an upsert, do not using it - release_insert = """INSERT INTO Release(ReleaseName, ReleaseSourceId) VALUES ($1, $2) - RETURNING ReleaseId - """ - release_id = await risotto_context.connection.fetchval(release_insert, - release_name, - source_id) - return {'release_id': release_id, - 'release_name': release_name} - - @register('v1.setting.source.release.create') - async def source_release_create(self, - risotto_context: Context, - source_name: str, - release_name: str, - release_distribution: str) -> Dict: - source_get = """SELECT SourceId as source_id, SourceName as source_name, SourceURL as source_url - FROM Source - WHERE SourceName = $1 - """ - release_upsert = """INSERT INTO Release(ReleaseName, ReleaseSourceId, ReleaseDistribution) VALUES ($1, $2, $3) - ON CONFLICT (ReleaseName, ReleaseSourceId) DO UPDATE SET ReleaseName = $1 - RETURNING ReleaseId - """ - source_obj = await risotto_context.connection.fetchrow(source_get, - source_name) - if not source_obj: - raise Exception(_(f'unable to find a source with name {source_name}')) - source = dict(source_obj) - release_id = await risotto_context.connection.fetchval(release_upsert, - release_name, - source['source_id'], - release_distribution) - del source['source_id'] - source['release_id'] = release_id - source['release_name'] = release_name - source['release_distribution'] = release_distribution - return source - - @register('v1.setting.source.release.list') - async def release_list(self, - risotto_context, - source_name: str) -> Dict: - release_query = """SELECT ReleaseId as release_id, SourceName as source_name, SourceURL as source_url, ReleaseName as release_name, ReleaseDistribution as release_distribution - FROM Release, Source - WHERE Source.SourceName=$1 AND Source.SourceId=Release.ReleaseSourceId""" - result = await risotto_context.connection.fetch(release_query, - source_name) - return [dict(r) for r in result] - - @register('v1.setting.source.release.describe') - async def release_describe(self, - risotto_context, - source_name: str, - release_distribution: str) -> Dict: - release_query = """SELECT ReleaseId as release_id, SourceName as source_name, SourceURL as source_url, ReleaseName as release_name, ReleaseDistribution as release_distribution - FROM Release, Source - WHERE Source.SourceName=$1 AND Source.SourceId=Release.ReleaseSourceId AND Release.ReleaseDistribution=$2""" - result = await risotto_context.connection.fetchrow(release_query, - source_name, - release_distribution) - if not result: - raise Exception(_(f'unknown release distribution {release_distribution} in source {source_name}')) - return dict(result) - - @register('v1.setting.source.release.get_by_id') - async def release_get_by_id(self, - risotto_context: Context, - release_id: int) -> Dict: - release_query = """SELECT ReleaseId as release_id, SourceName as source_name, SourceURL as source_url, ReleaseName as release_name, ReleaseDistribution as release_distribution - FROM Release, Source - WHERE Release.ReleaseId = $1 AND Source.SourceId = Release.ReleaseSourceId""" - result = await risotto_context.connection.fetchrow(release_query, - release_id) - if not result: - raise Exception(_(f'unknown release id {release_id}')) - return dict(result) diff --git a/src/risotto/services/template/__init__.py b/src/risotto/services/template/__init__.py deleted file mode 100644 index 9bb372b..0000000 --- a/src/risotto/services/template/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .template import Risotto diff --git a/src/risotto/services/template/template.py b/src/risotto/services/template/template.py deleted file mode 100644 index 4779289..0000000 --- a/src/risotto/services/template/template.py +++ /dev/null @@ -1,66 +0,0 @@ -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, 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, - test: bool) -> None: - self.storage = Storage(engine='dictionary') - self.cache_root_path = join(get_config().get('cache').get('root_path'), 'servermodel') - - @register('v1.setting.template.generate') - async def template_get(self, - risotto_context, - server_name: str) -> Dict: - # get informations for server - server = await self.call('v1.setting.server.describe', - risotto_context, - server_name=server_name) - server_id = server['server_id'] - servermodel_id = server['server_servermodel_id'] - # verify if server has deployed configuration - config_module = dispatcher.get_service('config') - server = config_module.server[server_id] - export = await server['server'].value.exportation() - if not export[0]: - raise Exception(_(f'configuration for server "{server_name}" is empty, you should deploy it first')) - # copy deployed configuration - async with await server['server'].config.deepcopy(storage=self.storage) as config: - meta = config - while True: - try: - children = list(await config.config.list()) - except: - break - if children: - config = children[0] - else: - break - configurations_dir = join(CONFIGURATION_DIR, - str(server_id)) - if isdir(configurations_dir): - rmtree(configurations_dir) - mkdir(configurations_dir) - tmp_dir = join(TMP_DIR, str(server_id)) - if isdir(tmp_dir): - rmtree(tmp_dir) - mkdir(tmp_dir) - templates_dir = join(self.cache_root_path, str(servermodel_id), 'templates') - await generate(config, - server['funcs_file'], - templates_dir, - tmp_dir, - configurations_dir) - del meta, config - # FIXME del session ! - return {'server_name': server_name, - 'template_dir': configurations_dir} diff --git a/src/risotto/services/uri/__init__.py b/src/risotto/services/uri/__init__.py deleted file mode 100644 index 51c174b..0000000 --- a/src/risotto/services/uri/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .uri import Risotto diff --git a/src/risotto/services/uri/uri.py b/src/risotto/services/uri/uri.py deleted file mode 100644 index d67008d..0000000 --- a/src/risotto/services/uri/uri.py +++ /dev/null @@ -1,117 +0,0 @@ -from typing import Dict, List - -from ...controller import Controller -from ...register import register -from ...context import Context -from ...utils import _ - - -class Risotto(Controller): - async def on_join(self, - risotto_context): - for uri in ['v1.setting.applicationservice.create', - 'v1.setting.applicationservice.dataset.updated', - 'v1.setting.applicationservice.dependency.add', - 'v1.setting.server.create', - 'v1.setting.servermodel.create', - 'v1.setting.servermodel.dataset.updated', - 'v1.setting.session.server.start', - 'v1.setting.source.create', - 'v1.setting.source.dataset.update', - 'v1.setting.source.release.create', - 'v1.setting.template.generate', - 'v1.setting.uri.role.join', - 'v1.setting.uri.role.list', - 'v1.setting.user.create', - 'v1.setting.user.delete', - 'v1.setting.user.list', - 'v1.setting.user.role.create', - 'v1.setting.config.configuration.server.get', - 'v1.setting.user.role.list']: - try: - await self._uri_role_join(risotto_context, - role_name='administrator', - uri_name=uri) - except: - pass - for uri in ['v1.setting.applicationservice.describe', - 'v1.setting.server.describe', - 'v1.setting.server.list', - 'v1.setting.servermodel.list', - 'v1.setting.session.server.configure', - 'v1.setting.session.server.filter', - 'v1.setting.session.server.get', - 'v1.setting.session.server.list', - 'v1.setting.session.servermodel.configure', - 'v1.setting.session.servermodel.filter', - 'v1.setting.session.servermodel.get', - 'v1.setting.session.servermodel.list', - 'v1.setting.session.servermodel.start', - 'v1.setting.session.servermodel.stop', - 'v1.setting.session.servermodel.validate', - 'v1.setting.session.server.stop', - 'v1.setting.session.server.validate', - 'v1.setting.source.describe', - 'v1.setting.source.list', - 'v1.setting.source.release.list']: - try: - await self._uri_role_join(risotto_context, - role_name='all', - uri_name=uri) - except: - pass - for uri in ['v1.setting.server.describe', - 'v1.setting.applicationservice.dependency.add', - 'v1.setting.config.configuration.server.get', - 'v1.setting.config.configuration.server.deploy', - 'v1.setting.session.server.start', - 'v1.setting.template.generate']: - try: - await self._uri_role_join(risotto_context, - role_name='server_rw', - uri_name=uri) - except: - pass - - @register('v1.setting.uri.role.join') - async def uri_role_join(self, - risotto_context: Context, - role_name: str, - uri_name: str) -> Dict: - return await self._uri_role_join(risotto_context, - role_name, - uri_name) - async def _uri_role_join(self, - risotto_context: Context, - role_name: str, - uri_name: str) -> Dict: - # Verify if user exists and get ID - sql = ''' - SELECT URIId - FROM URI - WHERE URIName = $1 - ''' - uri_id = await risotto_context.connection.fetchval(sql, - uri_name) - if uri_id is None: - raise Exception(_(f'unable to find message {uri_name}')) - sql = ''' - INSERT INTO RoleURI(RoleName, URIId) - VALUES ($1,$2) - ON CONFLICT DO NOTHING - ''' - uri_id = await risotto_context.connection.fetchrow(sql, - role_name, - uri_id) - return {'role_name': role_name, - 'uri_name': uri_name} - - @register('v1.setting.uri.role.list') - async def uri_role_list(self, - risotto_context: Context) -> List[Dict]: - sql = ''' - SELECT RoleName as role_name, URI.URIName as uri_name - FROM RoleURI, URI - WHERE RoleURI.URIId = URI.URIId - ''' - return [dict(r) for r in await risotto_context.connection.fetch(sql)] diff --git a/src/risotto/services/user/__init__.py b/src/risotto/services/user/__init__.py deleted file mode 100644 index 092fc52..0000000 --- a/src/risotto/services/user/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .user import Risotto diff --git a/src/risotto/services/user/user.py b/src/risotto/services/user/user.py deleted file mode 100644 index cfb842a..0000000 --- a/src/risotto/services/user/user.py +++ /dev/null @@ -1,211 +0,0 @@ -from typing import Dict, Optional - -from ...controller import Controller -from ...register import register -from ...context import Context -from ...utils import _ -from ...config import get_config - - -class Risotto(Controller): - async def on_join(self, - risotto_context: Context) -> None: - """ pre-load servermodel and server - """ - user_login = get_config()['global']['admin_user'] - sql = ''' - SELECT UserId - FROM RisottoUser - WHERE UserLogin = $1 - ''' - if await risotto_context.connection.fetchval(sql, - user_login) is None: - await self._user_create(risotto_context, - user_login, - user_login, - user_login) - await self._user_role_create(risotto_context, - user_login, - 'administrator', - None, - None) - - async def _user_create(self, - risotto_context: Context, - user_login: str, - user_name: str, - user_surname: str) -> Dict: - user_insert = """INSERT INTO RisottoUser(UserLogin, UserName, UserSurname) - VALUES ($1,$2,$3) - RETURNING UserId - """ - user_id = await risotto_context.connection.fetchval(user_insert, - user_login, - user_name, - user_surname) - await self.call('v1.setting.user.role.create', - risotto_context, - user_login=user_login, - role_name='all') - return {'user_id': user_id, - 'user_login': user_login, - 'user_name': user_name, - 'user_surname': user_surname} - - @register('v1.setting.user.create') - async def user_create(self, - risotto_context: Context, - user_login: str, - user_name: str, - user_surname: str) -> Dict: - return await self._user_create(risotto_context, - user_login, - user_name, - user_surname) - - @register('v1.setting.user.list') - async def user_list(self, - risotto_context: Context) -> Dict: - sql = ''' - SELECT UserId as user_id, UserLogin as user_login, UserName as user_name, UserSurname as user_surname - FROM RisottoUser - ''' - users = await risotto_context.connection.fetch(sql) - return [dict(r) for r in users] - - @register('v1.setting.user.delete') - async def user_delete(self, - risotto_context: Context, - user_login: str) -> Dict: - sql = ''' - DELETE FROM RisottoUser - WHERE UserLogin = $1 - RETURNING UserId as user_id, UserLogin as user_login, UserName as user_name, UserSurname as user_surname - ''' - user = await risotto_context.connection.fetchrow(sql, - user_login) - if user is None: - raise Exception(_(f'unable to find user {user_login}')) - return dict(user) - - async def _user_role_create(self, - risotto_context: Context, - user_login: str, - role_name: str, - role_attribute: str, - role_attribute_value: str) -> Dict: - # Verify if user exists and get ID - sql = ''' - SELECT UserId - FROM RisottoUser - WHERE UserLogin = $1 - ''' - user_id = await risotto_context.connection.fetchval(sql, - user_login) - if user_id is None: - raise Exception(_(f'unable to find user {user_login}')) - if role_attribute == role_attribute_value == None: - sql = '''SELECT RoleId - FROM UserRole - WHERE RoleUserId = $1 AND RoleName = $2 - ''' - role_id = await risotto_context.connection.fetchval(sql, - user_id, - role_name) - else: - sql = '''SELECT RoleId - FROM UserRole - WHERE RoleUserId = $1 AND RoleName = $2 AND RoleAttribute = $3 AND RoleAttributeValue = $4 - ''' - role_id = await risotto_context.connection.fetchval(sql, - user_id, - role_name, - role_attribute, - role_attribute_value) - if role_id is None: - sql = '''INSERT INTO UserRole(RoleUserId, RoleName, RoleAttribute, RoleAttributeValue) - VALUES($1,$2,$3,$4) - RETURNING RoleId - ''' - role_id = await risotto_context.connection.fetchval(sql, - user_id, - role_name, - role_attribute, - role_attribute_value) - return {'role_id': role_id, - 'user_login': user_login, - 'role_name': role_name, - 'role_attribute': role_attribute, - 'role_attribute_value': role_attribute_value} - - @register('v1.setting.user.role.create') - async def user_role_create(self, - risotto_context: Context, - user_login: str, - role_name: str, - role_attribute: str, - role_attribute_value: str) -> Dict: - return await self._user_role_create(risotto_context, - user_login, - role_name, - role_attribute, - role_attribute_value) - - @register('v1.setting.user.role.list') - async def user_role_list(self, - risotto_context: Context, - user_login: Optional[str]) -> Dict: - if not user_login: - sql = ''' - SELECT RoleId as role_id, RoleName as role_name, RoleAttribute as role_attribute, RoleAttributeValue as role_attribute_value, RisottoUser.UserLogin as user_login - FROM UserRole, RisottoUser - WHERE UserRole.RoleUserId = RisottoUser.UserId - ''' - roles = await risotto_context.connection.fetch(sql) - else: - # Verify if user exists and get ID - sql = ''' - SELECT UserId - FROM RisottoUser - WHERE UserLogin = $1 - ''' - user_id = await risotto_context.connection.fetchval(sql, - user_login) - if user_id is None: - raise Exception(_(f'unable to find user {user_login}')) - sql = ''' - SELECT RoleId as role_id, RoleName as role_name, RoleAttribute as role_attribute, RoleAttributeValue as role_attribute_value, RisottoUser.UserLogin as user_login - FROM UserRole, RisottoUser - WHERE UserRole.RoleUserId = RisottoUser.UserId AND UserRole.RoleUserId = $1 - ''' - roles = await risotto_context.connection.fetch(sql, - user_id) - return [dict(r) for r in roles] -# -# FIXME comment savoir quel role il faut supprimer ? avec attribut ou juste l'ID ? -# @register('v1.setting.user.role.delete') -# async def user_role_delete(self, -# risotto_context: Context, -# user_login: str, -# role_name: str) -> Dict: -# # Verify if user exists and get ID -# sql = ''' -# SELECT UserId -# FROM RisottoUser -# WHERE UserLogin = $1 -# ''' -# user_id = await risotto_context.connection.fetchval(sql, -# user_login) -# if user_id is None: -# raise Exception(_(f'unable to find user {user_login}')) -# sql = ''' -# DELETE FROM RisottoRole -# WHERE RoleName = $1 AND UserId = $2 -# RETURNING RoleId as role_id, RoleName as role_name, RoleAttribute as role_attribute, RoleAttributeValue as role_attribute_value -# ''' -# role = await risotto_context.connection.fetchrow(sql, -# role_name, -# user_id) -# if role is None: -# raise Exception(_(f'unable to find role {role_name}')) -# return dict(role)