Conecta las páginas del evento

AnsibleBeginner
Practicar Ahora

Introducción

La página principal de Riverlight Weekend está lista, pero los visitantes no pueden abrir el programa ni la página del recinto. Ambos servicios de origen ya funcionan. Usa Ansible para conectar la entrada a los miembros seleccionados del inventario, recargar solo cuando cambie la configuración y proteger las rutas funcionales frente a un sustituto inadecuado.

Necesitas navegación básica en terminal y práctica leyendo un inventario, variables y un playbook pequeños de Ansible. El laboratorio explica los roles HTTP, los grupos, las variables entre hosts, JSON, las consultas de solo lectura y los handlers antes de usarlos. Todo el software y los servicios están preparados. El tiempo es una estimación del autor que incluye lectura y correcciones habituales.

Conecta las páginas del programa y del recinto

En este paso, conectarás el sitio de un evento a sus orígenes preparados de programa y recinto, usando los miembros del inventario en lugar de direcciones fijas en una plantilla.

Riverlight Weekend tiene una página principal y una guía funcionales. Los enlaces del programa y del recinto muestran por ahora un mensaje de página no disponible. La entrada es un pequeño proxy inverso HTTP preparado: reenvía la solicitud a otro servicio y devuelve su respuesta real. No copia los datos del programa en la página principal. La entrada se ejecuta en el controlador; los dos nodos de origen son contenedores que comparten el kernel de esta VM de práctica. No son tres VM independientes. El software y los servicios ya están preparados; solo gestionarás las conexiones de la entrada.

Abre la pestaña Event Site. La página principal debe mostrar A little closer to the river. Pulsa Explore the program: This page is taking a break. es una respuesta HTTP 502 esperada porque la ruta aún no está conectada. Usa Back to the weekend en esa página y después Visitor guide en la navegación. Esta página ya funciona y debe seguir haciéndolo.

Cambia a Controller, que comienza en /home/labex/project. pwd muestra el directorio actual:

pwd

Si pierdes el directorio de trabajo, vuelve con cd /home/labex/project. Un nombre de archivo mal escrito causa “No such file or directory”; comprueba la escritura, usa ls templates para listar ese directorio si hace falta y vuelve a intentarlo. No necesitas reiniciar la VM.

cat muestra un archivo. Lee la selección aprobada, el inventario y los datos de cada host:

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

Los grupos [program] y [venue] seleccionan un origen cada uno. web1 proporciona el programa actual y web2 el recinto. Los archivos de host aportan su service_address real y sus puertos. Las direcciones pueden cambiar entre VM. Algunos nodos también tienen un servicio de archivo histórico; que responda no lo convierte en el programa actual aprobado.

El grupo [gateway] contiene entry. ansible_connection=local indica que Ansible gestiona la entrada en el controlador, sin un salto SSH. /usr/bin/python3 es el intérprete Python local preparado. Un puerto HTTP identifica un servicio que escucha en una dirección; un nodo puede ejecutar varios servicios en puertos diferentes.

Antes de cambiar la entrada, lee directamente cada origen seleccionado. Los archivos de configuración de curl contienen las URL reales. --config lee opciones de curl de un archivo; fail hace fallar los errores HTTP, silent oculta el medidor de progreso y show-error conserva mensajes útiles. Estos archivos no contienen contraseñas ni tokens.

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

Las respuestas JSON identifican program y venue, el sitio riverlight y sus ediciones. JSON es texto estructurado con campos nombrados. Una solicitud correcta demuestra que el origen responde directamente; todavía no prueba que funcionen las rutas del sitio.

Crea ahora la plantilla de rutas. groups de Ansible relaciona nombres de grupo con sus miembros; [0] elige el primer miembro del grupo que contiene uno solo. hostvars obtiene las variables de ese miembro. El playbook siguiente los llama program_host y venue_host. En las expresiones Jinja, ~ une valores como texto, incluidos puertos numéricos. | to_json genera una cadena JSON correctamente entrecomillada, evitando construir comillas manualmente de forma insegura.

El comando de shell usa > para reemplazar este único archivo. <<'EOF' entrega literalmente a cat las líneas siguientes; las comillas simples impiden que el shell interprete las llaves Jinja. Pega hasta el cierre EOF en su propia línea. Si el shell espera en un indicador de continuación por haber omitido ese delimitador, pulsa Ctrl+C y pega de nuevo el comando completo.

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

Escribe el playbook de la entrada. gather_facts: false evita recopilar datos de máquina innecesarios. vars define expresiones evaluadas con el inventario actual. template genera el archivo, establece el modo 0644 (el propietario puede escribir; todos pueden leer) y notifica al handler solo cuando cambia el archivo de rutas. Un handler es una tarea ejecutada tras recibir una notificación, normalmente al final del play.

La entrada conserva las rutas en memoria, así que reemplazar el archivo no basta. Su ayudante de recarga envía una señal SIGHUP real únicamente al proceso existente de esta entrada y espera su confirmación. El command del handler usa argv, una lista de argumentos separados. playbook_dir es el directorio del playbook y mantiene la ruta gestionada dentro de este proyecto. No necesitas sudo ni reiniciar un servicio.

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

Comprueba primero la estructura YAML y después previsualiza el cambio previsto. --syntax-check no aplica tareas. --check predice cambios compatibles y --diff muestra el contenido anterior y el propuesto. Esta vista previa no envía señales al gateway ni demuestra que el sitio final funcione.

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

El diff debe sustituir las rutas desconectadas 127.0.0.1:9 por las direcciones y puertos actuales. Aplica el playbook normalmente:

ansible-playbook connect.yml

Debes ver el cambio de plantilla y RUNNING HANDLER [Reload entry]. Regresa a Event Site, usa Program en la navegación y lee las tres sesiones actuales: Paper and ink, Acoustic afternoon y Shared supper. Pulsa Download the schedule para descargar schedule.csv; debe contener las mismas horas, sesiones y lugares de la tabla. Sigue Visit hasta Riverside Yard y después Visitor guide. La página principal y la guía deben seguir funcionando.

El programa conectado debe mostrar estas tres sesiones, con Download the schedule justo debajo de la tabla:

Programa actual de Riverlight y descarga del horario

Vuelve a Controller. También puedes guardar y examinar la descarga real dentro de la VM. En curl, -f hace fallar los errores HTTP, -sS oculta el progreso pero muestra errores y -o nombra el archivo de salida:

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

Contenido esperado:

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 significa este controlador, donde la entrada escucha en el puerto 8081. La dirección pública del navegador reenvía al mismo servicio.

Ejecuta el mismo playbook otra vez:

ansible-playbook connect.yml

El resumen debe indicar changed=0 y failed=0, sin ejecutar el handler. Esto es convergencia: la declaración actual ya coincide con el archivo. Las páginas y la descarga reales, junto con el resumen, establecen que el resultado es utilizable.

Protege las rutas funcionales antes de reemplazarlas

En este paso, añadirás comprobaciones reales de identidad HTTP antes de escribir rutas y rechazarás un servicio de archivo histórico accesible conservando el sitio funcional.

Continúa en Controller, dentro de /home/labex/project. HTTP 200 indica que el servidor respondió correctamente; no establece el tipo de servicio, el evento ni la edición. El programa y el recinto actuales se identifican mediante /identity. El archivo preparado group_vars/all.yml contiene el sitio y las ediciones aprobados:

cat group_vars/all.yml

Añade una comprobación previa, es decir, una revisión anterior al cambio. assert detiene el play si una condición es falsa. La primera aserción exige exactamente un miembro por grupo. Cada tarea uri realiza una solicitud HTTP GET real desde el controlador. return_content: true conserva el cuerpo; una respuesta JSON también está disponible mediante .json. register guarda el resultado bajo un nombre de variable para tareas posteriores. Las aserciones finales comparan las identidades reales con los valores aprobados.

Las tareas HTTP usan check_mode: false deliberadamente: estas solicitudes de solo lectura también deben ejecutarse durante la vista previa. De otro modo, una tarea uri puede omitirse en modo de comprobación. Esta opción pertenece únicamente a las consultas de solo lectura; no permite aplicar una plantilla ni recargar durante una vista previa. El límite de tres segundos evita que un origen ausente bloquee el ejercicio.

Reemplaza el playbook por esta versión completa con comprobaciones. Conserva la plantilla y coloca todas las aserciones de identidad antes de la tarea de plantilla:

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

Guarda una huella del archivo de rutas funcional. sha256sum calcula un hash de contenido; > guarda esa salida por separado para compararla después:

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

El inventario alternativo selecciona un archivo histórico como programa. Léelo y pruébalo deliberadamente con -i, que elige un inventario solo para este comando. El inventario normal no cambia:

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

Se espera que este comando falle con salida no nula y failed=1. El archivo histórico responde y devuelve JSON, pero su edición no está aprobada. La aserción debe fallar antes de Write the inventory-derived routes; el resumen debe mostrar changed=0 y no debe ejecutarse el handler. Es distinto de una conexión rechazada, en la que uri no puede obtener ninguna respuesta. Ambas situaciones deben impedir la escritura.

Comprueba la huella guardada. -c pide a sha256sum comparar el archivo actual con el hash registrado:

sha256sum -c routes-before.sha256

Espera entry/routes.json: OK. En Event Site, abre Program y vuelve a descargar el horario actual. Una propuesta rechazada debe dejar el programa utilizable, no solo conservar un archivo.

Regresa a Controller y usa el inventario normal:

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

Ambas identidades seleccionadas deben superar las comprobaciones. Las rutas ya correctas no necesitan cambios: el resumen indica changed=0 y el handler no se ejecuta. Si aparece un error de sangría YAML, compara el bloque completo, usa espacios en lugar de tabuladores y reescribe connect.yml; un error de sintaxis no demuestra el rechazo correcto de un origen.

Tu ámbito incluye connect.yml, templates/routes.json.j2 y las rutas gestionadas mediante ese playbook. Conserva inventarios, datos de hosts, ediciones aprobadas, solicitudes curl, contenido de los servicios, notas de organización, página principal y guía. Para recargar, usa /opt/labex/service-links/reload.py con el directorio de entrada de este proyecto. No fijes nombres o direcciones actuales en la plantilla ni en las consultas, no copies páginas de origen en la entrada, no ocultes fallos, no reinicies nodos de origen ni edites el gateway preparado. Los miembros y puertos configurados deben seguir determinando la conexión cuando cambie el inventario.

Resumen

Conectaste servicios reales de programa y recinto mediante rutas derivadas del inventario, examinaste el sitio y su descarga CSV exacta y usaste un handler para recargar únicamente la configuración modificada. Después rechazaste un origen accesible pero no aprobado antes de escribir las rutas, conservando el sitio actual. El siguiente laboratorio independiente cambia los miembros sin eliminar el origen anterior ni sus datos.