Compare commits

..

12 Commits

32 changed files with 1054 additions and 593 deletions

View File

@ -20,13 +20,13 @@ docker run -d --add-host reload.example.com:127.0.0.1 -p 80:80 coudot/lemonldap-
Démarrer un serveur postgresql de test
```
podman pull docker.io/library/postgres:11-alpine
podman run -dt -p 5432:5432 postgres:11-alpine
docker run -dt -p 5432:5432 --name postgres postgres:11-alpine
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;" risotto
```
Gestion de la base de données avec Sqitch
@ -44,22 +44,67 @@ 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 server
./script/cucchiaiata server.create -s test -d description -m eolebase -n 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 -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 --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.configure -s $S --creole.reseau.unbound_ip_address_cidr 192.168.1.1/24
./script/cucchiaiata session.server.validate -s $S
./script/cucchiaiata session.server.stop -s $S -a
@ -67,6 +112,14 @@ S=xxxxxxxxxxxxxxxxxxxxxx
./script/cucchiaiata config.configuration.server.deploy -s test
./script/cucchiaiata template.generate -s test
# Create a new user and set role 'server_rw' for this server
./script/cucchiaiata user.create -l gnunux -n gnunux -s gnunux
./script/cucchiaiata user.role.create -u gnunux -n 'server_rw' -a 'Server.ServerName' -v test
# OpenSSH
#add servermodel openssh link to eolebase
#add servermodel openssh2 lint to openssh
#link openssh applicationservice to this servermodel
./script/cucchiaiata servermodel.create -n openssh_1 -d description -p eolebase -s eole -r last
./script/cucchiaiata servermodel.create -n openssh_2 -d openssh_2 -p openssh_1 -s internal -r last
./script/cucchiaiata applicationservice.dependency.add -n local_openssh_1 -a openssh -s eole -r last
#./script/cucchiaiata server.create -s test -d description -m eolebase -r last

29
docker/Dockerfile Normal file
View File

@ -0,0 +1,29 @@
FROM python:3.7
# Requirements
ARG TIRAMISU_REPO_URL=https://framagit.org/tiramisu/tiramisu.git
ARG RISOTTO_REPO_URL=https://forge.cadoles.com/Infra/risotto.git
ARG ROUGAIL_REPO_URL=https://forge.cadoles.com/Infra/rougail.git
RUN apt-get update && apt-get install -y \
vim \
curl \
git \
jq \
&& apt-get clean
RUN git clone --branch develop ${TIRAMISU_REPO_URL} /srv/src/tiramisu
RUN git clone --branch docker ${RISOTTO_REPO_URL} /srv/src/risotto
RUN git clone --branch master ${ROUGAIL_REPO_URL} /srv/src/rougail
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 cd /srv/src/risotto && pip install -r requirements.txt
# Installation
RUN cp -r /srv/src/risotto/messages/ /usr/local/lib/
RUN mkdir -p /var/cache/risotto/servermodel
RUN mkdir -p /var/cache/risotto/database

14
docker/README.md Normal file
View File

@ -0,0 +1,14 @@
Docker
```
cd docker
docker build -t cadoles/risotto .
docker run -t -d --name risotto cadoles/risotto
docker exec -ti risotto bash
```
Docker-Compose
```
cd docker
docker-compose up
```

View File

@ -0,0 +1,31 @@
version: '2.2'
services:
risotto:
build:
context: ../
dockerfile: docker/Dockerfile
volumes:
- ../.:/srv/src/risotto
ports:
- "8080:8080"
depends_on:
- postgres
links:
- postgres
#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:
POSTGRES_USER: ${POSTGRES_USER:-postgres}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgres}
PGDATA: /data/postgres
volumes:
- ./postgres-init/:/docker-entrypoint-initdb.d/
ports:
- "5432:5432"
restart: unless-stopped

View File

@ -0,0 +1,103 @@
#!/bin/bash
set -e
psql --username "$POSTGRES_USER" <<-EOSQL
CREATE ROLE risotto WITH LOGIN PASSWORD 'risotto';
CREATE DATABASE risotto;
GRANT ALL ON DATABASE risotto TO risotto;
\c risotto
CREATE EXTENSION hstore;
EOSQL
psql --username "risotto" --password "risotto" <<-EOSQL
-- Création de la table Source
CREATE TABLE Source (
SourceId SERIAL PRIMARY KEY,
SourceName VARCHAR(255) NOT NULL UNIQUE,
SourceURL TEXT
);
-- Création de la table Release
CREATE TABLE Release (
ReleaseId SERIAL PRIMARY KEY,
ReleaseName VARCHAR(255) NOT NULL,
ReleaseSourceId INTEGER NOT NULL,
ReleaseDistribution VARCHAR(20) CONSTRAINT releasedistribution_choice CHECK (ReleaseDistribution IN ('last', 'n-1', 'n-2')),
UNIQUE (ReleaseName, ReleaseSourceId),
UNIQUE (ReleaseDistribution, ReleaseSourceId),
FOREIGN KEY (ReleaseSourceId) REFERENCES Source(SourceId)
);
-- Création de la table Servermodel
CREATE TABLE Servermodel (
ServermodelId SERIAL PRIMARY KEY,
ServermodelName VARCHAR(255) NOT NULL,
ServermodelDescription VARCHAR(255) NOT NULL,
ServermodelParentsId INTEGER [] DEFAULT '{}',
ServermodelReleaseId INTEGER NOT NULL,
ServermodelApplicationServiceId INTEGER NOT NULL,
ServermodelUsers hstore,
UNIQUE (ServermodelName, ServermodelReleaseId)
);
-- Création de la table ApplicationService
CREATE TABLE ApplicationService (
ApplicationServiceId SERIAL PRIMARY KEY,
ApplicationServiceName VARCHAR(255) NOT NULL,
ApplicationServiceDescription VARCHAR(255) NOT NULL,
ApplicationServiceReleaseId INTEGER NOT NULL,
ApplicationServiceDependencies JSON,
UNIQUE (ApplicationServiceName, ApplicationServiceReleaseId)
);
-- Server table creation
CREATE TABLE Server (
ServerId SERIAL PRIMARY KEY,
ServerName VARCHAR(255) NOT NULL UNIQUE,
ServerDescription VARCHAR(255) NOT NULL,
ServerServermodelId INTEGER NOT NULL
);
-- User, Role and ACL table creation
CREATE TABLE RisottoUser (
UserId SERIAL PRIMARY KEY,
UserLogin VARCHAR(100) NOT NULL UNIQUE,
UserName VARCHAR(100) NOT NULL,
UserSurname VARCHAR(100) NOT NULL
);
CREATE TABLE UserRole (
RoleId SERIAL PRIMARY KEY,
RoleUserId INTEGER NOT NULL,
RoleName VARCHAR(255) NOT NULL,
RoleAttribute VARCHAR(255),
RoleAttributeValue VARCHAR(255),
FOREIGN KEY (RoleUserId) REFERENCES RisottoUser(UserId)
);
CREATE TABLE URI (
URIId SERIAL PRIMARY KEY,
URIName VARCHAR(255) NOT NULL UNIQUE
);
CREATE TABLE RoleURI (
RoleName VARCHAR(255) NOT NULL,
URIId INTEGER NOT NULL,
FOREIGN KEY (URIId) REFERENCES URI(URIId),
PRIMARY KEY (RoleName, URIId)
);
-- Log table creation
CREATE TABLE log(
Msg VARCHAR(255) NOT NULL,
Level VARCHAR(10) NOT NULL,
Path VARCHAR(255),
Username VARCHAR(100) NOT NULL,
Data JSON,
Date timestamp DEFAULT current_timestamp
);
EOSQL

View File

@ -22,11 +22,6 @@ 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

@ -0,0 +1,30 @@
---
uri: applicationservice.dependency.add
description: |
Ajouter une dépendance à un service applicatif.
pattern: rpc
parameters:
applicationservice_name:
type: String
shortarg: n
description: |
Nom du service applicatif.
applicationservice_dependency:
type: String
shortarg: a
description: Service applicatif donc dépendant le service applicatif.
source_name:
type: String
shortarg: s
description: Source du service applicatif a ajouter en dépendance.
release_distribution:
type: String
shortarg: r
description: Version du service applicatif a ajouter en dépendance.
response:
type: ApplicationService
description: Informations sur le service applicatif modifié.

View File

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

View File

@ -0,0 +1,10 @@
---
uri: applicationservice.updated
description: Un service application a été modifié.
pattern: event
parameters:
type: 'ApplicationService'
description: Informations sur le service applicatif modifié.

View File

@ -19,11 +19,6 @@ parameters:
shortarg: m
ref: Servermodel.ServermodelName
description: Nom du modèle de serveur.
source_name:
type: String
shortarg: n
ref: Source.SourceName
description: Nom de la source.
release_distribution:
type: String
shortarg: r

View File

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

View File

@ -1,17 +0,0 @@
---
uri: servermodel.get_by_id
description: Retourne les attributs détaillés d'un modèle de serveur suivant son identifiant.
pattern: rpc
parameters:
servermodel_id:
type: Number
shortarg: s
description: Identifiant du modèle de serveur à récupérer.
ref: Servermodel.ServermodelId
response:
type: Servermodel
description: Description du modèle de serveur.

View File

@ -11,16 +11,6 @@ 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

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

View File

@ -23,8 +23,13 @@ properties:
type: number
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

7
requirements.txt Normal file
View File

@ -0,0 +1,7 @@
asyncpg==0.20.1
lxml==4.4.2
requests==2.22.0
aiohttp==3.6.2
pytest==5.3.3
PyYAML==5.3
tiramisu==3.0rc15

View File

@ -3,14 +3,14 @@ import asyncio
from risotto.config import get_config
VERSION_INIT = """
-- Création de la table Source
-- Source
CREATE TABLE Source (
SourceId SERIAL PRIMARY KEY,
SourceName VARCHAR(255) NOT NULL UNIQUE,
SourceURL TEXT
);
-- Création de la table Release
-- Release
CREATE TABLE Release (
ReleaseId SERIAL PRIMARY KEY,
ReleaseName VARCHAR(255) NOT NULL,
@ -21,30 +21,35 @@ CREATE TABLE Release (
FOREIGN KEY (ReleaseSourceId) REFERENCES Source(SourceId)
);
-- Création de la table Servermodel
-- Servermodel
CREATE TABLE Servermodel (
ServermodelId SERIAL PRIMARY KEY,
ServermodelName VARCHAR(255) NOT NULL,
ServermodelDescription VARCHAR(255) NOT NULL,
ServermodelParentsId INTEGER [] DEFAULT '{}',
ServermodelReleaseId INTEGER NOT NULL,
ServermodelApplicationServiceId INTEGER NOT NULL,
ServermodelUsers hstore,
ServermodelApplicationserviceId INTEGER NOT NULL,
UNIQUE (ServermodelName, ServermodelReleaseId)
);
CREATE INDEX ServermodelApplicationserviceId_index ON Servermodel (ServermodelApplicationserviceId);
-- Création de la table ApplicationService
CREATE TABLE ApplicationService (
ApplicationServiceId SERIAL PRIMARY KEY,
ApplicationServiceName VARCHAR(255) NOT NULL,
ApplicationServiceDescription VARCHAR(255) NOT NULL,
ApplicationServiceReleaseId INTEGER NOT NULL,
ApplicationServiceDependencies JSON,
UNIQUE (ApplicationServiceName, ApplicationServiceReleaseId)
-- Applicationservice
CREATE TABLE Applicationservice (
ApplicationserviceId SERIAL PRIMARY KEY,
ApplicationserviceName VARCHAR(255) NOT NULL,
ApplicationserviceDescription VARCHAR(255) NOT NULL,
ApplicationserviceReleaseId INTEGER NOT NULL,
UNIQUE (ApplicationserviceName, ApplicationserviceReleaseId)
);
CREATE TABLE ApplicationserviceDependency (
ApplicationserviceId INTEGER NOT NULL,
ApplicationserviceDependencyId INTEGER NOT NULL,
UNIQUE(ApplicationserviceId, ApplicationserviceDependencyId),
FOREIGN KEY (ApplicationserviceId) REFERENCES Applicationservice(ApplicationserviceId),
FOREIGN KEY (ApplicationserviceDependencyId) REFERENCES Applicationservice(ApplicationserviceId)
);
-- Server table creation
-- Server
CREATE TABLE Server (
ServerId SERIAL PRIMARY KEY,
ServerName VARCHAR(255) NOT NULL UNIQUE,
@ -52,8 +57,7 @@ CREATE TABLE Server (
ServerServermodelId INTEGER NOT NULL
);
-- User, Role and ACL table creation
-- User, Role and ACL
CREATE TABLE RisottoUser (
UserId SERIAL PRIMARY KEY,
UserLogin VARCHAR(100) NOT NULL UNIQUE,
@ -82,8 +86,7 @@ CREATE TABLE RoleURI (
PRIMARY KEY (RoleName, URIId)
);
-- Log table creation
-- Log
CREATE TABLE log(
Msg VARCHAR(255) NOT NULL,
Level VARCHAR(10) NOT NULL,
@ -92,12 +95,11 @@ CREATE TABLE log(
Data JSON,
Date timestamp DEFAULT current_timestamp
);
"""
async def main():
db_conf = get_config().get('database')
pool = await asyncpg.create_pool(database=db_conf.get('dbname'), user=db_conf.get('user'))
db_conf = get_config()['database']['dsn']
pool = await asyncpg.create_pool(db_conf)
async with pool.acquire() as connection:
async with connection.transaction():
returns = await connection.execute(VERSION_INIT)

View File

@ -1,6 +1,7 @@
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))
@ -8,5 +9,3 @@ if __name__ == '__main__':
loop.run_forever()
except KeyboardInterrupt:
pass

View File

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

View File

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

View File

@ -1,7 +1,7 @@
from aiohttp.web import Application, Response, get, post, HTTPBadRequest, HTTPInternalServerError, HTTPNotFound
from json import dumps
from traceback import print_exc
from tiramisu import Config
from tiramisu import Config, default_storage
from .dispatcher import dispatcher
@ -102,9 +102,9 @@ async def api(request, risotto_context):
WHERE RoleURI.URIId = URI.URIId
'''
uris = [uri['uriname'] for uri in await connection.fetch(sql)]
config = await Config(get_messages(load_shortarg=True, uris=uris)[1])
await config.property.read_write()
tiramisu = await config.option.dict(remotable='none')
async with await Config(get_messages(load_shortarg=True, uris=uris)[1]) as config:
await config.property.read_write()
tiramisu = await config.option.dict(remotable='none')
return tiramisu
@ -119,6 +119,7 @@ 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()

View File

@ -9,6 +9,7 @@ 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,
@ -59,13 +60,13 @@ class RegisterDispatcher:
"""
async def get_message_args():
# load config
config = await Config(self.option)
await config.property.read_write()
# set message to the uri name
await config.option('message').value.set(message)
# get message argument
dico = await config.option(message).value.dict()
return set(dico.keys())
async with await Config(self.option) as config:
await config.property.read_write()
# set message to the uri name
await config.option('message').value.set(message)
# get message argument
dico = await config.option(message).value.dict()
return set(dico.keys())
def get_function_args():
function_args = self.get_function_args(function)
@ -101,13 +102,13 @@ class RegisterDispatcher:
"""
async def get_message_args():
# load config
config = await Config(self.option)
await config.property.read_write()
# set message to the message name
await config.option('message').value.set(message)
# get message argument
dico = await config.option(message).value.dict()
return set(dico.keys())
async with await Config(self.option) as config:
await config.property.read_write()
# set message to the message name
await config.option('message').value.set(message)
# get message argument
dico = await config.option(message).value.dict()
return set(dico.keys())
def get_function_args():
function_args = self.get_function_args(function)
@ -234,6 +235,10 @@ 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,
@ -247,8 +252,8 @@ class RegisterDispatcher:
async def load(self):
# valid function's arguments
db_conf = get_config().get('database')
self.pool = await asyncpg.create_pool(database=db_conf.get('dbname'), user=db_conf.get('user'))
db_conf = get_config()['database']['dsn']
self.pool = await asyncpg.create_pool(db_conf)
async with self.pool.acquire() as connection:
async with connection.transaction():
for version, messages in self.messages.items():
@ -271,3 +276,4 @@ class RegisterDispatcher:
module_name)
await self.insert_message(connection,
f'{version}.{message}')

View File

@ -2,7 +2,7 @@ from os import listdir
from os.path import join
from traceback import print_exc
from yaml import load, SafeLoader
from typing import Dict, List
from typing import Dict, List, Set
from ...controller import Controller
from ...register import register
@ -15,6 +15,22 @@ 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']
self.internal_release_name = get_config()['servermodel']['internal_release_name']
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=self.internal_release_name,
release_distribution=self.internal_distribution_name)
self.internal_release_id = internal_release['release_id']
async def _applicationservice_create(self,
risotto_context: Context,
@ -22,43 +38,126 @@ class Risotto(Controller):
applicationservice_description: str,
applicationservice_dependencies: List[int],
release_id: int) -> Dict:
applicationservice_update_query = """INSERT INTO ApplicationService(ApplicationServiceName, ApplicationServiceDescription, ApplicationServiceDependencies, ApplicationServiceReleaseId) VALUES ($1,$2,$3,$4)
RETURNING ApplicationServiceId
"""
applicationservice_update_query = '''INSERT INTO Applicationservice(ApplicationserviceName, ApplicationserviceDescription, ApplicationserviceReleaseId)
VALUES ($1,$2,$3)
RETURNING ApplicationserviceId
'''
applicationservice_id = await risotto_context.connection.fetchval(applicationservice_update_query,
applicationservice_name,
applicationservice_description,
applicationservice_dependencies,
release_id)
await self.insert_dependency(risotto_context,
applicationservice_id,
applicationservice_dependencies)
return {'applicationservice_name': applicationservice_name,
'applicationservice_description': applicationservice_description,
'applicationservice_release_id': release_id,
'applicationservice_id': applicationservice_id}
async def insert_dependency(self,
risotto_context: Context,
applicationservice_id: int,
dependencies: list) -> None:
sql = '''INSERT INTO ApplicationserviceDependency(ApplicationserviceId, ApplicationserviceDependencyId)
VALUES ($1, $2)'''
for dependency in dependencies:
await risotto_context.connection.execute(sql,
applicationservice_id,
dependency)
@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,
applicationservice_dependency,
release['release_id'])
sql = '''SELECT ApplicationserviceDependencyId
FROM ApplicationserviceDependency
WHERE ApplicationserviceId = $1 AND ApplicationserviceDependencyId = $2'''
if await risotto_context.connection.fetchrow(sql,
as_descr['applicationservice_id'],
dependency_descr['applicationservice_id']):
raise Exception(_(f'{applicationservice_name} has already a dependency to {applicationservice_dependency}'))
else:
await self.insert_dependency(risotto_context,
as_descr['applicationservice_id'],
[dependency_descr['applicationservice_id']])
await self.publish('v1.applicationservice.updated',
risotto_context,
**as_descr)
await self.updated_related_applicationservice(risotto_context,
as_descr['applicationservice_id'])
return as_descr
async def updated_related_applicationservice(self,
risotto_context: Context,
applicationservice_id: int) -> None:
sql = """
SELECT ApplicationserviceId as applicationservice_id
FROM ApplicationserviceDependency
WHERE ApplicationserviceDependencyId = $1"""
for dependency in await risotto_context.connection.fetch(sql,
applicationservice_id):
dependency_id = dependency['applicationservice_id']
applicationservice = await self._applicationservice_get_by_id(risotto_context,
dependency_id)
await self.publish('v1.applicationservice.updated',
risotto_context,
**applicationservice)
await self.updated_related_applicationservice(risotto_context,
dependency_id)
async def get_dependencies(self,
risotto_context: Context,
applicationservice_id: int) -> List[int]:
dependencies = set()
sql = """
SELECT ApplicationserviceDependencyId as applicationservice_dependency_id
FROM ApplicationserviceDependency
WHERE ApplicationserviceId = $1"""
for dependency in await risotto_context.connection.fetch(sql,
applicationservice_id):
dependencies.add(dependency['applicationservice_dependency_id'])
for dependency in dependencies.copy():
dependencies |= await self.get_dependencies(risotto_context,
dependency)
return dependencies
@register('v1.applicationservice.create')
async def applicationservice_create(self,
risotto_context: Context,
applicationservice_name: str,
applicationservice_description: str,
applicationservice_dependencies: List[int],
release_id: int) -> Dict:
return await self._applicationservice_create(risotto_context,
applicationservice_name,
applicationservice_description,
applicationservice_dependencies,
release_id)
applicationservice_dependencies: List[int]) -> Dict:
applicationservice = await self._applicationservice_create(risotto_context,
applicationservice_name,
applicationservice_description,
applicationservice_dependencies,
self.internal_release_id)
dependencies = list(await self.get_dependencies(risotto_context,
applicationservice['applicationservice_id']))
applicationservice['applicationservice_dependencies'] = dependencies
return applicationservice
@register('v1.applicationservice.dataset.updated')
async def applicationservice_update(self,
risotto_context: Context,
source_name: str,
release_distribution: str) -> Dict:
source = await self.call('v1.source.describe',
risotto_context,
source_name=source_name)
release = await self.call('v1.source.release.get_by_distribution',
release = await self.call('v1.source.release.describe',
risotto_context,
source_id=source['source_id'],
source_name=source_name,
release_distribution=release_distribution)
applicationservice_path = join(self.source_root_path,
source_name,
@ -81,7 +180,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'):
@ -94,28 +193,56 @@ class Risotto(Controller):
async def applicationservice_get_by_id(self,
risotto_context: Context,
applicationservice_id: int) -> Dict:
return await self._applicationservice_get_by_id(risotto_context,
applicationservice_id)
async def _applicationservice_get_by_id(self,
risotto_context: Context,
applicationservice_id: int) -> Dict:
applicationservice_query = """
SELECT ApplicationServiceId as applicationservice_id, ApplicationServiceName as applicationservice_name, ApplicationServiceDependencies as applicationservice_dependencies, ApplicationServiceReleaseId as applicationservice_release_id
SELECT ApplicationserviceId as applicationservice_id, ApplicationserviceName as applicationservice_name, ApplicationserviceReleaseId as applicationservice_release_id
FROM applicationservice
WHERE applicationserviceid=$1"""
WHERE ApplicationserviceId=$1"""
applicationservice = await risotto_context.connection.fetchrow(applicationservice_query,
applicationservice_id)
if applicationservice is None:
raise Exception(_(f'unknown service with ID {applicationservice_id}'))
return dict(applicationservice)
dependencies = list(await self.get_dependencies(risotto_context,
applicationservice['applicationservice_id']))
applicationservice = dict(applicationservice)
applicationservice['applicationservice_dependencies'] = dependencies
return applicationservice
@register('v1.applicationservice.describe')
async def applicationservice_describe(self,
risotto_context: Context,
applicationservice_name,
release_id):
async def _applicationservice_describe(self,
risotto_context: Context,
applicationservice_name,
release_id):
applicationservice_query = """
SELECT ApplicationServiceId as applicationservice_id, ApplicationServiceName as applicationservice_name, ApplicationServiceDependencies as applicationservice_dependencies, ApplicationServiceReleaseId as applicationservice_release_id
FROM ApplicationService
WHERE ApplicationServiceName=$1 AND ApplicationServiceReleaseId=$2"""
SELECT ApplicationserviceId as applicationservice_id, ApplicationserviceName as applicationservice_name, ApplicationserviceReleaseId as applicationservice_release_id
FROM Applicationservice
WHERE ApplicationserviceName=$1 AND ApplicationserviceReleaseId=$2"""
applicationservice = await risotto_context.connection.fetchrow(applicationservice_query,
applicationservice_name,
release_id)
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)
applicationservice = await self._applicationservice_describe(risotto_context,
applicationservice_name,
release['release_id'])
dependencies = list(await self.get_dependencies(risotto_context,
applicationservice['applicationservice_id']))
applicationservice['applicationservice_dependencies'] = dependencies
return applicationservice

View File

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

View File

@ -3,10 +3,15 @@ from typing import Dict
from ...controller import Controller
from ...register import register
from ...context import Context
from ...config import get_config
from ...utils import _
class Risotto(Controller):
def __init__(self,
test: bool) -> None:
self.internal_source_name = get_config()['servermodel']['internal_source']
@register('v1.server.list')
async def server_list(self,
risotto_context: Context) -> Dict:
@ -23,12 +28,11 @@ class Risotto(Controller):
server_name: str,
server_description: str,
servermodel_name: str,
source_name: str,
release_distribution: str) -> Dict:
servermodel = await self.call('v1.servermodel.describe',
risotto_context,
servermodel_name=servermodel_name,
source_name=source_name,
source_name=self.internal_source_name,
release_distribution=release_distribution)
server_insert = """INSERT INTO Server(ServerName, ServerDescription, ServerServermodelId)
VALUES ($1,$2,$3)

View File

@ -0,0 +1,172 @@
from os.path import join, isdir, isfile
from os import listdir, makedirs
from shutil import rmtree, copyfile
from typing import Dict, List, Optional
from rougail import CreoleObjSpace
from rougail.config import dtdfilename
from ...controller import Controller
from ...context import Context
from ...logger import log
from ...utils import _
class Generator(Controller):
async def generate(self,
risotto_context: Context,
servermodel_name: str,
servermodel_id: int,
dependencies: List[int],
generate_cache: Optional[Dict]=None) -> None:
if generate_cache is None:
generate_cache = {'applicationservice': {},
'release_id': {}}
await self.servermodel_gen_funcs(servermodel_name,
servermodel_id,
dependencies,
generate_cache,
risotto_context)
await self.servermodel_gen_schema(servermodel_name,
servermodel_id,
dependencies,
generate_cache,
risotto_context)
await self.servermodel_copy_templates(servermodel_name,
servermodel_id,
dependencies,
generate_cache,
risotto_context)
async def servermodel_gen_funcs(self,
servermodel_name: str,
servermodel_id: int,
dependencies: Dict,
generate_cache: Dict,
risotto_context: Context) -> None:
as_names = []
dest_file = self.get_servermodel_cache(servermodel_id, 'funcs.py')
with open(dest_file, 'wb') as funcs:
funcs.write(b'from tiramisu import valid_network_netmask, valid_ip_netmask, valid_broadcast, valid_in_network, valid_not_equal as valid_differ, valid_not_equal, calc_value\n\n')
for dependency in dependencies:
if dependency not in generate_cache['applicationservice']:
applicationservice = await self.call('v1.applicationservice.get_by_id',
risotto_context,
applicationservice_id=dependency)
generate_cache['applicationservice'][dependency] = (applicationservice['applicationservice_name'],
applicationservice['applicationservice_release_id'])
applicationservice_name, release_id = generate_cache['applicationservice'][dependency]
if release_id not in generate_cache['release_id']:
release = await self.call('v1.source.release.get_by_id',
risotto_context,
release_id=release_id)
generate_cache['release_id'][release_id] = (release['source_name'],
release['release_name'])
source_name, release_name = generate_cache['release_id'][release_id]
path = join(self.source_root_path,
source_name,
release_name,
'applicationservice',
applicationservice_name,
'funcs')
if isdir(path):
as_names.append(applicationservice_name)
for fil in listdir(path):
if not fil.endswith('.py'):
continue
fil_path = join(path, fil)
with open(fil_path, 'rb') as fh:
funcs.write(f'# {fil_path}\n'.encode())
funcs.write(fh.read())
funcs.write(b'\n')
as_names_str = '", "'.join(as_names)
await log.info(risotto_context,
_(f'gen funcs for "{servermodel_name}" with application services "{as_names_str}"'))
async def servermodel_gen_schema(self,
servermodel_name: str,
servermodel_id: int,
dependencies: Dict,
generate_cache: Dict,
risotto_context: Context) -> None:
paths = []
extras = []
as_names = set()
for dependency in dependencies:
applicationservice_name, release_id = generate_cache['applicationservice'][dependency]
source_name, release_name = generate_cache['release_id'][release_id]
# load creole dictionaries
path = join(self.source_root_path,
source_name,
release_name,
'applicationservice',
applicationservice_name,
'dictionaries')
if isdir(path):
as_names.add(applicationservice_name)
paths.append(path)
# load extra dictionaries
path = join(self.source_root_path,
source_name,
release_name,
'applicationservice',
applicationservice_name,
'extras')
if isdir(path):
for namespace in listdir(path):
extra_dir = join(path, namespace)
if not isdir(extra_dir):
continue
as_names.add(applicationservice_name)
extras.append((namespace, [extra_dir]))
eolobj = CreoleObjSpace(dtdfilename)
as_names_str = '", "'.join(as_names)
await log.info(risotto_context,
_(f'gen schema for "{servermodel_name}" with application services "{as_names_str}"'))
eolobj.create_or_populate_from_xml('creole', paths)
for extra in extras:
eolobj.create_or_populate_from_xml(extra[0], extra[1])
# FIXME extra
funcs_file = self.get_servermodel_cache(servermodel_id, 'funcs.py')
eolobj.space_visitor(funcs_file)
dest_dir = self.get_servermodel_cache(servermodel_id, 'dictionaries.xml')
eolobj.save(dest_dir)
def get_servermodel_cache(self,
servermodel_id: int,
subdir: Optional[str]=None) -> str:
if subdir:
return join(self.cache_root_path, str(servermodel_id), subdir)
return join(self.cache_root_path, str(servermodel_id))
async def servermodel_copy_templates(self,
servermodel_name: str,
servermodel_id: int,
dependencies: Dict,
generate_cache: Dict,
risotto_context: Context) -> None:
as_names = []
dest_dir = self.get_servermodel_cache(servermodel_id, 'templates')
if isdir(dest_dir):
rmtree(dest_dir)
makedirs(dest_dir)
for dependency in dependencies:
applicationservice_name, release_id = generate_cache['applicationservice'][dependency]
source_name, release_name = generate_cache['release_id'][release_id]
path = join(self.source_root_path,
source_name,
release_name,
'applicationservice',
applicationservice_name,
'templates')
if isdir(path):
for template in listdir(path):
template_path = join(dest_dir, template)
if isfile(template_path):
as_names_str = '", "'.join(as_names)
raise Exception(_(f'duplicate "{template}" when copying template from "{applicationservice_name}" to "{dest_dir}" for servermodel "{servermodel_name}" (previous application services was "{as_names_str}"'))
copyfile(join(path, template), template_path)
as_names.append(applicationservice_name)
as_names_str = '", "'.join(as_names)
await log.info(risotto_context,
_(f'copy templates for "{servermodel_name}" with application services "{as_names_str}"'))

View File

@ -1,12 +1,10 @@
from shutil import rmtree, copyfile
from shutil import rmtree
from os import listdir, makedirs
from os.path import join, isdir, isfile
from os.path import join, isdir
from yaml import load, SafeLoader
from traceback import print_exc
from typing import Dict, List, Optional
from rougail import CreoleObjSpace
from rougail.config import dtdfilename
from ...controller import Controller
from .generator import Generator
from ...register import register
from ...utils import _
from ...context import Context
@ -15,168 +13,59 @@ from ...error import ExecutionError
from ...logger import log
class Risotto(Controller):
class Risotto(Generator):
def __init__(self,
test: bool) -> None:
self.source_root_path = get_config().get('source').get('root_path')
self.cache_root_path = join(get_config().get('cache').get('root_path'), 'servermodel')
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.internal_release_name = get_config()['servermodel']['internal_release_name']
if not isdir(self.cache_root_path):
makedirs(join(self.cache_root_path))
async def on_join(self,
risotto_context: Context) -> None:
internal_source = await self.call('v1.source.create',
risotto_context,
source_name='internal',
source_url='none')
internal_release = await self.call('v1.source.release.create',
internal_release = await self.call('v1.source.release.describe',
risotto_context,
source_name='internal',
release_name='none',
release_distribution='last')
source_name=self.internal_source_name,
release_distribution=self.internal_distribution_name)
self.internal_release_id = internal_release['release_id']
async def servermodel_gen_funcs(self,
servermodel_name: str,
servermodel_id: int,
dependencies: Dict,
release_cache: Dict,
risotto_context: Context) -> None:
as_names = []
dest_file = self.get_servermodel_cache(servermodel_id, 'funcs.py')
with open(dest_file, 'wb') as funcs:
funcs.write(b'from tiramisu import valid_network_netmask, valid_ip_netmask, valid_broadcast, valid_in_network, valid_not_equal as valid_differ, valid_not_equal, calc_value\n\n')
for applicationservice_id, applicationservice_infos in dependencies.items():
applicationservice_name, as_release_id = applicationservice_infos
path = join(self.source_root_path,
release_cache[as_release_id]['source_name'],
release_cache[as_release_id]['release_name'],
'applicationservice',
applicationservice_name,
'funcs')
if isdir(path):
as_names.append(applicationservice_name)
for fil in listdir(path):
if not fil.endswith('.py'):
continue
fil_path = join(path, fil)
with open(fil_path, 'rb') as fh:
funcs.write(f'# {fil_path}\n'.encode())
funcs.write(fh.read())
funcs.write(b'\n')
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,
servermodel_id: int,
dependencies: Dict,
release_cache: Dict,
risotto_context: Context) -> None:
paths = []
extras = []
as_names = set()
for applicationservice_id, applicationservice_infos in dependencies.items():
applicationservice_name, as_release_id = applicationservice_infos
# load creole dictionaries
path = join(self.source_root_path,
release_cache[as_release_id]['source_name'],
release_cache[as_release_id]['release_name'],
'applicationservice',
applicationservice_name,
'dictionaries')
if isdir(path):
as_names.add(applicationservice_name)
paths.append(path)
# load extra dictionaries
path = join(self.source_root_path,
release_cache[as_release_id]['source_name'],
release_cache[as_release_id]['release_name'],
'applicationservice',
applicationservice_name,
'extras')
if isdir(path):
for namespace in listdir(path):
extra_dir = join(path, namespace)
if not isdir(extra_dir):
continue
as_names.add(applicationservice_name)
extras.append((namespace, [extra_dir]))
eolobj = CreoleObjSpace(dtdfilename)
as_names_str = '", "'.join(as_names)
await log.info(risotto_context,
_(f'gen schema for "{servermodel_name}" with application services "{as_names_str}"'))
eolobj.create_or_populate_from_xml('creole', paths)
for extra in extras:
eolobj.create_or_populate_from_xml(extra[0], extra[1])
# FIXME extra
funcs_file = self.get_servermodel_cache(servermodel_id, 'funcs.py')
eolobj.space_visitor(funcs_file)
dest_dir = self.get_servermodel_cache(servermodel_id, 'dictionaries.xml')
eolobj.save(dest_dir)
def get_servermodel_cache(self,
servermodel_id: int,
subdir: Optional[str]=None) -> str:
if subdir:
return join(self.cache_root_path, str(servermodel_id), subdir)
return join(self.cache_root_path, str(servermodel_id))
async def servermodel_copy_templates(self,
servermodel_name: str,
servermodel_id: int,
dependencies: Dict,
release_cache: Dict,
risotto_context: Context) -> None:
as_names = []
dest_dir = self.get_servermodel_cache(servermodel_id, 'templates')
makedirs(dest_dir)
for applicationservice_id, applicationservice_infos in dependencies.items():
applicationservice_name, as_release_id = applicationservice_infos
path = join(self.source_root_path,
release_cache[as_release_id]['source_name'],
release_cache[as_release_id]['release_name'],
'applicationservice',
applicationservice_name,
'templates')
if isdir(path):
for template in listdir(path):
template_path = join(dest_dir, template)
if isfile(template_path):
as_names_str = '", "'.join(as_names)
raise Exception(_(f'duplicate "{template}" when copying template from "{applicationservice_name}" to "{dest_dir}" for servermodel "{servermodel_name}" (previous application services was "{as_names_str}"'))
copyfile(join(path, template), template_path)
as_names.append(applicationservice_name)
as_names_str = '", "'.join(as_names)
await log.info(risotto_context,
_(f'copy templates for "{servermodel_name}" with application services "{as_names_str}"'))
async def _servermodel_create(self,
risotto_context: Context,
servermodel_name: str,
servermodel_description: str,
servermodel_parents_id: List[int],
servermodel_parents: List[Dict],
dependencies: List[int],
release_id: int,
release_cache: Dict=None) -> Dict:
servermodel_update = """INSERT INTO Servermodel(ServermodelName, ServermodelDescription, ServermodelParentsId, ServermodelReleaseId, ServermodelApplicationServiceId)
generate_cache: Dict=None) -> Dict:
if generate_cache is None:
generate_cache = {'applicationservice': {},
'release_id': {}}
servermodel_insert = """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,
release_id=self.internal_release_id)
applicationservice_dependencies=dependencies)
applicationservice_id = applicationservice['applicationservice_id']
servermodel_id = await risotto_context.connection.fetchval(servermodel_update,
generate_cache['applicationservice'][applicationservice_id] = (as_name,
self.internal_release_id)
if self.internal_release_id not in generate_cache['release_id']:
generate_cache['release_id'][self.internal_release_id] = (self.internal_source_name,
self.internal_release_name)
servermodel_id = await risotto_context.connection.fetchval(servermodel_insert,
servermodel_name,
servermodel_description,
servermodel_parents_id,
@ -186,42 +75,24 @@ class Risotto(Controller):
if isdir(dest_dir):
rmtree(dest_dir)
makedirs(dest_dir)
# get all dependencies for this application service
dependencies = await self.get_applicationservices(risotto_context,
applicationservice_id)
# build cache to have all release informations
if release_cache is None:
release_cache = {}
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',
risotto_context,
release_id=as_release_id)
await self.servermodel_gen_funcs(servermodel_name,
servermodel_id,
dependencies,
release_cache,
risotto_context)
await self.servermodel_gen_schema(servermodel_name,
servermodel_id,
dependencies,
release_cache,
risotto_context)
await self.servermodel_copy_templates(servermodel_name,
servermodel_id,
dependencies,
release_cache,
risotto_context)
dependencies = applicationservice['applicationservice_dependencies']
# for as_release_id in dependencies.values():
# 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',
# risotto_context,
# release_id=as_release_id)
await self.generate(risotto_context,
servermodel_name,
servermodel_id,
dependencies,
generate_cache)
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,
@ -236,28 +107,48 @@ class Risotto(Controller):
self.parse_parents(servermodels, servermodels[parent], parents)
return parents
async def get_servermodel_id_by_name(self,
@register('v1.applicationservice.updated')
async def applicationservice_updated(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']
applicationservice_id):
# FIXME applicationservices qui depend de ce services => updated
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
FROM Servermodel
WHERE ServermodelApplicationServiceId = $1
'''
servermodel = await risotto_context.connection.fetchrow(sql,
applicationservice_id)
if servermodel is not None:
servermodel_name = servermodel['servermodel_name']
servermodel_id = servermodel['servermodel_id']
release_id = servermodel['release_id']
applicationservice = await self.call('v1.applicationservice.get_by_id',
risotto_context,
applicationservice_id=applicationservice_id)
dependencies = applicationservice['applicationservice_dependencies']
await self.generate(risotto_context,
servermodel_name,
servermodel_id,
dependencies,
None)
await self.publish('v1.servermodel.updated',
risotto_context,
**servermodel)
@register('v1.servermodel.dataset.updated')
async def servermodel_update(self,
risotto_context: Context,
source_name: str,
release_distribution: int):
source = await self.call('v1.source.describe',
risotto_context,
source_name=source_name)
release = await self.call('v1.source.release.get_by_distribution',
async def servermodel_dataset_updated(self,
risotto_context: Context,
source_name: str,
release_distribution: int):
release = await self.call('v1.source.release.describe',
risotto_context,
source_id=source['source_id'],
source_name=source_name,
release_distribution=release_distribution)
release_id = release['release_id']
generate_cache = {'applicationservice': {},
'release_id': {release['release_id']: (release['source_name'],
release['release_name'])}}
servermodel_path = join(self.source_root_path,
source_name,
release['release_name'],
@ -278,30 +169,29 @@ class Risotto(Controller):
servermodels[servermodel_description['name']] = servermodel_description
servermodels[servermodel_description['name']]['done'] = False
release_cache = {release['release_id']: release}
for servermodel in servermodels.values():
if not servermodel['done']:
# parent needs to create before child, so retrieve all parents
parents = self.parse_parents(servermodels,
servermodel)
parents.reverse()
servermodelparent_id = []
servermodel_parent = []
for new_servermodel in parents:
if not servermodels[new_servermodel]['done']:
servermodel_description = servermodels[new_servermodel]
parent = servermodel_description['parent']
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)]
if not servermodel_parent and parent is not None:
servermodel_parent = [await self._servermodel_describe(risotto_context,
parent,
release_id)]
# link application service with this servermodel
dependencies = []
for depend in servermodels[new_servermodel]['applicationservices']:
applicationservice = await self.call('v1.applicationservice.describe',
risotto_context,
applicationservice_name=depend,
release_id=release_id)
source_name=source_name,
release_distribution=release_distribution)
dependencies.append(applicationservice['applicationservice_id'])
sm_name = servermodel_description['name']
sm_description = servermodel_description['description']
@ -309,16 +199,18 @@ class Risotto(Controller):
servermodel_ob = await self._servermodel_create(risotto_context,
sm_name,
sm_description,
servermodelparent_id,
servermodel_parent,
dependencies,
release_id,
release_cache)
servermodel_id = servermodel_ob['servermodel_id']
generate_cache)
await self.publish('v1.servermodel.created',
risotto_context,
**servermodel_ob)
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}"))
servermodelparent_id = [servermodel_id]
servermodel_parent = [servermodel_ob]
servermodel_description['done'] = True
return {'retcode': 0, 'returns': _('Servermodels successfully loaded')}
@ -327,7 +219,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
SELECT ServermodelId as servermodel_id, ServermodelName as servermodel_name, ServermodelDescription as servermodel_description, ServermodelParentsId as servermodel_parents_id, ServermodelReleaseId as release_id, ServermodelApplicationServiceId as servermodel_applicationservice_id
FROM Servermodel
'''
servermodels = await risotto_context.connection.fetch(sql)
@ -343,82 +235,48 @@ 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
SELECT ServermodelId as servermodel_id, ServermodelName as servermodel_name, ServermodelDescription as servermodel_description, ServermodelParentsId as servermodel_parents_id, ServermodelReleaseId as release_id, ServermodelApplicationServiceId as servermodel_applicationservice_id
FROM Servermodel
WHERE ServermodelName=$1 AND ServermodelReleaseId=$2
'''
servermodel = await risotto_context.connection.fetchrow(sql,
servermodel_name,
release['release_id'])
release_id)
if not servermodel:
raise Exception(_(f'{servermodel_id} is not a valid ID for a servermodel'))
raise Exception(_(f'"{servermodel_name}" is not a valid name for a servermodel in source "{source_name}" and release "{release_distribution}"'))
return dict(servermodel)
@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
FROM Servermodel
WHERE ServermodelId=$1
'''
servermodel = await risotto_context.connection.fetchrow(sql,
servermodel_id)
if not servermodel:
raise Exception(_(f'{servermodel_id} is not a valid ID for a servermodel'))
return dict(servermodel)
async def _parse_depends(self,
risotto_context: Context,
applicationservice_id: int,
or_depends: list,
ids: list) -> None:
applicationservice = await self.call('v1.applicationservice.get_by_id',
risotto_context,
applicationservice_id=applicationservice_id)
ids[applicationservice_id] = (applicationservice['applicationservice_name'],
applicationservice['applicationservice_release_id'])
for depend in applicationservice['applicationservice_dependencies']:
if isinstance(depend, dict):
or_depends.append(depend['or'])
elif depend not in ids:
await self._parse_depends(risotto_context,
depend,
or_depends,
ids)
async def _parse_or_depends(self,
risotto_context: Context,
or_depends: list,
ids: list) -> None:
new_or_depends = []
set_ids = set(ids)
for or_depend in or_depends:
if not set(or_depend) & set_ids:
applicationservice_id= or_depend[0]
await self._parse_depends(risotto_context,
applicationservice_id,
new_or_depends,
ids)
if new_or_depends:
await self._parse_or_depends(risotto_context,
new_or_depends,
ids)
async def get_applicationservices(self,
risotto_context: Context,
applicationservice_id: int) -> list:
"""Return consolidated dependencies or raise.
"""
or_depends = []
ids = {}
await self._parse_depends(risotto_context,
applicationservice_id,
or_depends,
ids)
await self._parse_or_depends(risotto_context,
or_depends,
ids)
return ids
@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,
None)

View File

@ -12,12 +12,15 @@ 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):
@ -110,17 +113,15 @@ class Risotto(Controller):
@register('v1.session.servermodel.start')
async def start_session_servermodel(self,
risotto_context: Context,
servermodel_name: str,
source_name: str,
release_distribution: str) -> Dict:
servermodel_name: str) -> Dict:
""" start a new config session for a server or a servermodel
"""
config_module = dispatcher.get_service('config')
servermodel = await self.call('v1.servermodel.describe',
risotto_context,
servermodel_name=servermodel_name,
source_name=source_name,
release_distribution=release_distribution)
source_name=self.internal_source_name,
release_distribution=self.internal_distribution_name)
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']
@ -293,7 +294,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())
storage.del_session(session_id)
await storage.del_session(session_id)
return self.format_session(session_id, session)
@register_http('v1', '/config/server/{session_id}')

View File

@ -103,8 +103,21 @@ class Storage(object):
raise NotAllowedError()
return session
def del_session(self,
id: int):
async 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,10 +122,10 @@ class Risotto(Controller):
return [dict(r) for r in result]
@register('v1.source.release.describe')
async def release_list(self,
risotto_context,
source_name: str,
release_distribution: str) -> Dict:
async def release_describe(self,
risotto_context,
source_name: str,
release_distribution: str) -> Dict:
release_query = """SELECT ReleaseId as release_id, SourceName as source_name, SourceURL as source_url, ReleaseName as release_name, ReleaseDistribution as release_distribution
FROM Release, Source
WHERE Source.SourceName=$1 AND Source.SourceId=Release.ReleaseSourceId AND Release.ReleaseDistribution=$2"""
@ -148,18 +148,3 @@ 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,41 +21,46 @@ 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'))
config = meta = await server['server'].config.deepcopy(storage=self.storage)
while True:
try:
children = list(await config.config.list())
except:
break
if children:
config = children[0]
else:
break
configurations_dir = join(CONFIGURATION_DIR,
str(server_id))
if isdir(configurations_dir):
rmtree(configurations_dir)
mkdir(configurations_dir)
tmp_dir = join(TMP_DIR, str(server_id))
if isdir(tmp_dir):
rmtree(tmp_dir)
mkdir(tmp_dir)
templates_dir = join(self.cache_root_path, str(servermodel_id), 'templates')
await generate(config,
server['funcs_file'],
templates_dir,
tmp_dir,
configurations_dir)
# copy deployed configuration
async with await server['server'].config.deepcopy(storage=self.storage) as config:
meta = config
while True:
try:
children = list(await config.config.list())
except:
break
if children:
config = children[0]
else:
break
configurations_dir = join(CONFIGURATION_DIR,
str(server_id))
if isdir(configurations_dir):
rmtree(configurations_dir)
mkdir(configurations_dir)
tmp_dir = join(TMP_DIR, str(server_id))
if isdir(tmp_dir):
rmtree(tmp_dir)
mkdir(tmp_dir)
templates_dir = join(self.cache_root_path, str(servermodel_id), 'templates')
await generate(config,
server['funcs_file'],
templates_dir,
tmp_dir,
configurations_dir)
del meta, config
# FIXME del session !
return {'server_name': server_name,
'template_dir': configurations_dir}

View File

@ -11,7 +11,9 @@ class Risotto(Controller):
risotto_context):
for uri in ['v1.applicationservice.create',
'v1.applicationservice.dataset.updated',
'v1.applicationservice.dependency.add',
'v1.server.create',
'v1.servermodel.create',
'v1.servermodel.dataset.updated',
'v1.session.server.start',
'v1.source.create',
@ -33,7 +35,6 @@ class Risotto(Controller):
except:
pass
for uri in ['v1.applicationservice.describe',
'v1.applicationservice.get_by_id',
'v1.server.describe',
'v1.server.list',
'v1.servermodel.list',
@ -52,8 +53,6 @@ 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,
@ -62,6 +61,7 @@ class Risotto(Controller):
except:
pass
for uri in ['v1.server.describe',
'v1.applicationservice.dependency.add',
'v1.config.configuration.server.get',
'v1.config.configuration.server.deploy',
'v1.session.server.start',