Compare commits

..

2 Commits

Author SHA1 Message Date
f4d3430885 Test d’un service utilisant une base de données. 2019-12-04 16:00:29 +01:00
a152654b5b Vocabulary 2019-12-04 15:53:58 +01:00
35 changed files with 312 additions and 1143 deletions

View File

@ -11,20 +11,21 @@ Accéder à un message :
wget http://localhost:8080/v1/config.session.server.start wget http://localhost:8080/v1/config.session.server.start
``` ```
[Documentation WIKI cadoles](https://doku.cadoles.com/dokuwiki/doku.php?id=documentation:risotto) n'est qu'un liens vers la doc officiel (pour le moment) [dans la forge](https://forge.cadoles.com/Infra/eole-risotto/wiki) Démarrer un serveur LemonLDAP de test
```
docker pull coudot/lemonldap-ng
echo "127.0.0.1 auth.example.com manager.example.com test1.example.com test2.example.com" >> /etc/hosts
docker run -d --add-host reload.example.com:127.0.0.1 -p 80:80 coudot/lemonldap-ng
```
**branche :** Démarrer un serveur postgresql de test
```
podman pull docker.io/library/postgres:11-alpine
podman run -dt -p 5432:5432 postgres:11-alpine
master psql -U postgres -h localhost -c "CREATE ROLE risotto WITH LOGIN PASSWORD 'risotto';"
psql -U postgres -h localhost -c "CREATE DATABASE risotto;"
psql -U postgres -h localhost -c "GRANT ALL ON DATABASE risotto TO risotto;"
```
develop
dist/risotto/risotto-2.7.1/develop : pour faire des paquets
dist/risotto/risotto-2.8.0/develop : pour faire des paquets
docker : n'est pas a jour
feature/service_servermodel :
jwt :

View File

@ -18,10 +18,9 @@ parameters:
ref: Server.ServerId ref: Server.ServerId
description: | description: |
Identifiant du serveur. Identifiant du serveur.
deployed: deploy:
type: Boolean type: Boolean
description: Configuration de type déployée. description: Configuration de type déployée.
default: true
response: response:
type: ConfigConfiguration type: ConfigConfiguration

View File

@ -17,6 +17,6 @@ parameters:
type: Number type: Number
description: | description: |
Identifiant du serveur. Identifiant du serveur.
deployed: deploy:
type: Boolean type: Boolean
description: Configuration de type déployée. description: Configuration de type déployée.

View File

@ -10,5 +10,6 @@ public: false
domain: servermodel-domain domain: servermodel-domain
parameters: parameters:
type: Servermodel servermodels:
description: Informations sur les modèles de serveur créés. type: '[]Servermodel'
description: Informations sur les modèles de serveur créés.

View File

@ -0,0 +1,27 @@
uri: servermodel.init
description: |
Initialise la table pour les modèles de serveur.
sampleuse: |
zephir-client servermodel.init
pattern: rpc
public: true
domain: servermodel-domain
response:
type: ReturnStatus
description: Liste des modèles de serveur disponibles.
errors:
- uri: servermodel.list.error.database_engine_not_available
related:
- servermodel.describe
- servermodel.create
- servermodel.update
- servermodel.delete
- servermodel.event

View File

@ -10,5 +10,6 @@ public: false
domain: servermodel-domain domain: servermodel-domain
parameters: parameters:
type: 'Servermodel' servermodels:
description: Informations sur les modèles de serveur modifiés. type: '[]Servermodel'
description: Informations sur les modèles de serveur modifiés.

View File

@ -2,7 +2,7 @@
uri: session.server.get uri: session.server.get
description: | description: |
Récupérer la configuration du server. Configure le server.
pattern: rpc pattern: rpc
@ -16,11 +16,6 @@ parameters:
ref: Config.SessionId ref: Config.SessionId
shortarg: s shortarg: s
description: Identifiant de la configuration. description: Identifiant de la configuration.
name:
type: String
shortarg: n
description: Nom de la variable.
default: null
response: response:
type: Session type: Session

View File

@ -18,6 +18,6 @@ parameters:
description: Identifiant de la session. description: Identifiant de la session.
response: response:
type: Session type: SessionConfigurationStatus
description: Statut de la configuration. description: Statut de la configuration.

View File

@ -16,11 +16,6 @@ parameters:
ref: Config.SessionId ref: Config.SessionId
shortarg: s shortarg: s
description: Identifiant de la configuration. description: Identifiant de la configuration.
name:
type: String
shortarg: n
description: Nom de la variable.
default: null
response: response:
type: Session type: Session

View File

@ -18,6 +18,6 @@ parameters:
description: Identifiant de la session. description: Identifiant de la session.
response: response:
type: Session type: SessionConfigurationStatus
description: Statut de la configuration. description: Statut de la configuration.

View File

@ -3,15 +3,8 @@ title: ConfigConfiguration
type: object type: object
description: Description de la configuration. description: Description de la configuration.
properties: properties:
server_id:
type: number
description: Identifiant du serveur.
ref: Server.ServerId
deployed:
type: boolean
description: La configuration est déployée.
configuration: configuration:
type: object type: File
description: Détail de la configuration au format JSON. description: Détail de la configuration au format JSON.
required: required:
- configuration - configuration

View File

@ -0,0 +1,14 @@
---
title: ReturnStatus
type: object
description: Résultat dune commande.
properties:
retcode:
type: number
description: Code de retour de la commande.
return:
type: string
description: Retour de la commande.
required:
- retcode
- return

View File

@ -37,16 +37,16 @@ properties:
type: object type: object
description: Liste des services applicatifs déclarés pour ce modèle de serveur. description: Liste des services applicatifs déclarés pour ce modèle de serveur.
schema: schema:
type: string type: File
description: Contenu du schema. description: Contenu du schema.
probes: probes:
type: string type: File
description: Informations sur les sondes. description: Informations sur les sondes.
creolefuncs: creolefuncs:
type: string type: File
description: Fonctions Creole. description: Fonctions Creole.
conffiles: conffiles:
type: string type: File
description: Fichiers creole au format tar encodé base64 description: Fichiers creole au format tar encodé base64
required: required:
- servermodelid - servermodelid

View File

@ -0,0 +1,24 @@
---
title: SessionConfigurationStatus
type: object
description: Statut de la configuration.
properties:
session_id:
type: string
description: ID de la session.
ref: Config.SessionId
status:
type: string
description: Statut de la configuration (peut être ok, error, incomplete)
message:
type: string
description: Message d'erreur si la configuration a le statut error.
mandatories:
type: array
items:
type: string
description: Liste des variables obligatoires non renseignées si la configuration a le statut incomplete.
required:
- session_id
- status

View File

@ -12,6 +12,9 @@ properties:
index: index:
type: number type: number
description: Index de la variable a modifier. description: Index de la variable a modifier.
status:
type: string
description: Status de la modification.
message: message:
type: string type: string
description: Message d'erreur. description: Message d'erreur.

View File

@ -27,7 +27,7 @@ properties:
type: boolean type: boolean
description: La configuration est en mode debug. description: La configuration est en mode debug.
content: content:
type: object type: file
description: Contenu de la configuration. description: Contenu de la configuration.
required: required:
- session_id - session_id

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

View File

@ -1,4 +1,6 @@
from .http import get_app from .http import get_app
# just to register every route
from . import services as _services
__ALL__ = ('get_app',) __ALL__ = ('get_app',)

View File

@ -1,10 +1,26 @@
HTTP_PORT = 8080 HTTP_PORT = 8080
MESSAGE_ROOT_PATH = 'messages' MESSAGE_ROOT_PATH = 'messages'
ROOT_CACHE_DIR = 'cache' ROOT_CACHE_DIR = 'cache'
DEBUG = False DEBUG = True
DATABASE_DIR = 'database' DATABASE_DIR = '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' ROUGAIL_DTD_PATH = '../rougail/data/creole.dtd'
POSTGRESQL_ADDRESS = 'localhost'
POSTGRESQL_PORT = 5432
def get_config():
return {'database': {'host': 'localhost',
'port': 5432,
'dbname': 'risotto',
'user': 'risotto',
'password': 'risotto',
},
'http_server': {'port': 8080},
'global': {'message_root_path': 'messages',
'debug': False,
'internal_user': 'internal',
'rougail_dtd_path': '../rougail/data/creole.dtd'}
}

View File

@ -7,8 +7,10 @@ from .utils import _
from .error import CallError, NotAllowedError from .error import CallError, NotAllowedError
from .logger import log from .logger import log
from .config import DEBUG from .config import DEBUG
from .config import get_config
from .context import Context from .context import Context
from . import register from . import register
import asyncpg
class CallDispatcher: class CallDispatcher:
@ -35,6 +37,7 @@ class CallDispatcher:
raise CallError(str(err)) raise CallError(str(err))
else: else:
if not isinstance(returns, dict): if not isinstance(returns, dict):
log.error_msg(risotto_context, kwargs, returns)
err = _(f'function {module_name}.{function_name} has to return a dict') err = _(f'function {module_name}.{function_name} has to return a dict')
log.error_msg(risotto_context, kwargs, err) log.error_msg(risotto_context, kwargs, err)
raise CallError(str(err)) raise CallError(str(err))
@ -94,11 +97,19 @@ class CallDispatcher:
risotto_context.function = obj['function'] risotto_context.function = obj['function']
if obj['risotto_context']: if obj['risotto_context']:
kw['risotto_context'] = risotto_context kw['risotto_context'] = risotto_context
returns = await risotto_context.function(self.injected_self[obj['module']], **kw) if 'database' in obj and obj['database']:
db_conf = get_config().get('database')
pool = await asyncpg.create_pool(database=db_conf.get('dbname'), user=db_conf.get('user'))
async with pool.acquire() as connection:
risotto_context.connection = connection
async with connection.transaction():
returns = await risotto_context.function(self.injected_self[obj['module']], **kw)
else:
returns = await risotto_context.function(self.injected_self[obj['module']], **kw)
except CallError as err: except CallError as err:
raise err raise err
except Exception as err: except Exception as err:
if DEBUG: if get_config().get('global').get('debug'):
print_exc() print_exc()
log.error_msg(risotto_context, log.error_msg(risotto_context,
kwargs, kwargs,
@ -149,7 +160,7 @@ class PublishDispatcher:
return return
# config is ok, so publish the message # config is ok, so publish the message
for function_obj in self.messages[version][message].get('functions', []): for function_obj in self.messages[version][message]['functions']:
function = function_obj['function'] function = function_obj['function']
module_name = function.__module__.split('.')[-2] module_name = function.__module__.split('.')[-2]
function_name = function.__name__ function_name = function.__name__
@ -163,21 +174,21 @@ class PublishDispatcher:
if function_obj['risotto_context']: if function_obj['risotto_context']:
kw['risotto_context'] = risotto_context kw['risotto_context'] = risotto_context
# send event # send event
returns = await function(self.injected_self[function_obj['module']], **kw) await function(self.injected_self[function_obj['module']], **kw)
except Exception as err: except Exception as err:
if DEBUG: if DEBUG:
print_exc() print_exc()
log.error_msg(risotto_context, kwargs, err, info_msg) log.error_msg(risotto_context, kwargs, err, info_msg)
continue
else: else:
log.info_msg(risotto_context, kwargs, info_msg) log.info_msg(risotto_context, kwargs, info_msg)
# notification
if function_obj.get('notification'): # notification
notif_version, notif_message = function_obj['notification'].split('.', 1) if obj.get('notification'):
await self.publish(notif_version, notif_version, notif_message = obj['notification'].split('.', 1)
notif_message, await self.publish(notif_version,
risotto_context, notif_message,
**returns) risotto_context,
**returns)
class Dispatcher(register.RegisterDispatcher, CallDispatcher, PublishDispatcher): class Dispatcher(register.RegisterDispatcher, CallDispatcher, PublishDispatcher):

View File

@ -1,9 +1,6 @@
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 traceback import print_exc
from tiramisu import Config from tiramisu import Config
from json import dumps
from .dispatcher import dispatcher from .dispatcher import dispatcher
from .utils import _ from .utils import _
from .context import Context from .context import Context
@ -11,7 +8,7 @@ from .error import CallError, NotAllowedError, RegistrationError
from .message import get_messages from .message import get_messages
from .logger import log from .logger import log
from .config import DEBUG, HTTP_PORT from .config import DEBUG, HTTP_PORT
from .services import load_services from traceback import print_exc
def create_context(request): def create_context(request):
@ -99,7 +96,6 @@ async def get_app(loop):
""" build all routes """ build all routes
""" """
global extra_routes global extra_routes
load_services()
app = Application(loop=loop) app = Application(loop=loop)
routes = [] routes = []
for version, messages in dispatcher.messages.items(): for version, messages in dispatcher.messages.items():

View File

@ -1,7 +1,6 @@
from typing import Dict from typing import Dict
from .context import Context from .context import Context
from .utils import _ from .utils import _
from .config import DEBUG
class Logger: class Logger:
@ -31,7 +30,6 @@ class Logger:
""" send message when an error append """ send message when an error append
""" """
paths_msg = self._get_message_paths(risotto_context) paths_msg = self._get_message_paths(risotto_context)
# if DEBUG:
print(_(f'{risotto_context.username}: ERROR: {error} ({paths_msg} with arguments "{arguments}": {msg})')) print(_(f'{risotto_context.username}: ERROR: {error} ({paths_msg} with arguments "{arguments}": {msg})'))
def info_msg(self, def info_msg(self,
@ -50,8 +48,7 @@ class Logger:
if msg: if msg:
tmsg += f' {msg}' tmsg += f' {msg}'
if DEBUG: print(tmsg)
print(tmsg)
log = Logger() log = Logger()

View File

@ -9,7 +9,8 @@ from .config import INTERNAL_USER
def register(uris: str, def register(uris: str,
notification: str=undefined): notification: str=undefined,
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):
@ -21,6 +22,7 @@ def register(uris: str,
dispatcher.set_function(version, dispatcher.set_function(version,
message, message,
notification, notification,
database,
function) function)
return decorator return decorator
@ -129,6 +131,7 @@ 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
@ -180,6 +183,7 @@ class RegisterDispatcher:
function, function,
function_args, function_args,
inject_risotto_context, inject_risotto_context,
database,
notification) notification)
def register_rpc(self, def register_rpc(self,
@ -189,11 +193,13 @@ class RegisterDispatcher:
function: Callable, function: Callable,
function_args: list, function_args: list,
inject_risotto_context: bool, 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]['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
@ -204,15 +210,16 @@ class RegisterDispatcher:
function: Callable, function: Callable,
function_args: list, function_args: list,
inject_risotto_context: bool, 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, 'functions': function,
'arguments': function_args, 'arguments': function_args,
'risotto_context': inject_risotto_context} 'risotto_context': inject_risotto_context}
if notification and notification is not undefined: if notification:
dico['notification'] = notification dico['notification'] = notification
self.messages[version][message]['functions'].append(dico) self.messages[version][message]['functions'].append(dico)

View File

@ -4,16 +4,15 @@ from importlib import import_module
from ..dispatcher import dispatcher from ..dispatcher import dispatcher
def load_services(modules=None, def list_import():
validate: bool=True):
abs_here = dirname(abspath(__file__)) abs_here = dirname(abspath(__file__))
here = basename(abs_here) here = basename(abs_here)
module = basename(dirname(abs_here)) module = basename(dirname(abs_here))
if not modules: for filename in listdir(abs_here):
modules = listdir(abs_here)
for filename in modules:
absfilename = join(abs_here, filename) absfilename = join(abs_here, filename)
if isdir(absfilename) and isfile(join(absfilename, '__init__.py')): if isdir(absfilename) and isfile(join(absfilename, '__init__.py')):
dispatcher.set_module(filename, import_module(f'.{here}.{filename}', module)) dispatcher.set_module(filename, import_module(f'.{here}.{filename}', module))
if validate: dispatcher.validate()
dispatcher.validate()
list_import()

View File

@ -1,9 +1,9 @@
from lxml.etree import parse from lxml.etree import parse
from io import BytesIO from io import BytesIO
from os import unlink
from os.path import isdir, isfile, join from os.path import isdir, isfile, join
from traceback import print_exc from traceback import print_exc
from typing import Dict, List from json import dumps
from typing import Dict
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
@ -22,7 +22,7 @@ class Risotto(Controller):
server = {} server = {}
def __init__(self) -> None: def __init__(self) -> None:
for dirname in [ROOT_CACHE_DIR, DATABASE_DIR]: for dirname in [ROOT_CACHE_DIR, DATABASE_DIR, ROUGAIL_DTD_PATH]:
if not isdir(dirname): if not isdir(dirname):
raise RegistrationError(_(f'unable to find the cache dir "{dirname}"')) raise RegistrationError(_(f'unable to find the cache dir "{dirname}"'))
self.save_storage = Storage(engine='sqlite3', dir_database=DATABASE_DIR) self.save_storage = Storage(engine='sqlite3', dir_database=DATABASE_DIR)
@ -58,8 +58,7 @@ class Risotto(Controller):
for servermodel in servermodels: for servermodel in servermodels:
if 'servermodelparentsid' in servermodel: if 'servermodelparentsid' in servermodel:
for servermodelparentid in servermodel['servermodelparentsid']: for servermodelparentid in servermodel['servermodelparentsid']:
self.servermodel_legacy(risotto_context, self.servermodel_legacy(servermodel['servermodelname'],
servermodel['servermodelname'],
servermodel['servermodelid'], servermodel['servermodelid'],
servermodelparentid) servermodelparentid)
@ -157,7 +156,6 @@ class Risotto(Controller):
return metaconfig return metaconfig
def servermodel_legacy(self, def servermodel_legacy(self,
risotto_context: Context,
servermodel_name: str, servermodel_name: str,
servermodel_id: int, servermodel_id: int,
servermodel_parent_id: int) -> None: servermodel_parent_id: int) -> None:
@ -286,106 +284,99 @@ class Risotto(Controller):
async def server_deleted(self, async def server_deleted(self,
server_id: int) -> None: server_id: int) -> None:
# delete config to it's parents # delete config to it's parents
for server_type in ['server', 'server_to_deploy']: for config in self.server[server_id].values():
config = self.server[server_id]['server']
for parent in config.config.parents(): for parent in config.config.parents():
parent.config.pop(config.config.name()) parent.config.pop(config.config.name())
delete_session(storage=self.save_storage, delete_session(config.config.name())
session_id=config.config.name())
# delete metaconfig # delete metaconfig
del self.server[server_id] del self.server[server_id]
@register('v1.servermodel.created') @register('v1.servermodel.created')
async def servermodel_created(self, async def servermodel_created(self,
risotto_context: Context, servermodels) -> None:
servermodelid: int,
servermodelname: str,
servermodelparentsid: List[int]) -> None:
""" when servermodels are created, load it and do link """ when servermodels are created, load it and do link
""" """
await self.load_and_link_servermodel(risotto_context, for servermodel in servermodels:
servermodelid, await self.load_servermodel(servermodel['servermodelid'], servermodel['servermodelname'])
servermodelname, for servermodel in servermodels:
servermodelparentsid) if 'servermodelparentsid' in servermodel:
for servermodelparentid in servermodel['servermodelparentsid']:
self.servermodel_legacy(servermodel['servermodelname'], servermodel['servermodelid'], servermodelparentid)
async def load_and_link_servermodel(self,
risotto_context: Context,
servermodelid: int,
servermodelname: str,
servermodelparentsid: List[int]) -> None:
await self.load_servermodel(risotto_context,
servermodelid,
servermodelname)
if servermodelparentsid is not None:
for servermodelparentid in servermodelparentsid:
self.servermodel_legacy(risotto_context,
servermodelname,
servermodelid,
servermodelparentid)
def servermodel_delete(self,
servermodelid: int) -> List[MetaConfig]:
metaconfig = self.servermodel.pop(servermodelid)
mixconfig = next(metaconfig.config.list())
children = []
for child in mixconfig.config.list():
children.append(child)
mixconfig.config.pop(child.config.name())
metaconfig.config.pop(mixconfig.config.name())
delete_session(storage=self.save_storage,
session_id=mixconfig.config.name())
del mixconfig
for parent in metaconfig.config.parents():
parent.config.pop(metaconfig.config.name())
delete_session(storage=self.save_storage,
session_id=metaconfig.config.name())
return children
@register('v1.servermodel.updated') @register('v1.servermodel.updated')
async def servermodel_updated(self, async def servermodel_updated(self,
risotto_context: Context, risotto_context: Context,
servermodelid: int, servermodels) -> None:
servermodelname: str, for servermodel in servermodels:
servermodelparentsid: List[int]) -> None: servermodelid = servermodel['servermodelid']
log.info_msg(risotto_context, servermodelname = servermodel['servermodelname']
None, servermodelparentsid = servermodel.get('servermodelparentsid')
f'Reload servermodel {servermodelname} ({servermodelid})') log.info_msg(risotto_context,
# unlink cache to force download new aggregated file None,
cache_file = join(ROOT_CACHE_DIR, str(servermodelid)+".xml") f'Reload servermodel {servermodelname} ({servermodelid})')
if isfile(cache_file): # unlink cache to force download new aggregated file
unlink(cache_file) cache_file = join(ROOT_CACHE_DIR, str(servermodelid)+".xml")
if isfile(cache_file):
unlink(cache_file)
# store all informations # get current servermodel
if servermodelid in self.servermodel: old_servermodel = self.servermodel[servermodelid]
old_values = self.servermodel[servermodelid].value.exportation()
old_permissives = self.servermodel[servermodelid].permissive.exportation()
old_properties = self.servermodel[servermodelid].property.exportation()
children = self.servermodel_delete(servermodelid)
else:
old_values = None
# create new one # create new one
await self.load_and_link_servermodel(risotto_context, await self.load_servermodel(servermodelid, servermodelname)
servermodelid,
servermodelname,
servermodelparentsid)
# migrates informations # migrate all informations
if old_values is not None: self.servermodel[servermodelid].value.importation(old_servermodel.value.exportation())
self.servermodel[servermodelid].value.importation(old_values) self.servermodel[servermodelid].permissive.importation(old_servermodel.permissive.exportation())
self.servermodel[servermodelid].permissive.importation(old_permissives) self.servermodel[servermodelid].property.importation(old_servermodel.property.exportation())
self.servermodel[servermodelid].property.importation(old_properties)
for child in children: # remove link to legacy
self.servermodel_legacy(risotto_context, if servermodelparentsid:
child.information.get('servermodel_name'), for servermodelparentid in servermodelparentsid:
child.information.get('servermodel_id'), mix = self.servermodel[servermodelparentid].config.get('m_v_' + str(servermodelparentid))
servermodelid) try:
mix.config.pop(old_servermodel.config.name())
except:
# if mix config is reloaded too
pass
# add new link
self.servermodel_legacy(servermodelname, servermodelid, servermodelparentid)
# reload servers or servermodels in servermodel
for subconfig in old_servermodel.config.list():
if not isinstance(subconfig, MixConfig):
# a server
name = subconfig.config.name()
if name.startswith('str_'):
continue
server_id = subconfig.information.get('server_id')
server_name = subconfig.information.get('server_name')
try:
old_servermodel.config.pop(name)
old_servermodel.config.pop(f'std_{server_id}')
except:
pass
del self.server[server_id]
self.load_server(risotto_context,
server_id,
server_name,
servermodelid)
else:
# a servermodel
for subsubconfig in subconfig.config.list():
name = subsubconfig.config.name()
try:
subconfig.config.pop(name)
except:
pass
self.servermodel_legacy(subsubconfig.information.get('servermodel_name'),
subsubconfig.information.get('servermodel_id'),
servermodelid)
@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, server_id: int,
deployed: bool) -> bytes: deploy: bool) -> bytes:
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}')
log.error_msg(risotto_context, log.error_msg(risotto_context,
@ -393,16 +384,16 @@ class Risotto(Controller):
msg) msg)
raise CallError(msg) raise CallError(msg)
if deployed: if deploy:
server = self.server[server_id]['server'] server = self.server[server_id]['server']
else: else:
server = self.server[server_id]['server_to_deploy'] server = self.server[server_id]['server_to_deploy']
server.property.read_only() server.property.read_only()
try: try:
configuration = server.value.dict(fullpath=True) dico = server.value.dict(fullpath=True)
except: except:
if deployed: if deploy:
msg = _(f'No configuration available for server {server_id}') msg = _(f'No configuration available for server {server_id}')
else: else:
msg = _(f'No undeployed configuration available for server {server_id}') msg = _(f'No undeployed configuration available for server {server_id}')
@ -410,9 +401,8 @@ class Risotto(Controller):
None, None,
msg) msg)
raise CallError(msg) raise CallError(msg)
return {'server_id': server_id, return dumps(dico).encode()
'deployed': deployed,
'configuration': configuration}
@register('v1.config.configuration.server.deploy', 'v1.config.configuration.server.updated') @register('v1.config.configuration.server.deploy', 'v1.config.configuration.server.updated')
async def deploy_configuration(self, async def deploy_configuration(self,
@ -438,4 +428,4 @@ class Risotto(Controller):
config.property.importation(config_std.property.exportation()) config.property.importation(config_std.property.exportation())
return {'server_id': server_id, return {'server_id': server_id,
'deployed': True} 'deploy': True}

View File

@ -1,14 +1,35 @@
from ...controller import Controller from ...controller import Controller
from ...register import register from ...register import register
sql_init = """
-- Création de la table ServerModel
CREATE TABLE ServerModel (
ServerModelId SERIAL PRIMARY KEY,
ServerModelName VARCHAR(255) NOT NULL,
ServerModelDescription VARCHAR(255) NOT NULL,
ServerModelSourceId INTEGER NOT NULL,
ServerModelParentId INTEGER,
ServerModelSubReleaseId INTEGER NOT NULL,
ServerModelSubReleaseName VARCHAR(255) NOT NULL,
UNIQUE (ServerModelName, ServerModelSubReleaseId)
);
"""
class Risotto(Controller): class Risotto(Controller):
@register('v1.servermodel.list', None) @register('v1.servermodel.init', None, database=True)
async def servermodel_list(self, sourceid): async def servermodel_init(self, risotto_context):
return [{'servermodelid': 1, result = await risotto_context.connection.execute(sql_init)
'servermodelname': 'name', return {'retcode': 0, 'return': result}
'subreleasename': 'name',
'sourceid': 1,
'servermodeldescription': 'description'}] @register('v1.servermodel.list', None, database=True)
async def servermodel_list(self, risotto_context, sourceid):
sql = '''
SELECT * FROM ServerModel
'''
servermodels = await risotto_context.connection.fetch(sql)
return [dict(r) for r in servermodels]
@register('v1.servermodel.describe', None) @register('v1.servermodel.describe', None)
async def servermodel_describe(self, inheritance, creolefuncs, servermodelid, schema, conffiles, resolvdepends, probes): async def servermodel_describe(self, inheritance, creolefuncs, servermodelid, schema, conffiles, resolvdepends, probes):

View File

@ -1,6 +1,7 @@
from os import urandom # , unlink from os import urandom # , unlink
from binascii import hexlify from binascii import hexlify
from traceback import print_exc from traceback import print_exc
from json import dumps
from typing import Dict, List, Optional, Any from typing import Dict, List, Optional, Any
from tiramisu import Storage from tiramisu import Storage
@ -27,7 +28,6 @@ class Risotto(Controller):
return storage_servermodel return storage_servermodel
def get_session(self, def get_session(self,
risotto_context: Context,
session_id: str, session_id: str,
type: str) -> Dict: type: str) -> Dict:
""" Get session information from storage """ Get session information from storage
@ -36,8 +36,7 @@ class Risotto(Controller):
storage = storage_server storage = storage_server
else: else:
storage = storage_servermodel storage = storage_servermodel
return storage.get_session(session_id, return storage.get_session(session_id)
risotto_context.username)
def get_session_informations(self, def get_session_informations(self,
risotto_context: Context, risotto_context: Context,
@ -45,9 +44,9 @@ class Risotto(Controller):
type: str) -> Dict: type: str) -> Dict:
""" format session with a session ID name """ format session with a session ID name
""" """
session = self.get_session(risotto_context, session = self.get_session(session_id,
session_id, type,
type) risotto_context.username)
return self.format_session(session_id, return self.format_session(session_id,
session) session)
@ -105,16 +104,16 @@ class Risotto(Controller):
self.modify_storage) self.modify_storage)
# return session's information # return session's information
return self.get_session_informations(risotto_context, return self.get_session_informations(session_id,
session_id,
type) type)
@register(['v1.session.server.list', 'v1.session.servermodel.list'], None) @register(['v1.session.server.list', 'v1.session.servermodel.list'], None)
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]
storage = self.get_storage(type) storage = self.get_storage(type,
return [self.format_session(session_id, session) for session_id, session in storage.get_sessions().items()] risotto_context.username)
return [self.format_session(session_id, session) or 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'], None)
@ -128,7 +127,7 @@ class Risotto(Controller):
storage = self.get_storage(type) storage = self.get_storage(type)
# to validate the session right # to validate the session right
storage.get_session(session_id, storage.get_session(session_id,
risotto_context.username) username)
if namespace is not None: if namespace is not None:
storage.set_namespace(session_id, storage.set_namespace(session_id,
namespace) namespace)
@ -140,8 +139,7 @@ class Risotto(Controller):
if debug is not None: if debug is not None:
storage.set_config_debug(session_id, storage.set_config_debug(session_id,
debug) debug)
return self.get_session_informations(risotto_context, return self.get_session_informations(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'], None)
@ -154,25 +152,25 @@ class Risotto(Controller):
value: Any, value: Any,
value_multi: Optional[List]) -> Dict: value_multi: Optional[List]) -> Dict:
type = risotto_context.message.rsplit('.', 2)[-2] type = risotto_context.message.rsplit('.', 2)[-2]
session = self.get_session(risotto_context, session = self.get_session(session_id,
session_id, type,
type) risotto_context.username)
# if multi and not follower the value is in fact in value_multi # if multi and not follower the value is in fact in value_multi
option = session['option'].option(name).option option = session['config'].option(name).option
if option.ismulti() and not option.isfollower(): if option.ismulti() and not option.isfollower():
value = value_multi value = value_multi
namespace = session['namespace'] try:
update = {'name': f'{namespace}.{name}', update = {'name': name,
'action': action, 'action': action,
'value': value} 'value': value}
if index is not None: if index is not None:
update['index'] = index update['index'] = index
updates = {'updates': [update]} updates = {'updates': [update]}
ret = session['option'].updates(updates) session['option'].updates(updates)
if update['name'] in ret: except Exception as err:
for val in ret[update['name']][index]: if DEBUG:
if isinstance(val, ValueError): print_exc()
raise CallError(val) raise CallError(str(err))
ret = {'session_id': session_id, ret = {'session_id': session_id,
'name': name} 'name': name}
if index is not None: if index is not None:
@ -184,9 +182,9 @@ class Risotto(Controller):
risotto_context: Context, risotto_context: Context,
session_id: str) -> Dict: session_id: str) -> Dict:
type = risotto_context.message.rsplit('.', 2)[-2] type = risotto_context.message.rsplit('.', 2)[-2]
session = self.get_session(risotto_context, session = self.get_session(session_id,
session_id, type,
type) risotto_context.username)
try: try:
session['config'].forcepermissive.option(session['namespace']).value.dict() session['config'].forcepermissive.option(session['namespace']).value.dict()
except Exception as err: except Exception as err:
@ -207,17 +205,13 @@ class Risotto(Controller):
@register(['v1.session.server.get', 'v1.session.servermodel.get'], None) @register(['v1.session.server.get', 'v1.session.servermodel.get'], None)
async def get_session_server(self, async def get_session_server(self,
risotto_context: Context, risotto_context: Context,
session_id: str, session_id: str) -> Dict:
name: Optional[str]) -> Dict:
type = risotto_context.message.rsplit('.', 2)[-2] type = risotto_context.message.rsplit('.', 2)[-2]
session = self.get_session(risotto_context, session = self.get_session(session_id,
session_id, type,
type) risotto_context.username)
info = self.format_session(session_id, session) info = self.format_session(session_id, session)
if name is not None: info['content'] = dumps(session['option'].value.dict(fullpath=True))
info['content'] = {name: session['option'].option(name).value.get()}
else:
info['content'] = session['option'].value.dict()
return info return info
@register(['v1.session.server.stop', 'v1.session.servermodel.stop'], None) @register(['v1.session.server.stop', 'v1.session.servermodel.stop'], None)

View File

@ -66,7 +66,7 @@ class Storage(object):
mode: str): mode: str):
""" Define which edition mode to select """ Define which edition mode to select
""" """
config = self.sessions[id]['config'] config = self.session[id]['config']
for mode_level in modes.values(): for mode_level in modes.values():
if modes[mode] < mode_level: if modes[mode] < mode_level:
config.property.add(mode_level.name) config.property.add(mode_level.name)
@ -77,7 +77,7 @@ class Storage(object):
def set_config_debug(self, id_, is_debug): def set_config_debug(self, id_, is_debug):
""" Enable/Disable debug mode """ Enable/Disable debug mode
""" """
config = self.sessions[id_]['config'] config = self.session[id_]['config']
if is_debug: if is_debug:
config.property.pop('hidden') config.property.pop('hidden')
else: else:
@ -94,14 +94,13 @@ class Storage(object):
return self.sessions; return self.sessions;
def get_session(self, def get_session(self,
session_id: int, id: int,
username: str) -> Dict: username: str) -> Dict:
if session_id not in self.sessions: if id not in self.sessions:
raise Exception(f'the session {id} not exists') raise Exception(f'the session {id} not exists')
session = self.sessions[session_id] if username != storage.get_session(session_id)['username']:
if username != session['username']:
raise NotAllowedError() raise NotAllowedError()
return session return self.sessions[id]
def del_session(self, def del_session(self,
id: int): id: int):

View File

@ -1 +0,0 @@
from .server import Risotto

View File

@ -1,8 +0,0 @@
from risotto.controller import Controller
from risotto.register import register
class Risotto(Controller):
@register('v1.server.list', None)
async def server_list(self):
return [{'server_id': 3, 'servername': 'one', 'serverdescription': 'the first', 'servermodelid': 1}]

View File

@ -1 +0,0 @@
from .servermodel import Risotto

View File

@ -1,71 +0,0 @@
from risotto.controller import Controller
from risotto.register import register
class Risotto(Controller):
@register('v1.servermodel.list', None)
async def servermodel_list(self, sourceid):
return [{'servermodelid': 1,
'servermodelname': 'name1',
'subreleasename': 'name1',
'sourceid': 1,
'servermodeldescription': 'description1'},
{'servermodelid': 2,
'servermodelname': 'name2',
'subreleasename': 'name2',
'sourceid': 2,
'servermodeldescription': 'description2',
'servermodelparentsid': [1]}]
@register('v1.servermodel.describe', None)
async def servermodel_describe(self, inheritance, creolefuncs, servermodelid, schema, conffiles, resolvdepends, probes):
schema = """<?xml version='1.0' encoding='UTF-8'?>
<creole>
<family name="containers">
<family name="container0" doc="test">
<family doc="files" name="files">
<family doc="file0" name="file0">
<variable doc="" multi="False" name="mkdir" type="boolean">
<value>False</value>
</variable>
<variable doc="" multi="False" name="name" type="string">
<value>/etc/mailname</value>
</variable>
<variable doc="" multi="False" name="rm" type="boolean">
<value>False</value>
</variable>
<variable doc="" multi="False" name="source" type="string">
<value>mailname</value>
</variable>
<variable doc="" multi="False" name="activate" type="boolean">
<value>True</value>
</variable>
</family>
</family>
<property>basic</property>
</family>
</family>
<family doc="" name="creole">
<family doc="general" name="general">
<property>normal</property>
<variable doc="No change" multi="False" name="mode_conteneur_actif" type="choice">
<choice type="string">oui</choice>
<choice type="string">non</choice>
<property>mandatory</property>
<property>normal</property>
<value type="string">non</value>
</variable>
<leader doc="master" name="master">
<property>normal</property>
<variable doc="master" multi="True" name="master" type="string"/>
<variable doc="slave1" multi="True" name="slave1" type="string">
<property>normal</property>
</variable>
<variable doc="slave2" multi="True" name="slave2" type="string">
<property>normal</property>
</variable>
</leader>
</family>
<separators/>
</family>
</creole>"""
return {'servermodelid': 1, 'servermodelname': 'name', 'servermodeldescription': 'description', 'subreleasename': 'name', 'sourceid': 1, 'schema': schema, 'creolefuncs': ''}

View File

@ -1,334 +0,0 @@
from importlib import import_module
import pytest
from tiramisu import Storage, list_sessions, delete_session
from risotto.context import Context
from risotto.services import load_services
from risotto.dispatcher import dispatcher
from risotto.config import DATABASE_DIR
def setup_module(module):
load_services(['config'],
validate=False)
config_module = dispatcher.get_service('config')
config_module.save_storage = Storage(engine='sqlite3', dir_database=DATABASE_DIR, name='test')
dispatcher.set_module('server', import_module(f'.server', 'fake_services'))
dispatcher.set_module('servermodel', import_module(f'.servermodel', 'fake_services'))
def setup_function(function):
config_module = dispatcher.get_service('config')
config_module.server = {}
config_module.servermodel = {}
def teardown_function(function):
# delete all sessions
config_module = dispatcher.get_service('config')
for session in list_sessions(storage=config_module.save_storage):
delete_session(storage=config_module.save_storage, session_id=session)
def get_fake_context(module_name):
risotto_context = Context()
risotto_context.username = 'test'
risotto_context.paths.append(f'{module_name}.on_join')
risotto_context.type = None
return risotto_context
@pytest.mark.asyncio
async def test_on_join():
config_module = dispatcher.get_service('config')
assert config_module.servermodel == {}
assert config_module.server == {}
#
fake_context = get_fake_context('config')
await config_module.on_join(fake_context)
assert list(config_module.servermodel.keys()) == [1, 2]
assert list(config_module.server) == [3]
assert set(config_module.server[3]) == {'server', 'server_to_deploy', 'funcs_file'}
assert config_module.server[3]['funcs_file'] == 'cache/1.creolefuncs'
@pytest.mark.asyncio
async def test_server_created():
config_module = dispatcher.get_service('config')
fake_context = get_fake_context('config')
await config_module.on_join(fake_context)
#
assert list(config_module.server) == [3]
await dispatcher.publish('v1',
'server.created',
fake_context,
server_id=4,
servername='name3',
serverdescription='description3',
servermodelid=2)
assert list(config_module.server) == [3, 4]
assert set(config_module.server[4]) == {'server', 'server_to_deploy', 'funcs_file'}
assert config_module.server[4]['funcs_file'] == 'cache/2.creolefuncs'
@pytest.mark.asyncio
async def test_server_deleted():
config_module = dispatcher.get_service('config')
fake_context = get_fake_context('config')
await config_module.on_join(fake_context)
#
assert list(config_module.server) == [3]
await dispatcher.publish('v1',
'server.created',
fake_context,
server_id=4,
servername='name4',
serverdescription='description4',
servermodelid=2)
assert list(config_module.server) == [3, 4]
await dispatcher.publish('v1',
'server.deleted',
fake_context,
server_id=4)
assert list(config_module.server) == [3]
@pytest.mark.asyncio
async def test_servermodel_created():
config_module = dispatcher.get_service('config')
fake_context = get_fake_context('config')
await config_module.on_join(fake_context)
#
assert list(config_module.servermodel) == [1, 2]
servermodel = {'servermodeid': 3,
'servermodelname': 'name3'}
await dispatcher.publish('v1',
'servermodel.created',
fake_context,
servermodelid=3,
servermodeldescription='name3',
subreleasename='2.7.0',
sourceid=1,
servermodelname='name3')
assert list(config_module.servermodel) == [1, 2, 3]
assert not list(config_module.servermodel[3].config.parents())
@pytest.mark.asyncio
async def test_servermodel_herited_created():
config_module = dispatcher.get_service('config')
fake_context = get_fake_context('config')
await config_module.on_join(fake_context)
#
assert list(config_module.servermodel) == [1, 2]
await dispatcher.publish('v1',
'servermodel.created',
fake_context,
servermodelid=3,
servermodelname='name3',
subreleasename='2.7.0',
sourceid=1,
servermodeldescription='name3',
servermodelparentsid=[1])
assert list(config_module.servermodel) == [1, 2, 3]
assert len(list(config_module.servermodel[3].config.parents())) == 1
@pytest.mark.asyncio
async def test_servermodel_multi_herited_created():
config_module = dispatcher.get_service('config')
fake_context = get_fake_context('config')
await config_module.on_join(fake_context)
#
assert list(config_module.servermodel) == [1, 2]
await dispatcher.publish('v1',
'servermodel.created',
fake_context,
servermodelid=3,
servermodelname='name3',
subreleasename='2.7.0',
sourceid=1,
servermodeldescription='name3',
servermodelparentsid=[1, 2])
assert list(config_module.servermodel) == [1, 2, 3]
assert len(list(config_module.servermodel[3].config.parents())) == 2
@pytest.mark.asyncio
async def test_servermodel_updated_not_exists():
config_module = dispatcher.get_service('config')
fake_context = get_fake_context('config')
await config_module.on_join(fake_context)
#
assert list(config_module.servermodel) == [1, 2]
await dispatcher.publish('v1',
'servermodel.updated',
fake_context,
servermodelid=3,
servermodelname='name3',
subreleasename='2.7.0',
sourceid=1,
servermodeldescription='name3',
servermodelparentsid=[1, 2])
assert list(config_module.servermodel) == [1, 2, 3]
assert len(list(config_module.servermodel[3].config.parents())) == 2
@pytest.mark.asyncio
async def test_servermodel_updated1():
config_module = dispatcher.get_service('config')
fake_context = get_fake_context('config')
await config_module.on_join(fake_context)
#
assert list(config_module.servermodel) == [1, 2]
metaconfig1 = config_module.servermodel[1]
metaconfig2 = config_module.servermodel[2]
mixconfig1 = next(metaconfig1.config.list())
mixconfig2 = next(metaconfig2.config.list())
assert len(list(metaconfig1.config.parents())) == 0
assert len(list(metaconfig2.config.parents())) == 1
assert len(list(mixconfig1.config.list())) == 1
assert len(list(mixconfig2.config.list())) == 0
#
await dispatcher.publish('v1',
'servermodel.updated',
fake_context,
servermodelid=1,
servermodelname='name1-1',
subreleasename='2.7.0',
sourceid=1,
servermodeldescription='name1-1')
assert set(config_module.servermodel) == {1, 2}
assert config_module.servermodel[1].information.get('servermodel_name') == 'name1-1'
assert metaconfig1 != config_module.servermodel[1]
assert metaconfig2 == config_module.servermodel[2]
metaconfig1 = config_module.servermodel[1]
assert mixconfig1 != next(metaconfig1.config.list())
mixconfig1 = next(metaconfig1.config.list())
#
assert len(list(metaconfig1.config.parents())) == 0
assert len(list(metaconfig2.config.parents())) == 1
assert len(list(mixconfig1.config.list())) == 1
assert len(list(mixconfig2.config.list())) == 0
@pytest.mark.asyncio
async def test_servermodel_updated2():
config_module = dispatcher.get_service('config')
fake_context = get_fake_context('config')
await config_module.on_join(fake_context)
# create a new servermodel
assert list(config_module.servermodel) == [1, 2]
mixconfig1 = next(config_module.servermodel[1].config.list())
mixconfig2 = next(config_module.servermodel[2].config.list())
assert len(list(mixconfig1.config.list())) == 1
assert len(list(mixconfig2.config.list())) == 0
await dispatcher.publish('v1',
'servermodel.created',
fake_context,
servermodelid=3,
servermodelname='name3',
subreleasename='2.7.0',
sourceid=1,
servermodeldescription='name3',
servermodelparentsid=[1])
assert list(config_module.servermodel) == [1, 2, 3]
assert len(list(config_module.servermodel[3].config.parents())) == 1
assert config_module.servermodel[3].information.get('servermodel_name') == 'name3'
assert len(list(mixconfig1.config.list())) == 2
assert len(list(mixconfig2.config.list())) == 0
#
await dispatcher.publish('v1',
'servermodel.updated',
fake_context,
servermodelid=3,
servermodelname='name3-1',
subreleasename='2.7.0',
sourceid=1,
servermodeldescription='name3-1',
servermodelparentsid=[1, 2])
assert list(config_module.servermodel) == [1, 2, 3]
assert config_module.servermodel[3].information.get('servermodel_name') == 'name3-1'
assert len(list(mixconfig1.config.list())) == 2
assert len(list(mixconfig2.config.list())) == 1
@pytest.mark.asyncio
async def test_servermodel_updated_config():
config_module = dispatcher.get_service('config')
fake_context = get_fake_context('config')
await config_module.on_join(fake_context)
#
config_module.servermodel[1].property.read_write()
assert config_module.servermodel[1].option('creole.general.mode_conteneur_actif').value.get() == 'non'
config_module.servermodel[1].option('creole.general.mode_conteneur_actif').value.set('oui')
assert config_module.servermodel[1].option('creole.general.mode_conteneur_actif').value.get() == 'oui'
#
await dispatcher.publish('v1',
'servermodel.updated',
fake_context,
servermodelid=1,
servermodelname='name1-1',
subreleasename='2.7.0',
sourceid=1,
servermodeldescription='name1-1')
assert config_module.servermodel[1].option('creole.general.mode_conteneur_actif').value.get() == 'oui'
@pytest.mark.asyncio
async def test_server_configuration_get():
config_module = dispatcher.get_service('config')
fake_context = get_fake_context('config')
await config_module.on_join(fake_context)
#
config_module.server[3]['server_to_deploy'].property.read_write()
assert config_module.server[3]['server_to_deploy'].option('creole.general.mode_conteneur_actif').value.get() == 'non'
config_module.server[3]['server_to_deploy'].option('creole.general.mode_conteneur_actif').value.set('oui')
assert config_module.server[3]['server_to_deploy'].option('creole.general.mode_conteneur_actif').value.get() == 'oui'
assert config_module.server[3]['server'].option('creole.general.mode_conteneur_actif').value.get() == 'non'
#
values = await dispatcher.call('v1',
'config.configuration.server.get',
fake_context,
server_id=3)
configuration = {'configuration':
{'creole.general.mode_conteneur_actif': 'non',
'creole.general.master.master': [],
'creole.general.master.slave1': [],
'creole.general.master.slave2': [],
'containers.container0.files.file0.mkdir': False,
'containers.container0.files.file0.name': '/etc/mailname',
'containers.container0.files.file0.rm': False,
'containers.container0.files.file0.source': 'mailname',
'containers.container0.files.file0.activate': True},
'server_id': 3,
'deployed': True}
assert values == configuration
#
values = await dispatcher.call('v1',
'config.configuration.server.get',
fake_context,
server_id=3,
deployed=False)
configuration['configuration']['creole.general.mode_conteneur_actif'] = 'oui'
configuration['deployed'] = False
assert values == configuration
@pytest.mark.asyncio
async def test_config_deployed():
config_module = dispatcher.get_service('config')
fake_context = get_fake_context('config')
await config_module.on_join(fake_context)
#
config_module.server[3]['server_to_deploy'].property.read_write()
assert config_module.server[3]['server_to_deploy'].option('creole.general.mode_conteneur_actif').value.get() == 'non'
config_module.server[3]['server_to_deploy'].option('creole.general.mode_conteneur_actif').value.set('oui')
assert config_module.server[3]['server_to_deploy'].option('creole.general.mode_conteneur_actif').value.get() == 'oui'
assert config_module.server[3]['server'].option('creole.general.mode_conteneur_actif').value.get() == 'non'
values = await dispatcher.publish('v1',
'config.configuration.server.deploy',
fake_context,
server_id=3)
assert config_module.server[3]['server_to_deploy'].option('creole.general.mode_conteneur_actif').value.get() == 'oui'
assert config_module.server[3]['server'].option('creole.general.mode_conteneur_actif').value.get() == 'oui'

View File

@ -1,501 +0,0 @@
from importlib import import_module
import pytest
from tiramisu import Storage
from risotto.context import Context
from risotto.services import load_services
from risotto.dispatcher import dispatcher
from risotto.config import DATABASE_DIR
from risotto.services.session.storage import storage_server, storage_servermodel
def get_fake_context(module_name):
risotto_context = Context()
risotto_context.username = 'test'
risotto_context.paths.append(f'{module_name}.on_join')
risotto_context.type = None
return risotto_context
def setup_module(module):
load_services(['config', 'session'],
validate=False)
config_module = dispatcher.get_service('config')
config_module.save_storage = Storage(engine='sqlite3', dir_database=DATABASE_DIR, name='test')
dispatcher.set_module('server', import_module(f'.server', 'fake_services'))
dispatcher.set_module('servermodel', import_module(f'.servermodel', 'fake_services'))
def teardown_function(function):
config_module = dispatcher.get_service('session')
storage_server.sessions = {}
storage_servermodel.sessions = {}
@pytest.mark.asyncio
async def test_server_start():
fake_context = get_fake_context('session')
config_module = dispatcher.get_service('config')
if not config_module.server:
await config_module.on_join(fake_context)
await dispatcher.call('v1',
'session.server.start',
fake_context,
id=3)
@pytest.mark.asyncio
async def test_server_list():
fake_context = get_fake_context('session')
config_module = dispatcher.get_service('config')
if not config_module.server:
await config_module.on_join(fake_context)
assert not await dispatcher.call('v1',
'session.server.list',
fake_context)
await dispatcher.call('v1',
'session.server.start',
fake_context,
id=3)
assert await dispatcher.call('v1',
'session.server.list',
fake_context)
@pytest.mark.asyncio
async def test_server_filter_namespace():
fake_context = get_fake_context('session')
config_module = dispatcher.get_service('config')
if not config_module.server:
await config_module.on_join(fake_context)
session = await dispatcher.call('v1',
'session.server.start',
fake_context,
id=3)
session_id = session['session_id']
namespace = 'containers'
await dispatcher.call('v1',
'session.server.filter',
fake_context,
session_id=session_id,
namespace=namespace)
list_result = await dispatcher.call('v1',
'session.server.list',
fake_context)
assert list_result[0]['namespace'] == namespace
@pytest.mark.asyncio
async def test_server_filter_mode():
fake_context = get_fake_context('session')
config_module = dispatcher.get_service('config')
if not config_module.server:
await config_module.on_join(fake_context)
session = await dispatcher.call('v1',
'session.server.start',
fake_context,
id=3)
session_id = session['session_id']
assert session['mode'] == 'normal'
mode = 'expert'
await dispatcher.call('v1',
'session.server.filter',
fake_context,
session_id=session_id,
mode=mode)
list_result = await dispatcher.call('v1',
'session.server.list',
fake_context)
assert list_result[0]['mode'] == mode
@pytest.mark.asyncio
async def test_server_filter_debug():
fake_context = get_fake_context('session')
config_module = dispatcher.get_service('config')
if not config_module.server:
await config_module.on_join(fake_context)
session = await dispatcher.call('v1',
'session.server.start',
fake_context,
id=3)
session_id = session['session_id']
assert session['debug'] == False
debug = True
await dispatcher.call('v1',
'session.server.filter',
fake_context,
session_id=session_id,
debug=debug)
list_result = await dispatcher.call('v1',
'session.server.list',
fake_context)
assert list_result[0]['debug'] == debug
#FIXME
@pytest.mark.asyncio
async def test_server_filter_get():
fake_context = get_fake_context('session')
config_module = dispatcher.get_service('config')
if not config_module.server:
await config_module.on_join(fake_context)
session = await dispatcher.call('v1',
'session.server.start',
fake_context,
id=3)
session_id = session['session_id']
values = await dispatcher.call('v1',
'session.server.get',
fake_context,
session_id=session_id)
assert values == {'content': {"general.mode_conteneur_actif": "non",
"general.master.master": [],
"general.master.slave1": [],
"general.master.slave2": []},
'debug': False,
'id': 3,
'mode': 'normal',
'namespace': 'creole',
'session_id': session_id,
'timestamp': values['timestamp'],
'username': 'test'}
@pytest.mark.asyncio
async def test_server_filter_get_one_value():
fake_context = get_fake_context('session')
config_module = dispatcher.get_service('config')
if not config_module.server:
await config_module.on_join(fake_context)
session = await dispatcher.call('v1',
'session.server.start',
fake_context,
id=3)
session_id = session['session_id']
values = await dispatcher.call('v1',
'session.server.get',
fake_context,
session_id=session_id,
name="general.mode_conteneur_actif")
assert values == {'content': {"general.mode_conteneur_actif": "non"},
'debug': False,
'id': 3,
'mode': 'normal',
'namespace': 'creole',
'session_id': session_id,
'timestamp': values['timestamp'],
'username': 'test'}
@pytest.mark.asyncio
async def test_server_filter_configure():
fake_context = get_fake_context('session')
config_module = dispatcher.get_service('config')
if not config_module.server:
await config_module.on_join(fake_context)
session = await dispatcher.call('v1',
'session.server.start',
fake_context,
id=3)
session_id = session['session_id']
await dispatcher.call('v1',
'session.server.configure',
fake_context,
session_id=session_id,
action='modify',
name='general.mode_conteneur_actif',
value='oui')
list_result = await dispatcher.call('v1',
'session.server.list',
fake_context)
values = await dispatcher.call('v1',
'session.server.get',
fake_context,
session_id=session_id,
name="general.mode_conteneur_actif")
assert values == {'content': {"general.mode_conteneur_actif": "oui"},
'debug': False,
'id': 3,
'mode': 'normal',
'namespace': 'creole',
'session_id': session_id,
'timestamp': values['timestamp'],
'username': 'test'}
@pytest.mark.asyncio
async def test_server_filter_validate():
fake_context = get_fake_context('session')
config_module = dispatcher.get_service('config')
if not config_module.server:
await config_module.on_join(fake_context)
session = await dispatcher.call('v1',
'session.server.start',
fake_context,
id=3)
session_id = session['session_id']
await dispatcher.call('v1',
'session.server.validate',
fake_context,
session_id=session_id)
@pytest.mark.asyncio
async def test_server_stop():
fake_context = get_fake_context('session')
config_module = dispatcher.get_service('config')
if not config_module.server:
await config_module.on_join(fake_context)
assert not await dispatcher.call('v1',
'session.server.list',
fake_context)
start = await dispatcher.call('v1',
'session.server.start',
fake_context,
id=3)
session_id = start['session_id']
assert await dispatcher.call('v1',
'session.server.list',
fake_context)
await dispatcher.call('v1',
'session.server.stop',
fake_context,
session_id=session_id)
assert not await dispatcher.call('v1',
'session.server.list',
fake_context)
# servermodel
@pytest.mark.asyncio
async def test_servermodel_start():
fake_context = get_fake_context('session')
config_module = dispatcher.get_service('config')
if not config_module.servermodel:
await config_module.on_join(fake_context)
await dispatcher.call('v1',
'session.servermodel.start',
fake_context,
id=1)
@pytest.mark.asyncio
async def test_servermodel_list():
fake_context = get_fake_context('session')
config_module = dispatcher.get_service('config')
if not config_module.servermodel:
await config_module.on_join(fake_context)
assert not await dispatcher.call('v1',
'session.servermodel.list',
fake_context)
await dispatcher.call('v1',
'session.servermodel.start',
fake_context,
id=1)
assert await dispatcher.call('v1',
'session.servermodel.list',
fake_context)
@pytest.mark.asyncio
async def test_servermodel_filter_namespace():
fake_context = get_fake_context('session')
config_module = dispatcher.get_service('config')
if not config_module.servermodel:
await config_module.on_join(fake_context)
session = await dispatcher.call('v1',
'session.servermodel.start',
fake_context,
id=1)
session_id = session['session_id']
namespace = 'containers'
await dispatcher.call('v1',
'session.servermodel.filter',
fake_context,
session_id=session_id,
namespace=namespace)
list_result = await dispatcher.call('v1',
'session.servermodel.list',
fake_context)
assert list_result[0]['namespace'] == namespace
@pytest.mark.asyncio
async def test_servermodel_filter_mode():
fake_context = get_fake_context('session')
config_module = dispatcher.get_service('config')
if not config_module.servermodel:
await config_module.on_join(fake_context)
session = await dispatcher.call('v1',
'session.servermodel.start',
fake_context,
id=1)
session_id = session['session_id']
assert session['mode'] == 'normal'
mode = 'expert'
await dispatcher.call('v1',
'session.servermodel.filter',
fake_context,
session_id=session_id,
mode=mode)
list_result = await dispatcher.call('v1',
'session.servermodel.list',
fake_context)
assert list_result[0]['mode'] == mode
@pytest.mark.asyncio
async def test_servermodel_filter_debug():
fake_context = get_fake_context('session')
config_module = dispatcher.get_service('config')
if not config_module.servermodel:
await config_module.on_join(fake_context)
session = await dispatcher.call('v1',
'session.servermodel.start',
fake_context,
id=1)
session_id = session['session_id']
assert session['debug'] == False
debug = True
await dispatcher.call('v1',
'session.servermodel.filter',
fake_context,
session_id=session_id,
debug=debug)
list_result = await dispatcher.call('v1',
'session.servermodel.list',
fake_context)
assert list_result[0]['debug'] == debug
@pytest.mark.asyncio
async def test_servermodel_filter_get():
fake_context = get_fake_context('session')
config_module = dispatcher.get_service('config')
if not config_module.servermodel:
await config_module.on_join(fake_context)
session = await dispatcher.call('v1',
'session.servermodel.start',
fake_context,
id=1)
session_id = session['session_id']
values = await dispatcher.call('v1',
'session.servermodel.get',
fake_context,
session_id=session_id)
assert values == {'content': {"general.mode_conteneur_actif": "non",
"general.master.master": [],
"general.master.slave1": [],
"general.master.slave2": []},
'debug': False,
'id': 1,
'mode': 'normal',
'namespace': 'creole',
'session_id': session_id,
'timestamp': values['timestamp'],
'username': 'test'}
@pytest.mark.asyncio
async def test_servermodel_filter_get_one_value():
fake_context = get_fake_context('session')
config_module = dispatcher.get_service('config')
if not config_module.servermodel:
await config_module.on_join(fake_context)
session = await dispatcher.call('v1',
'session.servermodel.start',
fake_context,
id=1)
session_id = session['session_id']
values = await dispatcher.call('v1',
'session.servermodel.get',
fake_context,
session_id=session_id,
name="general.mode_conteneur_actif")
assert values == {'content': {"general.mode_conteneur_actif": "non"},
'debug': False,
'id': 1,
'mode': 'normal',
'namespace': 'creole',
'session_id': session_id,
'timestamp': values['timestamp'],
'username': 'test'}
@pytest.mark.asyncio
async def test_servermodel_filter_configure():
fake_context = get_fake_context('session')
config_module = dispatcher.get_service('config')
if not config_module.servermodel:
await config_module.on_join(fake_context)
session = await dispatcher.call('v1',
'session.servermodel.start',
fake_context,
id=1)
session_id = session['session_id']
await dispatcher.call('v1',
'session.servermodel.configure',
fake_context,
session_id=session_id,
action='modify',
name='general.mode_conteneur_actif',
value='oui')
list_result = await dispatcher.call('v1',
'session.servermodel.list',
fake_context)
values = await dispatcher.call('v1',
'session.servermodel.get',
fake_context,
session_id=session_id,
name="general.mode_conteneur_actif")
assert values == {'content': {"general.mode_conteneur_actif": "oui"},
'debug': False,
'id': 1,
'mode': 'normal',
'namespace': 'creole',
'session_id': session_id,
'timestamp': values['timestamp'],
'username': 'test'}
@pytest.mark.asyncio
async def test_servermodel_filter_validate():
fake_context = get_fake_context('session')
config_module = dispatcher.get_service('config')
if not config_module.servermodel:
await config_module.on_join(fake_context)
session = await dispatcher.call('v1',
'session.servermodel.start',
fake_context,
id=1)
session_id = session['session_id']
await dispatcher.call('v1',
'session.servermodel.validate',
fake_context,
session_id=session_id)
@pytest.mark.asyncio
async def test_servermodel_stop():
fake_context = get_fake_context('session')
config_module = dispatcher.get_service('config')
if not config_module.servermodel:
await config_module.on_join(fake_context)
assert not await dispatcher.call('v1',
'session.servermodel.list',
fake_context)
start = await dispatcher.call('v1',
'session.servermodel.start',
fake_context,
id=1)
session_id = start['session_id']
assert await dispatcher.call('v1',
'session.servermodel.list',
fake_context)
await dispatcher.call('v1',
'session.servermodel.stop',
fake_context,
session_id=session_id)
assert not await dispatcher.call('v1',
'session.servermodel.list',
fake_context)