diff --git a/README.md b/README.md index 2acf633..142c068 100644 --- a/README.md +++ b/README.md @@ -18,3 +18,14 @@ echo "127.0.0.1 auth.example.com manager.example.com test1.example.com test2.exa docker run -d --add-host reload.example.com:127.0.0.1 -p 80:80 coudot/lemonldap-ng ``` +Démarrer un serveur postgresql de test +``` +podman pull docker.io/library/postgres:11-alpine +podman run -dt -p 5432:5432 postgres:11-alpine + +psql -U postgres -h localhost -c "CREATE ROLE risotto WITH LOGIN PASSWORD 'risotto';" +psql -U postgres -h localhost -c "CREATE DATABASE risotto;" +psql -U postgres -h localhost -c "GRANT ALL ON DATABASE risotto TO risotto;" +``` + + diff --git a/messages/v1/messages/servermodel.init.yml b/messages/v1/messages/servermodel.init.yml new file mode 100644 index 0000000..354b1bb --- /dev/null +++ b/messages/v1/messages/servermodel.init.yml @@ -0,0 +1,27 @@ +uri: servermodel.init + +description: | + Initialise la table pour les modèles de serveur. + +sampleuse: | + zephir-client servermodel.init + +pattern: rpc + +public: true + +domain: servermodel-domain + +response: + type: ReturnStatus + description: Liste des modèles de serveur disponibles. + +errors: + - uri: servermodel.list.error.database_engine_not_available + +related: + - servermodel.describe + - servermodel.create + - servermodel.update + - servermodel.delete + - servermodel.event diff --git a/messages/v1/types/global.returnstatus.yml b/messages/v1/types/global.returnstatus.yml new file mode 100644 index 0000000..22e08b0 --- /dev/null +++ b/messages/v1/types/global.returnstatus.yml @@ -0,0 +1,14 @@ +--- +title: ReturnStatus +type: object +description: Résultat d’une commande. +properties: + retcode: + type: number + description: Code de retour de la commande. + return: + type: string + description: Retour de la commande. +required: + - retcode + - return \ No newline at end of file diff --git a/src/risotto/database.py b/src/risotto/database.py deleted file mode 100644 index 1159e4a..0000000 --- a/src/risotto/database.py +++ /dev/null @@ -1,21 +0,0 @@ -import psycopg2 - -KEY_DATABASE_NAME = 'dbname' -KEY_DATABASE_USER = 'user' -KEY_DATABASE_PASSWORD = 'password' -KEY_DATABASE_HOST = 'host' - - -def connect(conf, database_options=None): - if database_options is None: - option = conf.option['database'] - database_options = { - 'host': option[KEY_DATABASE_HOST], - 'dbname': option[KEY_DATABASE_NAME], - 'user': option[KEY_DATABASE_USER], - 'password': option[KEY_DATABASE_PASSWORD] - - } - if not database_options['host']: - raise Exception('cannot find postgresql') - return psycopg2.connect(**database_options) diff --git a/src/risotto/dispatcher.py b/src/risotto/dispatcher.py index 6d2cf1f..d912a4f 100644 --- a/src/risotto/dispatcher.py +++ b/src/risotto/dispatcher.py @@ -10,9 +10,8 @@ from .config import DEBUG from .config import get_config from .context import Context from . import register +import asyncpg -def connect(db_conf): - return psycopg2.connect(**db_conf) class CallDispatcher: def valid_public_function(self, @@ -38,6 +37,7 @@ class CallDispatcher: raise CallError(str(err)) else: if not isinstance(returns, dict): + log.error_msg(risotto_context, kwargs, returns) err = _(f'function {module_name}.{function_name} has to return a dict') log.error_msg(risotto_context, kwargs, err) raise CallError(str(err)) @@ -97,10 +97,15 @@ class CallDispatcher: risotto_context.function = obj['function'] if obj['risotto_context']: kw['risotto_context'] = risotto_context - if obj['database']: - db_conf = get_config.get('database') - risotto_context.db_cursor = await connect(db_conf).cursor() - returns = await risotto_context.function(self.injected_self[obj['module']], **kw) + if 'database' in obj and obj['database']: + db_conf = get_config().get('database') + pool = await asyncpg.create_pool(database=db_conf.get('dbname'), user=db_conf.get('user')) + async with pool.acquire() as connection: + risotto_context.connection = connection + async with connection.transaction(): + returns = await risotto_context.function(self.injected_self[obj['module']], **kw) + else: + returns = await risotto_context.function(self.injected_self[obj['module']], **kw) except CallError as err: raise err except Exception as err: diff --git a/src/risotto/register.py b/src/risotto/register.py index 8c28172..00215c5 100644 --- a/src/risotto/register.py +++ b/src/risotto/register.py @@ -9,7 +9,8 @@ from .config import INTERNAL_USER def register(uris: str, - notification: str=undefined): + notification: str=undefined, + database: bool=False): """ Decorator to register function to the dispatcher """ if not isinstance(uris, list): @@ -21,6 +22,7 @@ def register(uris: str, dispatcher.set_function(version, message, notification, + database, function) return decorator @@ -129,6 +131,7 @@ class RegisterDispatcher: version: str, message: str, notification: str, + database: bool, function: Callable): """ register a function to an URI URI is a message @@ -180,6 +183,7 @@ class RegisterDispatcher: function, function_args, inject_risotto_context, + database, notification) def register_rpc(self, @@ -189,11 +193,13 @@ class RegisterDispatcher: function: Callable, function_args: list, inject_risotto_context: bool, + database: bool, notification: Optional[str]): self.messages[version][message]['module'] = module_name self.messages[version][message]['function'] = function self.messages[version][message]['arguments'] = function_args self.messages[version][message]['risotto_context'] = inject_risotto_context + self.messages[version][message]['database'] = database if notification: self.messages[version][message]['notification'] = notification @@ -204,6 +210,7 @@ class RegisterDispatcher: function: Callable, function_args: list, inject_risotto_context: bool, + database: bool, notification: Optional[str]): if 'functions' not in self.messages[version][message]: self.messages[version][message]['functions'] = [] diff --git a/src/risotto/services/servermodel/servermodel.py b/src/risotto/services/servermodel/servermodel.py index 8729573..4021dd4 100644 --- a/src/risotto/services/servermodel/servermodel.py +++ b/src/risotto/services/servermodel/servermodel.py @@ -1,14 +1,35 @@ from ...controller import Controller from ...register import register +sql_init = """ +-- Création de la table ServerModel +CREATE TABLE ServerModel ( + ServerModelId SERIAL PRIMARY KEY, + ServerModelName VARCHAR(255) NOT NULL, + ServerModelDescription VARCHAR(255) NOT NULL, + ServerModelSourceId INTEGER NOT NULL, + ServerModelParentId INTEGER, + ServerModelSubReleaseId INTEGER NOT NULL, + ServerModelSubReleaseName VARCHAR(255) NOT NULL, + UNIQUE (ServerModelName, ServerModelSubReleaseId) +); +""" + + class Risotto(Controller): - @register('v1.servermodel.list', None) - async def servermodel_list(self, sourceid): - return [{'servermodelid': 1, - 'servermodelname': 'name', - 'subreleasename': 'name', - 'sourceid': 1, - 'servermodeldescription': 'description'}] + @register('v1.servermodel.init', None, database=True) + async def servermodel_init(self, risotto_context): + result = await risotto_context.connection.execute(sql_init) + return {'retcode': 0, 'return': result} + + + @register('v1.servermodel.list', None, database=True) + async def servermodel_list(self, risotto_context, sourceid): + sql = ''' + SELECT * FROM ServerModel + ''' + servermodels = await risotto_context.connection.fetch(sql) + return [dict(r) for r in servermodels] @register('v1.servermodel.describe', None) async def servermodel_describe(self, inheritance, creolefuncs, servermodelid, schema, conffiles, resolvdepends, probes):