Compare commits
11 Commits
a63b41c985
...
master
Author | SHA1 | Date | |
---|---|---|---|
8a7cf24cd6 | |||
669782cd35 | |||
4acd5d5a7f | |||
533ad2551f | |||
3b31f092bd | |||
3c5285a7d2 | |||
b944a609a5 | |||
bb1fdcbad0 | |||
03937baf51 | |||
939f93253e | |||
0846c4c5cc |
22
README.md
22
README.md
@ -11,10 +11,20 @@ Accéder à un message :
|
|||||||
wget http://localhost:8080/v1/config.session.server.start
|
wget http://localhost:8080/v1/config.session.server.start
|
||||||
```
|
```
|
||||||
|
|
||||||
Démarrer un serveur LemonLDAP de test
|
[Documentation WIKI cadoles](https://doku.cadoles.com/dokuwiki/doku.php?id=documentation:risotto) n'est qu'un liens vers la doc officiel (pour le moment) [dans la forge](https://forge.cadoles.com/Infra/eole-risotto/wiki)
|
||||||
```
|
|
||||||
docker pull coudot/lemonldap-ng
|
|
||||||
echo "127.0.0.1 auth.example.com manager.example.com test1.example.com test2.example.com" >> /etc/hosts
|
|
||||||
docker run -d --add-host reload.example.com:127.0.0.1 -p 80:80 coudot/lemonldap-ng
|
|
||||||
```
|
|
||||||
|
|
||||||
|
**branche :**
|
||||||
|
|
||||||
|
master
|
||||||
|
|
||||||
|
develop
|
||||||
|
|
||||||
|
dist/risotto/risotto-2.7.1/develop : pour faire des paquets
|
||||||
|
|
||||||
|
dist/risotto/risotto-2.8.0/develop : pour faire des paquets
|
||||||
|
|
||||||
|
docker : n'est pas a jour
|
||||||
|
|
||||||
|
feature/service_servermodel :
|
||||||
|
|
||||||
|
jwt :
|
||||||
|
6
Vocabulary.txt
Normal file
6
Vocabulary.txt
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
Message
|
||||||
|
=======
|
||||||
|
|
||||||
|
message: config.session.server.start
|
||||||
|
version: v1
|
||||||
|
uri: v1.config.session.server.start
|
@ -17,10 +17,11 @@ parameters:
|
|||||||
type: Number
|
type: Number
|
||||||
ref: Server.ServerId
|
ref: Server.ServerId
|
||||||
description: |
|
description: |
|
||||||
Identifiant de la configuration.
|
Identifiant du serveur.
|
||||||
deploy:
|
deployed:
|
||||||
type: Boolean
|
type: Boolean
|
||||||
description: Configuration de type déployée.
|
description: Configuration de type déployée.
|
||||||
|
default: true
|
||||||
|
|
||||||
response:
|
response:
|
||||||
type: ConfigConfiguration
|
type: ConfigConfiguration
|
||||||
|
@ -17,6 +17,6 @@ parameters:
|
|||||||
type: Number
|
type: Number
|
||||||
description: |
|
description: |
|
||||||
Identifiant du serveur.
|
Identifiant du serveur.
|
||||||
deploy:
|
deployed:
|
||||||
type: Boolean
|
type: Boolean
|
||||||
description: Configuration de type déployée.
|
description: Configuration de type déployée.
|
@ -13,7 +13,7 @@ public: false
|
|||||||
domain: server-domain
|
domain: server-domain
|
||||||
|
|
||||||
parameters:
|
parameters:
|
||||||
serverid:
|
server_id:
|
||||||
type: Number
|
type: Number
|
||||||
description: |
|
description: |
|
||||||
Identifiant du serveur supprimé.
|
Identifiant du serveur supprimé.
|
||||||
|
@ -10,6 +10,5 @@ public: false
|
|||||||
domain: servermodel-domain
|
domain: servermodel-domain
|
||||||
|
|
||||||
parameters:
|
parameters:
|
||||||
servermodels:
|
type: Servermodel
|
||||||
type: '[]Servermodel'
|
description: Informations sur les modèles de serveur créés.
|
||||||
description: Informations sur les modèles de serveur créés.
|
|
||||||
|
@ -10,6 +10,5 @@ public: false
|
|||||||
domain: servermodel-domain
|
domain: servermodel-domain
|
||||||
|
|
||||||
parameters:
|
parameters:
|
||||||
servermodels:
|
type: 'Servermodel'
|
||||||
type: '[]Servermodel'
|
description: Informations sur les modèles de serveur modifiés.
|
||||||
description: Informations sur les modèles de serveur modifiés.
|
|
||||||
|
@ -1,17 +1,14 @@
|
|||||||
---
|
---
|
||||||
uri: config.session.server.configure
|
uri: session.server.configure
|
||||||
|
|
||||||
description: |
|
description: |
|
||||||
Configure le server.
|
Configure le server.
|
||||||
|
|
||||||
sampleuse: |
|
|
||||||
zephir-client config.session.server.configure -s 2
|
|
||||||
|
|
||||||
pattern: rpc
|
pattern: rpc
|
||||||
|
|
||||||
public: true
|
public: true
|
||||||
|
|
||||||
domain: config-domain
|
domain: session-domain
|
||||||
|
|
||||||
parameters:
|
parameters:
|
||||||
session_id:
|
session_id:
|
||||||
@ -44,5 +41,5 @@ parameters:
|
|||||||
default: []
|
default: []
|
||||||
|
|
||||||
response:
|
response:
|
||||||
type: ConfigStatus
|
type: SessionStatus
|
||||||
description: Description de la session.
|
description: Description de la session.
|
@ -1,17 +1,14 @@
|
|||||||
---
|
---
|
||||||
uri: config.session.server.filter
|
uri: session.server.filter
|
||||||
|
|
||||||
description: |
|
description: |
|
||||||
Filter la configuration a éditer.
|
Filter la configuration a éditer.
|
||||||
|
|
||||||
sampleuse: |
|
|
||||||
zephir-client config.session.server.filter -s 2
|
|
||||||
|
|
||||||
pattern: rpc
|
pattern: rpc
|
||||||
|
|
||||||
public: true
|
public: true
|
||||||
|
|
||||||
domain: config-domain
|
domain: session-domain
|
||||||
|
|
||||||
parameters:
|
parameters:
|
||||||
session_id:
|
session_id:
|
||||||
@ -36,5 +33,5 @@ parameters:
|
|||||||
default: null
|
default: null
|
||||||
|
|
||||||
response:
|
response:
|
||||||
type: ConfigSession
|
type: Session
|
||||||
description: Description de la session.
|
description: Description de la session.
|
@ -1,17 +1,14 @@
|
|||||||
---
|
---
|
||||||
uri: config.session.server.get
|
uri: session.server.get
|
||||||
|
|
||||||
description: |
|
description: |
|
||||||
Configure le server.
|
Récupérer la configuration du server.
|
||||||
|
|
||||||
sampleuse: |
|
|
||||||
zephir-client config.session.server.get -s 2
|
|
||||||
|
|
||||||
pattern: rpc
|
pattern: rpc
|
||||||
|
|
||||||
public: true
|
public: true
|
||||||
|
|
||||||
domain: config-domain
|
domain: session-domain
|
||||||
|
|
||||||
parameters:
|
parameters:
|
||||||
session_id:
|
session_id:
|
||||||
@ -19,7 +16,12 @@ parameters:
|
|||||||
ref: Config.SessionId
|
ref: Config.SessionId
|
||||||
shortarg: s
|
shortarg: s
|
||||||
description: Identifiant de la configuration.
|
description: Identifiant de la configuration.
|
||||||
|
name:
|
||||||
|
type: String
|
||||||
|
shortarg: n
|
||||||
|
description: Nom de la variable.
|
||||||
|
default: null
|
||||||
|
|
||||||
response:
|
response:
|
||||||
type: ConfigSession
|
type: Session
|
||||||
description: Description de la session.
|
description: Description de la session.
|
@ -1,19 +1,16 @@
|
|||||||
---
|
---
|
||||||
uri: config.session.server.list
|
uri: session.server.list
|
||||||
|
|
||||||
description: |
|
description: |
|
||||||
Liste les sessions de configuration des serveurs.
|
Liste les sessions de configuration des serveurs.
|
||||||
|
|
||||||
sampleuse: |
|
|
||||||
zephir-client config.session.server.list
|
|
||||||
|
|
||||||
pattern: rpc
|
pattern: rpc
|
||||||
|
|
||||||
public: true
|
public: true
|
||||||
|
|
||||||
domain: config-domain
|
domain: session-domain
|
||||||
|
|
||||||
response:
|
response:
|
||||||
type: '[]ConfigSession'
|
type: '[]Session'
|
||||||
description: |
|
description: |
|
||||||
Liste des sessions.
|
Liste des sessions.
|
@ -1,17 +1,14 @@
|
|||||||
---
|
---
|
||||||
uri: config.session.server.start
|
uri: session.server.start
|
||||||
|
|
||||||
description: |
|
description: |
|
||||||
Démarre une session de configuration pour un serveur.
|
Démarre une session de configuration pour un serveur.
|
||||||
|
|
||||||
sampleuse: |
|
|
||||||
zephir-client config.session.server.start -c 2
|
|
||||||
|
|
||||||
pattern: rpc
|
pattern: rpc
|
||||||
|
|
||||||
public: true
|
public: true
|
||||||
|
|
||||||
domain: config-domain
|
domain: session-domain
|
||||||
|
|
||||||
parameters:
|
parameters:
|
||||||
id:
|
id:
|
||||||
@ -22,5 +19,5 @@ parameters:
|
|||||||
Identifiant de la configuration.
|
Identifiant de la configuration.
|
||||||
|
|
||||||
response:
|
response:
|
||||||
type: ConfigSession
|
type: Session
|
||||||
description: Description de la session.
|
description: Description de la session.
|
@ -1,17 +1,14 @@
|
|||||||
---
|
---
|
||||||
uri: config.session.server.stop
|
uri: session.server.stop
|
||||||
|
|
||||||
description: |
|
description: |
|
||||||
Termine une session de configuration d'un serveur.
|
Termine une session de configuration d'un serveur.
|
||||||
|
|
||||||
sampleuse: |
|
|
||||||
zephir-client config.session.server.stop -s xxxxx
|
|
||||||
|
|
||||||
pattern: rpc
|
pattern: rpc
|
||||||
|
|
||||||
public: true
|
public: true
|
||||||
|
|
||||||
domain: config-domain
|
domain: session-domain
|
||||||
|
|
||||||
parameters:
|
parameters:
|
||||||
session_id:
|
session_id:
|
||||||
@ -26,5 +23,5 @@ parameters:
|
|||||||
default: false
|
default: false
|
||||||
|
|
||||||
response:
|
response:
|
||||||
type: ConfigSession
|
type: Session
|
||||||
description: Description de la session.
|
description: Description de la session.
|
@ -1,17 +1,14 @@
|
|||||||
---
|
---
|
||||||
uri: config.session.server.validate
|
uri: session.server.validate
|
||||||
|
|
||||||
description: |
|
description: |
|
||||||
Valider la configuration d'un serveur.
|
Valider la configuration d'un serveur.
|
||||||
|
|
||||||
sampleuse: |
|
|
||||||
zephir-client config.session.server.validate -s xxxxx
|
|
||||||
|
|
||||||
pattern: rpc
|
pattern: rpc
|
||||||
|
|
||||||
public: true
|
public: true
|
||||||
|
|
||||||
domain: config-domain
|
domain: session-domain
|
||||||
|
|
||||||
parameters:
|
parameters:
|
||||||
session_id:
|
session_id:
|
||||||
@ -21,6 +18,6 @@ parameters:
|
|||||||
description: Identifiant de la session.
|
description: Identifiant de la session.
|
||||||
|
|
||||||
response:
|
response:
|
||||||
type: ConfigConfigurationStatus
|
type: Session
|
||||||
description: Statut de la configuration.
|
description: Statut de la configuration.
|
||||||
|
|
@ -1,17 +1,14 @@
|
|||||||
---
|
---
|
||||||
uri: config.session.servermodel.configure
|
uri: session.servermodel.configure
|
||||||
|
|
||||||
description: |
|
description: |
|
||||||
Configure le servermodel.
|
Configure le servermodel.
|
||||||
|
|
||||||
sampleuse: |
|
|
||||||
zephir-client config.session.servermodel.configure -s 2
|
|
||||||
|
|
||||||
pattern: rpc
|
pattern: rpc
|
||||||
|
|
||||||
public: true
|
public: true
|
||||||
|
|
||||||
domain: config-domain
|
domain: session-domain
|
||||||
|
|
||||||
parameters:
|
parameters:
|
||||||
session_id:
|
session_id:
|
||||||
@ -44,5 +41,5 @@ parameters:
|
|||||||
default: []
|
default: []
|
||||||
|
|
||||||
response:
|
response:
|
||||||
type: ConfigStatus
|
type: SessionStatus
|
||||||
description: Description de la session.
|
description: Description de la session.
|
@ -1,17 +1,14 @@
|
|||||||
---
|
---
|
||||||
uri: config.session.servermodel.filter
|
uri: session.servermodel.filter
|
||||||
|
|
||||||
description: |
|
description: |
|
||||||
Filter la configuration a éditer.
|
Filter la configuration a éditer.
|
||||||
|
|
||||||
sampleuse: |
|
|
||||||
zephir-client config.session.servermodel.filter -s 2
|
|
||||||
|
|
||||||
pattern: rpc
|
pattern: rpc
|
||||||
|
|
||||||
public: true
|
public: true
|
||||||
|
|
||||||
domain: config-domain
|
domain: session-domain
|
||||||
|
|
||||||
parameters:
|
parameters:
|
||||||
session_id:
|
session_id:
|
||||||
@ -36,5 +33,5 @@ parameters:
|
|||||||
default: null
|
default: null
|
||||||
|
|
||||||
response:
|
response:
|
||||||
type: ConfigSession
|
type: Session
|
||||||
description: Description de la session.
|
description: Description de la session.
|
@ -1,17 +1,14 @@
|
|||||||
---
|
---
|
||||||
uri: config.session.servermodel.get
|
uri: session.servermodel.get
|
||||||
|
|
||||||
description: |
|
description: |
|
||||||
Configure le servermodel.
|
Configure le servermodel.
|
||||||
|
|
||||||
sampleuse: |
|
|
||||||
zephir-client config.session.servermodel.get -s 2
|
|
||||||
|
|
||||||
pattern: rpc
|
pattern: rpc
|
||||||
|
|
||||||
public: true
|
public: true
|
||||||
|
|
||||||
domain: config-domain
|
domain: session-domain
|
||||||
|
|
||||||
parameters:
|
parameters:
|
||||||
session_id:
|
session_id:
|
||||||
@ -19,7 +16,12 @@ parameters:
|
|||||||
ref: Config.SessionId
|
ref: Config.SessionId
|
||||||
shortarg: s
|
shortarg: s
|
||||||
description: Identifiant de la configuration.
|
description: Identifiant de la configuration.
|
||||||
|
name:
|
||||||
|
type: String
|
||||||
|
shortarg: n
|
||||||
|
description: Nom de la variable.
|
||||||
|
default: null
|
||||||
|
|
||||||
response:
|
response:
|
||||||
type: ConfigSession
|
type: Session
|
||||||
description: Description de la session.
|
description: Description de la session.
|
@ -1,18 +1,15 @@
|
|||||||
uri: config.session.servermodel.list
|
uri: session.servermodel.list
|
||||||
|
|
||||||
description: |
|
description: |
|
||||||
Liste les sessions de configuration des modèles de serveur.
|
Liste les sessions de configuration des modèles de serveur.
|
||||||
|
|
||||||
sampleuse: |
|
|
||||||
zephir-client config.session.servermodel.list
|
|
||||||
|
|
||||||
pattern: rpc
|
pattern: rpc
|
||||||
|
|
||||||
public: true
|
public: true
|
||||||
|
|
||||||
domain: config-domain
|
domain: session-domain
|
||||||
|
|
||||||
response:
|
response:
|
||||||
type: '[]ConfigSession'
|
type: '[]Session'
|
||||||
description: |
|
description: |
|
||||||
Liste des sessions.
|
Liste des sessions.
|
@ -1,16 +1,13 @@
|
|||||||
uri: config.session.servermodel.start
|
uri: session.servermodel.start
|
||||||
|
|
||||||
description: |
|
description: |
|
||||||
Démarre une session de configuration pour un modèle de serveur.
|
Démarre une session de configuration pour un modèle de serveur.
|
||||||
|
|
||||||
sampleuse: |
|
|
||||||
zephir-client config.session.servermodel.start -c 2
|
|
||||||
|
|
||||||
pattern: rpc
|
pattern: rpc
|
||||||
|
|
||||||
public: true
|
public: true
|
||||||
|
|
||||||
domain: config-domain
|
domain: session-domain
|
||||||
|
|
||||||
parameters:
|
parameters:
|
||||||
id:
|
id:
|
||||||
@ -21,5 +18,5 @@ parameters:
|
|||||||
Identifiant de la configuration.
|
Identifiant de la configuration.
|
||||||
|
|
||||||
response:
|
response:
|
||||||
type: ConfigSession
|
type: Session
|
||||||
description: Description de la session.
|
description: Description de la session.
|
@ -1,16 +1,13 @@
|
|||||||
uri: config.session.servermodel.stop
|
uri: session.servermodel.stop
|
||||||
|
|
||||||
description: |
|
description: |
|
||||||
Termine une session de configuration d'un modèle de serveur.
|
Termine une session de configuration d'un modèle de serveur.
|
||||||
|
|
||||||
sampleuse: |
|
|
||||||
zephir-client config.session.servermodel.stop -s xxxxx
|
|
||||||
|
|
||||||
pattern: rpc
|
pattern: rpc
|
||||||
|
|
||||||
public: true
|
public: true
|
||||||
|
|
||||||
domain: config-domain
|
domain: session-domain
|
||||||
|
|
||||||
parameters:
|
parameters:
|
||||||
session_id:
|
session_id:
|
||||||
@ -25,5 +22,5 @@ parameters:
|
|||||||
default: false
|
default: false
|
||||||
|
|
||||||
response:
|
response:
|
||||||
type: ConfigSession
|
type: Session
|
||||||
description: Description de la session.
|
description: Description de la session.
|
@ -1,17 +1,14 @@
|
|||||||
---
|
---
|
||||||
uri: config.session.servermodel.validate
|
uri: session.servermodel.validate
|
||||||
|
|
||||||
description: |
|
description: |
|
||||||
Valider la configuration d'un modèle serveur.
|
Valider la configuration d'un modèle serveur.
|
||||||
|
|
||||||
sampleuse: |
|
|
||||||
zephir-client config.session.servermodel.validate -s xxxxx
|
|
||||||
|
|
||||||
pattern: rpc
|
pattern: rpc
|
||||||
|
|
||||||
public: true
|
public: true
|
||||||
|
|
||||||
domain: config-domain
|
domain: session-domain
|
||||||
|
|
||||||
parameters:
|
parameters:
|
||||||
session_id:
|
session_id:
|
||||||
@ -21,6 +18,6 @@ parameters:
|
|||||||
description: Identifiant de la session.
|
description: Identifiant de la session.
|
||||||
|
|
||||||
response:
|
response:
|
||||||
type: ConfigConfigurationStatus
|
type: Session
|
||||||
description: Statut de la configuration.
|
description: Statut de la configuration.
|
||||||
|
|
26
messages/v1/messages/template.generate.yml
Normal file
26
messages/v1/messages/template.generate.yml
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
---
|
||||||
|
uri: template.generate
|
||||||
|
|
||||||
|
description: |
|
||||||
|
Génère et récupère les templates générés.
|
||||||
|
|
||||||
|
sampleuse: ~
|
||||||
|
|
||||||
|
pattern: rpc
|
||||||
|
|
||||||
|
public: true
|
||||||
|
|
||||||
|
domain: template-domain
|
||||||
|
|
||||||
|
parameters:
|
||||||
|
server_id:
|
||||||
|
type: Number
|
||||||
|
ref: Server.ServerId
|
||||||
|
shortarg: s
|
||||||
|
description: |
|
||||||
|
Identifiant du serveur.
|
||||||
|
|
||||||
|
response:
|
||||||
|
type: Template
|
||||||
|
description: |
|
||||||
|
Les fichiers de configuration générés.
|
@ -1,24 +0,0 @@
|
|||||||
---
|
|
||||||
title: ConfigConfigurationStatus
|
|
||||||
type: object
|
|
||||||
description: Statut de la configuration.
|
|
||||||
properties:
|
|
||||||
session_id:
|
|
||||||
type: string
|
|
||||||
description: ID de la session.
|
|
||||||
ref: Config.SessionId
|
|
||||||
status:
|
|
||||||
type: string
|
|
||||||
description: Statut de la configuration (peut être ok, error, incomplete)
|
|
||||||
message:
|
|
||||||
type: string
|
|
||||||
description: Message d'erreur si la configuration a le statut error.
|
|
||||||
mandatories:
|
|
||||||
type: array
|
|
||||||
items:
|
|
||||||
type: string
|
|
||||||
description: Liste des variables obligatoires non renseignées si la configuration a le statut incomplete.
|
|
||||||
required:
|
|
||||||
- session_id
|
|
||||||
- status
|
|
||||||
|
|
@ -3,8 +3,15 @@ title: ConfigConfiguration
|
|||||||
type: object
|
type: object
|
||||||
description: Description de la configuration.
|
description: Description de la configuration.
|
||||||
properties:
|
properties:
|
||||||
|
server_id:
|
||||||
|
type: number
|
||||||
|
description: Identifiant du serveur.
|
||||||
|
ref: Server.ServerId
|
||||||
|
deployed:
|
||||||
|
type: boolean
|
||||||
|
description: La configuration est déployée.
|
||||||
configuration:
|
configuration:
|
||||||
type: File
|
type: object
|
||||||
description: Détail de la configuration au format JSON.
|
description: Détail de la configuration au format JSON.
|
||||||
required:
|
required:
|
||||||
- configuration
|
- configuration
|
||||||
|
@ -3,7 +3,7 @@ title: Server
|
|||||||
type: object
|
type: object
|
||||||
description: Description du serveur.
|
description: Description du serveur.
|
||||||
properties:
|
properties:
|
||||||
serverid:
|
server_id:
|
||||||
type: number
|
type: number
|
||||||
description: Identifiant du serveur.
|
description: Identifiant du serveur.
|
||||||
ref: Server.ServerId
|
ref: Server.ServerId
|
||||||
@ -33,7 +33,7 @@ properties:
|
|||||||
type: string
|
type: string
|
||||||
description: Timestamp de la dernière connexion avec le serveur.
|
description: Timestamp de la dernière connexion avec le serveur.
|
||||||
required:
|
required:
|
||||||
- serverid
|
- server_id
|
||||||
- servername
|
- servername
|
||||||
- serverdescription
|
- serverdescription
|
||||||
- servermodelid
|
- servermodelid
|
||||||
|
@ -37,16 +37,16 @@ properties:
|
|||||||
type: object
|
type: object
|
||||||
description: Liste des services applicatifs déclarés pour ce modèle de serveur.
|
description: Liste des services applicatifs déclarés pour ce modèle de serveur.
|
||||||
schema:
|
schema:
|
||||||
type: File
|
type: string
|
||||||
description: Contenu du schema.
|
description: Contenu du schema.
|
||||||
probes:
|
probes:
|
||||||
type: File
|
type: string
|
||||||
description: Informations sur les sondes.
|
description: Informations sur les sondes.
|
||||||
creolefuncs:
|
creolefuncs:
|
||||||
type: File
|
type: string
|
||||||
description: Fonctions Creole.
|
description: Fonctions Creole.
|
||||||
conffiles:
|
conffiles:
|
||||||
type: File
|
type: string
|
||||||
description: Fichiers creole au format tar encodé base64
|
description: Fichiers creole au format tar encodé base64
|
||||||
required:
|
required:
|
||||||
- servermodelid
|
- servermodelid
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
title: ConfigStatus
|
title: SessionStatus
|
||||||
type: object
|
type: object
|
||||||
description: Status de la modification de la configuration.
|
description: Status de la modification de la configuration.
|
||||||
properties:
|
properties:
|
||||||
@ -12,9 +12,6 @@ properties:
|
|||||||
index:
|
index:
|
||||||
type: number
|
type: number
|
||||||
description: Index de la variable a modifier.
|
description: Index de la variable a modifier.
|
||||||
status:
|
|
||||||
type: string
|
|
||||||
description: Status de la modification.
|
|
||||||
message:
|
message:
|
||||||
type: string
|
type: string
|
||||||
description: Message d'erreur.
|
description: Message d'erreur.
|
@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
title: ConfigSession
|
title: Session
|
||||||
type: object
|
type: object
|
||||||
description: Description de la session.
|
description: Description de la session.
|
||||||
properties:
|
properties:
|
||||||
@ -27,7 +27,7 @@ properties:
|
|||||||
type: boolean
|
type: boolean
|
||||||
description: La configuration est en mode debug.
|
description: La configuration est en mode debug.
|
||||||
content:
|
content:
|
||||||
type: file
|
type: object
|
||||||
description: Contenu de la configuration.
|
description: Contenu de la configuration.
|
||||||
required:
|
required:
|
||||||
- session_id
|
- session_id
|
14
messages/v1/types/template.yml
Normal file
14
messages/v1/types/template.yml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
---
|
||||||
|
title: Template
|
||||||
|
type: object
|
||||||
|
description: Les fichiers de configuration générés.
|
||||||
|
properties:
|
||||||
|
server_id:
|
||||||
|
type: Number
|
||||||
|
description: Identifiant du serveur.
|
||||||
|
template_dir:
|
||||||
|
type: String
|
||||||
|
description: Nom du répertoire avec les fichiers de configuration générés.
|
||||||
|
required:
|
||||||
|
- server_id
|
||||||
|
- template_dir
|
BIN
schema-tira.jpg
Normal file
BIN
schema-tira.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 86 KiB |
@ -1,6 +1,4 @@
|
|||||||
from .http import get_app
|
from .http import get_app
|
||||||
# just to register every route
|
|
||||||
from . import services as _services
|
|
||||||
|
|
||||||
__ALL__ = ('get_app',)
|
__ALL__ = ('get_app',)
|
||||||
|
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
HTTP_PORT = 8080
|
HTTP_PORT = 8080
|
||||||
MESSAGE_ROOT_PATH = 'messages'
|
MESSAGE_ROOT_PATH = 'messages'
|
||||||
ROOT_CACHE_DIR = 'cache'
|
ROOT_CACHE_DIR = 'cache'
|
||||||
DEBUG = True
|
DEBUG = False
|
||||||
DATABASE_DIR = 'database'
|
DATABASE_DIR = 'database'
|
||||||
INTERNAL_USER = 'internal'
|
INTERNAL_USER = 'internal'
|
||||||
|
CONFIGURATION_DIR = 'configurations'
|
||||||
|
TEMPLATE_DIR = 'templates'
|
||||||
|
TMP_DIR = 'tmp'
|
||||||
ROUGAIL_DTD_PATH = '../rougail/data/creole.dtd'
|
ROUGAIL_DTD_PATH = '../rougail/data/creole.dtd'
|
||||||
|
@ -60,7 +60,7 @@ class CallDispatcher:
|
|||||||
mandatories = list(config.value.mandatory())
|
mandatories = list(config.value.mandatory())
|
||||||
if mandatories:
|
if mandatories:
|
||||||
mand = [mand.split('.')[-1] for mand in mandatories]
|
mand = [mand.split('.')[-1] for mand in mandatories]
|
||||||
raise ValueError(_(f'missing parameters in response: {mand}'))
|
raise ValueError(_(f'missing parameters in response: {mand} in message "{risotto_context.message}"'))
|
||||||
try:
|
try:
|
||||||
config.value.dict()
|
config.value.dict()
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
@ -149,7 +149,7 @@ class PublishDispatcher:
|
|||||||
return
|
return
|
||||||
|
|
||||||
# config is ok, so publish the message
|
# config is ok, so publish the message
|
||||||
for function_obj in self.messages[version][message]['functions']:
|
for function_obj in self.messages[version][message].get('functions', []):
|
||||||
function = function_obj['function']
|
function = function_obj['function']
|
||||||
module_name = function.__module__.split('.')[-2]
|
module_name = function.__module__.split('.')[-2]
|
||||||
function_name = function.__name__
|
function_name = function.__name__
|
||||||
@ -163,21 +163,21 @@ class PublishDispatcher:
|
|||||||
if function_obj['risotto_context']:
|
if function_obj['risotto_context']:
|
||||||
kw['risotto_context'] = risotto_context
|
kw['risotto_context'] = risotto_context
|
||||||
# send event
|
# send event
|
||||||
await function(self.injected_self[function_obj['module']], **kw)
|
returns = await function(self.injected_self[function_obj['module']], **kw)
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
print_exc()
|
print_exc()
|
||||||
log.error_msg(risotto_context, kwargs, err, info_msg)
|
log.error_msg(risotto_context, kwargs, err, info_msg)
|
||||||
|
continue
|
||||||
else:
|
else:
|
||||||
log.info_msg(risotto_context, kwargs, info_msg)
|
log.info_msg(risotto_context, kwargs, info_msg)
|
||||||
|
# notification
|
||||||
# notification
|
if function_obj.get('notification'):
|
||||||
if obj.get('notification'):
|
notif_version, notif_message = function_obj['notification'].split('.', 1)
|
||||||
notif_version, notif_message = obj['notification'].split('.', 1)
|
await self.publish(notif_version,
|
||||||
await self.publish(notif_version,
|
notif_message,
|
||||||
notif_message,
|
risotto_context,
|
||||||
risotto_context,
|
**returns)
|
||||||
**returns)
|
|
||||||
|
|
||||||
|
|
||||||
class Dispatcher(register.RegisterDispatcher, CallDispatcher, PublishDispatcher):
|
class Dispatcher(register.RegisterDispatcher, CallDispatcher, PublishDispatcher):
|
||||||
@ -238,6 +238,10 @@ class Dispatcher(register.RegisterDispatcher, CallDispatcher, PublishDispatcher)
|
|||||||
# return the config
|
# return the config
|
||||||
return config
|
return config
|
||||||
|
|
||||||
|
def get_service(self,
|
||||||
|
name: str):
|
||||||
|
return self.injected_self[name]
|
||||||
|
|
||||||
|
|
||||||
dispatcher = Dispatcher()
|
dispatcher = Dispatcher()
|
||||||
register.dispatcher = dispatcher
|
register.dispatcher = dispatcher
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
from aiohttp.web import Application, Response, get, post, HTTPBadRequest, HTTPInternalServerError, HTTPNotFound
|
from aiohttp.web import Application, Response, get, post, HTTPBadRequest, HTTPInternalServerError, HTTPNotFound
|
||||||
from tiramisu import Config
|
|
||||||
from json import dumps
|
from json import dumps
|
||||||
|
from traceback import print_exc
|
||||||
|
from tiramisu import Config
|
||||||
|
|
||||||
|
|
||||||
from .dispatcher import dispatcher
|
from .dispatcher import dispatcher
|
||||||
from .utils import _
|
from .utils import _
|
||||||
from .context import Context
|
from .context import Context
|
||||||
@ -8,7 +11,7 @@ from .error import CallError, NotAllowedError, RegistrationError
|
|||||||
from .message import get_messages
|
from .message import get_messages
|
||||||
from .logger import log
|
from .logger import log
|
||||||
from .config import DEBUG, HTTP_PORT
|
from .config import DEBUG, HTTP_PORT
|
||||||
from traceback import print_exc
|
from .services import load_services
|
||||||
|
|
||||||
|
|
||||||
def create_context(request):
|
def create_context(request):
|
||||||
@ -96,6 +99,7 @@ async def get_app(loop):
|
|||||||
""" build all routes
|
""" build all routes
|
||||||
"""
|
"""
|
||||||
global extra_routes
|
global extra_routes
|
||||||
|
load_services()
|
||||||
app = Application(loop=loop)
|
app = Application(loop=loop)
|
||||||
routes = []
|
routes = []
|
||||||
for version, messages in dispatcher.messages.items():
|
for version, messages in dispatcher.messages.items():
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
from typing import Dict
|
from typing import Dict
|
||||||
from .context import Context
|
from .context import Context
|
||||||
from .utils import _
|
from .utils import _
|
||||||
|
from .config import DEBUG
|
||||||
|
|
||||||
|
|
||||||
class Logger:
|
class Logger:
|
||||||
@ -30,6 +31,7 @@ class Logger:
|
|||||||
""" send message when an error append
|
""" send message when an error append
|
||||||
"""
|
"""
|
||||||
paths_msg = self._get_message_paths(risotto_context)
|
paths_msg = self._get_message_paths(risotto_context)
|
||||||
|
# if DEBUG:
|
||||||
print(_(f'{risotto_context.username}: ERROR: {error} ({paths_msg} with arguments "{arguments}": {msg})'))
|
print(_(f'{risotto_context.username}: ERROR: {error} ({paths_msg} with arguments "{arguments}": {msg})'))
|
||||||
|
|
||||||
def info_msg(self,
|
def info_msg(self,
|
||||||
@ -48,7 +50,8 @@ class Logger:
|
|||||||
if msg:
|
if msg:
|
||||||
tmsg += f' {msg}'
|
tmsg += f' {msg}'
|
||||||
|
|
||||||
print(tmsg)
|
if DEBUG:
|
||||||
|
print(tmsg)
|
||||||
|
|
||||||
|
|
||||||
log = Logger()
|
log = Logger()
|
||||||
|
@ -159,7 +159,8 @@ class RegisterDispatcher:
|
|||||||
# valid function's arguments
|
# valid function's arguments
|
||||||
if self.messages[version][message]['pattern'] == 'rpc':
|
if self.messages[version][message]['pattern'] == 'rpc':
|
||||||
if notification is undefined:
|
if notification is undefined:
|
||||||
raise RegistrationError(_('notification is mandatory when registered {message} with {module_name}.{function_name} even if you set None'))
|
function_name = function.__name__
|
||||||
|
raise RegistrationError(_(f'notification is mandatory when registered "{message}" with "{module_name}.{function_name}" even if you set None'))
|
||||||
valid_params = self.valid_rpc_params
|
valid_params = self.valid_rpc_params
|
||||||
else:
|
else:
|
||||||
valid_params = self.valid_event_params
|
valid_params = self.valid_event_params
|
||||||
@ -208,10 +209,10 @@ class RegisterDispatcher:
|
|||||||
self.messages[version][message]['functions'] = []
|
self.messages[version][message]['functions'] = []
|
||||||
|
|
||||||
dico = {'module': module_name,
|
dico = {'module': module_name,
|
||||||
'functions': function,
|
'function': function,
|
||||||
'arguments': function_args,
|
'arguments': function_args,
|
||||||
'risotto_context': inject_risotto_context}
|
'risotto_context': inject_risotto_context}
|
||||||
if notification:
|
if notification and notification is not undefined:
|
||||||
dico['notification'] = notification
|
dico['notification'] = notification
|
||||||
self.messages[version][message]['functions'].append(dico)
|
self.messages[version][message]['functions'].append(dico)
|
||||||
|
|
||||||
|
@ -4,15 +4,16 @@ from importlib import import_module
|
|||||||
from ..dispatcher import dispatcher
|
from ..dispatcher import dispatcher
|
||||||
|
|
||||||
|
|
||||||
def list_import():
|
def load_services(modules=None,
|
||||||
|
validate: bool=True):
|
||||||
abs_here = dirname(abspath(__file__))
|
abs_here = dirname(abspath(__file__))
|
||||||
here = basename(abs_here)
|
here = basename(abs_here)
|
||||||
module = basename(dirname(abs_here))
|
module = basename(dirname(abs_here))
|
||||||
for filename in listdir(abs_here):
|
if not modules:
|
||||||
|
modules = listdir(abs_here)
|
||||||
|
for filename in modules:
|
||||||
absfilename = join(abs_here, filename)
|
absfilename = join(abs_here, filename)
|
||||||
if isdir(absfilename) and isfile(join(absfilename, '__init__.py')):
|
if isdir(absfilename) and isfile(join(absfilename, '__init__.py')):
|
||||||
dispatcher.set_module(filename, import_module(f'.{here}.{filename}', module))
|
dispatcher.set_module(filename, import_module(f'.{here}.{filename}', module))
|
||||||
dispatcher.validate()
|
if validate:
|
||||||
|
dispatcher.validate()
|
||||||
|
|
||||||
list_import()
|
|
||||||
|
@ -1,28 +1,20 @@
|
|||||||
from lxml.etree import parse
|
from lxml.etree import parse
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
from os import urandom # , unlink
|
from os import unlink
|
||||||
from os.path import isdir, isfile, join
|
from os.path import isdir, isfile, join
|
||||||
from binascii import hexlify
|
|
||||||
from traceback import print_exc
|
from traceback import print_exc
|
||||||
from json import dumps
|
from typing import Dict, List
|
||||||
from typing import Dict, List, Optional, Any
|
|
||||||
|
|
||||||
from tiramisu import Storage, list_sessions, delete_session, Config, MetaConfig, MixConfig
|
from tiramisu import Storage, delete_session, MetaConfig, MixConfig
|
||||||
from rougail import load as rougail_load
|
from rougail import load as rougail_load
|
||||||
|
|
||||||
from ...controller import Controller
|
from ...controller import Controller
|
||||||
from ...register import register
|
from ...register import register
|
||||||
from ...http import register as register_http
|
|
||||||
from ...config import ROOT_CACHE_DIR, DATABASE_DIR, DEBUG, ROUGAIL_DTD_PATH
|
from ...config import ROOT_CACHE_DIR, DATABASE_DIR, DEBUG, ROUGAIL_DTD_PATH
|
||||||
from ...context import Context
|
from ...context import Context
|
||||||
from ...utils import _
|
from ...utils import _
|
||||||
from ...error import CallError, NotAllowedError, RegistrationError
|
from ...error import CallError, RegistrationError
|
||||||
from ...logger import log
|
from ...logger import log
|
||||||
from .storage import storage_server, storage_servermodel
|
|
||||||
|
|
||||||
|
|
||||||
if not isdir(ROOT_CACHE_DIR):
|
|
||||||
raise RegistrationError(_(f'unable to find the cache dir "{ROOT_CACHE_DIR}"'))
|
|
||||||
|
|
||||||
|
|
||||||
class Risotto(Controller):
|
class Risotto(Controller):
|
||||||
@ -30,30 +22,18 @@ class Risotto(Controller):
|
|||||||
server = {}
|
server = {}
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
|
for dirname in [ROOT_CACHE_DIR, DATABASE_DIR]:
|
||||||
|
if not isdir(dirname):
|
||||||
|
raise RegistrationError(_(f'unable to find the cache dir "{dirname}"'))
|
||||||
self.save_storage = Storage(engine='sqlite3', dir_database=DATABASE_DIR)
|
self.save_storage = Storage(engine='sqlite3', dir_database=DATABASE_DIR)
|
||||||
self.modify_storage = Storage(engine='dictionary')
|
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
def valid_user(self,
|
|
||||||
session_id: str,
|
|
||||||
risotto_context: Context,
|
|
||||||
type: str) -> None:
|
|
||||||
""" check if current user is the session owner
|
|
||||||
"""
|
|
||||||
if type == 'server':
|
|
||||||
storage = storage_server
|
|
||||||
else:
|
|
||||||
storage = storage_servermodel
|
|
||||||
username = risotto_context.username
|
|
||||||
if username != storage.get_session(session_id)['username']:
|
|
||||||
raise NotAllowedError()
|
|
||||||
|
|
||||||
async def on_join(self,
|
async def on_join(self,
|
||||||
risotto_context: Context) -> None:
|
risotto_context: Context) -> None:
|
||||||
""" pre-load servermodel and server
|
""" pre-load servermodel and server
|
||||||
"""
|
"""
|
||||||
await self.load_servermodels(risotto_context)
|
await self.load_servermodels(risotto_context)
|
||||||
# FIXME await self.load_servers(risotto_context)
|
await self.load_servers(risotto_context)
|
||||||
|
|
||||||
async def load_servermodels(self,
|
async def load_servermodels(self,
|
||||||
risotto_context: Context) -> None:
|
risotto_context: Context) -> None:
|
||||||
@ -78,10 +58,16 @@ class Risotto(Controller):
|
|||||||
for servermodel in servermodels:
|
for servermodel in servermodels:
|
||||||
if 'servermodelparentsid' in servermodel:
|
if 'servermodelparentsid' in servermodel:
|
||||||
for servermodelparentid in servermodel['servermodelparentsid']:
|
for servermodelparentid in servermodel['servermodelparentsid']:
|
||||||
self.servermodel_legacy(servermodel['servermodelname'],
|
self.servermodel_legacy(risotto_context,
|
||||||
|
servermodel['servermodelname'],
|
||||||
servermodel['servermodelid'],
|
servermodel['servermodelid'],
|
||||||
servermodelparentid)
|
servermodelparentid)
|
||||||
|
|
||||||
|
def get_funcs_filename(self,
|
||||||
|
servermodelid: int):
|
||||||
|
return join(ROOT_CACHE_DIR, str(servermodelid)+".creolefuncs")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
async def load_servermodel(self,
|
async def load_servermodel(self,
|
||||||
risotto_context: Context,
|
risotto_context: Context,
|
||||||
@ -90,7 +76,7 @@ class Risotto(Controller):
|
|||||||
""" Loads a servermodel
|
""" Loads a servermodel
|
||||||
"""
|
"""
|
||||||
cache_file = join(ROOT_CACHE_DIR, str(servermodelid)+".xml")
|
cache_file = join(ROOT_CACHE_DIR, str(servermodelid)+".xml")
|
||||||
funcs_file = join(ROOT_CACHE_DIR, str(servermodelid)+".creolefuncs")
|
funcs_file = self.get_funcs_filename(servermodelid)
|
||||||
log.info_msg(risotto_context,
|
log.info_msg(risotto_context,
|
||||||
None,
|
None,
|
||||||
f'Load servermodel {servermodelname} ({servermodelid})')
|
f'Load servermodel {servermodelname} ({servermodelid})')
|
||||||
@ -171,6 +157,7 @@ class Risotto(Controller):
|
|||||||
return metaconfig
|
return metaconfig
|
||||||
|
|
||||||
def servermodel_legacy(self,
|
def servermodel_legacy(self,
|
||||||
|
risotto_context: Context,
|
||||||
servermodel_name: str,
|
servermodel_name: str,
|
||||||
servermodel_id: int,
|
servermodel_id: int,
|
||||||
servermodel_parent_id: int) -> None:
|
servermodel_parent_id: int) -> None:
|
||||||
@ -216,29 +203,32 @@ class Risotto(Controller):
|
|||||||
# loads servers
|
# loads servers
|
||||||
for server in servers:
|
for server in servers:
|
||||||
try:
|
try:
|
||||||
self.load_server(server['serverid'],
|
self.load_server(risotto_context,
|
||||||
|
server['server_id'],
|
||||||
server['servername'],
|
server['servername'],
|
||||||
server['servermodelid'])
|
server['servermodelid'])
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
|
if DEBUG:
|
||||||
|
print_exc()
|
||||||
servername = server['servername']
|
servername = server['servername']
|
||||||
serverid = server['serverid']
|
server_id = server['server_id']
|
||||||
msg = _(f'Unable to load server {servername} ({serverid}): {err}')
|
msg = _(f'unable to load server {servername} ({server_id}): {err}')
|
||||||
log.error_msg(risotto_context,
|
log.error_msg(risotto_context,
|
||||||
None,
|
None,
|
||||||
msg)
|
msg)
|
||||||
|
|
||||||
def load_server(self,
|
def load_server(self,
|
||||||
risotto_context: Context,
|
risotto_context: Context,
|
||||||
serverid: int,
|
server_id: int,
|
||||||
servername: str,
|
servername: str,
|
||||||
servermodelid: int) -> None:
|
servermodelid: int) -> None:
|
||||||
""" Loads a server
|
""" Loads a server
|
||||||
"""
|
"""
|
||||||
if serverid in self.server:
|
if server_id in self.server:
|
||||||
return
|
return
|
||||||
log.info_msg(risotto_context,
|
log.info_msg(risotto_context,
|
||||||
None,
|
None,
|
||||||
f'Load server {servername} ({serverid})')
|
f'Load server {servername} ({server_id})')
|
||||||
if not servermodelid in self.servermodel:
|
if not servermodelid in self.servermodel:
|
||||||
msg = f'unable to find servermodel with id {servermodelid}'
|
msg = f'unable to find servermodel with id {servermodelid}'
|
||||||
log.error_msg(risotto_context,
|
log.error_msg(risotto_context,
|
||||||
@ -247,147 +237,155 @@ class Risotto(Controller):
|
|||||||
raise CallError(msg)
|
raise CallError(msg)
|
||||||
|
|
||||||
# check if server was already created
|
# check if server was already created
|
||||||
session_id = f's_{serverid}'
|
session_id = f's_{server_id}'
|
||||||
is_new_config = session_id not in list_sessions()
|
|
||||||
|
|
||||||
# get the servermodel's metaconfig
|
# get the servermodel's metaconfig
|
||||||
metaconfig = self.servermodel[servermodelid]
|
metaconfig = self.servermodel[servermodelid]
|
||||||
|
|
||||||
# create server configuration and server 'to deploy' configuration and store it
|
# create server configuration and server 'to deploy' configuration and store it
|
||||||
self.server[serverid] = {'server': self.build_config(session_id,
|
self.server[server_id] = {'server': self.build_config(session_id,
|
||||||
is_new_config),
|
server_id,
|
||||||
'server_to_deploy': self.build_config(f'std_{serverid}',
|
servername,
|
||||||
is_new_config)}
|
metaconfig),
|
||||||
|
'server_to_deploy': self.build_config(f'std_{server_id}',
|
||||||
|
server_id,
|
||||||
|
servername,
|
||||||
|
metaconfig),
|
||||||
|
'funcs_file': self.get_funcs_filename(servermodelid)}
|
||||||
|
|
||||||
def build_config(self,
|
def build_config(self,
|
||||||
session_id: str,
|
session_id: str,
|
||||||
is_new_config: bool) -> None:
|
server_id: int,
|
||||||
|
servername: str,
|
||||||
|
metaconfig: MetaConfig) -> None:
|
||||||
""" build server's config
|
""" build server's config
|
||||||
"""
|
"""
|
||||||
config = metaconfig.config.new(session_id,
|
config = metaconfig.config.new(session_id,
|
||||||
|
storage=self.save_storage,
|
||||||
persistent=True)
|
persistent=True)
|
||||||
config.information.set('server_id', serverid)
|
config.information.set('server_id', server_id)
|
||||||
config.information.set('server_name', servername)
|
config.information.set('server_name', servername)
|
||||||
config.owner.set(servername)
|
config.owner.set(servername)
|
||||||
|
|
||||||
# if new config, remove force_store_value before switchint to read-only mode
|
|
||||||
# force_store_value is not allowed for new server (wait when configuration is deploy)
|
|
||||||
if is_new_config:
|
|
||||||
ro = list(config.property.getdefault('read_only', 'append'))
|
|
||||||
ro.remove('force_store_value')
|
|
||||||
config.property.setdefault(frozenset(ro), 'read_only', 'append')
|
|
||||||
rw = list(config.property.getdefault('read_write', 'append'))
|
|
||||||
rw.remove('force_store_value')
|
|
||||||
config.property.setdefault(frozenset(rw), 'read_write', 'append')
|
|
||||||
config.property.read_only()
|
config.property.read_only()
|
||||||
|
return config
|
||||||
|
|
||||||
@register('v1.server.created')
|
@register('v1.server.created')
|
||||||
async def server_created(self,
|
async def server_created(self,
|
||||||
serverid: int,
|
risotto_context: Context,
|
||||||
|
server_id: int,
|
||||||
servername: str,
|
servername: str,
|
||||||
servermodelid: int) -> None:
|
servermodelid: int) -> None:
|
||||||
""" Loads server's configuration when a new server is created
|
""" Loads server's configuration when a new server is created
|
||||||
"""
|
"""
|
||||||
self.load_server(serverid,
|
self.load_server(risotto_context,
|
||||||
|
server_id,
|
||||||
servername,
|
servername,
|
||||||
servermodelid)
|
servermodelid)
|
||||||
|
|
||||||
@register('v1.server.deleted')
|
@register('v1.server.deleted')
|
||||||
async def server_deleted(self,
|
async def server_deleted(self,
|
||||||
serverid: int) -> None:
|
server_id: int) -> None:
|
||||||
# delete config to it's parents
|
# delete config to it's parents
|
||||||
for config in self.server[serverid].values():
|
for server_type in ['server', 'server_to_deploy']:
|
||||||
|
config = self.server[server_id]['server']
|
||||||
for parent in config.config.parents():
|
for parent in config.config.parents():
|
||||||
parent.config.pop(config.config.name())
|
parent.config.pop(config.config.name())
|
||||||
delete_session(config.config.name())
|
delete_session(storage=self.save_storage,
|
||||||
|
session_id=config.config.name())
|
||||||
# delete metaconfig
|
# delete metaconfig
|
||||||
del self.server[serverid]
|
del self.server[server_id]
|
||||||
|
|
||||||
@register('v1.servermodel.created')
|
@register('v1.servermodel.created')
|
||||||
async def servermodel_created(self,
|
async def servermodel_created(self,
|
||||||
servermodels) -> None:
|
risotto_context: Context,
|
||||||
|
servermodelid: int,
|
||||||
|
servermodelname: str,
|
||||||
|
servermodelparentsid: List[int]) -> None:
|
||||||
""" when servermodels are created, load it and do link
|
""" when servermodels are created, load it and do link
|
||||||
"""
|
"""
|
||||||
for servermodel in servermodels:
|
await self.load_and_link_servermodel(risotto_context,
|
||||||
await self.load_servermodel(servermodel['servermodelid'], servermodel['servermodelname'])
|
servermodelid,
|
||||||
for servermodel in servermodels:
|
servermodelname,
|
||||||
if 'servermodelparentsid' in servermodel:
|
servermodelparentsid)
|
||||||
for servermodelparentid in servermodel['servermodelparentsid']:
|
|
||||||
self.servermodel_legacy(servermodel['servermodelname'], servermodel['servermodelid'], servermodelparentid)
|
|
||||||
|
async def load_and_link_servermodel(self,
|
||||||
|
risotto_context: Context,
|
||||||
|
servermodelid: int,
|
||||||
|
servermodelname: str,
|
||||||
|
servermodelparentsid: List[int]) -> None:
|
||||||
|
await self.load_servermodel(risotto_context,
|
||||||
|
servermodelid,
|
||||||
|
servermodelname)
|
||||||
|
if servermodelparentsid is not None:
|
||||||
|
for servermodelparentid in servermodelparentsid:
|
||||||
|
self.servermodel_legacy(risotto_context,
|
||||||
|
servermodelname,
|
||||||
|
servermodelid,
|
||||||
|
servermodelparentid)
|
||||||
|
|
||||||
|
def servermodel_delete(self,
|
||||||
|
servermodelid: int) -> List[MetaConfig]:
|
||||||
|
metaconfig = self.servermodel.pop(servermodelid)
|
||||||
|
mixconfig = next(metaconfig.config.list())
|
||||||
|
children = []
|
||||||
|
for child in mixconfig.config.list():
|
||||||
|
children.append(child)
|
||||||
|
mixconfig.config.pop(child.config.name())
|
||||||
|
metaconfig.config.pop(mixconfig.config.name())
|
||||||
|
delete_session(storage=self.save_storage,
|
||||||
|
session_id=mixconfig.config.name())
|
||||||
|
del mixconfig
|
||||||
|
for parent in metaconfig.config.parents():
|
||||||
|
parent.config.pop(metaconfig.config.name())
|
||||||
|
delete_session(storage=self.save_storage,
|
||||||
|
session_id=metaconfig.config.name())
|
||||||
|
return children
|
||||||
|
|
||||||
@register('v1.servermodel.updated')
|
@register('v1.servermodel.updated')
|
||||||
async def servermodel_updated(self,
|
async def servermodel_updated(self,
|
||||||
risotto_context: Context,
|
risotto_context: Context,
|
||||||
servermodels) -> None:
|
servermodelid: int,
|
||||||
for servermodel in servermodels:
|
servermodelname: str,
|
||||||
servermodelid = servermodel['servermodelid']
|
servermodelparentsid: List[int]) -> None:
|
||||||
servermodelname = servermodel['servermodelname']
|
log.info_msg(risotto_context,
|
||||||
servermodelparentsid = servermodel.get('servermodelparentsid')
|
None,
|
||||||
log.info_msg(risotto_context,
|
f'Reload servermodel {servermodelname} ({servermodelid})')
|
||||||
None,
|
# unlink cache to force download new aggregated file
|
||||||
f'Reload servermodel {servermodelname} ({servermodelid})')
|
cache_file = join(ROOT_CACHE_DIR, str(servermodelid)+".xml")
|
||||||
# unlink cache to force download new aggregated file
|
if isfile(cache_file):
|
||||||
cache_file = join(ROOT_CACHE_DIR, str(servermodelid)+".xml")
|
unlink(cache_file)
|
||||||
if isfile(cache_file):
|
|
||||||
unlink(cache_file)
|
|
||||||
|
|
||||||
# get current servermodel
|
# store all informations
|
||||||
old_servermodel = self.servermodel[servermodelid]
|
if servermodelid in self.servermodel:
|
||||||
|
old_values = self.servermodel[servermodelid].value.exportation()
|
||||||
|
old_permissives = self.servermodel[servermodelid].permissive.exportation()
|
||||||
|
old_properties = self.servermodel[servermodelid].property.exportation()
|
||||||
|
children = self.servermodel_delete(servermodelid)
|
||||||
|
else:
|
||||||
|
old_values = None
|
||||||
|
|
||||||
# create new one
|
# create new one
|
||||||
await self.load_servermodel(servermodelid, servermodelname)
|
await self.load_and_link_servermodel(risotto_context,
|
||||||
|
servermodelid,
|
||||||
|
servermodelname,
|
||||||
|
servermodelparentsid)
|
||||||
|
|
||||||
# migrate all informations
|
# migrates informations
|
||||||
self.servermodel[servermodelid].value.importation(old_servermodel.value.exportation())
|
if old_values is not None:
|
||||||
self.servermodel[servermodelid].permissive.importation(old_servermodel.permissive.exportation())
|
self.servermodel[servermodelid].value.importation(old_values)
|
||||||
self.servermodel[servermodelid].property.importation(old_servermodel.property.exportation())
|
self.servermodel[servermodelid].permissive.importation(old_permissives)
|
||||||
|
self.servermodel[servermodelid].property.importation(old_properties)
|
||||||
# remove link to legacy
|
for child in children:
|
||||||
if servermodelparentsid:
|
self.servermodel_legacy(risotto_context,
|
||||||
for servermodelparentid in servermodelparentsid:
|
child.information.get('servermodel_name'),
|
||||||
mix = self.servermodel[servermodelparentid].config.get('m_v_' + str(servermodelparentid))
|
child.information.get('servermodel_id'),
|
||||||
try:
|
servermodelid)
|
||||||
mix.config.pop(old_servermodel.config.name())
|
|
||||||
except:
|
|
||||||
# if mix config is reloaded too
|
|
||||||
pass
|
|
||||||
# add new link
|
|
||||||
self.servermodel_legacy(servermodelname, servermodelid, servermodelparentid)
|
|
||||||
|
|
||||||
# reload servers or servermodels in servermodel
|
|
||||||
for subconfig in old_servermodel.config.list():
|
|
||||||
if not isinstance(subconfig, MixConfig):
|
|
||||||
# a server
|
|
||||||
name = subconfig.config.name()
|
|
||||||
if name.startswith('str_'):
|
|
||||||
continue
|
|
||||||
server_id = subconfig.information.get('server_id')
|
|
||||||
server_name = subconfig.information.get('server_name')
|
|
||||||
try:
|
|
||||||
old_servermodel.config.pop(name)
|
|
||||||
old_servermodel.config.pop(f'std_{server_id}')
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
del self.server[server_id]
|
|
||||||
self.load_server(server_id,
|
|
||||||
server_name,
|
|
||||||
servermodelid)
|
|
||||||
else:
|
|
||||||
# a servermodel
|
|
||||||
for subsubconfig in subconfig.config.list():
|
|
||||||
name = subsubconfig.config.name()
|
|
||||||
try:
|
|
||||||
subconfig.config.pop(name)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
self.servermodel_legacy(subsubconfig.information.get('servermodel_name'),
|
|
||||||
subsubconfig.information.get('servermodel_id'),
|
|
||||||
servermodelid)
|
|
||||||
|
|
||||||
@register('v1.config.configuration.server.get', None)
|
@register('v1.config.configuration.server.get', None)
|
||||||
async def get_configuration(self,
|
async def get_configuration(self,
|
||||||
server_id: int,
|
server_id: int,
|
||||||
deploy: bool) -> bytes:
|
deployed: bool) -> bytes:
|
||||||
if server_id not in self.server:
|
if server_id not in self.server:
|
||||||
msg = _(f'cannot find server with id {server_id}')
|
msg = _(f'cannot find server with id {server_id}')
|
||||||
log.error_msg(risotto_context,
|
log.error_msg(risotto_context,
|
||||||
@ -395,16 +393,16 @@ class Risotto(Controller):
|
|||||||
msg)
|
msg)
|
||||||
raise CallError(msg)
|
raise CallError(msg)
|
||||||
|
|
||||||
if deploy:
|
if deployed:
|
||||||
server = self.server[server_id]['server']
|
server = self.server[server_id]['server']
|
||||||
else:
|
else:
|
||||||
server = self.server[server_id]['server_to_deploy']
|
server = self.server[server_id]['server_to_deploy']
|
||||||
|
|
||||||
server.property.read_only()
|
server.property.read_only()
|
||||||
try:
|
try:
|
||||||
dico = server.value.dict(fullpath=True)
|
configuration = server.value.dict(fullpath=True)
|
||||||
except:
|
except:
|
||||||
if deploy:
|
if deployed:
|
||||||
msg = _(f'No configuration available for server {server_id}')
|
msg = _(f'No configuration available for server {server_id}')
|
||||||
else:
|
else:
|
||||||
msg = _(f'No undeployed configuration available for server {server_id}')
|
msg = _(f'No undeployed configuration available for server {server_id}')
|
||||||
@ -412,8 +410,9 @@ class Risotto(Controller):
|
|||||||
None,
|
None,
|
||||||
msg)
|
msg)
|
||||||
raise CallError(msg)
|
raise CallError(msg)
|
||||||
return dumps(dico).encode()
|
return {'server_id': server_id,
|
||||||
|
'deployed': deployed,
|
||||||
|
'configuration': configuration}
|
||||||
|
|
||||||
@register('v1.config.configuration.server.deploy', 'v1.config.configuration.server.updated')
|
@register('v1.config.configuration.server.deploy', 'v1.config.configuration.server.updated')
|
||||||
async def deploy_configuration(self,
|
async def deploy_configuration(self,
|
||||||
@ -439,259 +438,4 @@ class Risotto(Controller):
|
|||||||
config.property.importation(config_std.property.exportation())
|
config.property.importation(config_std.property.exportation())
|
||||||
|
|
||||||
return {'server_id': server_id,
|
return {'server_id': server_id,
|
||||||
'deploy': True}
|
'deployed': True}
|
||||||
|
|
||||||
def get_session(self,
|
|
||||||
session_id: str,
|
|
||||||
type: str) -> Dict:
|
|
||||||
""" Get session information from storage
|
|
||||||
"""
|
|
||||||
if type == 'server':
|
|
||||||
return storage_server.get_session(session_id)
|
|
||||||
return storage_servermodel.get_session(session_id)
|
|
||||||
|
|
||||||
def get_session_informations(self,
|
|
||||||
session_id: str,
|
|
||||||
type: str) -> Dict:
|
|
||||||
""" format session with a session ID name
|
|
||||||
"""
|
|
||||||
session = self.get_session(session_id,
|
|
||||||
type)
|
|
||||||
return self.format_session(session_id,
|
|
||||||
session)
|
|
||||||
|
|
||||||
def format_session(self,
|
|
||||||
session_name: str,
|
|
||||||
session: Dict) -> Dict:
|
|
||||||
""" format session
|
|
||||||
"""
|
|
||||||
return {'session_id': session_name,
|
|
||||||
'id': session['id'],
|
|
||||||
'username': session['username'],
|
|
||||||
'timestamp': session['timestamp'],
|
|
||||||
'namespace': session['namespace'],
|
|
||||||
'mode': session['mode'],
|
|
||||||
'debug': session['debug']}
|
|
||||||
|
|
||||||
def list_sessions(self,
|
|
||||||
type: str) -> List:
|
|
||||||
ret = []
|
|
||||||
if type == 'server':
|
|
||||||
storage = storage_server
|
|
||||||
else:
|
|
||||||
storage = storage_servermodel
|
|
||||||
for session in storage.list_sessions():
|
|
||||||
ret.append(self.format_session(session['session_id'], session))
|
|
||||||
return ret
|
|
||||||
|
|
||||||
def load_dict(self,
|
|
||||||
session: Dict) -> Dict:
|
|
||||||
if not session['option']:
|
|
||||||
session['option'] = session['config'].option(session['namespace'])
|
|
||||||
return session['option'].dict(remotable='all')
|
|
||||||
|
|
||||||
@register(['v1.config.session.server.start', 'v1.config.session.servermodel.start'], None)
|
|
||||||
async def start_session(self,
|
|
||||||
risotto_context: Context,
|
|
||||||
id: int) -> Dict:
|
|
||||||
""" start a new config session for a server or a servermodel
|
|
||||||
"""
|
|
||||||
type = risotto_context.message.rsplit('.', 2)[-2]
|
|
||||||
server_list = getattr(self, type)
|
|
||||||
|
|
||||||
if id not in server_list:
|
|
||||||
raise Exception(_(f'cannot find {type} with id {id}'))
|
|
||||||
|
|
||||||
# check if a session already exists, in this case returns it
|
|
||||||
session_list = self.list_sessions(type)
|
|
||||||
for sess in session_list:
|
|
||||||
if sess['id'] == id and sess['username'] == risotto_context.username:
|
|
||||||
session_id = sess['session_id']
|
|
||||||
session = self.get_session(session_id, type)
|
|
||||||
return self.format_session(session_id, session)
|
|
||||||
|
|
||||||
# create a new session
|
|
||||||
if type == 'server':
|
|
||||||
storage = storage_server
|
|
||||||
else:
|
|
||||||
storage = storage_servermodel
|
|
||||||
while True:
|
|
||||||
session_id = 'z' + hexlify(urandom(23)).decode()
|
|
||||||
if not storage.has_session(session_id):
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
print('session {} already exists'.format(session_id))
|
|
||||||
username = risotto_context.username
|
|
||||||
storage.add_session(session_id,
|
|
||||||
server_list[id],
|
|
||||||
id,
|
|
||||||
username,
|
|
||||||
self.modify_storage)
|
|
||||||
return self.get_session_informations(session_id,
|
|
||||||
type)
|
|
||||||
|
|
||||||
@register(['v1.config.session.server.list', 'v1.config.session.servermodel.list'], None)
|
|
||||||
async def list_session_server(self,
|
|
||||||
risotto_context: Context):
|
|
||||||
type = risotto_context.message.rsplit('.', 2)[-2]
|
|
||||||
return self.list_sessions(type)
|
|
||||||
|
|
||||||
@register(['v1.config.session.server.filter', 'v1.config.session.servermodel.filter'], None)
|
|
||||||
async def filter_session(self,
|
|
||||||
risotto_context: Context,
|
|
||||||
session_id: str,
|
|
||||||
namespace: str,
|
|
||||||
mode: str,
|
|
||||||
debug: Optional[bool]):
|
|
||||||
type = risotto_context.message.rsplit('.', 2)[-2]
|
|
||||||
session = self.get_session(session_id,
|
|
||||||
type)
|
|
||||||
if namespace is not None:
|
|
||||||
session['option'] = None
|
|
||||||
session['namespace'] = namespace
|
|
||||||
if type == 'server':
|
|
||||||
storage = storage_server
|
|
||||||
else:
|
|
||||||
storage = storage_servermodel
|
|
||||||
if mode is not None:
|
|
||||||
if mode not in ('basic', 'normal', 'expert'):
|
|
||||||
raise CallError(f'unknown mode {mode}')
|
|
||||||
storage.set_config_mode(session_id,
|
|
||||||
mode)
|
|
||||||
if debug is not None:
|
|
||||||
storage.set_config_debug(session_id,
|
|
||||||
debug)
|
|
||||||
return self.get_session_informations(session_id,
|
|
||||||
type)
|
|
||||||
|
|
||||||
@register(['v1.config.session.server.configure', 'v1.config.session.servermodel.configure'], None)
|
|
||||||
async def configure_session(self,
|
|
||||||
risotto_context: Context,
|
|
||||||
session_id: str,
|
|
||||||
action: str,
|
|
||||||
name: str,
|
|
||||||
index: int,
|
|
||||||
value: Any,
|
|
||||||
value_multi: Optional[List]) -> Dict:
|
|
||||||
type = risotto_context.message.rsplit('.', 2)[-2]
|
|
||||||
session = self.get_session(session_id,
|
|
||||||
type)
|
|
||||||
ret = {'session_id': session_id,
|
|
||||||
'name': name}
|
|
||||||
if index is not None:
|
|
||||||
ret['index'] = index
|
|
||||||
option = session['config'].option(name).option
|
|
||||||
if option.ismulti() and not option.isfollower():
|
|
||||||
value = value_multi
|
|
||||||
try:
|
|
||||||
update = {'name': name,
|
|
||||||
'action': action,
|
|
||||||
'value': value}
|
|
||||||
if index is not None:
|
|
||||||
update['index'] = index
|
|
||||||
if not session['option']:
|
|
||||||
session['option'] = session['config'].option(session['namespace'])
|
|
||||||
self.load_dict(session)
|
|
||||||
updates = {'updates': [update]}
|
|
||||||
session['option'].updates(updates)
|
|
||||||
ret['status'] = 'ok'
|
|
||||||
except Exception as err:
|
|
||||||
if DEBUG:
|
|
||||||
print_exc()
|
|
||||||
ret['message'] = str(err)
|
|
||||||
ret['status'] = 'error'
|
|
||||||
return ret
|
|
||||||
|
|
||||||
@register(['v1.config.session.server.validate', 'v1.config.session.servermodel.validate'], None)
|
|
||||||
async def validate_session(self,
|
|
||||||
risotto_context: Context,
|
|
||||||
session_id: str) -> Dict:
|
|
||||||
type = risotto_context.message.rsplit('.', 2)[-2]
|
|
||||||
session = self.get_session(session_id, type)
|
|
||||||
ret = {}
|
|
||||||
try:
|
|
||||||
session['config'].forcepermissive.option(session['namespace']).value.dict()
|
|
||||||
except Exception as err:
|
|
||||||
ret['status'] = 'error'
|
|
||||||
ret['message'] = str(err)
|
|
||||||
else:
|
|
||||||
if type == 'server':
|
|
||||||
mandatories = list(session['config'].forcepermissive.value.mandatory())
|
|
||||||
if mandatories:
|
|
||||||
ret['status'] = 'incomplete'
|
|
||||||
ret['mandatories'] = mandatories
|
|
||||||
else:
|
|
||||||
ret['status'] = 'ok'
|
|
||||||
else:
|
|
||||||
ret['status'] = 'ok'
|
|
||||||
return ret
|
|
||||||
|
|
||||||
@register(['v1.config.session.server.get', 'v1.config.session.servermodel.get'], None)
|
|
||||||
async def get_session_(self,
|
|
||||||
risotto_context: Context,
|
|
||||||
session_id: str) -> Dict:
|
|
||||||
type = risotto_context.message.rsplit('.', 2)[-2]
|
|
||||||
info = self.get_session_informations(session_id,
|
|
||||||
type)
|
|
||||||
info['content'] = session_id
|
|
||||||
session = self.get_session(session_id,
|
|
||||||
type)
|
|
||||||
if not session['option']:
|
|
||||||
session['option'] = session['config'].option(session['namespace'])
|
|
||||||
info['content'] = dumps(session['option'].value.dict(fullpath=True))
|
|
||||||
|
|
||||||
return info
|
|
||||||
|
|
||||||
@register(['v1.config.session.server.stop', 'v1.config.session.servermodel.stop'], None)
|
|
||||||
async def stop_session(self,
|
|
||||||
risotto_context: Context,
|
|
||||||
session_id: str,
|
|
||||||
save: bool) -> Dict:
|
|
||||||
type = risotto_context.message.rsplit('.', 2)[-2]
|
|
||||||
self.valid_user(session_id,
|
|
||||||
risotto_context,
|
|
||||||
type)
|
|
||||||
session = self.get_session(session_id,
|
|
||||||
type)
|
|
||||||
id_ = session['id']
|
|
||||||
if type == 'server':
|
|
||||||
storage = storage_server
|
|
||||||
if save:
|
|
||||||
storage.save_values(session_id)
|
|
||||||
if self.server[id_].option('creole.general.available_probes').value.get() == "oui":
|
|
||||||
self.publish('v1.config.configuration.server.updated', server_id=id_, deploy=False)
|
|
||||||
else:
|
|
||||||
storage = storage_servermodel
|
|
||||||
if save:
|
|
||||||
storage.save_values(session_id)
|
|
||||||
for probe in self.servermodel[id_].config.list():
|
|
||||||
# FIXME should use config.information.get('server_id')
|
|
||||||
name = probe.config.name()
|
|
||||||
if name.startswith('p_'):
|
|
||||||
server_id = int(name.rsplit('_', 1)[-1])
|
|
||||||
if self.server[server_id].option('creole.general.available_probes').value.get() == "oui":
|
|
||||||
self.publish('v1.config.configuration.server.updated', server_id=server_id)
|
|
||||||
storage.del_session(session_id)
|
|
||||||
return self.format_session(session_id, session)
|
|
||||||
|
|
||||||
@register_http('v1', '/config/server/{session_id}')
|
|
||||||
async def get_server_api(self,
|
|
||||||
request,
|
|
||||||
risotto_context: Context,
|
|
||||||
session_id: str) -> Dict:
|
|
||||||
self.valid_user(session_id,
|
|
||||||
risotto_context,
|
|
||||||
'server')
|
|
||||||
session = storage_server.get_session(session_id)
|
|
||||||
return self.load_dict(session)
|
|
||||||
|
|
||||||
@register_http('v1', '/config/servermodel/{session_id}')
|
|
||||||
async def get_servermodel_api(self,
|
|
||||||
request,
|
|
||||||
risotto_context: Context,
|
|
||||||
session_id: str) -> Dict:
|
|
||||||
self.valid_user(session_id,
|
|
||||||
risotto_context,
|
|
||||||
'servermodel')
|
|
||||||
session = storage_servermodel.get_session(session_id)
|
|
||||||
return self.load_dict(session)
|
|
||||||
|
@ -1,138 +0,0 @@
|
|||||||
import time
|
|
||||||
from rougail import modes
|
|
||||||
|
|
||||||
|
|
||||||
class StorageError(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class Storage(object):
|
|
||||||
__slots__ = ('sessions',)
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
self.sessions = {}
|
|
||||||
|
|
||||||
def has_session(self, id_):
|
|
||||||
return id_ in self.sessions
|
|
||||||
|
|
||||||
def config_exists(self, id_):
|
|
||||||
return self.sessions[id_]['config_exists']
|
|
||||||
|
|
||||||
def add_session(self, session_id, orig_config, server_id, username, storage):
|
|
||||||
for session in self.sessions.values():
|
|
||||||
if session['id'] == server_id:
|
|
||||||
raise Storage(_(f'{username} already edits this configuration'))
|
|
||||||
prefix_id = "{}_".format(session_id)
|
|
||||||
config_server, orig_config = self.transform_orig_config(orig_config, server_id)
|
|
||||||
config_id = "{}{}".format(prefix_id, config_server)
|
|
||||||
meta = orig_config.config.deepcopy(session_id=config_id, storage=storage, metaconfig_prefix=prefix_id)
|
|
||||||
config = meta
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
children = list(config.config.list())
|
|
||||||
except:
|
|
||||||
break
|
|
||||||
if children:
|
|
||||||
config = children[0]
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
config.property.read_write()
|
|
||||||
self.set_owner(config, username)
|
|
||||||
orig_values = config.value.exportation()
|
|
||||||
config.information.set('orig_values', orig_values)
|
|
||||||
config_exists = False
|
|
||||||
for owner in orig_values[3]:
|
|
||||||
if isinstance(owner, list):
|
|
||||||
if set(owner) != {'forced'}:
|
|
||||||
config_exists = True
|
|
||||||
break
|
|
||||||
elif owner != 'forced':
|
|
||||||
config_exists = True
|
|
||||||
break
|
|
||||||
self.sessions[session_id] = {'config': config,
|
|
||||||
# do not delete meta, so keep it!
|
|
||||||
'meta': meta,
|
|
||||||
'orig_config': orig_config,
|
|
||||||
'id': server_id,
|
|
||||||
'timestamp': int(time.time()),
|
|
||||||
'username': username,
|
|
||||||
'option': None,
|
|
||||||
'namespace': 'creole',
|
|
||||||
'config_exists': config_exists}
|
|
||||||
self.set_config_mode(session_id, 'normal')
|
|
||||||
self.set_config_debug(session_id, False)
|
|
||||||
|
|
||||||
def list_sessions(self):
|
|
||||||
for session_id, session in self.sessions.items():
|
|
||||||
yield {'session_id': session_id,
|
|
||||||
'id': session['id'],
|
|
||||||
'timestamp': session['timestamp'],
|
|
||||||
'username': session['username'],
|
|
||||||
'namespace': session['namespace'],
|
|
||||||
'mode': session['mode'],
|
|
||||||
'debug': session['debug']}
|
|
||||||
|
|
||||||
def del_session(self, id_):
|
|
||||||
del self.sessions[id_]
|
|
||||||
|
|
||||||
def get_session(self, id_):
|
|
||||||
if id_ not in self.sessions:
|
|
||||||
raise Exception('please start a session before')
|
|
||||||
return self.sessions[id_]
|
|
||||||
|
|
||||||
def save_values(self, id_):
|
|
||||||
config = self.sessions[id_]['config']
|
|
||||||
server_id = self.sessions[id_]['id']
|
|
||||||
orig_config = self.sessions[id_]['orig_config']
|
|
||||||
values = config.value.exportation()
|
|
||||||
orig_config.value.importation(values)
|
|
||||||
orig_config.permissive.importation(config.permissive.exportation())
|
|
||||||
# current values become old values in diff_config
|
|
||||||
config.information.set('orig_values', values)
|
|
||||||
|
|
||||||
def get_username(self, id_):
|
|
||||||
return self.get_session(id_)['username']
|
|
||||||
|
|
||||||
def set_config_mode(self, id_, mode):
|
|
||||||
""" Define which edition mode to select
|
|
||||||
"""
|
|
||||||
config = self.get_session(id_)['config']
|
|
||||||
for mode_level in modes.values():
|
|
||||||
if modes[mode] < mode_level:
|
|
||||||
config.property.add(mode_level.name)
|
|
||||||
else:
|
|
||||||
config.property.pop(mode_level.name)
|
|
||||||
self.sessions[id_]['mode'] = mode
|
|
||||||
|
|
||||||
def set_config_debug(self, id_, is_debug):
|
|
||||||
""" Enable/Disable debug mode
|
|
||||||
"""
|
|
||||||
config = self.get_session(id_)['config']
|
|
||||||
if is_debug:
|
|
||||||
config.property.pop('hidden')
|
|
||||||
else:
|
|
||||||
config.property.add('hidden')
|
|
||||||
self.sessions[id_]['debug'] = is_debug
|
|
||||||
|
|
||||||
|
|
||||||
class StorageServer(Storage):
|
|
||||||
def transform_orig_config(self, orig_config, server_id):
|
|
||||||
config_server = "std_{}".format(server_id)
|
|
||||||
orig_config = orig_config.config(config_server)
|
|
||||||
return config_server, orig_config
|
|
||||||
|
|
||||||
def set_owner(self, config, username):
|
|
||||||
config.owner.set(username)
|
|
||||||
|
|
||||||
|
|
||||||
class StorageServermodel(Storage):
|
|
||||||
def transform_orig_config(self, orig_config, server_id):
|
|
||||||
config_server = "v_{}".format(server_id)
|
|
||||||
return config_server, orig_config
|
|
||||||
|
|
||||||
def set_owner(self, config, username):
|
|
||||||
config.owner.set('servermodel_' + username)
|
|
||||||
|
|
||||||
|
|
||||||
storage_server = StorageServer()
|
|
||||||
storage_servermodel = StorageServermodel()
|
|
1
src/risotto/services/server/__init__.py
Normal file
1
src/risotto/services/server/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
from .server import Risotto
|
8
src/risotto/services/server/server.py
Normal file
8
src/risotto/services/server/server.py
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
from ...controller import Controller
|
||||||
|
from ...register import register
|
||||||
|
|
||||||
|
|
||||||
|
class Risotto(Controller):
|
||||||
|
@register('v1.server.list', None)
|
||||||
|
async def server_list(self):
|
||||||
|
return [{'server_id': 1, 'servername': 'one', 'serverdescription': 'the first', 'servermodelid': 1}]
|
@ -14,6 +14,30 @@ class Risotto(Controller):
|
|||||||
async def servermodel_describe(self, inheritance, creolefuncs, servermodelid, schema, conffiles, resolvdepends, probes):
|
async def servermodel_describe(self, inheritance, creolefuncs, servermodelid, schema, conffiles, resolvdepends, probes):
|
||||||
schema = """<?xml version='1.0' encoding='UTF-8'?>
|
schema = """<?xml version='1.0' encoding='UTF-8'?>
|
||||||
<creole>
|
<creole>
|
||||||
|
<family name="containers">
|
||||||
|
<family name="container0" doc="test">
|
||||||
|
<family doc="files" name="files">
|
||||||
|
<family doc="file0" name="file0">
|
||||||
|
<variable doc="" multi="False" name="mkdir" type="boolean">
|
||||||
|
<value>False</value>
|
||||||
|
</variable>
|
||||||
|
<variable doc="" multi="False" name="name" type="string">
|
||||||
|
<value>/etc/mailname</value>
|
||||||
|
</variable>
|
||||||
|
<variable doc="" multi="False" name="rm" type="boolean">
|
||||||
|
<value>False</value>
|
||||||
|
</variable>
|
||||||
|
<variable doc="" multi="False" name="source" type="string">
|
||||||
|
<value>mailname</value>
|
||||||
|
</variable>
|
||||||
|
<variable doc="" multi="False" name="activate" type="boolean">
|
||||||
|
<value>True</value>
|
||||||
|
</variable>
|
||||||
|
</family>
|
||||||
|
</family>
|
||||||
|
<property>basic</property>
|
||||||
|
</family>
|
||||||
|
</family>
|
||||||
<family doc="" name="creole">
|
<family doc="" name="creole">
|
||||||
<family doc="general" name="general">
|
<family doc="general" name="general">
|
||||||
<property>normal</property>
|
<property>normal</property>
|
||||||
@ -38,5 +62,4 @@ class Risotto(Controller):
|
|||||||
<separators/>
|
<separators/>
|
||||||
</family>
|
</family>
|
||||||
</creole>"""
|
</creole>"""
|
||||||
print('pouet')
|
return {'servermodelid': 1, 'servermodelname': 'name', 'servermodeldescription': 'description', 'subreleasename': 'name', 'sourceid': 1, 'schema': schema, 'creolefuncs': ''}
|
||||||
return [{'servermodelid': 1, 'servermodelname': 'name', 'servermodeldescription': 'description', 'subreleasename': 'name', 'sourceid': 1, 'schema': schema, 'creolefuncs': ''}]
|
|
||||||
|
1
src/risotto/services/session/__init__.py
Normal file
1
src/risotto/services/session/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
from .session import Risotto
|
261
src/risotto/services/session/session.py
Normal file
261
src/risotto/services/session/session.py
Normal file
@ -0,0 +1,261 @@
|
|||||||
|
from os import urandom # , unlink
|
||||||
|
from binascii import hexlify
|
||||||
|
from traceback import print_exc
|
||||||
|
from typing import Dict, List, Optional, Any
|
||||||
|
from tiramisu import Storage
|
||||||
|
|
||||||
|
|
||||||
|
from ...http import register as register_http
|
||||||
|
from ...config import DEBUG
|
||||||
|
from ...context import Context
|
||||||
|
from ...utils import _
|
||||||
|
from ...error import CallError
|
||||||
|
from .storage import storage_server, storage_servermodel
|
||||||
|
from ...controller import Controller
|
||||||
|
from ...register import register
|
||||||
|
from ...dispatcher import dispatcher
|
||||||
|
|
||||||
|
|
||||||
|
class Risotto(Controller):
|
||||||
|
def __init__(self):
|
||||||
|
self.modify_storage = Storage(engine='dictionary')
|
||||||
|
|
||||||
|
def get_storage(self,
|
||||||
|
type: str):
|
||||||
|
if type == 'server':
|
||||||
|
return storage_server
|
||||||
|
return storage_servermodel
|
||||||
|
|
||||||
|
def get_session(self,
|
||||||
|
risotto_context: Context,
|
||||||
|
session_id: str,
|
||||||
|
type: str) -> Dict:
|
||||||
|
""" Get session information from storage
|
||||||
|
"""
|
||||||
|
if type == 'server':
|
||||||
|
storage = storage_server
|
||||||
|
else:
|
||||||
|
storage = storage_servermodel
|
||||||
|
return storage.get_session(session_id,
|
||||||
|
risotto_context.username)
|
||||||
|
|
||||||
|
def get_session_informations(self,
|
||||||
|
risotto_context: Context,
|
||||||
|
session_id: str,
|
||||||
|
type: str) -> Dict:
|
||||||
|
""" format session with a session ID name
|
||||||
|
"""
|
||||||
|
session = self.get_session(risotto_context,
|
||||||
|
session_id,
|
||||||
|
type)
|
||||||
|
return self.format_session(session_id,
|
||||||
|
session)
|
||||||
|
|
||||||
|
def format_session(self,
|
||||||
|
session_name: str,
|
||||||
|
session: Dict) -> Dict:
|
||||||
|
""" format session
|
||||||
|
"""
|
||||||
|
return {'session_id': session_name,
|
||||||
|
'id': session['id'],
|
||||||
|
'username': session['username'],
|
||||||
|
'timestamp': session['timestamp'],
|
||||||
|
'namespace': session['namespace'],
|
||||||
|
'mode': session['mode'],
|
||||||
|
'debug': session['debug']}
|
||||||
|
|
||||||
|
@register(['v1.session.server.start', 'v1.session.servermodel.start'], None)
|
||||||
|
async def start_session(self,
|
||||||
|
risotto_context: Context,
|
||||||
|
id: int) -> Dict:
|
||||||
|
""" start a new config session for a server or a servermodel
|
||||||
|
"""
|
||||||
|
type = risotto_context.message.rsplit('.', 2)[-2]
|
||||||
|
config_module = dispatcher.get_service('config')
|
||||||
|
if type == 'server':
|
||||||
|
if id not in config_module.server:
|
||||||
|
raise Exception(_(f'cannot find {type} with id {id}'))
|
||||||
|
config = config_module.server[id]['server']
|
||||||
|
else:
|
||||||
|
if id not in config_module.servermodel:
|
||||||
|
raise Exception(_(f'cannot find {type} with id {id}'))
|
||||||
|
config = config_module.servermodel[id]
|
||||||
|
|
||||||
|
storage = self.get_storage(type)
|
||||||
|
|
||||||
|
# check if a session already exists
|
||||||
|
sessions = storage.get_sessions()
|
||||||
|
for session in sessions.values():
|
||||||
|
if sess['id'] == id:
|
||||||
|
if sess['username'] == risotto_context.username:
|
||||||
|
# same user so returns it
|
||||||
|
return self.format_session(session['session_id'], session)
|
||||||
|
else:
|
||||||
|
raise CallError(_(f'{username} already edits this configuration'))
|
||||||
|
|
||||||
|
# create a new session
|
||||||
|
while True:
|
||||||
|
session_id = 'z' + hexlify(urandom(23)).decode()
|
||||||
|
if not session_id in sessions:
|
||||||
|
break
|
||||||
|
storage.add_session(session_id,
|
||||||
|
config,
|
||||||
|
id,
|
||||||
|
risotto_context.username,
|
||||||
|
self.modify_storage)
|
||||||
|
|
||||||
|
# return session's information
|
||||||
|
return self.get_session_informations(risotto_context,
|
||||||
|
session_id,
|
||||||
|
type)
|
||||||
|
|
||||||
|
@register(['v1.session.server.list', 'v1.session.servermodel.list'], None)
|
||||||
|
async def list_session_server(self,
|
||||||
|
risotto_context: Context) -> Dict:
|
||||||
|
type = risotto_context.message.rsplit('.', 2)[-2]
|
||||||
|
storage = self.get_storage(type)
|
||||||
|
return [self.format_session(session_id, session) for session_id, session in storage.get_sessions().items()]
|
||||||
|
|
||||||
|
|
||||||
|
@register(['v1.session.server.filter', 'v1.session.servermodel.filter'], None)
|
||||||
|
async def filter_session(self,
|
||||||
|
risotto_context: Context,
|
||||||
|
session_id: str,
|
||||||
|
namespace: str,
|
||||||
|
mode: str,
|
||||||
|
debug: Optional[bool]):
|
||||||
|
type = risotto_context.message.rsplit('.', 2)[-2]
|
||||||
|
storage = self.get_storage(type)
|
||||||
|
# to validate the session right
|
||||||
|
storage.get_session(session_id,
|
||||||
|
risotto_context.username)
|
||||||
|
if namespace is not None:
|
||||||
|
storage.set_namespace(session_id,
|
||||||
|
namespace)
|
||||||
|
if mode is not None:
|
||||||
|
if mode not in ('basic', 'normal', 'expert'):
|
||||||
|
raise CallError(f'unknown mode {mode}')
|
||||||
|
storage.set_config_mode(session_id,
|
||||||
|
mode)
|
||||||
|
if debug is not None:
|
||||||
|
storage.set_config_debug(session_id,
|
||||||
|
debug)
|
||||||
|
return self.get_session_informations(risotto_context,
|
||||||
|
session_id,
|
||||||
|
type)
|
||||||
|
|
||||||
|
@register(['v1.session.server.configure', 'v1.session.servermodel.configure'], None)
|
||||||
|
async def configure_session(self,
|
||||||
|
risotto_context: Context,
|
||||||
|
session_id: str,
|
||||||
|
action: str,
|
||||||
|
name: str,
|
||||||
|
index: int,
|
||||||
|
value: Any,
|
||||||
|
value_multi: Optional[List]) -> Dict:
|
||||||
|
type = risotto_context.message.rsplit('.', 2)[-2]
|
||||||
|
session = self.get_session(risotto_context,
|
||||||
|
session_id,
|
||||||
|
type)
|
||||||
|
# if multi and not follower the value is in fact in value_multi
|
||||||
|
option = session['option'].option(name).option
|
||||||
|
if option.ismulti() and not option.isfollower():
|
||||||
|
value = value_multi
|
||||||
|
namespace = session['namespace']
|
||||||
|
update = {'name': f'{namespace}.{name}',
|
||||||
|
'action': action,
|
||||||
|
'value': value}
|
||||||
|
if index is not None:
|
||||||
|
update['index'] = index
|
||||||
|
updates = {'updates': [update]}
|
||||||
|
ret = session['option'].updates(updates)
|
||||||
|
if update['name'] in ret:
|
||||||
|
for val in ret[update['name']][index]:
|
||||||
|
if isinstance(val, ValueError):
|
||||||
|
raise CallError(val)
|
||||||
|
ret = {'session_id': session_id,
|
||||||
|
'name': name}
|
||||||
|
if index is not None:
|
||||||
|
ret['index'] = index
|
||||||
|
return ret
|
||||||
|
|
||||||
|
@register(['v1.session.server.validate', 'v1.session.servermodel.validate'], None)
|
||||||
|
async def validate_session(self,
|
||||||
|
risotto_context: Context,
|
||||||
|
session_id: str) -> Dict:
|
||||||
|
type = risotto_context.message.rsplit('.', 2)[-2]
|
||||||
|
session = self.get_session(risotto_context,
|
||||||
|
session_id,
|
||||||
|
type)
|
||||||
|
try:
|
||||||
|
session['config'].forcepermissive.option(session['namespace']).value.dict()
|
||||||
|
except Exception as err:
|
||||||
|
raise CallError(str(err))
|
||||||
|
if type == 'server':
|
||||||
|
mandatories = list(session['config'].forcepermissive.value.mandatory())
|
||||||
|
if mandatories:
|
||||||
|
if len(mandatories) == 1:
|
||||||
|
mandatories = mandatories[0]
|
||||||
|
msg = _('the parameter "--{mandatories}" is mandatory')
|
||||||
|
else:
|
||||||
|
mandatories = '", "--'.join(mandatories)
|
||||||
|
msg = _('parameters "{mandatories}" are mandatories')
|
||||||
|
raise CallError(msg)
|
||||||
|
return self.format_session(session_id,
|
||||||
|
session)
|
||||||
|
|
||||||
|
@register(['v1.session.server.get', 'v1.session.servermodel.get'], None)
|
||||||
|
async def get_session_server(self,
|
||||||
|
risotto_context: Context,
|
||||||
|
session_id: str,
|
||||||
|
name: Optional[str]) -> Dict:
|
||||||
|
type = risotto_context.message.rsplit('.', 2)[-2]
|
||||||
|
session = self.get_session(risotto_context,
|
||||||
|
session_id,
|
||||||
|
type)
|
||||||
|
info = self.format_session(session_id, session)
|
||||||
|
if name is not None:
|
||||||
|
info['content'] = {name: session['option'].option(name).value.get()}
|
||||||
|
else:
|
||||||
|
info['content'] = session['option'].value.dict()
|
||||||
|
return info
|
||||||
|
|
||||||
|
@register(['v1.session.server.stop', 'v1.session.servermodel.stop'], None)
|
||||||
|
async def stop_session(self,
|
||||||
|
risotto_context: Context,
|
||||||
|
session_id: str,
|
||||||
|
save: bool) -> Dict:
|
||||||
|
type = risotto_context.message.rsplit('.', 2)[-2]
|
||||||
|
storage = self.get_storage(type)
|
||||||
|
session = storage.get_session(session_id,
|
||||||
|
risotto_context.username)
|
||||||
|
id_ = session['id']
|
||||||
|
config_module = dispatcher.get_service('config')
|
||||||
|
if type == 'server':
|
||||||
|
config = config_module.server[id_]['server']
|
||||||
|
else:
|
||||||
|
config = config_module.servermodel[id_]
|
||||||
|
if save:
|
||||||
|
modif_config = session['config']
|
||||||
|
config.value.importation(modif_config.value.exportation())
|
||||||
|
config.permissive.importation(modif_config.permissive.exportation())
|
||||||
|
storage.del_session(session_id)
|
||||||
|
return self.format_session(session_id, session)
|
||||||
|
|
||||||
|
@register_http('v1', '/config/server/{session_id}')
|
||||||
|
async def get_server_api(self,
|
||||||
|
request,
|
||||||
|
risotto_context: Context,
|
||||||
|
session_id: str) -> Dict:
|
||||||
|
session = storage_server.get_session(session_id,
|
||||||
|
risotto_context.username)
|
||||||
|
return session['option'].dict(remotable='all')
|
||||||
|
|
||||||
|
@register_http('v1', '/config/servermodel/{session_id}')
|
||||||
|
async def get_servermodel_api(self,
|
||||||
|
request,
|
||||||
|
risotto_context: Context,
|
||||||
|
session_id: str) -> Dict:
|
||||||
|
session = storage_servermodel.get_session(session_id,
|
||||||
|
risotto_context.username)
|
||||||
|
return session['option'].dict(remotable='all')
|
134
src/risotto/services/session/storage.py
Normal file
134
src/risotto/services/session/storage.py
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
import time
|
||||||
|
from typing import Dict
|
||||||
|
from tiramisu import Config
|
||||||
|
from rougail import modes
|
||||||
|
from ...error import CallError, NotAllowedError
|
||||||
|
|
||||||
|
|
||||||
|
class StorageError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Storage(object):
|
||||||
|
__slots__ = ('sessions',)
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.sessions = {}
|
||||||
|
|
||||||
|
def add_session(self,
|
||||||
|
session_id: int,
|
||||||
|
orig_config: Config,
|
||||||
|
server_id: int,
|
||||||
|
username: str,
|
||||||
|
config_storage):
|
||||||
|
prefix_id = f'{session_id}_'
|
||||||
|
config_name = self.get_config_name(server_id)
|
||||||
|
config_id = f'{prefix_id}{config_name}'
|
||||||
|
|
||||||
|
# copy Config and all it's parents
|
||||||
|
meta = orig_config.config.deepcopy(session_id=config_id,
|
||||||
|
storage=config_storage,
|
||||||
|
metaconfig_prefix=prefix_id)
|
||||||
|
|
||||||
|
# retrieve the copied config (not metaconfig)
|
||||||
|
config = meta
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
children = list(config.config.list())
|
||||||
|
if not children:
|
||||||
|
# it's an empty metaconfig
|
||||||
|
break
|
||||||
|
config = children[0]
|
||||||
|
except:
|
||||||
|
# it's a config, so no "list" method
|
||||||
|
break
|
||||||
|
config.property.read_write()
|
||||||
|
# set the default owner
|
||||||
|
self.set_owner(config,
|
||||||
|
username)
|
||||||
|
|
||||||
|
# store it
|
||||||
|
self.sessions[session_id] = {'config': config,
|
||||||
|
# do not delete meta, so keep it!
|
||||||
|
'meta': meta,
|
||||||
|
'id': server_id,
|
||||||
|
'timestamp': int(time.time()),
|
||||||
|
'username': username}
|
||||||
|
self.set_config_mode(session_id,
|
||||||
|
'normal')
|
||||||
|
self.set_config_debug(session_id,
|
||||||
|
False)
|
||||||
|
self.set_namespace(session_id,
|
||||||
|
'creole')
|
||||||
|
|
||||||
|
def set_config_mode(self,
|
||||||
|
id: int,
|
||||||
|
mode: str):
|
||||||
|
""" Define which edition mode to select
|
||||||
|
"""
|
||||||
|
config = self.sessions[id]['config']
|
||||||
|
for mode_level in modes.values():
|
||||||
|
if modes[mode] < mode_level:
|
||||||
|
config.property.add(mode_level.name)
|
||||||
|
else:
|
||||||
|
config.property.pop(mode_level.name)
|
||||||
|
self.sessions[id]['mode'] = mode
|
||||||
|
|
||||||
|
def set_config_debug(self, id_, is_debug):
|
||||||
|
""" Enable/Disable debug mode
|
||||||
|
"""
|
||||||
|
config = self.sessions[id_]['config']
|
||||||
|
if is_debug:
|
||||||
|
config.property.pop('hidden')
|
||||||
|
else:
|
||||||
|
config.property.add('hidden')
|
||||||
|
self.sessions[id_]['debug'] = is_debug
|
||||||
|
|
||||||
|
def set_namespace(self,
|
||||||
|
session_id: int,
|
||||||
|
namespace: str):
|
||||||
|
self.sessions[session_id]['option'] = self.sessions[session_id]['config'].option(namespace)
|
||||||
|
self.sessions[session_id]['namespace'] = namespace
|
||||||
|
|
||||||
|
def get_sessions(self):
|
||||||
|
return self.sessions;
|
||||||
|
|
||||||
|
def get_session(self,
|
||||||
|
session_id: int,
|
||||||
|
username: str) -> Dict:
|
||||||
|
if session_id not in self.sessions:
|
||||||
|
raise Exception(f'the session {id} not exists')
|
||||||
|
session = self.sessions[session_id]
|
||||||
|
if username != session['username']:
|
||||||
|
raise NotAllowedError()
|
||||||
|
return session
|
||||||
|
|
||||||
|
def del_session(self,
|
||||||
|
id: int):
|
||||||
|
del self.sessions[id]
|
||||||
|
|
||||||
|
|
||||||
|
class StorageServer(Storage):
|
||||||
|
def get_config_name(self,
|
||||||
|
server_id: int):
|
||||||
|
return f'std_{server_id}'
|
||||||
|
|
||||||
|
def set_owner(self,
|
||||||
|
config: Config,
|
||||||
|
username: str):
|
||||||
|
config.owner.set(username)
|
||||||
|
|
||||||
|
|
||||||
|
class StorageServermodel(Storage):
|
||||||
|
def get_config_name(self,
|
||||||
|
server_id: int):
|
||||||
|
return f'v_{server_id}'
|
||||||
|
|
||||||
|
def set_owner(self,
|
||||||
|
config: Config,
|
||||||
|
username: str):
|
||||||
|
config.owner.set('servermodel_' + username)
|
||||||
|
|
||||||
|
|
||||||
|
storage_server = StorageServer()
|
||||||
|
storage_servermodel = StorageServermodel()
|
1
src/risotto/services/template/__init__.py
Normal file
1
src/risotto/services/template/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
from .template import Risotto
|
49
src/risotto/services/template/template.py
Normal file
49
src/risotto/services/template/template.py
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
from os import mkdir
|
||||||
|
from os.path import isdir, join
|
||||||
|
from shutil import rmtree
|
||||||
|
from rougail.template import generate
|
||||||
|
from tiramisu import Storage
|
||||||
|
from ...config import ROOT_CACHE_DIR, CONFIGURATION_DIR, TEMPLATE_DIR, TMP_DIR
|
||||||
|
from ...controller import Controller
|
||||||
|
from ...register import register
|
||||||
|
from ...dispatcher import dispatcher
|
||||||
|
|
||||||
|
|
||||||
|
class Risotto(Controller):
|
||||||
|
def __init__(self):
|
||||||
|
self.storage = Storage(engine='dictionary')
|
||||||
|
|
||||||
|
@register('v1.template.generate', None)
|
||||||
|
async def template_get(self,
|
||||||
|
server_id: int):
|
||||||
|
config_module = dispatcher.get_service('config')
|
||||||
|
server = config_module.server[server_id]
|
||||||
|
config = meta = server['server'].config.deepcopy(storage=self.storage)
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
children = list(config.config.list())
|
||||||
|
except:
|
||||||
|
break
|
||||||
|
if children:
|
||||||
|
config = children[0]
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
print(config.value.dict())
|
||||||
|
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(TEMPLATE_DIR, str(server_id))
|
||||||
|
generate(config,
|
||||||
|
server['funcs_file'],
|
||||||
|
templates_dir,
|
||||||
|
tmp_dir,
|
||||||
|
configurations_dir)
|
||||||
|
|
||||||
|
return {'server_id': server_id,
|
||||||
|
'template_dir': configurations_dir}
|
1
templates/1/mailname
Normal file
1
templates/1/mailname
Normal file
@ -0,0 +1 @@
|
|||||||
|
mode_conteneur_actif: %%mode_conteneur_actif
|
0
tests/fake_services/__init__.py
Normal file
0
tests/fake_services/__init__.py
Normal file
1
tests/fake_services/server/__init__.py
Normal file
1
tests/fake_services/server/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
from .server import Risotto
|
8
tests/fake_services/server/server.py
Normal file
8
tests/fake_services/server/server.py
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
from risotto.controller import Controller
|
||||||
|
from risotto.register import register
|
||||||
|
|
||||||
|
|
||||||
|
class Risotto(Controller):
|
||||||
|
@register('v1.server.list', None)
|
||||||
|
async def server_list(self):
|
||||||
|
return [{'server_id': 3, 'servername': 'one', 'serverdescription': 'the first', 'servermodelid': 1}]
|
1
tests/fake_services/servermodel/__init__.py
Normal file
1
tests/fake_services/servermodel/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
from .servermodel import Risotto
|
71
tests/fake_services/servermodel/servermodel.py
Normal file
71
tests/fake_services/servermodel/servermodel.py
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
from risotto.controller import Controller
|
||||||
|
from risotto.register import register
|
||||||
|
|
||||||
|
class Risotto(Controller):
|
||||||
|
@register('v1.servermodel.list', None)
|
||||||
|
async def servermodel_list(self, sourceid):
|
||||||
|
return [{'servermodelid': 1,
|
||||||
|
'servermodelname': 'name1',
|
||||||
|
'subreleasename': 'name1',
|
||||||
|
'sourceid': 1,
|
||||||
|
'servermodeldescription': 'description1'},
|
||||||
|
{'servermodelid': 2,
|
||||||
|
'servermodelname': 'name2',
|
||||||
|
'subreleasename': 'name2',
|
||||||
|
'sourceid': 2,
|
||||||
|
'servermodeldescription': 'description2',
|
||||||
|
'servermodelparentsid': [1]}]
|
||||||
|
|
||||||
|
@register('v1.servermodel.describe', None)
|
||||||
|
async def servermodel_describe(self, inheritance, creolefuncs, servermodelid, schema, conffiles, resolvdepends, probes):
|
||||||
|
schema = """<?xml version='1.0' encoding='UTF-8'?>
|
||||||
|
<creole>
|
||||||
|
<family name="containers">
|
||||||
|
<family name="container0" doc="test">
|
||||||
|
<family doc="files" name="files">
|
||||||
|
<family doc="file0" name="file0">
|
||||||
|
<variable doc="" multi="False" name="mkdir" type="boolean">
|
||||||
|
<value>False</value>
|
||||||
|
</variable>
|
||||||
|
<variable doc="" multi="False" name="name" type="string">
|
||||||
|
<value>/etc/mailname</value>
|
||||||
|
</variable>
|
||||||
|
<variable doc="" multi="False" name="rm" type="boolean">
|
||||||
|
<value>False</value>
|
||||||
|
</variable>
|
||||||
|
<variable doc="" multi="False" name="source" type="string">
|
||||||
|
<value>mailname</value>
|
||||||
|
</variable>
|
||||||
|
<variable doc="" multi="False" name="activate" type="boolean">
|
||||||
|
<value>True</value>
|
||||||
|
</variable>
|
||||||
|
</family>
|
||||||
|
</family>
|
||||||
|
<property>basic</property>
|
||||||
|
</family>
|
||||||
|
</family>
|
||||||
|
<family doc="" name="creole">
|
||||||
|
<family doc="general" name="general">
|
||||||
|
<property>normal</property>
|
||||||
|
<variable doc="No change" multi="False" name="mode_conteneur_actif" type="choice">
|
||||||
|
<choice type="string">oui</choice>
|
||||||
|
<choice type="string">non</choice>
|
||||||
|
<property>mandatory</property>
|
||||||
|
<property>normal</property>
|
||||||
|
<value type="string">non</value>
|
||||||
|
</variable>
|
||||||
|
<leader doc="master" name="master">
|
||||||
|
<property>normal</property>
|
||||||
|
<variable doc="master" multi="True" name="master" type="string"/>
|
||||||
|
<variable doc="slave1" multi="True" name="slave1" type="string">
|
||||||
|
<property>normal</property>
|
||||||
|
</variable>
|
||||||
|
<variable doc="slave2" multi="True" name="slave2" type="string">
|
||||||
|
<property>normal</property>
|
||||||
|
</variable>
|
||||||
|
</leader>
|
||||||
|
</family>
|
||||||
|
<separators/>
|
||||||
|
</family>
|
||||||
|
</creole>"""
|
||||||
|
return {'servermodelid': 1, 'servermodelname': 'name', 'servermodeldescription': 'description', 'subreleasename': 'name', 'sourceid': 1, 'schema': schema, 'creolefuncs': ''}
|
334
tests/test_config.py
Normal file
334
tests/test_config.py
Normal file
@ -0,0 +1,334 @@
|
|||||||
|
from importlib import import_module
|
||||||
|
import pytest
|
||||||
|
from tiramisu import Storage, list_sessions, delete_session
|
||||||
|
|
||||||
|
from risotto.context import Context
|
||||||
|
from risotto.services import load_services
|
||||||
|
from risotto.dispatcher import dispatcher
|
||||||
|
from risotto.config import DATABASE_DIR
|
||||||
|
|
||||||
|
|
||||||
|
def setup_module(module):
|
||||||
|
load_services(['config'],
|
||||||
|
validate=False)
|
||||||
|
config_module = dispatcher.get_service('config')
|
||||||
|
config_module.save_storage = Storage(engine='sqlite3', dir_database=DATABASE_DIR, name='test')
|
||||||
|
dispatcher.set_module('server', import_module(f'.server', 'fake_services'))
|
||||||
|
dispatcher.set_module('servermodel', import_module(f'.servermodel', 'fake_services'))
|
||||||
|
|
||||||
|
|
||||||
|
def setup_function(function):
|
||||||
|
config_module = dispatcher.get_service('config')
|
||||||
|
config_module.server = {}
|
||||||
|
config_module.servermodel = {}
|
||||||
|
|
||||||
|
|
||||||
|
def teardown_function(function):
|
||||||
|
# delete all sessions
|
||||||
|
config_module = dispatcher.get_service('config')
|
||||||
|
for session in list_sessions(storage=config_module.save_storage):
|
||||||
|
delete_session(storage=config_module.save_storage, session_id=session)
|
||||||
|
|
||||||
|
|
||||||
|
def get_fake_context(module_name):
|
||||||
|
risotto_context = Context()
|
||||||
|
risotto_context.username = 'test'
|
||||||
|
risotto_context.paths.append(f'{module_name}.on_join')
|
||||||
|
risotto_context.type = None
|
||||||
|
return risotto_context
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_on_join():
|
||||||
|
config_module = dispatcher.get_service('config')
|
||||||
|
assert config_module.servermodel == {}
|
||||||
|
assert config_module.server == {}
|
||||||
|
#
|
||||||
|
fake_context = get_fake_context('config')
|
||||||
|
await config_module.on_join(fake_context)
|
||||||
|
assert list(config_module.servermodel.keys()) == [1, 2]
|
||||||
|
assert list(config_module.server) == [3]
|
||||||
|
assert set(config_module.server[3]) == {'server', 'server_to_deploy', 'funcs_file'}
|
||||||
|
assert config_module.server[3]['funcs_file'] == 'cache/1.creolefuncs'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_server_created():
|
||||||
|
config_module = dispatcher.get_service('config')
|
||||||
|
fake_context = get_fake_context('config')
|
||||||
|
await config_module.on_join(fake_context)
|
||||||
|
#
|
||||||
|
assert list(config_module.server) == [3]
|
||||||
|
await dispatcher.publish('v1',
|
||||||
|
'server.created',
|
||||||
|
fake_context,
|
||||||
|
server_id=4,
|
||||||
|
servername='name3',
|
||||||
|
serverdescription='description3',
|
||||||
|
servermodelid=2)
|
||||||
|
assert list(config_module.server) == [3, 4]
|
||||||
|
assert set(config_module.server[4]) == {'server', 'server_to_deploy', 'funcs_file'}
|
||||||
|
assert config_module.server[4]['funcs_file'] == 'cache/2.creolefuncs'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_server_deleted():
|
||||||
|
config_module = dispatcher.get_service('config')
|
||||||
|
fake_context = get_fake_context('config')
|
||||||
|
await config_module.on_join(fake_context)
|
||||||
|
#
|
||||||
|
assert list(config_module.server) == [3]
|
||||||
|
await dispatcher.publish('v1',
|
||||||
|
'server.created',
|
||||||
|
fake_context,
|
||||||
|
server_id=4,
|
||||||
|
servername='name4',
|
||||||
|
serverdescription='description4',
|
||||||
|
servermodelid=2)
|
||||||
|
assert list(config_module.server) == [3, 4]
|
||||||
|
await dispatcher.publish('v1',
|
||||||
|
'server.deleted',
|
||||||
|
fake_context,
|
||||||
|
server_id=4)
|
||||||
|
assert list(config_module.server) == [3]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_servermodel_created():
|
||||||
|
config_module = dispatcher.get_service('config')
|
||||||
|
fake_context = get_fake_context('config')
|
||||||
|
await config_module.on_join(fake_context)
|
||||||
|
#
|
||||||
|
assert list(config_module.servermodel) == [1, 2]
|
||||||
|
servermodel = {'servermodeid': 3,
|
||||||
|
'servermodelname': 'name3'}
|
||||||
|
await dispatcher.publish('v1',
|
||||||
|
'servermodel.created',
|
||||||
|
fake_context,
|
||||||
|
servermodelid=3,
|
||||||
|
servermodeldescription='name3',
|
||||||
|
subreleasename='2.7.0',
|
||||||
|
sourceid=1,
|
||||||
|
servermodelname='name3')
|
||||||
|
assert list(config_module.servermodel) == [1, 2, 3]
|
||||||
|
assert not list(config_module.servermodel[3].config.parents())
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_servermodel_herited_created():
|
||||||
|
config_module = dispatcher.get_service('config')
|
||||||
|
fake_context = get_fake_context('config')
|
||||||
|
await config_module.on_join(fake_context)
|
||||||
|
#
|
||||||
|
assert list(config_module.servermodel) == [1, 2]
|
||||||
|
await dispatcher.publish('v1',
|
||||||
|
'servermodel.created',
|
||||||
|
fake_context,
|
||||||
|
servermodelid=3,
|
||||||
|
servermodelname='name3',
|
||||||
|
subreleasename='2.7.0',
|
||||||
|
sourceid=1,
|
||||||
|
servermodeldescription='name3',
|
||||||
|
servermodelparentsid=[1])
|
||||||
|
assert list(config_module.servermodel) == [1, 2, 3]
|
||||||
|
assert len(list(config_module.servermodel[3].config.parents())) == 1
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_servermodel_multi_herited_created():
|
||||||
|
config_module = dispatcher.get_service('config')
|
||||||
|
fake_context = get_fake_context('config')
|
||||||
|
await config_module.on_join(fake_context)
|
||||||
|
#
|
||||||
|
assert list(config_module.servermodel) == [1, 2]
|
||||||
|
await dispatcher.publish('v1',
|
||||||
|
'servermodel.created',
|
||||||
|
fake_context,
|
||||||
|
servermodelid=3,
|
||||||
|
servermodelname='name3',
|
||||||
|
subreleasename='2.7.0',
|
||||||
|
sourceid=1,
|
||||||
|
servermodeldescription='name3',
|
||||||
|
servermodelparentsid=[1, 2])
|
||||||
|
assert list(config_module.servermodel) == [1, 2, 3]
|
||||||
|
assert len(list(config_module.servermodel[3].config.parents())) == 2
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_servermodel_updated_not_exists():
|
||||||
|
config_module = dispatcher.get_service('config')
|
||||||
|
fake_context = get_fake_context('config')
|
||||||
|
await config_module.on_join(fake_context)
|
||||||
|
#
|
||||||
|
assert list(config_module.servermodel) == [1, 2]
|
||||||
|
await dispatcher.publish('v1',
|
||||||
|
'servermodel.updated',
|
||||||
|
fake_context,
|
||||||
|
servermodelid=3,
|
||||||
|
servermodelname='name3',
|
||||||
|
subreleasename='2.7.0',
|
||||||
|
sourceid=1,
|
||||||
|
servermodeldescription='name3',
|
||||||
|
servermodelparentsid=[1, 2])
|
||||||
|
assert list(config_module.servermodel) == [1, 2, 3]
|
||||||
|
assert len(list(config_module.servermodel[3].config.parents())) == 2
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_servermodel_updated1():
|
||||||
|
config_module = dispatcher.get_service('config')
|
||||||
|
fake_context = get_fake_context('config')
|
||||||
|
await config_module.on_join(fake_context)
|
||||||
|
#
|
||||||
|
assert list(config_module.servermodel) == [1, 2]
|
||||||
|
metaconfig1 = config_module.servermodel[1]
|
||||||
|
metaconfig2 = config_module.servermodel[2]
|
||||||
|
mixconfig1 = next(metaconfig1.config.list())
|
||||||
|
mixconfig2 = next(metaconfig2.config.list())
|
||||||
|
assert len(list(metaconfig1.config.parents())) == 0
|
||||||
|
assert len(list(metaconfig2.config.parents())) == 1
|
||||||
|
assert len(list(mixconfig1.config.list())) == 1
|
||||||
|
assert len(list(mixconfig2.config.list())) == 0
|
||||||
|
#
|
||||||
|
await dispatcher.publish('v1',
|
||||||
|
'servermodel.updated',
|
||||||
|
fake_context,
|
||||||
|
servermodelid=1,
|
||||||
|
servermodelname='name1-1',
|
||||||
|
subreleasename='2.7.0',
|
||||||
|
sourceid=1,
|
||||||
|
servermodeldescription='name1-1')
|
||||||
|
assert set(config_module.servermodel) == {1, 2}
|
||||||
|
assert config_module.servermodel[1].information.get('servermodel_name') == 'name1-1'
|
||||||
|
assert metaconfig1 != config_module.servermodel[1]
|
||||||
|
assert metaconfig2 == config_module.servermodel[2]
|
||||||
|
metaconfig1 = config_module.servermodel[1]
|
||||||
|
assert mixconfig1 != next(metaconfig1.config.list())
|
||||||
|
mixconfig1 = next(metaconfig1.config.list())
|
||||||
|
#
|
||||||
|
assert len(list(metaconfig1.config.parents())) == 0
|
||||||
|
assert len(list(metaconfig2.config.parents())) == 1
|
||||||
|
assert len(list(mixconfig1.config.list())) == 1
|
||||||
|
assert len(list(mixconfig2.config.list())) == 0
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_servermodel_updated2():
|
||||||
|
config_module = dispatcher.get_service('config')
|
||||||
|
fake_context = get_fake_context('config')
|
||||||
|
await config_module.on_join(fake_context)
|
||||||
|
# create a new servermodel
|
||||||
|
assert list(config_module.servermodel) == [1, 2]
|
||||||
|
mixconfig1 = next(config_module.servermodel[1].config.list())
|
||||||
|
mixconfig2 = next(config_module.servermodel[2].config.list())
|
||||||
|
assert len(list(mixconfig1.config.list())) == 1
|
||||||
|
assert len(list(mixconfig2.config.list())) == 0
|
||||||
|
await dispatcher.publish('v1',
|
||||||
|
'servermodel.created',
|
||||||
|
fake_context,
|
||||||
|
servermodelid=3,
|
||||||
|
servermodelname='name3',
|
||||||
|
subreleasename='2.7.0',
|
||||||
|
sourceid=1,
|
||||||
|
servermodeldescription='name3',
|
||||||
|
servermodelparentsid=[1])
|
||||||
|
assert list(config_module.servermodel) == [1, 2, 3]
|
||||||
|
assert len(list(config_module.servermodel[3].config.parents())) == 1
|
||||||
|
assert config_module.servermodel[3].information.get('servermodel_name') == 'name3'
|
||||||
|
assert len(list(mixconfig1.config.list())) == 2
|
||||||
|
assert len(list(mixconfig2.config.list())) == 0
|
||||||
|
#
|
||||||
|
await dispatcher.publish('v1',
|
||||||
|
'servermodel.updated',
|
||||||
|
fake_context,
|
||||||
|
servermodelid=3,
|
||||||
|
servermodelname='name3-1',
|
||||||
|
subreleasename='2.7.0',
|
||||||
|
sourceid=1,
|
||||||
|
servermodeldescription='name3-1',
|
||||||
|
servermodelparentsid=[1, 2])
|
||||||
|
assert list(config_module.servermodel) == [1, 2, 3]
|
||||||
|
assert config_module.servermodel[3].information.get('servermodel_name') == 'name3-1'
|
||||||
|
assert len(list(mixconfig1.config.list())) == 2
|
||||||
|
assert len(list(mixconfig2.config.list())) == 1
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_servermodel_updated_config():
|
||||||
|
config_module = dispatcher.get_service('config')
|
||||||
|
fake_context = get_fake_context('config')
|
||||||
|
await config_module.on_join(fake_context)
|
||||||
|
#
|
||||||
|
config_module.servermodel[1].property.read_write()
|
||||||
|
assert config_module.servermodel[1].option('creole.general.mode_conteneur_actif').value.get() == 'non'
|
||||||
|
config_module.servermodel[1].option('creole.general.mode_conteneur_actif').value.set('oui')
|
||||||
|
assert config_module.servermodel[1].option('creole.general.mode_conteneur_actif').value.get() == 'oui'
|
||||||
|
#
|
||||||
|
await dispatcher.publish('v1',
|
||||||
|
'servermodel.updated',
|
||||||
|
fake_context,
|
||||||
|
servermodelid=1,
|
||||||
|
servermodelname='name1-1',
|
||||||
|
subreleasename='2.7.0',
|
||||||
|
sourceid=1,
|
||||||
|
servermodeldescription='name1-1')
|
||||||
|
assert config_module.servermodel[1].option('creole.general.mode_conteneur_actif').value.get() == 'oui'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_server_configuration_get():
|
||||||
|
config_module = dispatcher.get_service('config')
|
||||||
|
fake_context = get_fake_context('config')
|
||||||
|
await config_module.on_join(fake_context)
|
||||||
|
#
|
||||||
|
config_module.server[3]['server_to_deploy'].property.read_write()
|
||||||
|
assert config_module.server[3]['server_to_deploy'].option('creole.general.mode_conteneur_actif').value.get() == 'non'
|
||||||
|
config_module.server[3]['server_to_deploy'].option('creole.general.mode_conteneur_actif').value.set('oui')
|
||||||
|
assert config_module.server[3]['server_to_deploy'].option('creole.general.mode_conteneur_actif').value.get() == 'oui'
|
||||||
|
assert config_module.server[3]['server'].option('creole.general.mode_conteneur_actif').value.get() == 'non'
|
||||||
|
#
|
||||||
|
values = await dispatcher.call('v1',
|
||||||
|
'config.configuration.server.get',
|
||||||
|
fake_context,
|
||||||
|
server_id=3)
|
||||||
|
configuration = {'configuration':
|
||||||
|
{'creole.general.mode_conteneur_actif': 'non',
|
||||||
|
'creole.general.master.master': [],
|
||||||
|
'creole.general.master.slave1': [],
|
||||||
|
'creole.general.master.slave2': [],
|
||||||
|
'containers.container0.files.file0.mkdir': False,
|
||||||
|
'containers.container0.files.file0.name': '/etc/mailname',
|
||||||
|
'containers.container0.files.file0.rm': False,
|
||||||
|
'containers.container0.files.file0.source': 'mailname',
|
||||||
|
'containers.container0.files.file0.activate': True},
|
||||||
|
'server_id': 3,
|
||||||
|
'deployed': True}
|
||||||
|
assert values == configuration
|
||||||
|
#
|
||||||
|
values = await dispatcher.call('v1',
|
||||||
|
'config.configuration.server.get',
|
||||||
|
fake_context,
|
||||||
|
server_id=3,
|
||||||
|
deployed=False)
|
||||||
|
configuration['configuration']['creole.general.mode_conteneur_actif'] = 'oui'
|
||||||
|
configuration['deployed'] = False
|
||||||
|
assert values == configuration
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_config_deployed():
|
||||||
|
config_module = dispatcher.get_service('config')
|
||||||
|
fake_context = get_fake_context('config')
|
||||||
|
await config_module.on_join(fake_context)
|
||||||
|
#
|
||||||
|
config_module.server[3]['server_to_deploy'].property.read_write()
|
||||||
|
assert config_module.server[3]['server_to_deploy'].option('creole.general.mode_conteneur_actif').value.get() == 'non'
|
||||||
|
config_module.server[3]['server_to_deploy'].option('creole.general.mode_conteneur_actif').value.set('oui')
|
||||||
|
assert config_module.server[3]['server_to_deploy'].option('creole.general.mode_conteneur_actif').value.get() == 'oui'
|
||||||
|
assert config_module.server[3]['server'].option('creole.general.mode_conteneur_actif').value.get() == 'non'
|
||||||
|
values = await dispatcher.publish('v1',
|
||||||
|
'config.configuration.server.deploy',
|
||||||
|
fake_context,
|
||||||
|
server_id=3)
|
||||||
|
assert config_module.server[3]['server_to_deploy'].option('creole.general.mode_conteneur_actif').value.get() == 'oui'
|
||||||
|
assert config_module.server[3]['server'].option('creole.general.mode_conteneur_actif').value.get() == 'oui'
|
501
tests/test_session.py
Normal file
501
tests/test_session.py
Normal file
@ -0,0 +1,501 @@
|
|||||||
|
from importlib import import_module
|
||||||
|
import pytest
|
||||||
|
from tiramisu import Storage
|
||||||
|
from risotto.context import Context
|
||||||
|
from risotto.services import load_services
|
||||||
|
from risotto.dispatcher import dispatcher
|
||||||
|
from risotto.config import DATABASE_DIR
|
||||||
|
from risotto.services.session.storage import storage_server, storage_servermodel
|
||||||
|
|
||||||
|
|
||||||
|
def get_fake_context(module_name):
|
||||||
|
risotto_context = Context()
|
||||||
|
risotto_context.username = 'test'
|
||||||
|
risotto_context.paths.append(f'{module_name}.on_join')
|
||||||
|
risotto_context.type = None
|
||||||
|
return risotto_context
|
||||||
|
|
||||||
|
|
||||||
|
def setup_module(module):
|
||||||
|
load_services(['config', 'session'],
|
||||||
|
validate=False)
|
||||||
|
config_module = dispatcher.get_service('config')
|
||||||
|
config_module.save_storage = Storage(engine='sqlite3', dir_database=DATABASE_DIR, name='test')
|
||||||
|
dispatcher.set_module('server', import_module(f'.server', 'fake_services'))
|
||||||
|
dispatcher.set_module('servermodel', import_module(f'.servermodel', 'fake_services'))
|
||||||
|
|
||||||
|
|
||||||
|
def teardown_function(function):
|
||||||
|
config_module = dispatcher.get_service('session')
|
||||||
|
storage_server.sessions = {}
|
||||||
|
storage_servermodel.sessions = {}
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_server_start():
|
||||||
|
fake_context = get_fake_context('session')
|
||||||
|
config_module = dispatcher.get_service('config')
|
||||||
|
if not config_module.server:
|
||||||
|
await config_module.on_join(fake_context)
|
||||||
|
await dispatcher.call('v1',
|
||||||
|
'session.server.start',
|
||||||
|
fake_context,
|
||||||
|
id=3)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_server_list():
|
||||||
|
fake_context = get_fake_context('session')
|
||||||
|
config_module = dispatcher.get_service('config')
|
||||||
|
if not config_module.server:
|
||||||
|
await config_module.on_join(fake_context)
|
||||||
|
assert not await dispatcher.call('v1',
|
||||||
|
'session.server.list',
|
||||||
|
fake_context)
|
||||||
|
await dispatcher.call('v1',
|
||||||
|
'session.server.start',
|
||||||
|
fake_context,
|
||||||
|
id=3)
|
||||||
|
assert await dispatcher.call('v1',
|
||||||
|
'session.server.list',
|
||||||
|
fake_context)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_server_filter_namespace():
|
||||||
|
fake_context = get_fake_context('session')
|
||||||
|
config_module = dispatcher.get_service('config')
|
||||||
|
if not config_module.server:
|
||||||
|
await config_module.on_join(fake_context)
|
||||||
|
session = await dispatcher.call('v1',
|
||||||
|
'session.server.start',
|
||||||
|
fake_context,
|
||||||
|
id=3)
|
||||||
|
session_id = session['session_id']
|
||||||
|
namespace = 'containers'
|
||||||
|
await dispatcher.call('v1',
|
||||||
|
'session.server.filter',
|
||||||
|
fake_context,
|
||||||
|
session_id=session_id,
|
||||||
|
namespace=namespace)
|
||||||
|
list_result = await dispatcher.call('v1',
|
||||||
|
'session.server.list',
|
||||||
|
fake_context)
|
||||||
|
assert list_result[0]['namespace'] == namespace
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_server_filter_mode():
|
||||||
|
fake_context = get_fake_context('session')
|
||||||
|
config_module = dispatcher.get_service('config')
|
||||||
|
if not config_module.server:
|
||||||
|
await config_module.on_join(fake_context)
|
||||||
|
session = await dispatcher.call('v1',
|
||||||
|
'session.server.start',
|
||||||
|
fake_context,
|
||||||
|
id=3)
|
||||||
|
session_id = session['session_id']
|
||||||
|
assert session['mode'] == 'normal'
|
||||||
|
mode = 'expert'
|
||||||
|
await dispatcher.call('v1',
|
||||||
|
'session.server.filter',
|
||||||
|
fake_context,
|
||||||
|
session_id=session_id,
|
||||||
|
mode=mode)
|
||||||
|
list_result = await dispatcher.call('v1',
|
||||||
|
'session.server.list',
|
||||||
|
fake_context)
|
||||||
|
assert list_result[0]['mode'] == mode
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_server_filter_debug():
|
||||||
|
fake_context = get_fake_context('session')
|
||||||
|
config_module = dispatcher.get_service('config')
|
||||||
|
if not config_module.server:
|
||||||
|
await config_module.on_join(fake_context)
|
||||||
|
session = await dispatcher.call('v1',
|
||||||
|
'session.server.start',
|
||||||
|
fake_context,
|
||||||
|
id=3)
|
||||||
|
session_id = session['session_id']
|
||||||
|
assert session['debug'] == False
|
||||||
|
debug = True
|
||||||
|
await dispatcher.call('v1',
|
||||||
|
'session.server.filter',
|
||||||
|
fake_context,
|
||||||
|
session_id=session_id,
|
||||||
|
debug=debug)
|
||||||
|
list_result = await dispatcher.call('v1',
|
||||||
|
'session.server.list',
|
||||||
|
fake_context)
|
||||||
|
assert list_result[0]['debug'] == debug
|
||||||
|
#FIXME
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_server_filter_get():
|
||||||
|
fake_context = get_fake_context('session')
|
||||||
|
config_module = dispatcher.get_service('config')
|
||||||
|
if not config_module.server:
|
||||||
|
await config_module.on_join(fake_context)
|
||||||
|
session = await dispatcher.call('v1',
|
||||||
|
'session.server.start',
|
||||||
|
fake_context,
|
||||||
|
id=3)
|
||||||
|
session_id = session['session_id']
|
||||||
|
values = await dispatcher.call('v1',
|
||||||
|
'session.server.get',
|
||||||
|
fake_context,
|
||||||
|
session_id=session_id)
|
||||||
|
assert values == {'content': {"general.mode_conteneur_actif": "non",
|
||||||
|
"general.master.master": [],
|
||||||
|
"general.master.slave1": [],
|
||||||
|
"general.master.slave2": []},
|
||||||
|
'debug': False,
|
||||||
|
'id': 3,
|
||||||
|
'mode': 'normal',
|
||||||
|
'namespace': 'creole',
|
||||||
|
'session_id': session_id,
|
||||||
|
'timestamp': values['timestamp'],
|
||||||
|
'username': 'test'}
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_server_filter_get_one_value():
|
||||||
|
fake_context = get_fake_context('session')
|
||||||
|
config_module = dispatcher.get_service('config')
|
||||||
|
if not config_module.server:
|
||||||
|
await config_module.on_join(fake_context)
|
||||||
|
session = await dispatcher.call('v1',
|
||||||
|
'session.server.start',
|
||||||
|
fake_context,
|
||||||
|
id=3)
|
||||||
|
session_id = session['session_id']
|
||||||
|
values = await dispatcher.call('v1',
|
||||||
|
'session.server.get',
|
||||||
|
fake_context,
|
||||||
|
session_id=session_id,
|
||||||
|
name="general.mode_conteneur_actif")
|
||||||
|
assert values == {'content': {"general.mode_conteneur_actif": "non"},
|
||||||
|
'debug': False,
|
||||||
|
'id': 3,
|
||||||
|
'mode': 'normal',
|
||||||
|
'namespace': 'creole',
|
||||||
|
'session_id': session_id,
|
||||||
|
'timestamp': values['timestamp'],
|
||||||
|
'username': 'test'}
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_server_filter_configure():
|
||||||
|
fake_context = get_fake_context('session')
|
||||||
|
config_module = dispatcher.get_service('config')
|
||||||
|
if not config_module.server:
|
||||||
|
await config_module.on_join(fake_context)
|
||||||
|
session = await dispatcher.call('v1',
|
||||||
|
'session.server.start',
|
||||||
|
fake_context,
|
||||||
|
id=3)
|
||||||
|
session_id = session['session_id']
|
||||||
|
await dispatcher.call('v1',
|
||||||
|
'session.server.configure',
|
||||||
|
fake_context,
|
||||||
|
session_id=session_id,
|
||||||
|
action='modify',
|
||||||
|
name='general.mode_conteneur_actif',
|
||||||
|
value='oui')
|
||||||
|
list_result = await dispatcher.call('v1',
|
||||||
|
'session.server.list',
|
||||||
|
fake_context)
|
||||||
|
values = await dispatcher.call('v1',
|
||||||
|
'session.server.get',
|
||||||
|
fake_context,
|
||||||
|
session_id=session_id,
|
||||||
|
name="general.mode_conteneur_actif")
|
||||||
|
assert values == {'content': {"general.mode_conteneur_actif": "oui"},
|
||||||
|
'debug': False,
|
||||||
|
'id': 3,
|
||||||
|
'mode': 'normal',
|
||||||
|
'namespace': 'creole',
|
||||||
|
'session_id': session_id,
|
||||||
|
'timestamp': values['timestamp'],
|
||||||
|
'username': 'test'}
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_server_filter_validate():
|
||||||
|
fake_context = get_fake_context('session')
|
||||||
|
config_module = dispatcher.get_service('config')
|
||||||
|
if not config_module.server:
|
||||||
|
await config_module.on_join(fake_context)
|
||||||
|
session = await dispatcher.call('v1',
|
||||||
|
'session.server.start',
|
||||||
|
fake_context,
|
||||||
|
id=3)
|
||||||
|
session_id = session['session_id']
|
||||||
|
await dispatcher.call('v1',
|
||||||
|
'session.server.validate',
|
||||||
|
fake_context,
|
||||||
|
session_id=session_id)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_server_stop():
|
||||||
|
fake_context = get_fake_context('session')
|
||||||
|
config_module = dispatcher.get_service('config')
|
||||||
|
if not config_module.server:
|
||||||
|
await config_module.on_join(fake_context)
|
||||||
|
assert not await dispatcher.call('v1',
|
||||||
|
'session.server.list',
|
||||||
|
fake_context)
|
||||||
|
start = await dispatcher.call('v1',
|
||||||
|
'session.server.start',
|
||||||
|
fake_context,
|
||||||
|
id=3)
|
||||||
|
session_id = start['session_id']
|
||||||
|
assert await dispatcher.call('v1',
|
||||||
|
'session.server.list',
|
||||||
|
fake_context)
|
||||||
|
await dispatcher.call('v1',
|
||||||
|
'session.server.stop',
|
||||||
|
fake_context,
|
||||||
|
session_id=session_id)
|
||||||
|
assert not await dispatcher.call('v1',
|
||||||
|
'session.server.list',
|
||||||
|
fake_context)
|
||||||
|
|
||||||
|
|
||||||
|
# servermodel
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_servermodel_start():
|
||||||
|
fake_context = get_fake_context('session')
|
||||||
|
config_module = dispatcher.get_service('config')
|
||||||
|
if not config_module.servermodel:
|
||||||
|
await config_module.on_join(fake_context)
|
||||||
|
await dispatcher.call('v1',
|
||||||
|
'session.servermodel.start',
|
||||||
|
fake_context,
|
||||||
|
id=1)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_servermodel_list():
|
||||||
|
fake_context = get_fake_context('session')
|
||||||
|
config_module = dispatcher.get_service('config')
|
||||||
|
if not config_module.servermodel:
|
||||||
|
await config_module.on_join(fake_context)
|
||||||
|
assert not await dispatcher.call('v1',
|
||||||
|
'session.servermodel.list',
|
||||||
|
fake_context)
|
||||||
|
await dispatcher.call('v1',
|
||||||
|
'session.servermodel.start',
|
||||||
|
fake_context,
|
||||||
|
id=1)
|
||||||
|
assert await dispatcher.call('v1',
|
||||||
|
'session.servermodel.list',
|
||||||
|
fake_context)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_servermodel_filter_namespace():
|
||||||
|
fake_context = get_fake_context('session')
|
||||||
|
config_module = dispatcher.get_service('config')
|
||||||
|
if not config_module.servermodel:
|
||||||
|
await config_module.on_join(fake_context)
|
||||||
|
session = await dispatcher.call('v1',
|
||||||
|
'session.servermodel.start',
|
||||||
|
fake_context,
|
||||||
|
id=1)
|
||||||
|
session_id = session['session_id']
|
||||||
|
namespace = 'containers'
|
||||||
|
await dispatcher.call('v1',
|
||||||
|
'session.servermodel.filter',
|
||||||
|
fake_context,
|
||||||
|
session_id=session_id,
|
||||||
|
namespace=namespace)
|
||||||
|
list_result = await dispatcher.call('v1',
|
||||||
|
'session.servermodel.list',
|
||||||
|
fake_context)
|
||||||
|
assert list_result[0]['namespace'] == namespace
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_servermodel_filter_mode():
|
||||||
|
fake_context = get_fake_context('session')
|
||||||
|
config_module = dispatcher.get_service('config')
|
||||||
|
if not config_module.servermodel:
|
||||||
|
await config_module.on_join(fake_context)
|
||||||
|
session = await dispatcher.call('v1',
|
||||||
|
'session.servermodel.start',
|
||||||
|
fake_context,
|
||||||
|
id=1)
|
||||||
|
session_id = session['session_id']
|
||||||
|
assert session['mode'] == 'normal'
|
||||||
|
mode = 'expert'
|
||||||
|
await dispatcher.call('v1',
|
||||||
|
'session.servermodel.filter',
|
||||||
|
fake_context,
|
||||||
|
session_id=session_id,
|
||||||
|
mode=mode)
|
||||||
|
list_result = await dispatcher.call('v1',
|
||||||
|
'session.servermodel.list',
|
||||||
|
fake_context)
|
||||||
|
assert list_result[0]['mode'] == mode
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_servermodel_filter_debug():
|
||||||
|
fake_context = get_fake_context('session')
|
||||||
|
config_module = dispatcher.get_service('config')
|
||||||
|
if not config_module.servermodel:
|
||||||
|
await config_module.on_join(fake_context)
|
||||||
|
session = await dispatcher.call('v1',
|
||||||
|
'session.servermodel.start',
|
||||||
|
fake_context,
|
||||||
|
id=1)
|
||||||
|
session_id = session['session_id']
|
||||||
|
assert session['debug'] == False
|
||||||
|
debug = True
|
||||||
|
await dispatcher.call('v1',
|
||||||
|
'session.servermodel.filter',
|
||||||
|
fake_context,
|
||||||
|
session_id=session_id,
|
||||||
|
debug=debug)
|
||||||
|
list_result = await dispatcher.call('v1',
|
||||||
|
'session.servermodel.list',
|
||||||
|
fake_context)
|
||||||
|
assert list_result[0]['debug'] == debug
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_servermodel_filter_get():
|
||||||
|
fake_context = get_fake_context('session')
|
||||||
|
config_module = dispatcher.get_service('config')
|
||||||
|
if not config_module.servermodel:
|
||||||
|
await config_module.on_join(fake_context)
|
||||||
|
session = await dispatcher.call('v1',
|
||||||
|
'session.servermodel.start',
|
||||||
|
fake_context,
|
||||||
|
id=1)
|
||||||
|
session_id = session['session_id']
|
||||||
|
values = await dispatcher.call('v1',
|
||||||
|
'session.servermodel.get',
|
||||||
|
fake_context,
|
||||||
|
session_id=session_id)
|
||||||
|
assert values == {'content': {"general.mode_conteneur_actif": "non",
|
||||||
|
"general.master.master": [],
|
||||||
|
"general.master.slave1": [],
|
||||||
|
"general.master.slave2": []},
|
||||||
|
'debug': False,
|
||||||
|
'id': 1,
|
||||||
|
'mode': 'normal',
|
||||||
|
'namespace': 'creole',
|
||||||
|
'session_id': session_id,
|
||||||
|
'timestamp': values['timestamp'],
|
||||||
|
'username': 'test'}
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_servermodel_filter_get_one_value():
|
||||||
|
fake_context = get_fake_context('session')
|
||||||
|
config_module = dispatcher.get_service('config')
|
||||||
|
if not config_module.servermodel:
|
||||||
|
await config_module.on_join(fake_context)
|
||||||
|
session = await dispatcher.call('v1',
|
||||||
|
'session.servermodel.start',
|
||||||
|
fake_context,
|
||||||
|
id=1)
|
||||||
|
session_id = session['session_id']
|
||||||
|
values = await dispatcher.call('v1',
|
||||||
|
'session.servermodel.get',
|
||||||
|
fake_context,
|
||||||
|
session_id=session_id,
|
||||||
|
name="general.mode_conteneur_actif")
|
||||||
|
assert values == {'content': {"general.mode_conteneur_actif": "non"},
|
||||||
|
'debug': False,
|
||||||
|
'id': 1,
|
||||||
|
'mode': 'normal',
|
||||||
|
'namespace': 'creole',
|
||||||
|
'session_id': session_id,
|
||||||
|
'timestamp': values['timestamp'],
|
||||||
|
'username': 'test'}
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_servermodel_filter_configure():
|
||||||
|
fake_context = get_fake_context('session')
|
||||||
|
config_module = dispatcher.get_service('config')
|
||||||
|
if not config_module.servermodel:
|
||||||
|
await config_module.on_join(fake_context)
|
||||||
|
session = await dispatcher.call('v1',
|
||||||
|
'session.servermodel.start',
|
||||||
|
fake_context,
|
||||||
|
id=1)
|
||||||
|
session_id = session['session_id']
|
||||||
|
await dispatcher.call('v1',
|
||||||
|
'session.servermodel.configure',
|
||||||
|
fake_context,
|
||||||
|
session_id=session_id,
|
||||||
|
action='modify',
|
||||||
|
name='general.mode_conteneur_actif',
|
||||||
|
value='oui')
|
||||||
|
list_result = await dispatcher.call('v1',
|
||||||
|
'session.servermodel.list',
|
||||||
|
fake_context)
|
||||||
|
values = await dispatcher.call('v1',
|
||||||
|
'session.servermodel.get',
|
||||||
|
fake_context,
|
||||||
|
session_id=session_id,
|
||||||
|
name="general.mode_conteneur_actif")
|
||||||
|
assert values == {'content': {"general.mode_conteneur_actif": "oui"},
|
||||||
|
'debug': False,
|
||||||
|
'id': 1,
|
||||||
|
'mode': 'normal',
|
||||||
|
'namespace': 'creole',
|
||||||
|
'session_id': session_id,
|
||||||
|
'timestamp': values['timestamp'],
|
||||||
|
'username': 'test'}
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_servermodel_filter_validate():
|
||||||
|
fake_context = get_fake_context('session')
|
||||||
|
config_module = dispatcher.get_service('config')
|
||||||
|
if not config_module.servermodel:
|
||||||
|
await config_module.on_join(fake_context)
|
||||||
|
session = await dispatcher.call('v1',
|
||||||
|
'session.servermodel.start',
|
||||||
|
fake_context,
|
||||||
|
id=1)
|
||||||
|
session_id = session['session_id']
|
||||||
|
await dispatcher.call('v1',
|
||||||
|
'session.servermodel.validate',
|
||||||
|
fake_context,
|
||||||
|
session_id=session_id)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_servermodel_stop():
|
||||||
|
fake_context = get_fake_context('session')
|
||||||
|
config_module = dispatcher.get_service('config')
|
||||||
|
if not config_module.servermodel:
|
||||||
|
await config_module.on_join(fake_context)
|
||||||
|
assert not await dispatcher.call('v1',
|
||||||
|
'session.servermodel.list',
|
||||||
|
fake_context)
|
||||||
|
start = await dispatcher.call('v1',
|
||||||
|
'session.servermodel.start',
|
||||||
|
fake_context,
|
||||||
|
id=1)
|
||||||
|
session_id = start['session_id']
|
||||||
|
assert await dispatcher.call('v1',
|
||||||
|
'session.servermodel.list',
|
||||||
|
fake_context)
|
||||||
|
await dispatcher.call('v1',
|
||||||
|
'session.servermodel.stop',
|
||||||
|
fake_context,
|
||||||
|
session_id=session_id)
|
||||||
|
assert not await dispatcher.call('v1',
|
||||||
|
'session.servermodel.list',
|
||||||
|
fake_context)
|
Reference in New Issue
Block a user