Relier les pages de l’événement

AnsibleBeginner
Pratiquer maintenant

Introduction

La page d’accueil de Riverlight Weekend est prête, mais les visiteurs ne peuvent pas ouvrir le programme ni la page du lieu. Les deux services sources fonctionnent déjà. Avec Ansible, reliez l’entrée aux membres choisis dans l’inventaire, rechargez uniquement une configuration modifiée et protégez les routes fonctionnelles contre un remplacement inadapté.

Vous devez savoir vous déplacer dans un terminal et avoir pratiqué la lecture d’un petit inventaire, de variables et d’un playbook Ansible. Ce laboratoire explique les rôles HTTP, les groupes, les variables entre hôtes, JSON, les requêtes en lecture seule et les handlers avant leur utilisation. Les logiciels et services sont prêts. La durée est une estimation de l’auteur comprenant lecture et corrections courantes.

Relier les pages du programme et du lieu

Dans cette étape, vous relierez le site d’un événement à ses sources préparées de programme et de lieu, en utilisant les membres de l’inventaire plutôt que des adresses fixes dans un modèle.

Riverlight Weekend possède une page d’accueil et un guide fonctionnels. Les liens du programme et du lieu affichent actuellement une page indisponible. L’entrée est un petit proxy inverse HTTP préparé : elle transmet une requête à un autre service et renvoie sa véritable réponse. Elle ne copie pas le programme dans l’accueil. L’entrée s’exécute sur le contrôleur ; les deux nœuds sources sont des conteneurs partageant le noyau de cette VM d’apprentissage. Ce ne sont pas trois VM indépendantes. Logiciels et services sont prêts ; vous gérez uniquement les connexions de l’entrée.

Ouvrez l’onglet Event Site. L’accueil doit afficher A little closer to the river. Cliquez sur Explore the program : This page is taking a break. est une réponse HTTP 502 attendue, car la route n’est pas connectée. Utilisez Back to the weekend sur cette page, puis Visitor guide dans la navigation. Ce guide fonctionne déjà et doit rester disponible.

Passez à Controller, qui démarre dans /home/labex/project. pwd affiche le répertoire courant :

pwd

Si vous perdez votre répertoire de travail, revenez avec cd /home/labex/project. Un nom de fichier mal saisi produit « No such file or directory » ; vérifiez l’orthographe, utilisez si nécessaire ls templates pour lister ce répertoire, puis réessayez. Inutile de réinitialiser la VM.

cat affiche un fichier. Lisez la sélection approuvée, l’inventaire et les données de chaque hôte :

cat approved-services.txt
cat inventory.ini
cat host_vars/web1.yml
cat host_vars/web2.yml

Les groupes [program] et [venue] sélectionnent chacun une source. web1 fournit le programme actuel ; web2 fournit le lieu. Les fichiers d’hôte donnent leur véritable service_address et leurs ports. Les adresses peuvent varier entre VM. Certains nœuds proposent aussi un service d’archive ; être accessible ne signifie pas être le programme actuel approuvé.

Le groupe [gateway] contient entry. ansible_connection=local signifie qu’Ansible gère l’entrée sur le contrôleur, sans connexion SSH supplémentaire. /usr/bin/python3 est l’interpréteur Python local préparé. Un port HTTP identifie un service à l’écoute sur une adresse ; un nœud peut faire fonctionner plusieurs services sur des ports différents.

Avant de modifier l’entrée, interrogez directement chaque source choisie. Les fichiers de configuration curl contiennent les véritables URL. --config lit les options depuis un fichier ; fail fait échouer la commande en cas d’erreur HTTP, silent masque la progression et show-error conserve les messages utiles. Ces fichiers ne contiennent ni mot de passe ni jeton.

cat requests/web1.conf
curl --config requests/web1.conf
cat requests/web2.conf
curl --config requests/web2.conf

Les réponses JSON identifient program et venue, le site riverlight et leurs éditions. JSON est du texte structuré avec des champs nommés. Une requête réussie prouve que la source répond directement, pas encore que les routes du site fonctionnent.

Créez ensuite le modèle de routes. La variable groups d’Ansible associe chaque groupe à ses membres ; [0] sélectionne le premier membre du groupe qui n’en contient qu’un. hostvars récupère les variables de ce membre. Le playbook ci-dessous les nomme program_host et venue_host. Dans Jinja, ~ joint les valeurs sous forme de texte, y compris les ports numériques. | to_json produit une chaîne JSON correctement délimitée, sans assembler dangereusement les guillemets à la main.

La commande shell utilise > pour remplacer ce fichier uniquement. <<'EOF' transmet littéralement les lignes suivantes à cat ; les apostrophes empêchent le shell d’interpréter les accolades Jinja. Collez jusqu’au délimiteur final EOF, seul sur sa ligne. Si son omission laisse le shell attendre à une invite de continuation, appuyez sur Ctrl+C et recollez la commande complète.

cat > templates/routes.json.j2 <<'EOF'
{
  "program": {{ ('http://' ~ hostvars[program_host].service_address ~ ':' ~ hostvars[program_host].program_port) | to_json }},
  "venue": {{ ('http://' ~ hostvars[venue_host].service_address ~ ':' ~ hostvars[venue_host].venue_port) | to_json }}
}
EOF

Écrivez le playbook de l’entrée. gather_facts: false évite de recueillir des informations machine inutilisées. vars définit les expressions évaluées à partir de l’inventaire courant. template génère le fichier, applique le mode 0644 (écriture pour le propriétaire, lecture pour tous) et notifie un handler uniquement si les routes changent. Un handler est une tâche exécutée après notification, normalement à la fin du play.

L’entrée conserve les routes en mémoire : remplacer le fichier ne suffit donc pas. L’utilitaire préparé envoie un véritable signal SIGHUP de rechargement uniquement au processus existant de cette entrée et attend sa confirmation. Le command du handler utilise argv, une liste d’arguments séparés. playbook_dir est le répertoire contenant le playbook ; il limite le chemin de l’entrée gérée à ce projet. Ni sudo ni redémarrage du service ne sont nécessaires.

cat > connect.yml <<'EOF'
- name: Connect the event services
  hosts: gateway
  gather_facts: false
  vars:
    program_host: "{{ groups['program'][0] }}"
    venue_host: "{{ groups['venue'][0] }}"
  tasks:
    - name: Write the inventory-derived routes
      ansible.builtin.template:
        src: templates/routes.json.j2
        dest: "{{ playbook_dir }}/entry/routes.json"
        mode: '0644'
      notify: Reload entry
  handlers:
    - name: Reload entry
      ansible.builtin.command:
        argv:
          - python3
          - /opt/labex/service-links/reload.py
          - "{{ playbook_dir }}/entry"
EOF

Vérifiez d’abord la structure YAML, puis prévisualisez le changement prévu. --syntax-check n’applique aucune tâche. --check prédit les changements pris en charge et --diff montre l’ancien contenu et celui proposé. Cette prévisualisation n’envoie aucun signal à la passerelle et ne prouve pas le fonctionnement du site final.

ansible-playbook connect.yml --syntax-check
ansible-playbook connect.yml --check --diff

Le diff doit remplacer les routes déconnectées 127.0.0.1:9 par les adresses et ports actuels. Appliquez normalement le playbook :

ansible-playbook connect.yml

Vous devez voir le changement du modèle et RUNNING HANDLER [Reload entry]. Revenez dans Event Site, utilisez Program et lisez les trois sessions actuelles : Paper and ink, Acoustic afternoon et Shared supper. Cliquez sur Download the schedule pour télécharger schedule.csv ; heures, sessions et lieux doivent correspondre au tableau. Suivez Visit jusqu’à Riverside Yard, puis Visitor guide. L’accueil et le guide doivent toujours fonctionner.

Le programme connecté doit afficher ces trois sessions, avec Download the schedule juste sous le tableau :

Programme actuel de Riverlight et téléchargement du planning

Revenez dans Controller. Vous pouvez aussi enregistrer et examiner le véritable téléchargement dans la VM. Avec curl, -f fait échouer les erreurs HTTP, -sS masque la progression mais affiche les erreurs, et -o indique le fichier de sortie :

curl -fsS http://127.0.0.1:8081/program/schedule.csv -o schedule.csv
cat schedule.csv

Contenu attendu :

time,session,place
10:30,Paper and ink,Making table
13:00,Acoustic afternoon,River stage
16:00,Shared supper,Long table

127.0.0.1 désigne ce contrôleur, où l’entrée écoute sur le port 8081. L’adresse publique du navigateur redirige vers le même service.

Relancez le même playbook :

ansible-playbook connect.yml

Le récapitulatif doit indiquer changed=0 et failed=0, sans exécuter le handler. C’est la convergence : la déclaration actuelle correspond déjà au fichier. Les véritables pages et le téléchargement établissent le résultat utilisable ; le récapitulatif seul ne suffit pas.

Protéger les routes fonctionnelles avant leur remplacement

Dans cette étape, vous ajouterez de vrais contrôles d’identité HTTP avant l’écriture des routes, puis rejetterez un service d’archive accessible tout en préservant le site fonctionnel.

Continuez dans Controller, dans /home/labex/project. HTTP 200 signifie que le serveur a répondu avec succès ; cela n’établit ni le type de service, ni l’événement, ni l’édition. Le programme et le lieu actuels s’identifient via /identity. Le fichier préparé group_vars/all.yml contient le site et les éditions approuvés :

cat group_vars/all.yml

Ajoutez un contrôle préalable, c’est-à-dire une vérification avant le changement. assert arrête le play si une condition est fausse. La première assertion exige exactement un membre par groupe de service. Chaque tâche uri effectue une véritable requête HTTP GET depuis le contrôleur. return_content: true conserve le corps ; une réponse JSON est aussi accessible via .json. register enregistre le résultat sous un nom de variable pour les tâches suivantes. Les assertions finales comparent les identités réelles aux valeurs approuvées.

Les tâches HTTP utilisent volontairement check_mode: false : ces requêtes en lecture seule doivent aussi s’exécuter pendant la prévisualisation. Sinon, une tâche uri peut être ignorée en mode de vérification. Cette option appartient uniquement aux requêtes de lecture ; elle n’autorise ni l’application d’un modèle ni le rechargement pendant la prévisualisation. Le délai de trois secondes évite qu’une source absente bloque longtemps l’exercice.

Remplacez le playbook par cette version complète avec contrôles. Conservez le modèle et placez toutes les assertions d’identité avant sa tâche :

cat > connect.yml <<'EOF'
- name: Connect the event services
  hosts: gateway
  gather_facts: false
  vars:
    program_host: "{{ groups['program'][0] }}"
    venue_host: "{{ groups['venue'][0] }}"
  tasks:
    - name: Require one member for each service
      ansible.builtin.assert:
        that:
          - groups['program'] | length == 1
          - groups['venue'] | length == 1
    - name: Read the selected program identity
      ansible.builtin.uri:
        url: "http://{{ hostvars[program_host].service_address }}:{{ hostvars[program_host].program_port }}/identity"
        return_content: true
        timeout: 3
      check_mode: false
      register: program_probe
    - name: Read the selected venue identity
      ansible.builtin.uri:
        url: "http://{{ hostvars[venue_host].service_address }}:{{ hostvars[venue_host].venue_port }}/identity"
        return_content: true
        timeout: 3
      check_mode: false
      register: venue_probe
    - name: Check the actual service identities
      ansible.builtin.assert:
        that:
          - program_probe.json.service == 'program'
          - program_probe.json.site == event_site
          - program_probe.json.edition == program_edition
          - venue_probe.json.service == 'venue'
          - venue_probe.json.site == event_site
          - venue_probe.json.edition == venue_edition
    - name: Write the inventory-derived routes
      ansible.builtin.template:
        src: templates/routes.json.j2
        dest: "{{ playbook_dir }}/entry/routes.json"
        mode: '0644'
      notify: Reload entry
  handlers:
    - name: Reload entry
      ansible.builtin.command:
        argv:
          - python3
          - /opt/labex/service-links/reload.py
          - "{{ playbook_dir }}/entry"
EOF
ansible-playbook connect.yml --syntax-check

Enregistrez maintenant une empreinte du fichier de routes fonctionnel. sha256sum calcule un hachage du contenu ; > conserve cette sortie dans un fichier séparé pour une comparaison ultérieure :

sha256sum entry/routes.json > routes-before.sha256

L’inventaire alternatif sélectionne une archive comme programme. Lisez-le, puis essayez-le volontairement avec -i, qui choisit l’inventaire pour cette commande uniquement. L’inventaire normal n’est pas modifié :

cat inventory-wrong-service.ini
ansible-playbook -i inventory-wrong-service.ini connect.yml

Cette commande doit échouer avec un code non nul et failed=1. L’archive est accessible et renvoie du JSON, mais son édition n’est pas approuvée. L’assertion doit échouer avant Write the inventory-derived routes ; le récapitulatif doit indiquer changed=0, sans handler. C’est différent d’un refus de connexion, où uri ne peut obtenir aucune réponse. Les deux cas doivent empêcher l’écriture.

Contrôlez l’empreinte sauvegardée. -c demande à sha256sum de comparer le fichier courant au hachage enregistré :

sha256sum -c routes-before.sha256

Attendez entry/routes.json: OK. Dans Event Site, ouvrez Program et téléchargez à nouveau le planning actuel. Une proposition rejetée doit laisser le programme utilisable, pas seulement laisser un fichier présent.

Revenez dans Controller et utilisez l’inventaire normal :

ansible-playbook connect.yml --check --diff
ansible-playbook connect.yml

Les deux identités choisies doivent être acceptées. Les routes déjà correctes n’ont pas besoin de changement : changed=0 est affiché et aucun handler ne s’exécute. Si une erreur d’indentation YAML apparaît, comparez le bloc complet, utilisez des espaces plutôt que des tabulations et réécrivez connect.yml. Une erreur de syntaxe n’est pas un rejet réussi par le contrôle préalable.

Votre périmètre est connect.yml, templates/routes.json.j2 et les routes d’entrée gérées par ce playbook. Conservez les inventaires fournis, données d’hôtes, éditions approuvées, requêtes curl, contenus des sources, notes d’organisation, accueil et guide. Pour recharger, utilisez /opt/labex/service-links/reload.py avec le répertoire d’entrée de ce projet. Ne figez pas les noms ou adresses actuels dans le modèle ou les requêtes, ne copiez pas les pages sources dans l’entrée, ne masquez pas les échecs, ne redémarrez pas les sources et ne modifiez pas la passerelle préparée. Les membres et ports configurés doivent rester la référence lorsque l’inventaire change.

Résumé

Vous avez relié de vrais services de programme et de lieu par des routes issues de l’inventaire, examiné le site et son téléchargement CSV exact, puis utilisé un handler pour recharger uniquement une configuration modifiée. Vous avez ensuite rejeté une source accessible mais non approuvée avant l’écriture des routes, préservant le site actuel. Le prochain laboratoire indépendant change les membres tout en conservant l’ancienne source et ses données.