From 1adae63e181e8c494f7497344eb85e2cdedb11c1 Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Wed, 19 Nov 2025 12:08:46 +0100 Subject: [PATCH] fix: caracteristique.md --- caracteristique.md | 620 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 620 insertions(+) create mode 100644 caracteristique.md diff --git a/caracteristique.md b/caracteristique.md new file mode 100644 index 000000000..fe9ef120e --- /dev/null +++ b/caracteristique.md @@ -0,0 +1,620 @@ +--- +gitea: none +include_toc: true +--- + +# Rougail : caractéristiques + +Rougail est un outil qui permet de gérer le cycle de vie des variables et de gestion des valeurs de ces variables. + +Au moment de la conception de Rougail, il y a eu des choix structurant qui ont défini le fonctionnement de l'outil. + +Voici la liste des principales caractéristiques : + +## Logiciel libre + +Rougail est un logiciel libre (et Open Source) de gestion externe de variables. +Le développement est réalisé de manière ouverte. + +Rougail repose sur le logiciel libre Tiramisu comme moteur de contrainte. + +Rougail est composé : + +- d'un format de description +- d'un projet principal "Rougail" qui : + + - charge les fichiers de structures, + - applique les valeurs des données utilisateur, + - représente les variables avec leurs valeurs. + +- différents sous projet pour étendre les fonctionnalités de base +- un outil en ligne de commande pour facilité l'utilisation de la bibliothèque. + +## Les acteurs + +Rougail est destiné a séparer le cycle de vie de la variable entre 3 acteurs : + +- l'acteur qui défini les variables +- l'acteur qui adapte les valeurs +- l'acteur qui utilise les variables avec leurs valeurs + +Exemples concret d'acteur : + +Dans le cadre du déploiement d'une configuration : + +- l'intégrateur défini les variables +- l'exploitant adapte les valeurs +- l'installeur utilise les variables avec leurs valeurs + +Dans le cadre du développement d'une application : + +- le dévelopeur défini les variables +- l'utilisateur adapte les valeurs +- l'application utilise les variables avec leurs valeurs + +## Cycle de vie des variables + +Rougail a pour but de définir les variables puis de gérer tout son cycle de vie. + +Dans le cycle de vie d'une variable, on inclut les étapes générique d'une variable (par exemple pour le langage C) : + +- déclaration (elles se voient attribuer un nom et un type) ; +- définition (elles se voient affecter leur première valeur) ; +- affectation (elles se voient modifier la valeur de la variable) ; +- lecture (elles se voient utilisent la valeur de la variable) ; +- fin de vie (elles se terminent à la destruction de l'objet). + +Mais d'autres notions sont inclusent dans le cycle de vie : + +- extension de la déclaration en ajoutant la "description" de la variable +- présentation, l'acteur qui adapte les valeurs doit avoir toutes les informations nécessaires pour renseigner les valeurs, c'est ainsi qu'il est possible de généré automatiquement la documentation, le journal des modifications, ... +- autorisations, des propriétés décrivent les contraintes d'accès +- spécialisation, qui décrit l'usage possible d'une variable + +Rôle des différents composants Rougail : + +Le format permet de décrire : + +- la déclaration (nom, type et description) +- les autorisations +- la spécialisation + +Rougail et ces composants : + +- la définition (via Tiramisu) +- la présentation +- l'affectation (via Tiramisu) +- la lecture +- la fin de vie + + +## Architecture Structurals-UserDatas-Outputs + + +### Structurals + +Les fichiers de "Structures" sont des fichiers au format Rougail dans laquelle toutes les informations du cycle de vie sont définies. +Il est important de tout mettre ces informations au même endroit. Ainsi on connaitre toutes les aspects de la variable en lisant ces fichiers. +On y retrouve : + +- un schéma +- la définition des contraintes +- des éléments de documentation +- ... + +Les variables sont ici mutables, elles peuvent être redéfinit à tout moment. +Ces fichiers sont créées par l'acteur qui défini les variables. + + +### UserDatas + +Une fois la structure définie, il est possible de charger les "Données Utilisateur" (UserDatas). On retrouve plusieurs type de données utilisateurs : + +- des fichiers de configuration +- des variables d'environnement +- des sources externes +- des options de lignes de commande +- un formulaire +- ... + +Les variables sont ici immuables, par contre les valeurs sont mutables. +Ces sources sont peuplées par l'acteur qui adapte les valeurs. + + +### Outputs + +Ensuite on pourra définir sous quelle forme on veut recueillir l'information (Outputs) : + +- un objet Tiramisu +- une extraction JSON +- un export pour l'inventaire Ansible +- de la documetation +- ... + +Les variables et les valeurs sont ici immuables. + +Voici un exemple concret : + +Un intégrateur a besoin d'une variable et défini la défini ainsi (dans le fichier `structure_architecture.yml`) : + +```yaml +%YAML 1.2 +--- +version: 1.1 + +my_variable: +... +``` + +L'exploitant défini la valeur de cette variable ainsi (dans le fichier `userdata.yml`) : + +```yaml +--- +my_variable: a value +``` + +On désire afficher de manière lisible la configuration : + +```bash +rougail -m structure_architecture.yml -u yaml -yf userdata.yml +╭──────── Caption ────────╮ +│ Variable Modified value │ +╰─────────────────────────╯ +Variables: +┗━━ 📓 my_variable: a value ◀ loaded from the YAML file "userdata.yml" +``` + + +### Valeur par défaut + +Les variables ont une valeur. Une valeur par défaut est définit à la variable (None ou []) mais il est possible d'en définir une autre. + +Il ne faut pas confondre la valeur par défaut ou la/les valeur(s) défini par l'acteur adaptant la configuration. + +Par exemple, si je veux définir la variable my_variable en y spécifiant une valeur par défaut (dans le fichier `structure_default.yml`) : + +```yaml +%YAML 1.2 +--- +version: 1.1 + +my_variable: + default: a default value +... +``` + +```bash +rougail -m structure_default.yml +╭─────── Caption ────────╮ +│ Variable Default value │ +╰────────────────────────╯ +Variables: +┗━━ 📓 my_variable: a default value +``` + + +## Le format : un langage + + +### DSL (Domain Specific Language) + +Contrairement à un langage générique, un langage dédié est conçu pour répondre à un domaine d'application précis. + +La description des variables se faire dans des fichiers YAML version 1.2. Le langage de configuration de Rougail permet de décrire tout le cycle de vie de la variable. + + +### Abstraction déclarative + +Les variables sont décrite suivant un modèle déclaratif. Cela signigie que l'utilisateur définit simplement l'état final souhaité de celle-ci. Tiramisu determinera les actions nécessaires pour atteindre cet état. + +Dit autrement l'utilisateur défini le schéma des variables qui sera ensuite appliqué de manière déterministe. + + + +### Redéfinition explicite + +Les variables peuvent être redéfinis à tout moment (utile notamment lorsqu'on définit des modèles de configuration). Mais la redéfinition d'une variable doit être explicitement déclaré comme tel. + +Par exemple, si je veux redéfinir la variable my_variable en y spécifiant une valeur par défaut (dans le fichier `structure_redefine.yml`) : + +```yaml +%YAML 1.2 +--- +version: 1.1 + +my_variable: + redefine: true + default: a new default value +... +``` + +```bash +rougail -m structure_default.yml structure_redefine.yml +╭─────── Caption ────────╮ +│ Variable Default value │ +╰────────────────────────╯ +Variables: +┗━━ 📓 my_variable: a new default value +``` + + +## Typage + + +### Type standard + +Rougail (et Tiramisu) accepte les types standards suivant : + +- string (type par défaut d'une variable) +- integer +- float +- boolean + + +### Type métier + +Mais on va retrouver également tout une série de type métier : + +- IP +- domainname +- port +- MAC +- choice +- secret +- ... + +Voici quelques exemples : + +```structure_type.yml +%YAML 1.2 +--- +version: 1.1 + +my_integer: 1 + +my_mail: + type: mail + default: foo@bar.net + +my_date: + type: date + default: "2025-11-19" +... +``` + +```rougail -m structure_type.yml +╭─────── Caption ────────╮ +│ Variable Default value │ +╰────────────────────────╯ +Variables: +┣━━ 📓 my_integer: 1 +┣━━ 📓 my_mail: foo@bar.net +┗━━ 📓 my_date: 2025-11-19 +``` + + +### Fortement typé + +Rougail utilise en interne la bibliothèque Tiramisu. Les variables dans Tiramisu sont fortement typé. +C'est à dire que le chargement des données utilisateur implique une attention sur le type des variables. Pour les données utilisateurs non typées (comme les variables d'environnement), en pré traitement, il y aura une adaptation du type de la valeur. + +Par exemple si l'exploitant adapte la valeur de cette variable ainsi (dans le fichier userdata_fort_type.yml : + +```yaml +--- +my_variable: 1 +``` + +La valeur ne pourra pas être chargée (le type par défaut étant le type "string") : + +```bash +rougail -m structure_architecture.yml -u yaml -yf userdata_fort_type.yml +🔔 WARNINGS +┗━━ the value "1" is an invalid string for "my_variable", which is not a string, it will be ignored when loading from the YAML file "userdata.yml" +🛑 ERRORS +┗━━ The following variables are mandatory but have no value: + ┗━━ my_variable +``` + +### Typage dynamique + +Au moment de la définition de la structure, le type est dynamique. C'est à dire que l'acteur qui défini la variable peut changé à tout moment le type de la variable. + +Par exemple (dans le fichier `structure_redefine_type.yml`) : + +```yaml +%YAML 1.2 +--- +version: 1.1 + +my_variable: + redefine: true + type: integer +... +``` + +```bash +rougail -m structure_architecture.yml structure_redefine_type.yml -u yaml -yf userdata_fort_type.yml +╭──────── Caption ────────╮ +│ Variable Modified value │ +╰─────────────────────────╯ +Variables: +┗━━ 📓 my_variable: 1 ◀ loaded from the YAML file "userdata.yml" +``` + +Par contre, comme l'exemple du typage fort le suggère, l'acteur qui adapte la valeur n'a pas la possiblité de redéfinir le type de la variable. + +### Inférence de type + +Le type peut être défini explicitement (comme dans le fichier structure_type.yml) ou déduit du typage des variables YAML. + +Par exemple la variable avec une valeur par défaut à 1 est une variable de type "integer" : + +```structure3.yml +%YAML 1.2 +--- +version: 1.1 + +my_variable: 1 +... +``` + +```rougail -m structure3.yml +╭─────── Caption ────────╮ +│ Variable Default value │ +╰────────────────────────╯ +Variables: +┗━━ 📓 my_variable: 1 +``` + + +### Valeur "nullable" + +Le type "null" (ou "None" en python) n'existe pas dans Rougail. "null" est une valeur. Tous les types peuvent accepter cette valeur, mais par défaut, ce n'est pas le cas. + +Voici la déclaration d'une variable avec la valeur par défaut à "null" (dans le fichier `structure_nullable.yml`) : + +```yaml +%YAML 1.2 +--- +version: 1.1 + +my_variable: +... +``` + +```bash +rougail -m structure_nullable.yml +🛑 ERRORS +┗━━ The following variables are mandatory but have no value: + ┗━━ my_variable +``` + +En réalité la variable n'est pas accessible lorsque Tiramisu est mode "lecture seule" (ce qui est le cas lors des étapes Outputs par défaut). Lorsqu'on force le mode "lecture écriture" on a bien accès : + +```bash +rougail -m structure_nullable.yml --cli.read_write +╭─────── Caption ────────╮ +│ Variable Default value │ +╰────────────────────────╯ +Variables: +┗━━ 📓 my_variable: null +``` + +Pour que notre variable accepte dans tous les cas "null" il faut modifier le fichier de structure comme cela : + +```yaml +%YAML 1.2 +--- +version: 1.1 + +my_variable: + mandatory: false +... +``` + +```bash +rougail -m structure_nullable.yml --cli.read_write +╭─────── Caption ────────╮ +│ Variable Default value │ +╰────────────────────────╯ +Variables: +┗━━ 📓 my_variable: null +``` + + +## Intégrité des données + +L'intégrité des données fait référence au fait que les données doivent être fiables et précises tout au long de leur cycle de vie. + +Cela signifie que la valeur doit être : + +- de qualité +- adapté au context globale + + +### Qualité de la donnée + +Pour avoir des données de qualité, il faut que l'outil valide la saisie utilisateur. + +La première façon de valider la donnée est bien évidement de définir le bon type. + +Mais cela ne suffit pas. + +#### Paramètres de type + +Il existe, pour certains type, un certains nombres de paramètres qui vont pouvoir compléter le typage des variables : + +```structure_param_type.yml +%YAML 1.2 +--- +version: 1.1 + +my_percent: + type: integer + params: + min_integer: 0 + max_integer: 100 + default: + 10 +... +``` + +```rougail -m structure_param_type.yml +╭─────── Caption ────────╮ +│ Variable Default value │ +╰────────────────────────╯ +Variables: +┗━━ 📓 my_percent: 10 +``` + +Mais avec une donnée utilisateur invalide, la valeur ne sera pas chargé (dans le fichier `userdata1.yml`) : + +```yaml +--- +my_percent: 120 +``` + +```bash +rougail -m structure6.yml -u yaml -yf userdata1.yml +🔔 WARNINGS +┗━━ the value "120" is an invalid integer for "my_percent", value must be less than "100", it will be + ignored when loading from the YAML file "userdata1.yml" +╭─────── Caption ────────╮ +│ Variable Default value │ +╰────────────────────────╯ +Variables: +┗━━ 📓 my_percent: 10 +``` + +Ou pourra même généré une erreur : + +```bash +rougail -m structure6.yml -u yaml -yf userdata1.yml --cli.invalid_user_datas_error +🛑 ERRORS +┗━━ the value "120" is an invalid integer for "my_percent", value must be less than "100", it will be + ignored when loading from the YAML file "userdata1.yml +``` + + +#### Validation + +Mais il est possible d'ajouter des validations complémentaires, par exemple ici vérifier que la variable est impaire (dans le fichier `structure_validators.yml`) : + +```structure_validators.yml +%YAML 1.2 +--- +version: 1.1 + +my_odd_variable: + type: integer + validators: + - jinja: "{% if not (_.my_odd_variable % 2) %}not an odd integer{% endif %}" + default: + 10 +... +``` + +```rougail -m structure7.yml +🛑 ERRORS +┗━━ "10" is an invalid integer for "my_odd_variable", not an odd integer +``` + +Par contre cela passe avec une valeur impaire (dans le fichier `userdata_validators.yml`) : +```yaml +--- +my_odd_variable: 11 +``` + + +```bash +rougail -m structure_validators.yml -u yaml -ff userdata_validators.yml +╭────────────── Caption ───────────────╮ +│ Variable Modified value │ +│ (⏳ Original default value) │ +╰──────────────────────────────────────╯ +Variables: +┗━━ 📓 my_odd_variable: 11 ◀ loaded from the YAML file "userdata_validators.yml" (⏳ 10) +``` + +### Cohérence globale + +Une variable isolée peut être considéré comme étant de qualité mais devenir incohérence suivant le contexte. + +Par exemple, si on demande une valeur minimum puis une valeur maximum, la minimal doit être inférieur à la maximal. Dans le fichier `structure_consistency.yml` on a : + +```yaml +%YAML 1.2 +--- +version: 1.1 + +my_min_value: 11 + +my_max_value: + default: + variable: _.my_min_value + validators: + - jinja: |- + {% if _.my_min_value >= _.my_max_value %} + must but upper than {{ _.my_min_value }} (the value of "my_min_value") + {% endif %} +... +``` + +```bash +rougail -m structure_consistency.yml +🛑 ERRORS +┗━━ "11" is an invalid integer for "my_max_value", must but upper than 11 (the value of "my_min_value") +``` + +Si on défini la bonne valeur : + +```yaml +--- +my_max_value: 13 +``` + +```bash +%YAML 1.2 +--- +version: 1.1 + +my_min_value: 11 + +my_max_value: + default: + variable: _.my_min_value + validators: + - jinja: |- + {% if _.my_min_value >= _.my_max_value %} + must but upper than {{ _.my_min_value }} (the value of "my_min_value") + {% endif %} +... +``` + +```bash +rougail -m structure_consistency.yml -u yaml -ff userdata_consistency.yml +╭────────────── Caption ───────────────╮ +│ Variable Default value │ +│ Modified value │ +│ (⏳ Original default value) │ +╰──────────────────────────────────────╯ +Variables: +┣━━ 📓 my_min_value: 11 +┗━━ 📓 my_max_value: 13 ◀ loaded from the YAML file "userdata_consistency.yml" (⏳ 11) +``` + + + + +Arborescent +Inspiré par ABAC +Spécialisation des variables +Modèle de configuration +Réutilisable/partageable +Simple/list/array/dynamique +retutilisable +jit +traduit +templating +linter