Compare commits

...

7 Commits

22 changed files with 469 additions and 323 deletions

View File

@ -44,22 +44,67 @@ su - postgres
psql -U postgres risotto psql -U postgres risotto
drop table log; drop table userrole; drop table release; drop table source; drop table server; drop table servermodel; drop table applicationservice; drop table roleuri; drop table risottouser; drop table uri; drop table log; drop table userrole; drop table release; drop table source; drop table server; drop table servermodel; drop table applicationservice; drop table roleuri; drop table risottouser; drop table uri;
psql -U postgres tiramisu
drop table value; drop table property; drop table permissive; drop table information; drop table session;
# Import EOLE # Import EOLE
./script/cucchiaiata source.create -n eole -u http://localhost ./script/cucchiaiata source.create -n eole -u http://localhost
./script/cucchiaiata source.release.create -s eole -n 2.7.1.1 -d last ./script/cucchiaiata source.release.create -s eole -n 2.7.1.1 -d last
./script/cucchiaiata applicationservice.dataset.updated -s eole -r last ./script/cucchiaiata applicationservice.dataset.updated -s eole -r last
./script/cucchiaiata servermodel.dataset.updated -s eole -r last ./script/cucchiaiata servermodel.dataset.updated -s eole -r last
# Create a server # Create a new user and set role 'server_rw' for this server
./script/cucchiaiata server.create -s test -d description -m eolebase -n eole -r last ./script/cucchiaiata user.create -l gnunux -n gnunux -s gnunux
./script/cucchiaiata user.role.create -u gnunux -n 'server_rw' -a 'Server.ServerName' -v test
# Heritage
## ACA
./script/cucchiaiata servermodel.create -n aca -d Aca -p eolebase -s eole -r last
./script/cucchiaiata session.servermodel.start -s aca
S=xxxxxxxxxxxxxxxxxxxxxx
### verif
./script/cucchiaiata session.servermodel.get -s $S -n creole.reseau.unbound_route_address
./script/cucchiaiata session.servermodel.get -s $S -n creole.reseau.unbound_domain_name
./script/cucchiaiata session.servermodel.get -s $S -n creole.serveur_dns.unbound_local_zones
./script/cucchiaiata session.servermodel.get -s $S -n creole.reseau.unbound_ip_address_cidr
./script/cucchiaiata session.servermodel.configure -s $S --creole.reseau.unbound_route_address 192.168.1.2
./script/cucchiaiata session.servermodel.configure -s $S --creole.serveur_dns.unbound_allowed_client_cidr 192.168.1.0/24
./script/cucchiaiata session.servermodel.stop -s $S -a
## etab1
./script/cucchiaiata servermodel.create -n etab1 -d "Etab 1" -p aca -s internal -r last
./script/cucchiaiata session.servermodel.start -s etab1
S=xxxxxxxxxxxxxxxxxxxxxx
./script/cucchiaiata session.servermodel.configure -s $S --creole.reseau.unbound_domain_name test.cadoles.com
./script/cucchiaiata session.servermodel.stop -s $S -a
## unbound
./script/cucchiaiata servermodel.create -n unbound -d "generic unbound configuration" -p eolebase -s eole -r last
./script/cucchiaiata session.servermodel.start -s unbound
S=xxxxxxxxxxxxxxxxxxxxxx
./script/cucchiaiata session.servermodel.configure -s $S --creole.serveur_dns.unbound_local_zones cadoles.com
./script/cucchiaiata session.servermodel.filter -s $S -n unbound
./script/cucchiaiata session.servermodel.configure -s $S --unbound.unbound_zone_cadoles_com.hostname_cadoles_com.hostname_cadoles_com toto titi
./script/cucchiaiata session.servermodel.configure -s $S --unbound.unbound_zone_cadoles_com.hostname_cadoles_com.ip_cadoles_com 0 192.168.1.25
./script/cucchiaiata session.servermodel.configure -s $S --unbound.unbound_zone_cadoles_com.hostname_cadoles_com.type_cadoles_com 1 CNAME
./script/cucchiaiata session.servermodel.configure -s $S --unbound.unbound_zone_cadoles_com.hostname_cadoles_com.cname_cadoles_com 1 toto.cadoles.com
./script/cucchiaiata session.servermodel.stop -s $S -a
## unbound_etab1
./script/cucchiaiata servermodel.create -n unbound_etab1 -d "unbound configuration for etab1" -p etab1 unbound -s internal -r last
### verif
./script/cucchiaiata session.servermodel.start -s unbound_etab1
S=xxxxxxxxxxxxxxxxxxxxxx
XXXXX
# Create a server
./script/cucchiaiata server.create -s test -d description -m unbound_etab1 -n internal -r last
# Configure the server
./script/cucchiaiata session.server.start -s test ./script/cucchiaiata session.server.start -s test
S=xxxxxxxxxxxxxxxxxxxxxx S=xxxxxxxxxxxxxxxxxxxxxx
./script/cucchiaiata session.server.configure -s $S --creole.reseau.unbound_ip_address_cidr 192.168.1.1/24 --creole.reseau.unbound_route_address 192.168.1.2 --creole.serveur_dns.unbound_allowed_client_cidr 192.168.1.0/24 --creole.serveur_dns.unbound_local_zones cadoles.com ./script/cucchiaiata session.server.configure -s $S --creole.reseau.unbound_ip_address_cidr 192.168.1.1/24
./script/cucchiaiata session.server.configure -s $S --creole.reseau.unbound_domain_name test.cadoles.com
./script/cucchiaiata session.server.filter -s $S -n unbound
./script/cucchiaiata session.server.configure -s $S --unbound.unbound_zone_cadoles_com.hostname_cadoles_com.hostname_cadoles_com toto titi --unbound.unbound_zone_cadoles_com.hostname_cadoles_com.ip_cadoles_com 0 192.168.1.25 --unbound.unbound_zone_cadoles_com.hostname_cadoles_com.type_cadoles_com 1 CNAME --unbound.unbound_zone_cadoles_com.hostname_cadoles_com.cname_cadoles_com 1 toto.cadoles.com
./script/cucchiaiata session.server.validate -s $S ./script/cucchiaiata session.server.validate -s $S
./script/cucchiaiata session.server.stop -s $S -a ./script/cucchiaiata session.server.stop -s $S -a
@ -67,6 +112,6 @@ S=xxxxxxxxxxxxxxxxxxxxxx
./script/cucchiaiata config.configuration.server.deploy -s test ./script/cucchiaiata config.configuration.server.deploy -s test
./script/cucchiaiata template.generate -s test ./script/cucchiaiata template.generate -s test
# Create a new user and set role 'server_rw' for this server
./script/cucchiaiata user.create -l gnunux -n gnunux -s gnunux # OpenSSH:
./script/cucchiaiata user.role.create -u gnunux -n 'server_rw' -a 'Server.ServerName' -v test ./script/cucchiaiata server.create -s test -d description -m eolebase -n internal -r last

View File

@ -13,8 +13,11 @@ services:
links: links:
- postgres - postgres
#command: tail -F /var/log #command: tail -F /var/log
command: python /srv/src/risotto/script/server.py command: python -u /srv/src/risotto/script/server.py
restart: unless-stopped restart: on-failure
environment:
RISOTTO_DSN: ${RISOTTO_DSN:-postgres://risotto:risotto@postgres:5432/risotto}
RISOTTO_TIRAMISU_DSN: ${RISOTTO_TIRAMISU_DSN:-postgres://risotto:risotto@postgres:5432/tiramisu}
postgres: postgres:
image: postgres:11-alpine image: postgres:11-alpine
environment: environment:
@ -25,4 +28,4 @@ services:
- ./postgres-init/:/docker-entrypoint-initdb.d/ - ./postgres-init/:/docker-entrypoint-initdb.d/
ports: ports:
- "5432:5432" - "5432:5432"
restart: unless-stopped restart: unless-stopped

View File

@ -22,11 +22,6 @@ parameters:
shortarg: a shortarg: a
description: ID des services applicatif donc dépendant le service applicatif. description: ID des services applicatif donc dépendant le service applicatif.
default: [] default: []
release_id:
type: Number
shortarg: r
description: |
Identifiant de la version associée au service applicatif.
response: response:
type: ApplicationService type: ApplicationService

View File

@ -12,11 +12,16 @@ parameters:
shortarg: n shortarg: n
description: | description: |
Nom du service applicatif à créer. Nom du service applicatif à créer.
release_id: source_name:
type: Number type: String
shortarg: s
description: |
Nom de la source.
release_distribution:
type: String
shortarg: r shortarg: r
description: | description: |
Identifiant de la version associée au service applicatif. Version associée au service applicatif.
response: response:
type: ApplicationService type: ApplicationService

View File

@ -0,0 +1,35 @@
---
uri: servermodel.create
description: |
Crée un modèle de serveur.
pattern: rpc
parameters:
servermodel_name:
type: String
shortarg: n
description: Nom du modèle de serveur à créer.
servermodel_description:
type: String
shortarg: d
description: |
Description du modèle de serveur à créer.
servermodel_parents_name:
type: "[]String"
ref: Servermodel.ServermodelName
shortarg: p
description: Nom des modèles de serveur parents auquels rattacher le nouveau modèle.
servermodel_parents_source_name:
type: String
shortarg: s
description: Nom de la source des modèles parents.
servermodel_parents_release_distribution:
type: String
shortarg: r
description: Nom de la distribution des modèles parents.
response:
type: Servermodel
description: Informations sur le modèle de serveur créé.

View File

@ -11,16 +11,6 @@ parameters:
ref: Servermodel.ServermodelName ref: Servermodel.ServermodelName
shortarg: s shortarg: s
description: Nom du serveurmodel. description: Nom du serveurmodel.
source_name:
type: String
shortarg: n
description: Nom de la source.
ref: Source.SourceName
release_distribution:
type: String
shortarg: r
description: Nom de la distribution.
ref: Source.ReleaseDistribution
response: response:
type: Session type: Session

View File

@ -1,22 +0,0 @@
---
uri: source.release.get_by_distribution
description: |
Retourne version suivant le nom de la distribution.
pattern: rpc
parameters:
source_id:
type: Number
shortarg: s
description: ID de la source.
release_distribution:
type: String
shortarg: r
description: Distribution de la version.
response:
type: 'Release'
description: La version disponibles.

View File

@ -23,8 +23,13 @@ properties:
type: number type: number
ref: Servermodel.SubreleaseId ref: Servermodel.SubreleaseId
description: Version du modèle de serveur. description: Version du modèle de serveur.
servermodel_applicationservice_id:
type: number
ref: Applicationservice.ApplicationserviceId
description: Identifiant de l'application service local.
required: required:
- servermodel_id - servermodel_id
- servermodel_name - servermodel_name
- servermodel_description - servermodel_description
- release_id - release_id
- servermodel_applicationservice_id

View File

@ -96,16 +96,8 @@ CREATE TABLE log(
""" """
async def main(): async def main():
db_conf = get_config().get('database') db_conf = get_config()['database']['dsn']
#asyncpg.connect('postgresql://postgres@localhost/test') pool = await asyncpg.create_pool(db_conf)
engine = db_conf.get('engine')
host = db_conf.get('host')
dbname = db_conf.get('dbname')
dbuser = db_conf.get('user')
dbpassword = db_conf.get('password')
dbport = db_conf.get('port')
cfg = "{}://{}:{}@{}:{}/{}".format(engine, dbuser, dbpassword, host, dbport, dbname)
pool = await asyncpg.create_pool(cfg)
async with pool.acquire() as connection: async with pool.acquire() as connection:
async with connection.transaction(): async with connection.transaction():
returns = await connection.execute(VERSION_INIT) returns = await connection.execute(VERSION_INIT)

View File

@ -1,6 +1,7 @@
from asyncio import get_event_loop from asyncio import get_event_loop
from risotto import get_app from risotto import get_app
if __name__ == '__main__': if __name__ == '__main__':
loop = get_event_loop() loop = get_event_loop()
loop.run_until_complete(get_app(loop)) loop.run_until_complete(get_app(loop))
@ -8,5 +9,3 @@ if __name__ == '__main__':
loop.run_forever() loop.run_forever()
except KeyboardInterrupt: except KeyboardInterrupt:
pass pass

View File

@ -1,23 +1,19 @@
MESSAGE_ROOT_PATH = 'messages' MESSAGE_ROOT_PATH = 'messages'
DATABASE_DIR = '/var/cache/risotto/database'
INTERNAL_USER = 'internal' INTERNAL_USER = 'internal'
CONFIGURATION_DIR = 'configurations' CONFIGURATION_DIR = 'configurations'
TEMPLATE_DIR = 'templates' TEMPLATE_DIR = 'templates'
TMP_DIR = 'tmp' TMP_DIR = 'tmp'
ROUGAIL_DTD_PATH = '../rougail/data/creole.dtd'
DEFAULT_USER = 'Anonymous' DEFAULT_USER = 'Anonymous'
DEFAULT_DSN = 'postgres:///risotto?host=/var/run/postgresql/&user=risotto'
DEFAULT_TIRAMISU_DSN = 'postgres:///tiramisu?host=/var/run/postgresql/&user=tiramisu'
import os from os import environ
from pathlib import PurePosixPath from pathlib import PurePosixPath
CURRENT_PATH = PurePosixPath(__file__) CURRENT_PATH = PurePosixPath(__file__)
def get_config(): def get_config():
return {'database': {'engine': 'postgres', return {'database': {'dsn': environ.get('RISOTTO_DSN', DEFAULT_DSN),
'host': 'postgres', 'tiramisu_dsn': environ.get('RISOTTO_TIRAMISU_DSN', DEFAULT_TIRAMISU_DSN),
'port': 5432,
'dbname': 'risotto',
'user': 'risotto',
'password': 'risotto',
}, },
'http_server': {'port': 8080, 'http_server': {'port': 8080,
#'default_user': "gnunux"}, #'default_user': "gnunux"},
@ -26,9 +22,10 @@ def get_config():
'debug': True, 'debug': True,
'internal_user': 'internal', 'internal_user': 'internal',
'check_role': True, 'check_role': True,
'rougail_dtd_path': '../rougail/data/creole.dtd',
'admin_user': DEFAULT_USER}, 'admin_user': DEFAULT_USER},
'source': {'root_path': '/srv/seed'}, 'source': {'root_path': '/srv/seed'},
'cache': {'root_path': '/var/cache/risotto'} 'cache': {'root_path': '/var/cache/risotto'},
'servermodel': {'internal_source': 'internal',
'internal_distribution': 'last'},
} }

View File

@ -38,31 +38,30 @@ class CallDispatcher:
raise Exception('hu?') raise Exception('hu?')
else: else:
for ret in returns: for ret in returns:
config = await Config(response, async with await Config(response, display_name=lambda self, dyn_name: self.impl_getname()) as config:
display_name=lambda self, dyn_name: self.impl_getname()) await config.property.read_write()
await config.property.read_write() try:
try: for key, value in ret.items():
for key, value in ret.items(): await config.option(key).value.set(value)
await config.option(key).value.set(value) except AttributeError:
except AttributeError: err = _(f'function {module_name}.{function_name} return the unknown parameter "{key}"')
err = _(f'function {module_name}.{function_name} return the unknown parameter "{key}"') await log.error_msg(risotto_context, kwargs, err)
await log.error_msg(risotto_context, kwargs, err) raise CallError(str(err))
raise CallError(str(err)) except ValueError:
except ValueError: err = _(f'function {module_name}.{function_name} return the parameter "{key}" with an unvalid value "{value}"')
err = _(f'function {module_name}.{function_name} return the parameter "{key}" with an unvalid value "{value}"') await log.error_msg(risotto_context, kwargs, err)
await log.error_msg(risotto_context, kwargs, err) raise CallError(str(err))
raise CallError(str(err)) await config.property.read_only()
await config.property.read_only() mandatories = await config.value.mandatory()
mandatories = await config.value.mandatory() if mandatories:
if mandatories: mand = [mand.split('.')[-1] for mand in mandatories]
mand = [mand.split('.')[-1] for mand in mandatories] raise ValueError(_(f'missing parameters in response: {mand} in message "{risotto_context.message}"'))
raise ValueError(_(f'missing parameters in response: {mand} in message "{risotto_context.message}"')) try:
try: await config.value.dict()
await config.value.dict() except Exception as err:
except Exception as err: err = _(f'function {module_name}.{function_name} return an invalid response {err}')
err = _(f'function {module_name}.{function_name} return an invalid response {err}') await log.error_msg(risotto_context, kwargs, err)
await log.error_msg(risotto_context, kwargs, err) raise CallError(str(err))
raise CallError(str(err))
async def call(self, async def call(self,
version: str, version: str,
@ -88,21 +87,39 @@ class CallDispatcher:
kwargs, kwargs,
function_objs) function_objs)
else: else:
async with self.pool.acquire() as connection: try:
await connection.set_type_codec( async with self.pool.acquire() as connection:
'json', await connection.set_type_codec(
encoder=dumps, 'json',
decoder=loads, encoder=dumps,
schema='pg_catalog' decoder=loads,
) schema='pg_catalog'
risotto_context.connection = connection )
async with connection.transaction(): risotto_context.connection = connection
return await self.launch(version, async with connection.transaction():
message, return await self.launch(version,
risotto_context, message,
check_role, risotto_context,
kwargs, check_role,
function_objs) kwargs,
function_objs)
except CallError as err:
raise err
except Exception as err:
# if there is a problem with arguments, just send an error and do nothing
if get_config()['global']['debug']:
print_exc()
async with self.pool.acquire() as connection:
await connection.set_type_codec(
'json',
encoder=dumps,
decoder=loads,
schema='pg_catalog'
)
risotto_context.connection = connection
async with connection.transaction():
await log.error_msg(risotto_context, kwargs, err)
raise err
class PublishDispatcher: class PublishDispatcher:
@ -127,21 +144,39 @@ class PublishDispatcher:
kwargs, kwargs,
function_objs) function_objs)
else: else:
async with self.pool.acquire() as connection: try:
await connection.set_type_codec( async with self.pool.acquire() as connection:
'json', await connection.set_type_codec(
encoder=dumps, 'json',
decoder=loads, encoder=dumps,
schema='pg_catalog' decoder=loads,
) schema='pg_catalog'
risotto_context.connection = connection )
async with connection.transaction(): risotto_context.connection = connection
return await self.launch(version, async with connection.transaction():
message, return await self.launch(version,
risotto_context, message,
check_role, risotto_context,
kwargs, check_role,
function_objs) kwargs,
function_objs)
except CallError as err:
raise err
except Exception as err:
# if there is a problem with arguments, just send an error and do nothing
if get_config()['global']['debug']:
print_exc()
async with self.pool.acquire() as connection:
await connection.set_type_codec(
'json',
encoder=dumps,
decoder=loads,
schema='pg_catalog'
)
risotto_context.connection = connection
async with connection.transaction():
await log.error_msg(risotto_context, kwargs, err)
raise err
class Dispatcher(register.RegisterDispatcher, CallDispatcher, PublishDispatcher): class Dispatcher(register.RegisterDispatcher, CallDispatcher, PublishDispatcher):
@ -182,31 +217,31 @@ class Dispatcher(register.RegisterDispatcher, CallDispatcher, PublishDispatcher)
""" create a new Config et set values to it """ create a new Config et set values to it
""" """
# create a new config # create a new config
config = await Config(self.option) async with await Config(self.option) as config:
await config.property.read_write() await config.property.read_write()
# set message's option # set message's option
await config.option('message').value.set(risotto_context.message) await config.option('message').value.set(risotto_context.message)
# store values # store values
subconfig = config.option(risotto_context.message) subconfig = config.option(risotto_context.message)
for key, value in kwargs.items(): for key, value in kwargs.items():
try: try:
await subconfig.option(key).value.set(value) await subconfig.option(key).value.set(value)
except AttributeError: except AttributeError:
if get_config()['global']['debug']: if get_config()['global']['debug']:
print_exc() print_exc()
raise ValueError(_(f'unknown parameter in "{uri}": "{key}"')) raise ValueError(_(f'unknown parameter in "{uri}": "{key}"'))
# check mandatories options # check mandatories options
if check_role and get_config().get('global').get('check_role'): if check_role and get_config().get('global').get('check_role'):
await self.check_role(subconfig, await self.check_role(subconfig,
risotto_context.username, risotto_context.username,
uri) uri)
await config.property.read_only() await config.property.read_only()
mandatories = await config.value.mandatory() mandatories = await config.value.mandatory()
if mandatories: if mandatories:
mand = [mand.split('.')[-1] for mand in mandatories] mand = [mand.split('.')[-1] for mand in mandatories]
raise ValueError(_(f'missing parameters in "{uri}": {mand}')) raise ValueError(_(f'missing parameters in "{uri}": {mand}'))
# return complete an validated kwargs # return complete an validated kwargs
return await subconfig.value.dict() return await subconfig.value.dict()
def get_service(self, def get_service(self,
name: str): name: str):
@ -268,19 +303,10 @@ class Dispatcher(register.RegisterDispatcher, CallDispatcher, PublishDispatcher)
function_objs: List) -> Optional[Dict]: function_objs: List) -> Optional[Dict]:
await self.check_message_type(risotto_context, await self.check_message_type(risotto_context,
kwargs) kwargs)
try: config_arguments = await self.load_kwargs_to_config(risotto_context,
config_arguments = await self.load_kwargs_to_config(risotto_context, f'{version}.{message}',
f'{version}.{message}', kwargs,
kwargs, check_role)
check_role)
except Exception as err:
# if there is a problem with arguments, just send an error and do nothing
if get_config()['global']['debug']:
print_exc()
await log.error_msg(risotto_context, kwargs, err)
if risotto_context.type == 'rpc':
raise err
return
# config is ok, so send the message # config is ok, so send the message
for function_obj in function_objs: for function_obj in function_objs:
function = function_obj['function'] function = function_obj['function']
@ -306,13 +332,13 @@ class Dispatcher(register.RegisterDispatcher, CallDispatcher, PublishDispatcher)
raise err raise err
continue continue
except Exception as err: except Exception as err:
if risotto_context.type == 'rpc':
raise err
if get_config().get('global').get('debug'): if get_config().get('global').get('debug'):
print_exc() print_exc()
await log.error_msg(risotto_context, await log.error_msg(risotto_context,
kwargs, kwargs,
err) err)
if risotto_context.type == 'rpc':
raise CallError(str(err))
continue continue
else: else:
if risotto_context.type == 'rpc': if risotto_context.type == 'rpc':
@ -325,7 +351,7 @@ class Dispatcher(register.RegisterDispatcher, CallDispatcher, PublishDispatcher)
await log.info_msg(risotto_context, await log.info_msg(risotto_context,
{'arguments': kwargs, {'arguments': kwargs,
'returns': returns}, 'returns': returns},
info_msg) info_msg)
# notification # notification
if function_obj.get('notification'): if function_obj.get('notification'):
notif_version, notif_message = function_obj['notification'].split('.', 1) notif_version, notif_message = function_obj['notification'].split('.', 1)

View File

@ -1,7 +1,7 @@
from aiohttp.web import Application, Response, get, post, HTTPBadRequest, HTTPInternalServerError, HTTPNotFound from aiohttp.web import Application, Response, get, post, HTTPBadRequest, HTTPInternalServerError, HTTPNotFound
from json import dumps from json import dumps
from traceback import print_exc from traceback import print_exc
from tiramisu import Config from tiramisu import Config, default_storage
from .dispatcher import dispatcher from .dispatcher import dispatcher
@ -102,9 +102,9 @@ async def api(request, risotto_context):
WHERE RoleURI.URIId = URI.URIId WHERE RoleURI.URIId = URI.URIId
''' '''
uris = [uri['uriname'] for uri in await connection.fetch(sql)] uris = [uri['uriname'] for uri in await connection.fetch(sql)]
config = await Config(get_messages(load_shortarg=True, uris=uris)[1]) async with await Config(get_messages(load_shortarg=True, uris=uris)[1]) as config:
await config.property.read_write() await config.property.read_write()
tiramisu = await config.option.dict(remotable='none') tiramisu = await config.option.dict(remotable='none')
return tiramisu return tiramisu
@ -119,6 +119,7 @@ async def get_app(loop):
load_services() load_services()
app = Application(loop=loop) app = Application(loop=loop)
routes = [] routes = []
default_storage.engine('dictionary')
await dispatcher.load() await dispatcher.load()
for version, messages in dispatcher.messages.items(): for version, messages in dispatcher.messages.items():
print() print()

View File

@ -9,6 +9,7 @@ from .error import RegistrationError
from .message import get_messages from .message import get_messages
from .context import Context from .context import Context
from .config import INTERNAL_USER, get_config from .config import INTERNAL_USER, get_config
from .logger import log
def register(uris: str, def register(uris: str,
@ -59,13 +60,13 @@ class RegisterDispatcher:
""" """
async def get_message_args(): async def get_message_args():
# load config # load config
config = await Config(self.option) async with await Config(self.option) as config:
await config.property.read_write() await config.property.read_write()
# set message to the uri name # set message to the uri name
await config.option('message').value.set(message) await config.option('message').value.set(message)
# get message argument # get message argument
dico = await config.option(message).value.dict() dico = await config.option(message).value.dict()
return set(dico.keys()) return set(dico.keys())
def get_function_args(): def get_function_args():
function_args = self.get_function_args(function) function_args = self.get_function_args(function)
@ -101,13 +102,13 @@ class RegisterDispatcher:
""" """
async def get_message_args(): async def get_message_args():
# load config # load config
config = await Config(self.option) async with await Config(self.option) as config:
await config.property.read_write() await config.property.read_write()
# set message to the message name # set message to the message name
await config.option('message').value.set(message) await config.option('message').value.set(message)
# get message argument # get message argument
dico = await config.option(message).value.dict() dico = await config.option(message).value.dict()
return set(dico.keys()) return set(dico.keys())
def get_function_args(): def get_function_args():
function_args = self.get_function_args(function) function_args = self.get_function_args(function)
@ -234,6 +235,10 @@ class RegisterDispatcher:
risotto_context.paths.append(f'{module_name}.on_join') risotto_context.paths.append(f'{module_name}.on_join')
risotto_context.type = None risotto_context.type = None
risotto_context.connection = connection risotto_context.connection = connection
info_msg = _(f'in module {module_name}.on_join')
await log.info_msg(risotto_context,
None,
info_msg)
await module.on_join(risotto_context) await module.on_join(risotto_context)
async def insert_message(self, async def insert_message(self,
@ -247,16 +252,8 @@ class RegisterDispatcher:
async def load(self): async def load(self):
# valid function's arguments # valid function's arguments
db_conf = get_config().get('database') db_conf = get_config()['database']['dsn']
self.pool = await asyncpg.create_pool(db_conf)
engine = db_conf.get('engine')
host = db_conf.get('host')
dbname = db_conf.get('dbname')
dbuser = db_conf.get('user')
dbpassword = db_conf.get('password')
dbport = db_conf.get('port')
cfg = "{}://{}:{}@{}:{}/{}".format(engine, dbuser, dbpassword, host, dbport, dbname)
self.pool = await asyncpg.create_pool(cfg)
async with self.pool.acquire() as connection: async with self.pool.acquire() as connection:
async with connection.transaction(): async with connection.transaction():
for version, messages in self.messages.items(): for version, messages in self.messages.items():

View File

@ -15,6 +15,21 @@ class Risotto(Controller):
def __init__(self, def __init__(self,
test: bool) -> None: test: bool) -> None:
self.source_root_path = get_config().get('source').get('root_path') 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']
async def on_join(self,
risotto_context: Context) -> None:
internal_source = await self.call('v1.source.create',
risotto_context,
source_name=self.internal_source_name,
source_url='none')
internal_release = await self.call('v1.source.release.create',
risotto_context,
source_name=self.internal_source_name,
release_name='none',
release_distribution=self.internal_distribution_name)
self.internal_release_id = internal_release['release_id']
async def _applicationservice_create(self, async def _applicationservice_create(self,
risotto_context: Context, risotto_context: Context,
@ -35,30 +50,51 @@ class Risotto(Controller):
'applicationservice_release_id': release_id, 'applicationservice_release_id': release_id,
'applicationservice_id': applicationservice_id} 'applicationservice_id': applicationservice_id}
@register('v1.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.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,
dependency,
release['release_id'])
as_descr['applicationservice_dependencies'].append(dependency_descr['applicationservice_id'])
sql = "UPDATE ApplicationService SET ApplicationServiceDependencies = $1 WHERE ApplicationServiceId = $2"
await risotto_context.connection.execute(sql,
as_descr['applicationservice_dependencies'],
as_descr['applicationserviceid'])
return as_descr
@register('v1.applicationservice.create') @register('v1.applicationservice.create')
async def applicationservice_create(self, async def applicationservice_create(self,
risotto_context: Context, risotto_context: Context,
applicationservice_name: str, applicationservice_name: str,
applicationservice_description: str, applicationservice_description: str,
applicationservice_dependencies: List[int], applicationservice_dependencies: List[int]) -> Dict:
release_id: int) -> Dict:
return await self._applicationservice_create(risotto_context, return await self._applicationservice_create(risotto_context,
applicationservice_name, applicationservice_name,
applicationservice_description, applicationservice_description,
applicationservice_dependencies, applicationservice_dependencies,
release_id) self.internal_release_id)
@register('v1.applicationservice.dataset.updated') @register('v1.applicationservice.dataset.updated')
async def applicationservice_update(self, async def applicationservice_update(self,
risotto_context: Context, risotto_context: Context,
source_name: str, source_name: str,
release_distribution: str) -> Dict: release_distribution: str) -> Dict:
source = await self.call('v1.source.describe', release = await self.call('v1.source.release.describe',
risotto_context,
source_name=source_name)
release = await self.call('v1.source.release.get_by_distribution',
risotto_context, risotto_context,
source_id=source['source_id'], source_name=source_name,
release_distribution=release_distribution) release_distribution=release_distribution)
applicationservice_path = join(self.source_root_path, applicationservice_path = join(self.source_root_path,
source_name, source_name,
@ -81,7 +117,7 @@ class Risotto(Controller):
await self._applicationservice_create(risotto_context, await self._applicationservice_create(risotto_context,
applicationservice_description['name'], applicationservice_description['name'],
applicationservice_description['description'], applicationservice_description['description'],
[], # FIXME dependencies [],
release_id) release_id)
except Exception as err: except Exception as err:
if get_config().get('global').get('debug'): if get_config().get('global').get('debug'):
@ -104,11 +140,10 @@ class Risotto(Controller):
raise Exception(_(f'unknown service with ID {applicationservice_id}')) raise Exception(_(f'unknown service with ID {applicationservice_id}'))
return dict(applicationservice) return dict(applicationservice)
@register('v1.applicationservice.describe') async def _applicationservice_describe(self,
async def applicationservice_describe(self, risotto_context: Context,
risotto_context: Context, applicationservice_name,
applicationservice_name, release_id):
release_id):
applicationservice_query = """ applicationservice_query = """
SELECT ApplicationServiceId as applicationservice_id, ApplicationServiceName as applicationservice_name, ApplicationServiceDependencies as applicationservice_dependencies, ApplicationServiceReleaseId as applicationservice_release_id SELECT ApplicationServiceId as applicationservice_id, ApplicationServiceName as applicationservice_name, ApplicationServiceDependencies as applicationservice_dependencies, ApplicationServiceReleaseId as applicationservice_release_id
FROM ApplicationService FROM ApplicationService
@ -119,3 +154,18 @@ class Risotto(Controller):
if applicationservice is None: if applicationservice is None:
raise Exception(_(f'unknown service {applicationservice_name} in release ID {release_id}')) raise Exception(_(f'unknown service {applicationservice_name} in release ID {release_id}'))
return dict(applicationservice) return dict(applicationservice)
@register('v1.applicationservice.describe')
async def applicationservice_describe(self,
risotto_context: Context,
applicationservice_name,
source_name,
release_distribution):
release = await self.call('v1.source.release.describe',
risotto_context,
source_name=source_name,
release_distribution=release_distribution)
return await self._applicationservice_describe(risotto_context,
applicationservice_name,
release['release_id'])

View File

@ -7,10 +7,11 @@ from typing import Dict, List
from tiramisu import Storage, delete_session, MetaConfig, MixConfig from tiramisu import Storage, delete_session, MetaConfig, MixConfig
from rougail import load as rougail_load from rougail import load as rougail_load
from rougail.config import dtdfilename
from ...controller import Controller from ...controller import Controller
from ...register import register from ...register import register
from ...config import DATABASE_DIR, ROUGAIL_DTD_PATH, get_config from ...config import get_config
from ...context import Context from ...context import Context
from ...utils import _ from ...utils import _
from ...error import CallError, RegistrationError from ...error import CallError, RegistrationError
@ -23,11 +24,12 @@ class Risotto(Controller):
test) -> None: test) -> None:
global conf_storage global conf_storage
self.cache_root_path = join(get_config().get('cache').get('root_path'), 'servermodel') self.cache_root_path = join(get_config().get('cache').get('root_path'), 'servermodel')
for dirname in [self.cache_root_path, DATABASE_DIR]: if not isdir(self.cache_root_path):
if not isdir(dirname): raise RegistrationError(_(f'unable to find the cache dir "{self.cache_root_path}"'))
raise RegistrationError(_(f'unable to find the cache dir "{dirname}"'))
if not test: if not test:
self.save_storage = Storage(engine='sqlite3', dir_database=DATABASE_DIR) db_conf = get_config()['database']['tiramisu_dsn']
self.save_storage = Storage(engine='postgres')
self.save_storage.setting(dsn=db_conf)
self.servermodel = {} self.servermodel = {}
self.server = {} self.server = {}
super().__init__(test) super().__init__(test)
@ -109,18 +111,16 @@ class Risotto(Controller):
# build tiramisu's session ID # build tiramisu's session ID
session_id = f'v_{servermodel_id}' session_id = f'v_{servermodel_id}'
optiondescription = rougail_load(xmlroot, optiondescription = rougail_load(xmlroot,
ROUGAIL_DTD_PATH, dtdfilename,
funcs_file) funcs_file)
# build servermodel metaconfig (v_xxx.m_v_xxx) # build servermodel metaconfig (v_xxx.m_v_xxx)
metaconfig = await MetaConfig([], metaconfig = await MetaConfig([],
optiondescription=optiondescription, optiondescription=optiondescription,
persistent=True,
session_id=session_id, session_id=session_id,
storage=self.save_storage) storage=self.save_storage)
mixconfig = await MixConfig(children=[], mixconfig = await MixConfig(children=[],
optiondescription=optiondescription, optiondescription=optiondescription,
persistent=True,
session_id='m_' + session_id, session_id='m_' + session_id,
storage=self.save_storage) storage=self.save_storage)
await metaconfig.config.add(mixconfig) await metaconfig.config.add(mixconfig)
@ -248,8 +248,7 @@ class Risotto(Controller):
""" build server's config """ build server's config
""" """
config = await metaconfig.config.new(session_id, config = await metaconfig.config.new(session_id,
storage=self.save_storage, storage=self.save_storage)
persistent=True)
await config.information.set('server_id', server_id) await config.information.set('server_id', server_id)
await config.information.set('server_name', server_name) await config.information.set('server_name', server_name)
await config.owner.set(server_name) await config.owner.set(server_name)

View File

@ -18,8 +18,10 @@ from ...logger import log
class Risotto(Controller): class Risotto(Controller):
def __init__(self, def __init__(self,
test: bool) -> None: test: bool) -> None:
self.source_root_path = get_config().get('source').get('root_path') self.source_root_path = get_config()['source']['root_path']
self.cache_root_path = join(get_config().get('cache').get('root_path'), 'servermodel') 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']
if not isdir(self.cache_root_path): if not isdir(self.cache_root_path):
makedirs(join(self.cache_root_path)) makedirs(join(self.cache_root_path))
@ -27,13 +29,13 @@ class Risotto(Controller):
risotto_context: Context) -> None: risotto_context: Context) -> None:
internal_source = await self.call('v1.source.create', internal_source = await self.call('v1.source.create',
risotto_context, risotto_context,
source_name='internal', source_name=self.internal_source_name,
source_url='none') source_url='none')
internal_release = await self.call('v1.source.release.create', internal_release = await self.call('v1.source.release.create',
risotto_context, risotto_context,
source_name='internal', source_name=self.internal_source_name,
release_name='none', release_name='none',
release_distribution='last') release_distribution=self.internal_distribution_name)
self.internal_release_id = internal_release['release_id'] self.internal_release_id = internal_release['release_id']
async def servermodel_gen_funcs(self, async def servermodel_gen_funcs(self,
@ -68,7 +70,6 @@ class Risotto(Controller):
as_names_str = '", "'.join(as_names) as_names_str = '", "'.join(as_names)
await log.info(risotto_context, await log.info(risotto_context,
_(f'gen funcs for "{servermodel_name}" with application services "{as_names_str}"')) _(f'gen funcs for "{servermodel_name}" with application services "{as_names_str}"'))
eolobj = CreoleObjSpace(dtdfilename)
async def servermodel_gen_schema(self, async def servermodel_gen_schema(self,
servermodel_name: str, servermodel_name: str,
@ -159,24 +160,27 @@ class Risotto(Controller):
risotto_context: Context, risotto_context: Context,
servermodel_name: str, servermodel_name: str,
servermodel_description: str, servermodel_description: str,
servermodel_parents_id: List[int], servermodel_parents: List[Dict],
dependencies: List[int], dependencies: List[int],
release_id: int, release_id: int,
release_cache: Dict=None) -> Dict: release_cache: Dict=None) -> Dict:
servermodel_update = """INSERT INTO Servermodel(ServermodelName, ServermodelDescription, ServermodelParentsId, ServermodelReleaseId, ServermodelApplicationServiceId) servermodel_insert = """INSERT INTO Servermodel(ServermodelName, ServermodelDescription, ServermodelParentsId, ServermodelReleaseId, ServermodelApplicationServiceId)
VALUES ($1,$2,$3,$4,$5) VALUES ($1,$2,$3,$4,$5)
RETURNING ServermodelId RETURNING ServermodelId
""" """
as_name = f"local_{servermodel_name}" as_name = f"local_{servermodel_name}"
as_description = f'local application service for {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.applicationservice.create', applicationservice = await self.call('v1.applicationservice.create',
risotto_context, risotto_context,
applicationservice_name=as_name, applicationservice_name=as_name,
applicationservice_description=as_description, applicationservice_description=as_description,
applicationservice_dependencies=dependencies, applicationservice_dependencies=dependencies)
release_id=self.internal_release_id)
applicationservice_id = applicationservice['applicationservice_id'] applicationservice_id = applicationservice['applicationservice_id']
servermodel_id = await risotto_context.connection.fetchval(servermodel_update, servermodel_id = await risotto_context.connection.fetchval(servermodel_insert,
servermodel_name, servermodel_name,
servermodel_description, servermodel_description,
servermodel_parents_id, servermodel_parents_id,
@ -192,7 +196,7 @@ class Risotto(Controller):
# build cache to have all release informations # build cache to have all release informations
if release_cache is None: if release_cache is None:
release_cache = {} release_cache = {}
for applicationservice_id, applicationservice_infos in dependencies.items(): for applicationservice_infos in dependencies.values():
applicationservice_name, as_release_id = applicationservice_infos applicationservice_name, as_release_id = applicationservice_infos
if as_release_id not in release_cache: if as_release_id not in release_cache:
release_cache[as_release_id] = await self.call('v1.source.release.get_by_id', release_cache[as_release_id] = await self.call('v1.source.release.get_by_id',
@ -217,11 +221,9 @@ class Risotto(Controller):
sm_dict = {'servermodel_name': servermodel_name, sm_dict = {'servermodel_name': servermodel_name,
'servermodel_description': servermodel_description, 'servermodel_description': servermodel_description,
'servermodel_parents_id': servermodel_parents_id, 'servermodel_parents_id': servermodel_parents_id,
'servermodel_applicationservice_id': applicationservice_id,
'release_id': release_id, 'release_id': release_id,
'servermodel_id': servermodel_id} 'servermodel_id': servermodel_id}
await self.publish('v1.servermodel.created',
risotto_context,
**sm_dict)
return sm_dict return sm_dict
def parse_parents(self, def parse_parents(self,
@ -236,26 +238,14 @@ class Risotto(Controller):
self.parse_parents(servermodels, servermodels[parent], parents) self.parse_parents(servermodels, servermodels[parent], parents)
return parents return parents
async def get_servermodel_id_by_name(self,
risotto_context: Context,
servermodel_name: str,
release_id: int):
sql = 'SELECT ServermodelId as servermodel_id FROM Servermodel WHERE ServermodelName = $1 AND ServermodelReleaseId = $2',
return await risotto_context.connection.fetchval(sql,
servermodel_name,
release_id)['servermodel_id']
@register('v1.servermodel.dataset.updated') @register('v1.servermodel.dataset.updated')
async def servermodel_update(self, async def servermodel_update(self,
risotto_context: Context, risotto_context: Context,
source_name: str, source_name: str,
release_distribution: int): release_distribution: int):
source = await self.call('v1.source.describe', release = await self.call('v1.source.release.describe',
risotto_context,
source_name=source_name)
release = await self.call('v1.source.release.get_by_distribution',
risotto_context, risotto_context,
source_id=source['source_id'], source_name=source_name,
release_distribution=release_distribution) release_distribution=release_distribution)
release_id = release['release_id'] release_id = release['release_id']
servermodel_path = join(self.source_root_path, servermodel_path = join(self.source_root_path,
@ -285,23 +275,23 @@ class Risotto(Controller):
parents = self.parse_parents(servermodels, parents = self.parse_parents(servermodels,
servermodel) servermodel)
parents.reverse() parents.reverse()
servermodelparent_id = [] servermodel_parent = []
for new_servermodel in parents: for new_servermodel in parents:
if not servermodels[new_servermodel]['done']: if not servermodels[new_servermodel]['done']:
servermodel_description = servermodels[new_servermodel] servermodel_description = servermodels[new_servermodel]
parent = servermodel_description['parent'] parent = servermodel_description['parent']
if not servermodelparent_id and parent is not None: if not servermodel_parent and parent is not None:
# parent is a str, so get ID servermodel_parent = [await self._servermodel_describe(risotto_context,
servermodelparent_id = [await self.get_servermodel_id_by_name(risotto_context, parent,
parent, release_id)]
release_id)]
# link application service with this servermodel # link application service with this servermodel
dependencies = [] dependencies = []
for depend in servermodels[new_servermodel]['applicationservices']: for depend in servermodels[new_servermodel]['applicationservices']:
applicationservice = await self.call('v1.applicationservice.describe', applicationservice = await self.call('v1.applicationservice.describe',
risotto_context, risotto_context,
applicationservice_name=depend, applicationservice_name=depend,
release_id=release_id) source_name=source_name,
release_distribution=release_distribution)
dependencies.append(applicationservice['applicationservice_id']) dependencies.append(applicationservice['applicationservice_id'])
sm_name = servermodel_description['name'] sm_name = servermodel_description['name']
sm_description = servermodel_description['description'] sm_description = servermodel_description['description']
@ -309,16 +299,18 @@ class Risotto(Controller):
servermodel_ob = await self._servermodel_create(risotto_context, servermodel_ob = await self._servermodel_create(risotto_context,
sm_name, sm_name,
sm_description, sm_description,
servermodelparent_id, servermodel_parent,
dependencies, dependencies,
release_id, release_id,
release_cache) release_cache)
servermodel_id = servermodel_ob['servermodel_id'] await self.publish('v1.servermodel.created',
risotto_context,
**servermodel_ob)
except Exception as err: except Exception as err:
if get_config().get('global').get('debug'): if get_config().get('global').get('debug'):
print_exc() print_exc()
raise ExecutionError(_(f"Error while injecting servermodel {sm_name} in database: {err}")) raise ExecutionError(_(f"Error while injecting servermodel {sm_name} in database: {err}"))
servermodelparent_id = [servermodel_id] servermodel_parent = [servermodel_ob]
servermodel_description['done'] = True servermodel_description['done'] = True
return {'retcode': 0, 'returns': _('Servermodels successfully loaded')} return {'retcode': 0, 'returns': _('Servermodels successfully loaded')}
@ -327,7 +319,7 @@ class Risotto(Controller):
risotto_context: Context, risotto_context: Context,
source_id: int): source_id: int):
sql = ''' sql = '''
SELECT ServermodelId as servermodel_id, ServermodelName as servermodel_name, ServermodelDescription as servermodel_description, ServermodelParentsId as servermodel_parents_id, ServermodelReleaseId as release_id 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 FROM Servermodel
''' '''
servermodels = await risotto_context.connection.fetch(sql) servermodels = await risotto_context.connection.fetch(sql)
@ -343,24 +335,58 @@ class Risotto(Controller):
risotto_context, risotto_context,
source_name=source_name, source_name=source_name,
release_distribution=release_distribution) release_distribution=release_distribution)
return await self._servermodel_describe(risotto_context,
servermodel_name,
release['release_id'])
async def _servermodel_describe(self,
risotto_context,
servermodel_name,
release_id):
sql = ''' sql = '''
SELECT ServermodelId as servermodel_id, ServermodelName as servermodel_name, ServermodelDescription as servermodel_description, ServermodelParentsId as servermodel_parents_id, ServermodelReleaseId as release_id 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 FROM Servermodel
WHERE ServermodelName=$1 AND ServermodelReleaseId=$2 WHERE ServermodelName=$1 AND ServermodelReleaseId=$2
''' '''
servermodel = await risotto_context.connection.fetchrow(sql, servermodel = await risotto_context.connection.fetchrow(sql,
servermodel_name, servermodel_name,
release['release_id']) release_id)
if not servermodel: if not servermodel:
raise Exception(_(f'{servermodel_id} is not a valid ID for a 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) return dict(servermodel)
@register('v1.servermodel.create', notification='v1.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.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))
return await self._servermodel_create(risotto_context,
servermodel_name,
servermodel_description,
servermodel_parents,
[],
self.internal_release_id,
{})
@register('v1.servermodel.get_by_id') @register('v1.servermodel.get_by_id')
async def servermodel_get_by_id(self, async def servermodel_get_by_id(self,
risotto_context: Context, risotto_context: Context,
servermodel_id: int) -> Dict: servermodel_id: int) -> Dict:
sql = ''' sql = '''
SELECT ServermodelId as servermodel_id, ServermodelName as servermodel_name, ServermodelDescription as servermodel_description, ServermodelParentsId as servermodel_parents_id, ServermodelReleaseId as release_id 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 FROM Servermodel
WHERE ServermodelId=$1 WHERE ServermodelId=$1
''' '''

View File

@ -12,12 +12,15 @@ from .storage import storage_server, storage_servermodel
from ...controller import Controller from ...controller import Controller
from ...register import register from ...register import register
from ...dispatcher import dispatcher from ...dispatcher import dispatcher
from ...config import get_config
class Risotto(Controller): class Risotto(Controller):
def __init__(self, def __init__(self,
test): test):
self.modify_storage = Storage(engine='dictionary') 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, def get_storage(self,
type: str): type: str):
@ -110,17 +113,15 @@ class Risotto(Controller):
@register('v1.session.servermodel.start') @register('v1.session.servermodel.start')
async def start_session_servermodel(self, async def start_session_servermodel(self,
risotto_context: Context, risotto_context: Context,
servermodel_name: str, servermodel_name: str) -> Dict:
source_name: str,
release_distribution: str) -> Dict:
""" start a new config session for a server or a servermodel """ start a new config session for a server or a servermodel
""" """
config_module = dispatcher.get_service('config') config_module = dispatcher.get_service('config')
servermodel = await self.call('v1.servermodel.describe', servermodel = await self.call('v1.servermodel.describe',
risotto_context, risotto_context,
servermodel_name=servermodel_name, servermodel_name=servermodel_name,
source_name=source_name, source_name=self.internal_source_name,
release_distribution=release_distribution) release_distribution=self.internal_distribution_name)
if not servermodel or servermodel['servermodel_id'] not in config_module.servermodel: if not servermodel or servermodel['servermodel_id'] not in config_module.servermodel:
raise Exception(_(f'cannot find servermodel with name {servermodel_name}')) raise Exception(_(f'cannot find servermodel with name {servermodel_name}'))
id = servermodel['servermodel_id'] id = servermodel['servermodel_id']
@ -293,7 +294,7 @@ class Risotto(Controller):
modif_config = session['config'] modif_config = session['config']
await config.value.importation(await modif_config.value.exportation()) await config.value.importation(await modif_config.value.exportation())
await config.permissive.importation(await modif_config.permissive.exportation()) await config.permissive.importation(await modif_config.permissive.exportation())
storage.del_session(session_id) await storage.del_session(session_id)
return self.format_session(session_id, session) return self.format_session(session_id, session)
@register_http('v1', '/config/server/{session_id}') @register_http('v1', '/config/server/{session_id}')

View File

@ -103,8 +103,21 @@ class Storage(object):
raise NotAllowedError() raise NotAllowedError()
return session return session
def del_session(self, async def del_session(self,
id: int): 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] del self.sessions[id]

View File

@ -122,10 +122,10 @@ class Risotto(Controller):
return [dict(r) for r in result] return [dict(r) for r in result]
@register('v1.source.release.describe') @register('v1.source.release.describe')
async def release_list(self, async def release_describe(self,
risotto_context, risotto_context,
source_name: str, source_name: str,
release_distribution: str) -> Dict: 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 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 FROM Release, Source
WHERE Source.SourceName=$1 AND Source.SourceId=Release.ReleaseSourceId AND Release.ReleaseDistribution=$2""" WHERE Source.SourceName=$1 AND Source.SourceId=Release.ReleaseSourceId AND Release.ReleaseDistribution=$2"""
@ -148,18 +148,3 @@ class Risotto(Controller):
if not result: if not result:
raise Exception(_(f'unknown release id {release_id}')) raise Exception(_(f'unknown release id {release_id}'))
return dict(result) return dict(result)
@register('v1.source.release.get_by_distribution')
async def release_get_by_distribution(self,
risotto_context: Context,
source_id: int,
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 Release.ReleaseSourceId = $1 AND Release.ReleaseDistribution = $2 AND Source.SourceId = Release.ReleaseSourceId"""
result = await risotto_context.connection.fetchrow(release_query,
source_id,
release_distribution)
if not result:
raise Exception(_(f'unknown distribution {release_distribution} with source {source_id}'))
return dict(result)

View File

@ -21,41 +21,46 @@ class Risotto(Controller):
async def template_get(self, async def template_get(self,
risotto_context, risotto_context,
server_name: str) -> Dict: server_name: str) -> Dict:
# get informations for server
server = await self.call('v1.server.describe', server = await self.call('v1.server.describe',
risotto_context, risotto_context,
server_name=server_name) server_name=server_name)
server_id = server['server_id'] server_id = server['server_id']
servermodel_id = server['server_servermodel_id'] servermodel_id = server['server_servermodel_id']
# verify if server has deployed configuration
config_module = dispatcher.get_service('config') config_module = dispatcher.get_service('config')
server = config_module.server[server_id] server = config_module.server[server_id]
export = await server['server'].value.exportation() export = await server['server'].value.exportation()
if not export[0]: if not export[0]:
raise Exception(_(f'configuration for server "{server_name}" is empty, you should deploy it first')) raise Exception(_(f'configuration for server "{server_name}" is empty, you should deploy it first'))
config = meta = await server['server'].config.deepcopy(storage=self.storage) # copy deployed configuration
while True: async with await server['server'].config.deepcopy(storage=self.storage) as config:
try: meta = config
children = list(await config.config.list()) while True:
except: try:
break children = list(await config.config.list())
if children: except:
config = children[0] break
else: if children:
break config = children[0]
configurations_dir = join(CONFIGURATION_DIR, else:
str(server_id)) break
if isdir(configurations_dir): configurations_dir = join(CONFIGURATION_DIR,
rmtree(configurations_dir) str(server_id))
mkdir(configurations_dir) if isdir(configurations_dir):
tmp_dir = join(TMP_DIR, str(server_id)) rmtree(configurations_dir)
if isdir(tmp_dir): mkdir(configurations_dir)
rmtree(tmp_dir) tmp_dir = join(TMP_DIR, str(server_id))
mkdir(tmp_dir) if isdir(tmp_dir):
templates_dir = join(self.cache_root_path, str(servermodel_id), 'templates') rmtree(tmp_dir)
await generate(config, mkdir(tmp_dir)
server['funcs_file'], templates_dir = join(self.cache_root_path, str(servermodel_id), 'templates')
templates_dir, await generate(config,
tmp_dir, server['funcs_file'],
configurations_dir) templates_dir,
tmp_dir,
configurations_dir)
del meta, config
# FIXME del session !
return {'server_name': server_name, return {'server_name': server_name,
'template_dir': configurations_dir} 'template_dir': configurations_dir}

View File

@ -12,6 +12,7 @@ class Risotto(Controller):
for uri in ['v1.applicationservice.create', for uri in ['v1.applicationservice.create',
'v1.applicationservice.dataset.updated', 'v1.applicationservice.dataset.updated',
'v1.server.create', 'v1.server.create',
'v1.servermodel.create',
'v1.servermodel.dataset.updated', 'v1.servermodel.dataset.updated',
'v1.session.server.start', 'v1.session.server.start',
'v1.source.create', 'v1.source.create',
@ -52,8 +53,6 @@ class Risotto(Controller):
'v1.session.server.validate', 'v1.session.server.validate',
'v1.source.describe', 'v1.source.describe',
'v1.source.list', 'v1.source.list',
'v1.source.release.get_by_distribution',
'v1.source.release.get_by_id',
'v1.source.release.list']: 'v1.source.release.list']:
try: try:
await self._uri_role_join(risotto_context, await self._uri_role_join(risotto_context,