Compare commits

..

4 Commits

Author SHA1 Message Date
424273360d verify audience in jwt 2020-01-30 15:46:18 +01:00
ae6dfb2644 add audience claim data to jwt 2020-01-24 15:07:30 +01:00
d78d581c65 implement basicauth and jwt token 2020-01-24 13:43:14 +01:00
52c878b0ab replace all zephir occurence 2020-01-23 14:05:07 +01:00
58 changed files with 473 additions and 513 deletions

View File

@ -26,7 +26,8 @@ docker exec -ti postgres bash
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;"
psql -U postgres -h localhost -c "CREATE EXTENSION hstore;" risotto
psql -U postgres -h localhost -c "CREATE EXTENSION hstore;"
psql -U postgres -h localhost -c "CREATE EXTENSION pgcrypto;"
```
Gestion de la base de données avec Sqitch
@ -44,67 +45,22 @@ 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;
psql -U postgres tiramisu
drop table value; drop table property; drop table permissive; drop table information; drop table session;
# 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 new user and set role 'server_rw' for this server
./script/cucchiaiata user.create -l gnunux -n gnunux -s gnunux
./script/cucchiaiata user.role.create -u gnunux -n 'server_rw' -a 'Server.ServerName' -v test
# Heritage
## ACA
./script/cucchiaiata servermodel.create -n aca -d Aca -p eolebase -s eole -r last
./script/cucchiaiata session.servermodel.start -s aca
S=xxxxxxxxxxxxxxxxxxxxxx
### verif
./script/cucchiaiata session.servermodel.get -s $S -n creole.reseau.unbound_route_address
./script/cucchiaiata session.servermodel.get -s $S -n creole.reseau.unbound_domain_name
./script/cucchiaiata session.servermodel.get -s $S -n creole.serveur_dns.unbound_local_zones
./script/cucchiaiata session.servermodel.get -s $S -n creole.reseau.unbound_ip_address_cidr
./script/cucchiaiata session.servermodel.configure -s $S --creole.reseau.unbound_route_address 192.168.1.2
./script/cucchiaiata session.servermodel.configure -s $S --creole.serveur_dns.unbound_allowed_client_cidr 192.168.1.0/24
./script/cucchiaiata session.servermodel.stop -s $S -a
## etab1
./script/cucchiaiata servermodel.create -n etab1 -d "Etab 1" -p aca -s internal -r last
./script/cucchiaiata session.servermodel.start -s etab1
S=xxxxxxxxxxxxxxxxxxxxxx
./script/cucchiaiata session.servermodel.configure -s $S --creole.reseau.unbound_domain_name test.cadoles.com
./script/cucchiaiata session.servermodel.stop -s $S -a
## unbound
./script/cucchiaiata servermodel.create -n unbound -d "generic unbound configuration" -p eolebase -s eole -r last
./script/cucchiaiata session.servermodel.start -s unbound
S=xxxxxxxxxxxxxxxxxxxxxx
./script/cucchiaiata session.servermodel.configure -s $S --creole.serveur_dns.unbound_local_zones cadoles.com
./script/cucchiaiata session.servermodel.filter -s $S -n unbound
./script/cucchiaiata session.servermodel.configure -s $S --unbound.unbound_zone_cadoles_com.hostname_cadoles_com.hostname_cadoles_com toto titi
./script/cucchiaiata session.servermodel.configure -s $S --unbound.unbound_zone_cadoles_com.hostname_cadoles_com.ip_cadoles_com 0 192.168.1.25
./script/cucchiaiata session.servermodel.configure -s $S --unbound.unbound_zone_cadoles_com.hostname_cadoles_com.type_cadoles_com 1 CNAME
./script/cucchiaiata session.servermodel.configure -s $S --unbound.unbound_zone_cadoles_com.hostname_cadoles_com.cname_cadoles_com 1 toto.cadoles.com
./script/cucchiaiata session.servermodel.stop -s $S -a
## unbound_etab1
./script/cucchiaiata servermodel.create -n unbound_etab1 -d "unbound configuration for etab1" -p etab1 unbound -s internal -r last
### verif
./script/cucchiaiata session.servermodel.start -s unbound_etab1
S=xxxxxxxxxxxxxxxxxxxxxx
XXXXX
# Create a server
./script/cucchiaiata server.create -s test -d description -m unbound_etab1 -n internal -r last
./script/cucchiaiata server.create -s test -d description -m eolebase -n eole -r last
# Configure the server
./script/cucchiaiata session.server.start -s test
S=xxxxxxxxxxxxxxxxxxxxxx
./script/cucchiaiata session.server.configure -s $S --creole.reseau.unbound_ip_address_cidr 192.168.1.1/24
./script/cucchiaiata session.server.configure -s $S --creole.reseau.unbound_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
@ -112,6 +68,6 @@ S=xxxxxxxxxxxxxxxxxxxxxx
./script/cucchiaiata config.configuration.server.deploy -s test
./script/cucchiaiata template.generate -s test
# OpenSSH:
./script/cucchiaiata server.create -s test -d description -m eolebase -n internal -r last
# Create a new user and set role 'server_rw' for this server
./script/cucchiaiata user.create -l gnunux -n gnunux -s gnunux
./script/cucchiaiata user.role.create -u gnunux -n 'server_rw' -a 'Server.ServerName' -v test

View File

@ -20,7 +20,7 @@ RUN ln -s /srv/src/tiramisu/tiramisu /usr/local/lib/python3.7
RUN ln -s /srv/src/rougail/src/rougail /usr/local/lib/python3.7
RUN ln -s /srv/src/risotto/src/risotto /usr/local/lib/python3.7
RUN pip install Cheetah3
RUN pip install Cheetah3 PyJWT
RUN cd /srv/src/risotto && pip install -r requirements.txt
# Installation

View File

@ -6,6 +6,7 @@ services:
dockerfile: docker/Dockerfile
volumes:
- ../.:/srv/src/risotto
- ../messages:/usr/local/lib/messages
ports:
- "8080:8080"
depends_on:
@ -15,9 +16,6 @@ services:
#command: tail -F /var/log
command: python -u /srv/src/risotto/script/server.py
restart: on-failure
environment:
RISOTTO_DSN: ${RISOTTO_DSN:-postgres://risotto:risotto@postgres:5432/risotto}
RISOTTO_TIRAMISU_DSN: ${RISOTTO_TIRAMISU_DSN:-postgres://risotto:risotto@postgres:5432/tiramisu}
postgres:
image: postgres:11-alpine
environment:

View File

@ -7,6 +7,7 @@ psql --username "$POSTGRES_USER" <<-EOSQL
GRANT ALL ON DATABASE risotto TO risotto;
\c risotto
CREATE EXTENSION hstore;
CREATE EXTENSION pgcrypto;
EOSQL
psql --username "risotto" --password "risotto" <<-EOSQL
@ -64,6 +65,7 @@ psql --username "risotto" --password "risotto" <<-EOSQL
CREATE TABLE RisottoUser (
UserId SERIAL PRIMARY KEY,
UserLogin VARCHAR(100) NOT NULL UNIQUE,
UserPassword TEXT NOT NULL,
UserName VARCHAR(100) NOT NULL,
UserSurname VARCHAR(100) NOT NULL
);

View File

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

View File

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

View File

@ -5,7 +5,7 @@ description: |
Retourne des informations sur la session HTTP courante de l'utilisateur.
sampleuse: |
zephir-client identity.session-user.get
cucchiaiata identity.session-user.get
pattern: rpc

View File

@ -5,7 +5,7 @@ description: |
Retourne les préférences de l'utilisateur spécifié.
sampleuse: |
zephir-client identity.settings.get -u yo
cucchiaiata identity.settings.get -u yo
pattern: rpc

View File

@ -5,7 +5,7 @@ description: |
Enregistre des préférences pour l'utilisateur spécifié.
sampleuse: |
zephir-client identity.settings.set -u yo
cucchiaiata identity.settings.set -u yo
pattern: rpc

View File

@ -11,7 +11,7 @@ pattern: rpc
domain: server-domain
sampleuse: |
zephir-client server.delete -s 1
cucchiaiata server.delete -s 1
parameters:
serverid:

View File

@ -5,7 +5,7 @@ description: |
Transmet une commande à exécuter sur un serveur donné.
sampleuse: |
zephir-client server.exec.command -s 1 -c reconfigure
cucchiaiata server.exec.command -s 1 -c reconfigure
domain: server-domain

View File

@ -5,7 +5,7 @@ description: |
Déploie la configuration sur un serveur donné.
sampleuse: |
zephir-client server.exec.deploy -s 1
cucchiaiata server.exec.deploy -s 1
domain: server-domain

View File

@ -5,7 +5,7 @@ description: |
Liste les commandes exécuté pour un identifiant de tâche.
sampleuse: |
zephir-client server.exec.list -j 1
cucchiaiata server.exec.list -j 1
domain: execution-domain

View File

@ -5,7 +5,7 @@ description: |
Liste les commandes exécutées sur un serveur donné.
sampleuse: |
zephir-client server.exec.list -s 1
cucchiaiata server.exec.list -s 1
domain: execution-domain

View File

@ -5,7 +5,7 @@ description: |
Retourne la liste des sélections de serveurs d'un serveur
sampleuse: |
zephir-client server.serverselection.list
cucchiaiata server.serverselection.list
pattern: rpc

View File

@ -7,7 +7,7 @@ description: |
public: true
sampleuse: |
zephir-client server.update -s 1 -n toto -d "server description"
cucchiaiata server.update -s 1 -n toto -d "server description"
pattern: rpc

View File

@ -5,7 +5,7 @@ description: |
Associe un service applicatif à un modèle de serveur.
sampleuse: |
zephir-client servermodel.applicationservice.join -m 1 -s 1
cucchiaiata servermodel.applicationservice.join -m 1 -s 1
pattern: rpc

View File

@ -5,7 +5,7 @@ description: |
Retourne la liste des applications service.
sampleuse: |
zephir-client servermodel.applicationservice.list -s 6
cucchiaiata servermodel.applicationservice.list -s 6
pattern: rpc

View File

@ -5,7 +5,7 @@ description: |
Crée un modèle de serveur.
sampleuse: |
zephir-client servermodel.create -p 1 -n "MonServeurModele" -d "Ma description" -s 1
cucchiaiata servermodel.create -p 1 -n "MonServeurModele" -d "Ma description" -s 1
pattern: rpc

View File

@ -5,7 +5,7 @@ description: |
Retourne la liste des subreleases.
sampleuse: |
zephir-client servermodel.subrelease.list
cucchiaiata servermodel.subrelease.list
pattern: rpc

View File

@ -5,7 +5,7 @@ description: |
Crée un sélection de serveurs.
sampleuse: |
zephir-client serverselection.create -n Select1 -d "Ma description"
cucchiaiata serverselection.create -n Select1 -d "Ma description"
pattern: rpc

View File

@ -5,7 +5,7 @@ description: |
Supprime une sélection de serveurs.
sampleuse: |
zephir-client serverselection.delete -s 1
cucchiaiata serverselection.delete -s 1
pattern: rpc

View File

@ -6,7 +6,7 @@ description: |
sampleuse: |
zephir-client serverselection.describe -s 1
cucchiaiata serverselection.describe -s 1
pattern: rpc

View File

@ -5,7 +5,7 @@ description: |
Transmet une commande à exécuter sur une sélection de serveurs.
sampleuse: |
zephir-client serverselection.exec.command -s 1 -c reconfigure
cucchiaiata serverselection.exec.command -s 1 -c reconfigure
domain: server-domain

View File

@ -5,7 +5,7 @@ description: |
Déploie la configuration sur les serveurs d'une sélection de serveurs.
sampleuse: |
zephir-client serverselection.exec.deploy -s 1
cucchiaiata serverselection.exec.deploy -s 1
domain: server-domain

View File

@ -5,7 +5,7 @@ description: |
Retourne la liste des sélections de serveurs.
sampleuse: |
zephir-client serverselection.list
cucchiaiata serverselection.list
pattern: rpc

View File

@ -5,7 +5,7 @@ description: |
Ajoute un serveur à une sélection de serveurs.
sampleuse: |
zephir-client serverselection.add.server -s 1 -i 1
cucchiaiata serverselection.add.server -s 1 -i 1
pattern: rpc

View File

@ -5,7 +5,7 @@ description: |
Supprime un serveur d'une sélection de serveurs.
sampleuse: |
zephir-client serverselection.remove.server -s 1 -i 1
cucchiaiata serverselection.remove.server -s 1 -i 1
pattern: rpc

View File

@ -5,7 +5,7 @@ description: |
Renseigne une liste de serveur dans une sélection de serveurs.
sampleuse: |
zephir-client serverselection.server.set -s 1 -i 1
cucchiaiata serverselection.server.set -s 1 -i 1
pattern: rpc

View File

@ -5,7 +5,7 @@ description: |
Modifie une sélection de serveur.
sampleuse: |
zephir-client serverselection.update -s 1 -n Select1 -d "Ma description"
cucchiaiata serverselection.update -s 1 -n Select1 -d "Ma description"
pattern: rpc

View File

@ -5,7 +5,7 @@ description: |
Associe un utilisateur à une sélection de serveurs.
sampleuse: |
zephir-client serverselection.add.user -s 1 -u yo -r admin
cucchiaiata serverselection.add.user -s 1 -u yo -r admin
pattern: rpc

View File

@ -5,7 +5,7 @@ description: |
Retourne la sélection de serveurs par défaut de l'utilisateur.
sampleuse: |
zephir-client serverselection.user.default
cucchiaiata serverselection.user.default
pattern: rpc

View File

@ -5,7 +5,7 @@ description: |
Retourne les sélections de serveurs dont l'utilisateur fait parti.
sampleuse: |
zephir-client serverselection.user.list
cucchiaiata serverselection.user.list
pattern: rpc

View File

@ -5,7 +5,7 @@ description: |
Dissocie un utilisateur d'une sélection de serveurs.
sampleuse: |
zephir-client serverselection.remove.user -s 1 -u yo
cucchiaiata serverselection.remove.user -s 1 -u yo
pattern: rpc

View File

@ -5,7 +5,7 @@ description: |
Retourne le rôle d'utilisateur sur une selection de serveurs.
sampleuse: |
zephir-client serverselection.user.role.get -d '{}'
cucchiaiata serverselection.user.role.get -d '{}'
pattern: rpc

View File

@ -5,7 +5,7 @@ description: |
Retourne le rôle d'un utlisateur sur un serveur.
sampleuse: |
zephir-client serverselection.user.role.server.get -d '{}'
cucchiaiata serverselection.user.role.server.get -d '{}'
pattern: rpc

View File

@ -5,7 +5,7 @@ description: |
Modifie le rôle d'un utilisateur pour une sélection de serveurs.
sampleuse: |
zephir-client serverselection.update.user -s 1 -u yo -r admin
cucchiaiata serverselection.update.user -s 1 -u yo -r admin
pattern: rpc

View File

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

View File

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

View File

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

View File

@ -11,6 +11,10 @@ parameters:
shortarg: l
description: Login de l'utilisateur.
ref: User.Login
user_password:
type: String
shortarg: p
description: Password de l'utilisateur.
user_name:
type: String
shortarg: n

View File

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

View File

@ -57,6 +57,7 @@ CREATE TABLE Server (
CREATE TABLE RisottoUser (
UserId SERIAL PRIMARY KEY,
UserLogin VARCHAR(100) NOT NULL UNIQUE,
UserPassword TEXT NOT NULL,
UserName VARCHAR(100) NOT NULL,
UserSurname VARCHAR(100) NOT NULL
);
@ -96,8 +97,16 @@ CREATE TABLE log(
"""
async def main():
db_conf = get_config()['database']['dsn']
pool = await asyncpg.create_pool(db_conf)
db_conf = get_config().get('database')
#asyncpg.connect('postgresql://postgres@localhost/test')
engine = db_conf.get('engine')
host = db_conf.get('host')
dbname = db_conf.get('dbname')
dbuser = db_conf.get('user')
dbpassword = db_conf.get('password')
dbport = db_conf.get('port')
cfg = "{}://{}:{}@{}:{}/{}".format(engine, dbuser, dbpassword, host, dbport, dbname)
pool = await asyncpg.create_pool(cfg)
async with pool.acquire() as connection:
async with connection.transaction():
returns = await connection.execute(VERSION_INIT)

View File

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

View File

@ -1,31 +1,45 @@
MESSAGE_ROOT_PATH = 'messages'
DATABASE_DIR = '/var/cache/risotto/database'
INTERNAL_USER = 'internal'
CONFIGURATION_DIR = 'configurations'
TEMPLATE_DIR = 'templates'
TMP_DIR = 'tmp'
DEFAULT_USER = 'Anonymous'
DEFAULT_DSN = 'postgres:///risotto?host=/var/run/postgresql/&user=risotto'
DEFAULT_TIRAMISU_DSN = 'postgres:///tiramisu?host=/var/run/postgresql/&user=tiramisu'
ROUGAIL_DTD_PATH = '../rougail/data/creole.dtd'
DEFAULT_USER = 'gnunux'
DEFAULT_USER_PASSWORD = 'gnunux'
URI = 'http://localhost'
PORT = 8080
JWT_SECRET = 'MY_SUPER_SECRET'
JWT_TOKEN_EXPIRE = 3600
JWT_TOKEN_AUDIENCE = "Risotto"
from os import environ
import os
from pathlib import PurePosixPath
CURRENT_PATH = PurePosixPath(__file__)
def get_config():
return {'database': {'dsn': environ.get('RISOTTO_DSN', DEFAULT_DSN),
'tiramisu_dsn': environ.get('RISOTTO_TIRAMISU_DSN', DEFAULT_TIRAMISU_DSN),
return {'database': {'engine': 'postgres',
'host': 'postgres',
'port': 5432,
'dbname': 'risotto',
'user': 'risotto',
'password': 'risotto',
},
'http_server': {'port': 8080,
#'default_user': "gnunux"},
'http_server': {'port': PORT,
'default_user': DEFAULT_USER},
'global': {'message_root_path': CURRENT_PATH.parents[2] / 'messages',
'debug': True,
'internal_user': 'internal',
'check_role': True,
'admin_user': DEFAULT_USER},
'rougail_dtd_path': '../rougail/data/creole.dtd',
'admin_user': DEFAULT_USER,
'admin_user_password': DEFAULT_USER_PASSWORD},
'source': {'root_path': '/srv/seed'},
'cache': {'root_path': '/var/cache/risotto'},
'servermodel': {'internal_source': 'internal',
'internal_distribution': 'last'},
'jwt': {
'secret': JWT_SECRET,
'token_expire': JWT_TOKEN_EXPIRE,
'issuer': URI,
'audience': JWT_TOKEN_AUDIENCE}
}

View File

@ -38,7 +38,8 @@ class CallDispatcher:
raise Exception('hu?')
else:
for ret in returns:
async with await Config(response, display_name=lambda self, dyn_name: self.impl_getname()) as config:
config = await Config(response,
display_name=lambda self, dyn_name: self.impl_getname())
await config.property.read_write()
try:
for key, value in ret.items():
@ -87,7 +88,6 @@ class CallDispatcher:
kwargs,
function_objs)
else:
try:
async with self.pool.acquire() as connection:
await connection.set_type_codec(
'json',
@ -103,23 +103,6 @@ class CallDispatcher:
check_role,
kwargs,
function_objs)
except CallError as err:
raise err
except Exception as err:
# if there is a problem with arguments, just send an error and do nothing
if get_config()['global']['debug']:
print_exc()
async with self.pool.acquire() as connection:
await connection.set_type_codec(
'json',
encoder=dumps,
decoder=loads,
schema='pg_catalog'
)
risotto_context.connection = connection
async with connection.transaction():
await log.error_msg(risotto_context, kwargs, err)
raise err
class PublishDispatcher:
@ -144,7 +127,6 @@ class PublishDispatcher:
kwargs,
function_objs)
else:
try:
async with self.pool.acquire() as connection:
await connection.set_type_codec(
'json',
@ -160,23 +142,6 @@ class PublishDispatcher:
check_role,
kwargs,
function_objs)
except CallError as err:
raise err
except Exception as err:
# if there is a problem with arguments, just send an error and do nothing
if get_config()['global']['debug']:
print_exc()
async with self.pool.acquire() as connection:
await connection.set_type_codec(
'json',
encoder=dumps,
decoder=loads,
schema='pg_catalog'
)
risotto_context.connection = connection
async with connection.transaction():
await log.error_msg(risotto_context, kwargs, err)
raise err
class Dispatcher(register.RegisterDispatcher, CallDispatcher, PublishDispatcher):
@ -217,7 +182,7 @@ class Dispatcher(register.RegisterDispatcher, CallDispatcher, PublishDispatcher)
""" create a new Config et set values to it
"""
# create a new config
async with await Config(self.option) as config:
config = await Config(self.option)
await config.property.read_write()
# set message's option
await config.option('message').value.set(risotto_context.message)
@ -303,10 +268,19 @@ class Dispatcher(register.RegisterDispatcher, CallDispatcher, PublishDispatcher)
function_objs: List) -> Optional[Dict]:
await self.check_message_type(risotto_context,
kwargs)
try:
config_arguments = await self.load_kwargs_to_config(risotto_context,
f'{version}.{message}',
kwargs,
check_role)
except Exception as err:
# if there is a problem with arguments, just send an error and do nothing
if get_config()['global']['debug']:
print_exc()
await log.error_msg(risotto_context, kwargs, err)
if risotto_context.type == 'rpc':
raise err
return
# config is ok, so send the message
for function_obj in function_objs:
function = function_obj['function']
@ -332,13 +306,13 @@ class Dispatcher(register.RegisterDispatcher, CallDispatcher, PublishDispatcher)
raise err
continue
except Exception as err:
if risotto_context.type == 'rpc':
raise err
if get_config().get('global').get('debug'):
print_exc()
await log.error_msg(risotto_context,
kwargs,
err)
if risotto_context.type == 'rpc':
raise CallError(str(err))
continue
else:
if risotto_context.type == 'rpc':

View File

@ -1,8 +1,10 @@
from aiohttp.web import Application, Response, get, post, HTTPBadRequest, HTTPInternalServerError, HTTPNotFound
from aiohttp.web import Application, Response, get, post, HTTPBadRequest, HTTPInternalServerError, HTTPNotFound, HTTPUnauthorized
from aiohttp import BasicAuth, RequestInfo
from json import dumps
from traceback import print_exc
from tiramisu import Config, default_storage
from tiramisu import Config
import datetime
import jwt
from .dispatcher import dispatcher
from .utils import _
@ -16,6 +18,16 @@ from .services import load_services
def create_context(request):
risotto_context = Context()
if 'Authorization' in request.headers:
token = request.headers['Authorization']
if not token.startswith("Bearer "):
raise HTTPBadRequest(reason='Unexpected bearer format')
token = token[7:]
decoded = verify_token(token)
if 'user' in decoded:
risotto_context.username = decoded['user']
return risotto_context
else:
risotto_context.username = request.match_info.get('username',
get_config()['http_server']['default_user'])
return risotto_context
@ -49,7 +61,7 @@ class extra_route_handler:
try:
returns = await cls.function(**kwargs)
except NotAllowedError as err:
raise HTTPNotFound(reason=str(err))
raise HTTPUnauthorized(reason=str(err))
except CallError as err:
raise HTTPBadRequest(reason=str(err))
except Exception as err:
@ -77,7 +89,7 @@ async def handle(request):
check_role=True,
**kwargs)
except NotAllowedError as err:
raise HTTPNotFound(reason=str(err))
raise HTTPUnauthorized(reason=str(err))
except CallError as err:
raise HTTPBadRequest(reason=str(err).replace('\n', ' '))
except Exception as err:
@ -102,7 +114,7 @@ async def api(request, risotto_context):
WHERE RoleURI.URIId = URI.URIId
'''
uris = [uri['uriname'] for uri in await connection.fetch(sql)]
async with await Config(get_messages(load_shortarg=True, uris=uris)[1]) as config:
config = await Config(get_messages(load_shortarg=True, uris=uris)[1])
await config.property.read_write()
tiramisu = await config.option.dict(remotable='none')
return tiramisu
@ -119,7 +131,6 @@ async def get_app(loop):
load_services()
app = Application(loop=loop)
routes = []
default_storage.engine('dictionary')
await dispatcher.load()
for version, messages in dispatcher.messages.items():
print()
@ -142,8 +153,76 @@ async def get_app(loop):
print()
del extra_routes
app.add_routes(routes)
app.router.add_post('/auth', auth)
app.router.add_post('/access_token', access_token)
await dispatcher.on_join()
return await loop.create_server(app.make_handler(), '*', get_config()['http_server']['port'])
async def auth(request):
auth_code = request.headers['Authorization']
if not auth_code.startswith("Basic "):
raise HTTPBadRequest(reason='Unexpected bearer format')
auth = BasicAuth.decode(auth_code)
async with dispatcher.pool.acquire() as connection:
async with connection.transaction():
# Check role with ACL
sql = '''
SELECT UserName
FROM RisottoUser
WHERE UserLogin = $1
AND UserPassword = crypt($2, UserPassword);
'''
res = await connection.fetch(sql, auth.login, auth.password)
if res:
res = gen_token(auth)
if verify_token(res):
return Response(text=str(res.decode('utf-8')))
else:
return HTTPInternalServerError(reason='Token could not be verified just after creation')
else:
raise HTTPUnauthorized(reason='Unauthorized')
def gen_token(auth):
secret = get_config()['jwt']['secret']
expire = get_config()['jwt']['token_expire']
issuer = get_config()['jwt']['issuer']
audience = get_config()['jwt']['audience']
payload = {
'user': auth.login,
'exp': datetime.datetime.utcnow() + datetime.timedelta(seconds=expire),
'iss': issuer,
'aud': audience
}
token = jwt.encode(payload, secret, algorithm='HS256')
return token
def access_token(request):
expire = get_config()['jwt']['token_expire']
secret = get_config()['jwt']['secret']
token = request.headers['Authorization']
if not token.startswith("Bearer "):
raise HTTPBadRequest(reason='Unexpected bearer format')
token = token[7:]
decoded = verify_token(token)
if decoded:
decoded['exp'] = datetime.datetime.utcnow() + datetime.timedelta(seconds=expire)
token = jwt.encode(decoded, secret, algorithm='HS256')
return Response(text=str(token.decode('utf-8')))
else:
return HTTPUnauthorized(reason='Token could not be verified')
def verify_token(token):
secret = get_config()['jwt']['secret']
issuer = get_config()['jwt']['issuer']
audience = get_config()['jwt']['audience']
try:
decoded = jwt.decode(token, secret, issuer=issuer, audience=audience, algorithms=['HS256'])
except jwt.ExpiredSignatureError:
raise HTTPUnauthorized(reason='Token Expired')
except jwt.InvalidIssuerError:
raise HTTPUnauthorized(reason='Token could not be verified')
except jwt.InvalidAudienceError:
raise HTTPUnauthorized(reason='Token audience not match')
return decoded
tiramisu = None

View File

@ -38,7 +38,7 @@ class AnyOption(Option):
class MessageDefinition:
"""
A MessageDefinition is a representation of a message in the Zephir application messaging context
A MessageDefinition is a representation of a message in the Risotto application messaging context
"""
__slots__ = ('version',
'uri',
@ -135,7 +135,7 @@ class ParameterDefinition:
class ResponseDefinition:
"""
An ResponseDefinition is a representation of a response in the Zephir application messaging context
An ResponseDefinition is a representation of a response in the Risotto application messaging context
"""
__slots__ = ('description',
'type',
@ -184,7 +184,7 @@ class ResponseDefinition:
class ErrorDefinition:
"""
An ErrorDefinition is a representation of an error in the Zephir application messaging context
An ErrorDefinition is a representation of an error in the Risotto application messaging context
"""
__slots__ = ('uri',)

View File

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

View File

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

View File

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

View File

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

View File

@ -12,15 +12,12 @@ from .storage import storage_server, storage_servermodel
from ...controller import Controller
from ...register import register
from ...dispatcher import dispatcher
from ...config import get_config
class Risotto(Controller):
def __init__(self,
test):
self.modify_storage = Storage(engine='dictionary')
self.internal_source_name = get_config()['servermodel']['internal_source']
self.internal_distribution_name = get_config()['servermodel']['internal_distribution']
def get_storage(self,
type: str):
@ -113,15 +110,17 @@ class Risotto(Controller):
@register('v1.session.servermodel.start')
async def start_session_servermodel(self,
risotto_context: Context,
servermodel_name: str) -> Dict:
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=self.internal_source_name,
release_distribution=self.internal_distribution_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']
@ -294,7 +293,7 @@ class Risotto(Controller):
modif_config = session['config']
await config.value.importation(await modif_config.value.exportation())
await config.permissive.importation(await modif_config.permissive.exportation())
await storage.del_session(session_id)
storage.del_session(session_id)
return self.format_session(session_id, session)
@register_http('v1', '/config/server/{session_id}')

View File

@ -103,21 +103,8 @@ class Storage(object):
raise NotAllowedError()
return session
async def del_session(self,
def del_session(self,
id: int):
config = self.sessions[id]['meta']
while True:
try:
children = list(await config.config.list())
if not children:
# it's an empty metaconfig
break
config = children[0]
await config.session.reset()
except:
# it's a config, so no "list" method
break
await self.sessions[id]['meta'].session.reset()
del self.sessions[id]

View File

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

View File

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

View File

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

View File

@ -13,6 +13,7 @@ class Risotto(Controller):
""" pre-load servermodel and server
"""
user_login = get_config()['global']['admin_user']
user_password = get_config()['global']['admin_user_password']
sql = '''
SELECT UserId
FROM RisottoUser
@ -22,6 +23,7 @@ class Risotto(Controller):
user_login) is None:
await self._user_create(risotto_context,
user_login,
user_password,
user_login,
user_login)
await self._user_role_create(risotto_context,
@ -33,14 +35,16 @@ class Risotto(Controller):
async def _user_create(self,
risotto_context: Context,
user_login: str,
user_password: str,
user_name: str,
user_surname: str) -> Dict:
user_insert = """INSERT INTO RisottoUser(UserLogin, UserName, UserSurname)
VALUES ($1,$2,$3)
user_insert = """INSERT INTO RisottoUser(UserLogin, UserPassword, UserName, UserSurname)
VALUES ($1,crypt($2, gen_salt('bf')),$3,$4)
RETURNING UserId
"""
user_id = await risotto_context.connection.fetchval(user_insert,
user_login,
user_password,
user_name,
user_surname)
await self.call('v1.user.role.create',
@ -56,10 +60,12 @@ class Risotto(Controller):
async def user_create(self,
risotto_context: Context,
user_login: str,
user_password: str,
user_name: str,
user_surname: str) -> Dict:
return await self._user_create(risotto_context,
user_login,
user_password,
user_name,
user_surname)