This commit is contained in:
Emmanuel Garette 2020-01-13 19:53:09 +01:00
parent 4020f97db0
commit 722d4894a1
25 changed files with 351 additions and 193 deletions

View File

@ -35,3 +35,32 @@ Gestion de la base de données avec Sqitch
cpanm --quiet --notest App::Sqitch cpanm --quiet --notest App::Sqitch
sqitch init risotto --uri https://forge.cadoles.com/Infra/risotto --engine pg sqitch init risotto --uri https://forge.cadoles.com/Infra/risotto --engine pg
``` ```
Commande :
# Empty database:
su - postgres
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;
# Import EOLE
./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 applicationservice.dataset.updated -s eole -r last
./script/cucchiaiata servermodel.dataset.updated -s eole -r last
# Create a server
./script/cucchiaiata server.create -s test -d description -m eolebase -n eole -r last
# Configure the server
./script/cucchiaiata session.server.start -s test
./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_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.stop -s $S -a
# Generate configuration
./script/cucchiaiata template.generate -s test

View File

@ -7,11 +7,10 @@ description: |
pattern: rpc pattern: rpc
parameters: parameters:
server_id: server_name:
type: Number type: String
ref: Server.ServerId ref: Server.ServerName
description: | description: Nom du serveur.
Identifiant du serveur.
deployed: deployed:
type: Boolean type: Boolean
description: Configuration de type déployée. description: Configuration de type déployée.

View File

@ -1,32 +0,0 @@
---
uri: servermodel.describe
description: |
Retourne les attributs détaillés d'un modèle de serveur.
pattern: rpc
public: true
parameters:
servermodel_id:
type: Number
shortarg: s
description: Identifiant du modèle de serveur à récupérer.
ref: Servermodel.ServermodelId
response:
type: Servermodel
description: Description du modèle de serveur.
errors:
- uri: servermodel.describe.error.database_not_available
- uri: servermodel.describe.error.invalid_servermodel_id
- uri: servermodel.describe.error.unknown_servermodel_id
related:
- servermodel.list
- servermodel.create
- servermodel.update
- servermodel.delete
- servermodel.event

View File

@ -14,11 +14,21 @@ parameters:
type: String type: String
shortarg: d shortarg: d
description: Description du serveur. description: Description du serveur.
server_servermodel_id: servermodel_name:
type: Number type: String
shortarg: m shortarg: m
ref: Servermodel.ServermodelId ref: Servermodel.ServermodelName
description: Identifiant du modèle de serveur. description: Nom du modèle de serveur.
source_name:
type: String
shortarg: n
ref: Source.SourceName
description: Nom de la source.
release_distribution:
type: String
shortarg: r
ref: Source.ReleaseDistribution
description: Nom de la sous-version.
response: response:
type: Server type: Server

View File

@ -0,0 +1,28 @@
---
uri: servermodel.describe
description: |
Retourne les attributs détaillés d'un modèle de serveur.
pattern: rpc
parameters:
servermodel_name:
type: String
shortarg: s
description: Identifiant du modèle de serveur à récupérer.
ref: Servermodel.ServermodelId
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:
type: Servermodel
description: Description du modèle de serveur.

View File

@ -7,12 +7,11 @@ description: |
pattern: rpc pattern: rpc
parameters: parameters:
id: server_name:
type: Number type: String
ref: Server.ServerId ref: Server.ServerName
shortarg: c shortarg: s
description: | description: Nom du serveur.
Identifiant de la configuration.
response: response:
type: Session type: Session

View File

@ -6,12 +6,21 @@ description: |
pattern: rpc pattern: rpc
parameters: parameters:
id: servermodel_name:
type: Number type: String
ref: Servermodel.ServermodelId ref: Servermodel.ServermodelName
shortarg: c shortarg: s
description: | description: Nom du serveurmodel.
Identifiant de la configuration. 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

@ -7,10 +7,10 @@ description: |
pattern: rpc pattern: rpc
parameters: parameters:
source_id: source_name:
type: Number type: String
shortarg: i shortarg: s
description: ID de la source. description: Nom de la source.
release_name: release_name:
type: String type: String
shortarg: n shortarg: n

View File

@ -0,0 +1,21 @@
---
uri: source.release.describe
description: |
Retourne la sous-version.
pattern: rpc
parameters:
source_name:
type: String
shortarg: s
description: Nom de la source.
release_distribution:
type: String
shortarg: r
description: Nom de la sous-version
response:
type: 'Release'
description: Sous-version.

View File

@ -6,6 +6,12 @@ description: |
pattern: rpc pattern: rpc
parameters:
source_name:
type: String
shortarg: s
description: Nom de la source.
response: response:
type: '[]Release' type: '[]Release'
description: Liste des versions disponibles. description: Liste des versions disponibles.

View File

@ -3,10 +3,10 @@ title: ConfigConfiguration
type: object type: object
description: Description de la configuration. description: Description de la configuration.
properties: properties:
server_id: server_name:
type: number type: string
description: Identifiant du serveur. description: Nom du serveur.
ref: Server.ServerId ref: Server.ServerName
deployed: deployed:
type: boolean type: boolean
description: La configuration est déployée. description: La configuration est déployée.

View File

@ -87,7 +87,7 @@ CREATE TABLE RoleURI (
CREATE TABLE log( CREATE TABLE log(
Msg VARCHAR(255) NOT NULL, Msg VARCHAR(255) NOT NULL,
Level VARCHAR(10) NOT NULL, Level VARCHAR(10) NOT NULL,
Path VARCHAR(255) NOT NULL, Path VARCHAR(255),
Username VARCHAR(100) NOT NULL, Username VARCHAR(100) NOT NULL,
Data JSON, Data JSON,
Date timestamp DEFAULT current_timestamp Date timestamp DEFAULT current_timestamp

View File

@ -298,7 +298,6 @@ class Dispatcher(register.RegisterDispatcher, CallDispatcher, PublishDispatcher)
if function_obj['risotto_context']:
kw['risotto_context'] = risotto_context kw['risotto_context'] = risotto_context
returns = await function(self.injected_self[function_obj['module']], **kw) returns = await function(self.injected_self[function_obj['module']], **kw)
except CallError as err: except CallError as err:

View File

@ -55,8 +55,8 @@ class extra_route_handler:
if DEBUG: if DEBUG:
print_exc() print_exc()
raise HTTPInternalServerError(reason=str(err)) raise HTTPInternalServerError(reason=str(err))
await log.info_msg(kwargs['risotto_context'], # await log.info_msg(kwargs['risotto_context'],
dict(request.match_info)) # dict(request.match_info))
return Response(text=dumps(returns)) return Response(text=dumps(returns))

View File

@ -26,6 +26,9 @@ class Logger:
sql = insert + ') ' + values + ')' sql = insert + ') ' + values + ')'
print(sql, args) print(sql, args)
if not hasattr(risotto_context, 'connection'): if not hasattr(risotto_context, 'connection'):
if path == ' http_get message: /api/v1:':
raise Exception('pouet')
print(path)
print('MANQUE CONNEXION !!!') print('MANQUE CONNEXION !!!')
print(sql) print(sql)
else: else:
@ -92,7 +95,7 @@ class Logger:
if DEBUG: if DEBUG:
print(msg) print(msg)
await self.insert(msg, await self.insert(msg,
paths_msg, None,
risotto_context, risotto_context,
'Info') 'Info')

View File

@ -3,7 +3,7 @@ from inspect import signature
from typing import Callable, Optional from typing import Callable, Optional
import asyncpg import asyncpg
from .utils import undefined, _ from .utils import _
from .error import RegistrationError from .error import RegistrationError
from .message import get_messages from .message import get_messages
from .context import Context from .context import Context
@ -11,8 +11,7 @@ from .config import INTERNAL_USER, get_config
def register(uris: str, def register(uris: str,
notification: str=undefined, notification: str=None):
database: bool=False):
""" Decorator to register function to the dispatcher """ Decorator to register function to the dispatcher
""" """
if not isinstance(uris, list): if not isinstance(uris, list):
@ -24,7 +23,6 @@ def register(uris: str,
dispatcher.set_function(version, dispatcher.set_function(version,
message, message,
notification, notification,
database,
function) function)
return decorator return decorator
@ -71,7 +69,6 @@ class RegisterDispatcher:
def get_function_args(): def get_function_args():
function_args = self.get_function_args(function) function_args = self.get_function_args(function)
# risotto_context is a special argument, remove it # risotto_context is a special argument, remove it
if function_args and function_args[0] == 'risotto_context':
function_args = function_args[1:] function_args = function_args[1:]
return set(function_args) return set(function_args)
@ -114,7 +111,6 @@ class RegisterDispatcher:
def get_function_args(): def get_function_args():
function_args = self.get_function_args(function) function_args = self.get_function_args(function)
# risotto_context is a special argument, remove it # risotto_context is a special argument, remove it
if function_args[0] == 'risotto_context':
function_args = function_args[1:] function_args = function_args[1:]
return set(function_args) return set(function_args)
@ -135,7 +131,6 @@ class RegisterDispatcher:
version: str, version: str,
message: str, message: str,
notification: str, notification: str,
database: bool,
function: Callable): function: Callable):
""" register a function to an URI """ register a function to an URI
URI is a message URI is a message
@ -153,22 +148,12 @@ class RegisterDispatcher:
# True if first argument is the risotto_context # True if first argument is the risotto_context
function_args = self.get_function_args(function) function_args = self.get_function_args(function)
if function_args and function_args[0] == 'risotto_context':
inject_risotto_context = True
function_args.pop(0) function_args.pop(0)
else:
inject_risotto_context = False
# check if already register # check if already register
if 'function' in self.messages[version][message]: if 'function' in self.messages[version][message]:
raise RegistrationError(_(f'uri {version}.{message} already registered')) raise RegistrationError(_(f'uri {version}.{message} already registered'))
# check notification
if self.messages[version][message]['pattern'] == 'rpc':
if notification is undefined:
function_name = function.__name__
raise RegistrationError(_(f'notification is mandatory when registered "{message}" with "{module_name}.{function_name}" even if you set None'))
# register # register
if self.messages[version][message]['pattern'] == 'rpc': if self.messages[version][message]['pattern'] == 'rpc':
register = self.register_rpc register = self.register_rpc
@ -179,8 +164,6 @@ class RegisterDispatcher:
module_name, module_name,
function, function,
function_args, function_args,
inject_risotto_context,
database,
notification) notification)
def register_rpc(self, def register_rpc(self,
@ -189,14 +172,10 @@ class RegisterDispatcher:
module_name: str, module_name: str,
function: Callable, function: Callable,
function_args: list, function_args: list,
inject_risotto_context: bool,
database: bool,
notification: Optional[str]): notification: Optional[str]):
self.messages[version][message]['module'] = module_name self.messages[version][message]['module'] = module_name
self.messages[version][message]['function'] = function self.messages[version][message]['function'] = function
self.messages[version][message]['arguments'] = function_args self.messages[version][message]['arguments'] = function_args
self.messages[version][message]['risotto_context'] = inject_risotto_context
self.messages[version][message]['database'] = database
if notification: if notification:
self.messages[version][message]['notification'] = notification self.messages[version][message]['notification'] = notification
@ -206,18 +185,14 @@ class RegisterDispatcher:
module_name: str, module_name: str,
function: Callable, function: Callable,
function_args: list, function_args: list,
inject_risotto_context: bool,
database: bool,
notification: Optional[str]): notification: Optional[str]):
if 'functions' not in self.messages[version][message]: if 'functions' not in self.messages[version][message]:
self.messages[version][message]['functions'] = [] self.messages[version][message]['functions'] = []
dico = {'module': module_name, dico = {'module': module_name,
'function': function, 'function': function,
'arguments': function_args, 'arguments': function_args}
'database': database, if notification and notification:
'risotto_context': inject_risotto_context}
if notification and notification is not undefined:
dico['notification'] = notification dico['notification'] = notification
self.messages[version][message]['functions'].append(dico) self.messages[version][message]['functions'].append(dico)

View File

@ -35,7 +35,7 @@ class Risotto(Controller):
'applicationservice_release_id': release_id, 'applicationservice_release_id': release_id,
'applicationservice_id': applicationservice_id} 'applicationservice_id': applicationservice_id}
@register('v1.applicationservice.create', None, database=True) @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,
@ -48,7 +48,7 @@ class Risotto(Controller):
applicationservice_dependencies, applicationservice_dependencies,
release_id) release_id)
@register('v1.applicationservice.dataset.updated', None, database=True) @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,
@ -90,7 +90,7 @@ class Risotto(Controller):
return {'retcode': 0, return {'retcode': 0,
'returns': _('Application Services successfully loaded')} 'returns': _('Application Services successfully loaded')}
@register('v1.applicationservice.get_by_id', None, database=True) @register('v1.applicationservice.get_by_id')
async def applicationservice_get_by_id(self, async def applicationservice_get_by_id(self,
risotto_context: Context, risotto_context: Context,
applicationservice_id: int) -> Dict: applicationservice_id: int) -> Dict:
@ -104,7 +104,7 @@ 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', None, database=True) @register('v1.applicationservice.describe')
async def applicationservice_describe(self, async def applicationservice_describe(self,
risotto_context: Context, risotto_context: Context,
applicationservice_name, applicationservice_name,

View File

@ -86,10 +86,18 @@ class Risotto(Controller):
# use file in cache # use file in cache
with open(cache_file) as fileio: with open(cache_file) as fileio:
xmlroot = parse(fileio).getroot() xmlroot = parse(fileio).getroot()
try:
self.servermodel[servermodel_id] = await self.build_metaconfig(servermodel_id, self.servermodel[servermodel_id] = await self.build_metaconfig(servermodel_id,
servermodel_name, servermodel_name,
xmlroot, xmlroot,
funcs_file) 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_metaconfig(self, async def build_metaconfig(self,
servermodel_id: int, servermodel_id: int,
@ -187,7 +195,7 @@ class Risotto(Controller):
server['server_name'], server['server_name'],
server['server_servermodel_id']) server['server_servermodel_id'])
except Exception as err: except Exception as err:
if DEBUG: if get_config().get('global').get('debug'):
print_exc() print_exc()
server_name = server['server_name'] server_name = server['server_name']
server_id = server['server_id'] server_id = server['server_id']
@ -363,8 +371,13 @@ class Risotto(Controller):
@register('v1.config.configuration.server.get', None) @register('v1.config.configuration.server.get', None)
async def get_configuration(self, async def get_configuration(self,
server_id: int, risotto_context: Context,
server_name: str,
deployed: bool) -> bytes: deployed: bool) -> bytes:
server = await self.call('v1.server.describe',
risotto_context,
server_name=server_name)
server_id = server['server_id']
if server_id not in self.server: if server_id not in self.server:
msg = _(f'cannot find server with id {server_id}') msg = _(f'cannot find server with id {server_id}')
await log.error_msg(risotto_context, await log.error_msg(risotto_context,
@ -379,7 +392,8 @@ class Risotto(Controller):
await server.property.read_only() await server.property.read_only()
try: try:
configuration = await server.value.dict(fullpath=True) configuration = await server.value.dict(fullpath=True,
leader_to_list=True)
except: except:
if deployed: if deployed:
msg = _(f'No configuration available for server {server_id}') msg = _(f'No configuration available for server {server_id}')
@ -389,7 +403,7 @@ class Risotto(Controller):
None, None,
msg) msg)
raise CallError(msg) raise CallError(msg)
return {'server_id': server_id, return {'server_name': server_name,
'deployed': deployed, 'deployed': deployed,
'configuration': configuration} 'configuration': configuration}

View File

@ -7,7 +7,7 @@ from ...utils import _
class Risotto(Controller): class Risotto(Controller):
@register('v1.server.list', None, database=True) @register('v1.server.list')
async def server_list(self, async def server_list(self,
risotto_context: Context) -> Dict: risotto_context: Context) -> Dict:
sql = ''' sql = '''
@ -17,16 +17,20 @@ class Risotto(Controller):
servers = await risotto_context.connection.fetch(sql) servers = await risotto_context.connection.fetch(sql)
return [dict(r) for r in servers] return [dict(r) for r in servers]
@register('v1.server.create', 'v1.server.created', database=True) @register('v1.server.create', 'v1.server.created')
async def server_create(self, async def server_create(self,
risotto_context: Context, risotto_context: Context,
server_name: str, server_name: str,
server_description: str, server_description: str,
server_servermodel_id: int) -> Dict: servermodel_name: str,
source_name: str,
release_distribution: str) -> Dict:
await self.call('v1.servermodel.get_by_id', servermodel = await self.call('v1.servermodel.describe',
risotto_context, risotto_context,
servermodel_id=server_servermodel_id) servermodel_name=servermodel_name,
source_name=source_name,
release_distribution=release_distribution)
server_insert = """INSERT INTO Server(ServerName, ServerDescription, ServerServermodelId) server_insert = """INSERT INTO Server(ServerName, ServerDescription, ServerServermodelId)
VALUES ($1,$2,$3) VALUES ($1,$2,$3)
RETURNING ServerId RETURNING ServerId
@ -34,13 +38,13 @@ class Risotto(Controller):
server_id = await risotto_context.connection.fetchval(server_insert, server_id = await risotto_context.connection.fetchval(server_insert,
server_name, server_name,
server_description, server_description,
server_servermodel_id) servermodel['servermodel_id'])
return {'server_id': server_id, return {'server_id': server_id,
'server_name': server_name, 'server_name': server_name,
'server_description': server_description, 'server_description': server_description,
'server_servermodel_id': server_servermodel_id} 'server_servermodel_id': servermodel['servermodel_id']}
@register('v1.server.describe', None, database=True) @register('v1.server.describe')
async def server_describe(self, async def server_describe(self,
risotto_context: Context, risotto_context: Context,
server_name: str) -> Dict: server_name: str) -> Dict:

View File

@ -31,9 +31,9 @@ class Risotto(Controller):
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_id=internal_source['source_id'], source_name='internal',
release_name='none', release_name='none',
release_distribution='stable') release_distribution='last')
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,
@ -245,7 +245,7 @@ class Risotto(Controller):
servermodel_name, servermodel_name,
release_id)['servermodel_id'] release_id)['servermodel_id']
@register('v1.servermodel.dataset.updated', None, database=True) @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,
@ -322,7 +322,7 @@ class Risotto(Controller):
servermodel_description['done'] = True servermodel_description['done'] = True
return {'retcode': 0, 'returns': _('Servermodels successfully loaded')} return {'retcode': 0, 'returns': _('Servermodels successfully loaded')}
@register('v1.servermodel.list', None, database=True) @register('v1.servermodel.list')
async def servermodel_list(self, async def servermodel_list(self,
risotto_context: Context, risotto_context: Context,
source_id: int): source_id: int):
@ -333,10 +333,32 @@ class Risotto(Controller):
servermodels = await risotto_context.connection.fetch(sql) servermodels = await risotto_context.connection.fetch(sql)
return [dict(r) for r in servermodels] return [dict(r) for r in servermodels]
@register('v1.servermodel.get_by_id', None, database=True) @register('v1.servermodel.describe')
async def servermodel_describe(self,
risotto_context: Context,
servermodel_name,
source_name,
release_distribution) -> Dict:
release = await self.call('v1.source.release.describe',
risotto_context,
source_name=source_name,
release_distribution=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
FROM Servermodel
WHERE ServermodelName=$1 AND ServermodelReleaseId=$2
'''
servermodel = await risotto_context.connection.fetchrow(sql,
servermodel_name,
release['release_id'])
if not servermodel:
raise Exception(_(f'{servermodel_id} is not a valid ID for a servermodel'))
return dict(servermodel)
@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): 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
FROM Servermodel FROM Servermodel

View File

@ -64,24 +64,22 @@ class Risotto(Controller):
'mode': session['mode'], 'mode': session['mode'],
'debug': session['debug']} 'debug': session['debug']}
@register(['v1.session.server.start', 'v1.session.servermodel.start'], None) @register('v1.session.server.start')
async def start_session(self, async def start_session_server(self,
risotto_context: Context, risotto_context: Context,
id: int) -> Dict: server_name: str) -> Dict:
""" start a new config session for a server or a servermodel """ start a new config session for a server
""" """
type = risotto_context.message.rsplit('.', 2)[-2]
config_module = dispatcher.get_service('config') config_module = dispatcher.get_service('config')
if type == 'server': server = await self.call('v1.server.describe',
if id not in config_module.server: risotto_context,
raise Exception(_(f'cannot find {type} with id {id}')) 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'] config = config_module.server[id]['server']
else:
if id not in config_module.servermodel:
raise Exception(_(f'cannot find {type} with id {id}'))
config = config_module.servermodel[id]
storage = self.get_storage(type) storage = self.get_storage('server')
# check if a session already exists # check if a session already exists
sessions = storage.get_sessions() sessions = storage.get_sessions()
@ -108,9 +106,57 @@ class Risotto(Controller):
# return session's information # return session's information
return self.get_session_informations(risotto_context, return self.get_session_informations(risotto_context,
session_id, session_id,
type) 'server')
@register(['v1.session.server.list', 'v1.session.servermodel.list'], None) @register('v1.session.servermodel.start')
async def start_session_servermodel(self,
risotto_context: Context,
servermodel_name: str,
source_name: str,
release_distribution: str) -> Dict:
""" start a new config session for a server or a servermodel
"""
config_module = dispatcher.get_service('config')
servermodel = await self.call('v1.servermodel.describe',
risotto_context,
servermodel_name=servermodel_name,
source_name=source_name,
release_distribution=release_distribution)
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.session.server.list', 'v1.session.servermodel.list'])
async def list_session_server(self, async def list_session_server(self,
risotto_context: Context) -> Dict: risotto_context: Context) -> Dict:
type = risotto_context.message.rsplit('.', 2)[-2] type = risotto_context.message.rsplit('.', 2)[-2]
@ -118,7 +164,7 @@ class Risotto(Controller):
return [self.format_session(session_id, session) for session_id, session in storage.get_sessions().items()] return [self.format_session(session_id, session) for session_id, session in storage.get_sessions().items()]
@register(['v1.session.server.filter', 'v1.session.servermodel.filter'], None) @register(['v1.session.server.filter', 'v1.session.servermodel.filter'])
async def filter_session(self, async def filter_session(self,
risotto_context: Context, risotto_context: Context,
session_id: str, session_id: str,
@ -145,7 +191,7 @@ class Risotto(Controller):
session_id, session_id,
type) type)
@register(['v1.session.server.configure', 'v1.session.servermodel.configure'], None) @register(['v1.session.server.configure', 'v1.session.servermodel.configure'])
async def configure_session(self, async def configure_session(self,
risotto_context: Context, risotto_context: Context,
session_id: str, session_id: str,
@ -182,7 +228,7 @@ class Risotto(Controller):
ret['index'] = index ret['index'] = index
return ret return ret
@register(['v1.session.server.validate', 'v1.session.servermodel.validate'], None) @register(['v1.session.server.validate', 'v1.session.servermodel.validate'])
async def validate_session(self, async def validate_session(self,
risotto_context: Context, risotto_context: Context,
session_id: str) -> Dict: session_id: str) -> Dict:
@ -211,7 +257,7 @@ class Risotto(Controller):
return self.format_session(session_id, return self.format_session(session_id,
session) session)
@register(['v1.session.server.get', 'v1.session.servermodel.get'], None) @register(['v1.session.server.get', 'v1.session.servermodel.get'])
async def get_session_server(self, async def get_session_server(self,
risotto_context: Context, risotto_context: Context,
session_id: str, session_id: str,
@ -229,7 +275,7 @@ class Risotto(Controller):
info['content'] = content info['content'] = content
return info return info
@register(['v1.session.server.stop', 'v1.session.servermodel.stop'], None) @register(['v1.session.server.stop', 'v1.session.servermodel.stop'])
async def stop_session(self, async def stop_session(self,
risotto_context: Context, risotto_context: Context,
session_id: str, session_id: str,

View File

@ -10,7 +10,7 @@ from ...config import get_config
class Risotto(Controller): class Risotto(Controller):
@register('v1.source.create', None, database=True) @register('v1.source.create')
async def source_create(self, async def source_create(self,
risotto_context: Context, risotto_context: Context,
source_name: str, source_name: str,
@ -43,7 +43,7 @@ class Risotto(Controller):
'source_url': source_url, 'source_url': source_url,
'source_id': source_id} 'source_id': source_id}
@register('v1.source.describe', None, database=True) @register('v1.source.describe')
async def source_describe(self, async def source_describe(self,
risotto_context: Context, risotto_context: Context,
source_name: str) -> Dict: source_name: str) -> Dict:
@ -57,7 +57,7 @@ class Risotto(Controller):
raise Exception(_(f'unknown source with name {source_name}')) raise Exception(_(f'unknown source with name {source_name}'))
return dict(source) return dict(source)
@register('v1.source.list', None, database=True) @register('v1.source.list')
async def source_list(self, async def source_list(self,
risotto_context: Context) -> List[Dict]: risotto_context: Context) -> List[Dict]:
source_list = """SELECT SourceId as source_id, SourceName as source_name, SourceURL as source_url source_list = """SELECT SourceId as source_id, SourceName as source_name, SourceURL as source_url
@ -66,7 +66,7 @@ class Risotto(Controller):
result = await risotto_context.connection.fetch(source_list) result = await risotto_context.connection.fetch(source_list)
return [dict(r) for r in result] return [dict(r) for r in result]
@register('v1.source.dataset.update', None, database=True) @register('v1.source.dataset.update')
async def version_update(self, async def version_update(self,
risotto_context: Context, risotto_context: Context,
source_id: int, source_id: int,
@ -81,25 +81,28 @@ class Risotto(Controller):
return {'release_id': release_id, return {'release_id': release_id,
'release_name': release_name} 'release_name': release_name}
@register('v1.source.release.create', None, database=True) @register('v1.source.release.create')
async def source_release_create(self, async def source_release_create(self,
risotto_context: Context, risotto_context: Context,
source_id: int, source_name: str,
release_name: str, release_name: str,
release_distribution: str) -> Dict: release_distribution: str) -> Dict:
source_get = """SELECT SourceId as source_id, SourceName as source_name, SourceURL as source_url source_get = """SELECT SourceId as source_id, SourceName as source_name, SourceURL as source_url
FROM Source FROM Source
WHERE SourceId = $1 WHERE SourceName = $1
""" """
release_upsert = """INSERT INTO Release(ReleaseName, ReleaseSourceId, ReleaseDistribution) VALUES ($1, $2, $3) release_upsert = """INSERT INTO Release(ReleaseName, ReleaseSourceId, ReleaseDistribution) VALUES ($1, $2, $3)
ON CONFLICT (ReleaseName, ReleaseSourceId) DO UPDATE SET ReleaseName = $1 ON CONFLICT (ReleaseName, ReleaseSourceId) DO UPDATE SET ReleaseName = $1
RETURNING ReleaseId RETURNING ReleaseId
""" """
source = dict(await risotto_context.connection.fetchrow(source_get, source_obj = await risotto_context.connection.fetchrow(source_get,
source_id)) 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_id = await risotto_context.connection.fetchval(release_upsert,
release_name, release_name,
source_id, source['source_id'],
release_distribution) release_distribution)
del source['source_id'] del source['source_id']
source['release_id'] = release_id source['release_id'] = release_id
@ -107,16 +110,33 @@ class Risotto(Controller):
source['release_distribution'] = release_distribution source['release_distribution'] = release_distribution
return source return source
@register('v1.source.release.list', None, database=True) @register('v1.source.release.list')
async def release_list(self, async def release_list(self,
risotto_context): 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 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.SourceId=Release.ReleaseSourceId""" WHERE Source.SourceName=$1 AND Source.SourceId=Release.ReleaseSourceId"""
result = await risotto_context.connection.fetch(release_query) result = await risotto_context.connection.fetch(release_query,
source_name)
return [dict(r) for r in result] return [dict(r) for r in result]
@register('v1.source.release.get_by_id', None, database=True) @register('v1.source.release.describe')
async def release_list(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.source.release.get_by_id')
async def release_get_by_id(self, async def release_get_by_id(self,
risotto_context: Context, risotto_context: Context,
release_id: int) -> Dict: release_id: int) -> Dict:
@ -129,7 +149,7 @@ class Risotto(Controller):
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', None, database=True) @register('v1.source.release.get_by_distribution')
async def release_get_by_distribution(self, async def release_get_by_distribution(self,
risotto_context: Context, risotto_context: Context,
source_id: int, source_id: int,

View File

@ -17,7 +17,7 @@ class Risotto(Controller):
self.storage = Storage(engine='dictionary') self.storage = Storage(engine='dictionary')
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')
@register('v1.template.generate', None) @register('v1.template.generate')
async def template_get(self, async def template_get(self,
risotto_context, risotto_context,
server_name: str) -> Dict: server_name: str) -> Dict:
@ -28,10 +28,10 @@ class Risotto(Controller):
servermodel_id = server['server_servermodel_id'] servermodel_id = server['server_servermodel_id']
config_module = dispatcher.get_service('config') config_module = dispatcher.get_service('config')
server = config_module.server[server_id] server = config_module.server[server_id]
config = meta = server['server'].config.deepcopy(storage=self.storage) config = meta = await server['server'].config.deepcopy(storage=self.storage)
while True: while True:
try: try:
children = list(config.config.list()) children = list(await config.config.list())
except: except:
break break
if children: if children:
@ -48,7 +48,7 @@ class Risotto(Controller):
rmtree(tmp_dir) rmtree(tmp_dir)
mkdir(tmp_dir) mkdir(tmp_dir)
templates_dir = join(self.cache_root_path, str(servermodel_id), 'templates') templates_dir = join(self.cache_root_path, str(servermodel_id), 'templates')
generate(config, await generate(config,
server['funcs_file'], server['funcs_file'],
templates_dir, templates_dir,
tmp_dir, tmp_dir,

View File

@ -24,10 +24,10 @@ class Risotto(Controller):
'v1.user.delete', 'v1.user.delete',
'v1.user.list', 'v1.user.list',
'v1.user.role.create', 'v1.user.role.create',
'v1.config.configuration.server.get',
'v1.user.role.list']: 'v1.user.role.list']:
try: try:
await self.call('v1.uri.role.join', await self._uri_role_join(risotto_context,
risotto_context,
role_name='administrator', role_name='administrator',
uri_name=uri) uri_name=uri)
except: except:
@ -56,15 +56,21 @@ class Risotto(Controller):
'v1.source.release.get_by_id', 'v1.source.release.get_by_id',
'v1.source.release.list']: 'v1.source.release.list']:
try: try:
await self.call('v1.uri.role.join', await self._uri_role_join(risotto_context,
risotto_context,
role_name='all', role_name='all',
uri_name=uri) uri_name=uri)
except: except:
pass pass
@register('v1.uri.role.join', None, database=True) @register('v1.uri.role.join')
async def uri_role_join(self, async def _uri_role_join(self,
risotto_context: Context,
role_name: str,
uri_name: str) -> Dict:
await self._uri_role_join(risotto_context,
role_name,
uri_name)
async def _uri_role_join(self,
risotto_context: Context, risotto_context: Context,
role_name: str, role_name: str,
uri_name: str) -> Dict: uri_name: str) -> Dict:
@ -89,7 +95,7 @@ class Risotto(Controller):
return {'role_name': role_name, return {'role_name': role_name,
'uri_name': uri_name} 'uri_name': uri_name}
@register('v1.uri.role.list', None, database=True) @register('v1.uri.role.list')
async def uri_role_list(self, async def uri_role_list(self,
risotto_context: Context) -> List[Dict]: risotto_context: Context) -> List[Dict]:
sql = ''' sql = '''

View File

@ -7,7 +7,7 @@ from ...utils import _
class Risotto(Controller): class Risotto(Controller):
@register('v1.user.create', None, database=True) @register('v1.user.create')
async def user_create(self, async def user_create(self,
risotto_context: Context, risotto_context: Context,
user_login: str, user_login: str,
@ -30,7 +30,7 @@ class Risotto(Controller):
'user_name': user_name, 'user_name': user_name,
'user_surname': user_surname} 'user_surname': user_surname}
@register('v1.user.list', None, database=True) @register('v1.user.list')
async def user_list(self, async def user_list(self,
risotto_context: Context) -> Dict: risotto_context: Context) -> Dict:
sql = ''' sql = '''
@ -40,7 +40,7 @@ class Risotto(Controller):
users = await risotto_context.connection.fetch(sql) users = await risotto_context.connection.fetch(sql)
return [dict(r) for r in users] return [dict(r) for r in users]
@register('v1.user.delete', None, database=True) @register('v1.user.delete')
async def user_delete(self, async def user_delete(self,
risotto_context: Context, risotto_context: Context,
user_login: str) -> Dict: user_login: str) -> Dict:
@ -55,7 +55,7 @@ class Risotto(Controller):
raise Exception(_(f'unable to find user {user_login}')) raise Exception(_(f'unable to find user {user_login}'))
return dict(user) return dict(user)
@register('v1.user.role.create', None, database=True) @register('v1.user.role.create')
async def user_role_create(self, async def user_role_create(self,
risotto_context: Context, risotto_context: Context,
user_login: str, user_login: str,
@ -87,7 +87,7 @@ class Risotto(Controller):
'role_attribute': role_attribute, 'role_attribute': role_attribute,
'role_attribute_value': role_attribute_value} 'role_attribute_value': role_attribute_value}
@register('v1.user.role.list', None, database=True) @register('v1.user.role.list')
async def user_role_list(self, async def user_role_list(self,
risotto_context: Context, risotto_context: Context,
user_login: Optional[str]) -> Dict: user_login: Optional[str]) -> Dict:
@ -119,7 +119,7 @@ class Risotto(Controller):
return [dict(r) for r in roles] return [dict(r) for r in roles]
# #
# FIXME comment savoir quel role il faut supprimer ? avec attribut ou juste l'ID ? # FIXME comment savoir quel role il faut supprimer ? avec attribut ou juste l'ID ?
# @register('v1.user.role.delete', None, database=True) # @register('v1.user.role.delete')
# async def user_role_delete(self, # async def user_role_delete(self,
# risotto_context: Context, # risotto_context: Context,
# user_login: str, # user_login: str,