# remote_users_fact Rôle Ansible qui gère un **local fact** comptant les sessions distantes par protocole (SSH, Citrix, Horizon) et évaluant la fiabilité en comparant avec `who`. ## Gestion du state Le rôle est piloté par la variable `remote_users_fact_state` : | State | Comportement | | --- | --- | | `noop` (défaut) | Aucune action — le rôle ne touche à rien | | `present` | Déploie le fact, valide le JSON, affiche le résumé | | `absent` | Supprime le fact, purge ansible_local, nettoie le répertoire si vide | Le state peut être défini à tout niveau (all, groupe, hôte, extra-vars). `noop` par défaut garantit qu'un hôte ajouté à l'inventaire sans configuration explicite ne sera pas impacté. ## Arborescence ```text ├── site.yml # Playbook principal ├── inventories/ │ └── hosts.yml # Inventaire exemple └── roles/ └── remote_users_fact/ ├── defaults/main.yml # Variables (dont state) ├── files/remote_users.fact # Script fact ├── handlers/main.yml # Rechargement facts ├── meta/main.yml # Métadonnées Galaxy └── tasks/ ├── main.yml # Assertions → routage par state ├── assert.yml # Validation stricte du paramétrage ├── present.yml # Déploiement (state=present) ├── absent.yml # Suppression (state=absent) ├── validate.yml # Exécution + assert structure JSON └── summary.yml # Affichage matrice + alertes ``` ## Usage ```bash # Appliquer le state défini dans l'inventaire ansible-playbook -i inventories/hosts.yml site.yml # Forcer le déploiement partout (override) ansible-playbook -i inventories/hosts.yml site.yml -e remote_users_fact_state=present # Supprimer partout ansible-playbook -i inventories/hosts.yml site.yml -e remote_users_fact_state=absent # Sur un groupe spécifique ansible-playbook -i inventories/hosts.yml site.yml -l citrix_servers # Tags disponibles ansible-playbook ... --tags assert # Assertions seules ansible-playbook ... --tags present,deploy # Déploiement seul ansible-playbook ... --tags validate # Validation seule ansible-playbook ... --tags summary # Résumé seul ansible-playbook ... --tags absent,remove # Suppression seule ``` ## Variables | Variable | Défaut | Description | | --- | --- | --- | | `remote_users_fact_state` | `noop` | `present` / `absent` / `noop` | | `remote_users_fact_dir` | `/etc/ansible/facts.d` | Répertoire de destination | | `remote_users_fact_name` | `remote_users.fact` | Nom du script | | `remote_users_fact_owner` | `root` | Propriétaire | | `remote_users_fact_group` | `root` | Groupe | | `remote_users_fact_validate` | `true` | Activer la validation post-deploy | | `remote_users_fact_display_summary` | `true` | Afficher le résumé | | `remote_users_fact_warn_verdicts` | voir defaults | Verdicts déclenchant un warning | ## Assertions Le rôle valide le paramétrage **avant** toute action : - `remote_users_fact_state` est défini et vaut `present`, `absent` ou `noop` - `remote_users_fact_dir` est un chemin absolu (si state != noop) - `remote_users_fact_name` respecte le pattern `*.fact` (si state != noop) - `remote_users_fact_owner` et `group` sont définis (si state == present) - `remote_users_fact_validate` et `display_summary` sont des booléens - `remote_users_fact_warn_verdicts` est une liste de verdicts valides En cas de state `present`, la validation post-déploiement vérifie aussi : - Le script s'exécute sans erreur (rc == 0) - La sortie est du JSON parsable - Toutes les clés obligatoires sont présentes - Les compteurs sont >= 0 - `total_by_protocol == ssh + citrix + horizon` - Le verdict est dans la liste des verdicts connus - Le fact est chargé dans `ansible_local` ## Fact déployé Accessible via `ansible_local.remote_users` : ```json { "timestamp": "2026-04-13T10:30:00Z", "sessions": { "ssh": 3, "citrix": 12, "horizon": 0, "total_by_protocol": 15, "who_remote": 14 }, "users_remote": "alice,bob,charlie", "reliability": { "ratio_who_over_total": 0.93, "verdict": "WHO_INF_TOTAL", "detail": "who manque 1 session(s) sans TTY" }, "detection": { "citrix_vda_installed": true, "horizon_agent_installed": false, "ssh_method": "sshd_process_and_ss", "citrix_method": "ctxquery", "horizon_method": "fallback_ports" } } ``` ## Verdicts | Verdict | Signification | | --- | --- | | `FIABLE` | who == total → compteurs alignés | | `OK` | Écart <= 1 → tolérable | | `WHO_SUP_TOTAL` | who > total → protocole non surveillé | | `WHO_INF_TOTAL` | who < total → sessions headless sans TTY | | `WHO_SEUL` | total == 0 → protocoles non détectés | | `PROTO_SEUL` | who == 0 → sessions sans allocation TTY | | `NEUTRE` | 0 == 0 → aucune session | ## Exemple d'inventaire avec states ```yaml all: vars: remote_users_fact_state: present # Défaut global children: prod_servers: hosts: srv-01: {} srv-02: {} # Hôte exclu dev_servers: hosts: dev-01: remote_users_fact_state: noop # Groupe en décommission legacy: vars: remote_users_fact_state: absent ``` ## CI / Tests Le rôle est testé automatiquement sur toutes les distributions déclarées dans `meta/main.yml` via Docker. ### Commandes Make ```bash make help # Affiche les cibles disponibles make matrix # Affiche la matrice JSON des distros make lint # yamllint + ansible-lint make test # Teste toutes les distros make test-el9 # Teste une seule distro make clean # Supprime les images Docker de test ``` ### Registry privée Par défaut les images sont tirées depuis Docker Hub. Pour utiliser une registry privée (Artifactory, Harbor, etc.), définir les variables d'environnement : | Variable | Défaut | Exemple | | --- | --- | --- | | `DOCKER_REGISTRY` | *(vide = Docker Hub)* | `registry.nuevolia.dev` | | `DOCKER_REGISTRY_PREFIX` | *(vide)* | `library/` | ```bash # Artifactory DOCKER_REGISTRY=registry.nuevolia.dev DOCKER_REGISTRY_PREFIX=library/ make test # Harbor DOCKER_REGISTRY=harbor.local DOCKER_REGISTRY_PREFIX=proxy/ make test ``` ### Pipelines CI Trois configurations sont fournies : | Fichier | Système | Stratégie | | --- | --- | --- | | `.gitea/workflows/ci.yml` | Gitea Actions | Matrix dynamique parallèle | | `.gitlab-ci.yml` | GitLab CI | Séquentiel | | `Jenkinsfile` | Jenkins | Stages parallèles | Les variables `DOCKER_REGISTRY` et `DOCKER_REGISTRY_PREFIX` peuvent être définies dans les secrets/variables de chaque CI. ## Utilisation dans d'autres playbooks ```yaml - hosts: all gather_facts: true tasks: - name: Bloquer un déploiement si trop de sessions ansible.builtin.fail: msg: "{{ ansible_local.remote_users.sessions.total_by_protocol }} sessions actives" when: - ansible_local.remote_users is defined - ansible_local.remote_users.sessions.total_by_protocol | int > 10 ```