Actualiza ambos menús

AnsibleBeginner
Practicar Ahora

Introducción

Juniper & Oat necesita los mismos precios de bebidas aprobados en dos cafeterías, sin perder la identidad, el horario ni la especialidad de cada local. Utilizarás una plantilla y un playbook de Ansible para actualizar dos destinos reales administrados mediante SSH y después corregirás una desviación deliberada del menú.

Necesitas navegación básica en el terminal y práctica leyendo un inventario y un playbook pequeños de Ansible. Las variables de host, el renderizado JSON, la previsualización segura y la diferencia entre contenido administrado y local se explican al utilizarlos. Las herramientas y los sitios preparados te permiten centrarte en la automatización, no en la instalación.

Separa los precios compartidos de los detalles de cada local

En este paso, identificarás qué comparten las dos cafeterías y qué debe seguir siendo diferente, y declararás los datos aprobados para una plantilla reutilizable.

Juniper & Oat tiene dos cafeterías de barrio. Ambas utilizan las mismas bebidas y precios habituales, pero cada una tiene sus propios horarios, especialidad y aviso local. Debes actualizar el menú compartido sin sustituir esos detalles. Los hosts preparados web1 y web2 son contenedores administrados mediante SSH que comparten el núcleo de la VM de prácticas, no VM independientes. Controller ejecuta Ansible; cada destino ejecuta su propio servicio real de menú.

Abre Menu Preview, selecciona First branch y lee el menú, el horario y la especialidad. Usa el botón Atrás del navegador para volver a la lista y selecciona Second branch. Ambos muestran un precio antiguo de Flat white; Park Café también tiene un horario incorrecto. Las especialidades y los avisos locales ya son correctos. Visit abre la información de visita del mismo local; Download menu descarga su CSV real actual. Son enlaces de página, no pestañas de LabEx.

Cambia a la pestaña Controller. El terminal comienza en el directorio del proyecto; este comando explícito también te devuelve allí si te equivocas de directorio:

cd /home/labex/project

Los nombres web1 y web2 del inventario apuntan a destinos SSH preparados diferentes. Lee el inventario y las entradas aprobadas con cat, que muestra los archivos sin modificarlos:

cat inventory.ini
cat host_vars/web1.yml host_vars/web2.yml

Harbor Café debe abrir de 07:00–16:00 y Park Café de 08:00–18:00. El directorio host_vars proporciona variables al host del inventario cuyo nombre coincide. Conserva estas entradas y la configuración SSH preparada. La diferencia es intencionada, no un error que debas eliminar.

El menú compartido aprobado se proporciona como datos del escenario. Léelo antes de escribir las variables:

cat approved-menu.json

Incluye Espresso a 3.20, Flat white a 4.20 y Tea a 3.00. Un precio se almacena como cadena entre comillas para conservar sus dos decimales al formatearlo. menu_items será una lista YAML de objetos con nombre y precio compartida por ambos hosts.

Los directorios preparados group_vars y templates están vacíos. El archivo group_vars/all.yml proporciona variables a todos los hosts del inventario. El siguiente here-document escribe un archivo completo: > sustituye ese destino exacto y el delimitador YAML entre comillas impide que el shell expanda su contenido. El delimitador final debe aparecer solo al principio de una línea. Si escribes mal el contenido, repite todo el bloque; solo sustituirá tu archivo de variables.

cat > group_vars/all.yml <<'YAML'
menu_items:
  - name: Espresso
    price: "3.20"
  - name: Flat white
    price: "4.20"
  - name: Tea
    price: "3.00"
YAML

Una plantilla Jinja inserta valores resueltos en un archivo administrado. Las llaves dobles evalúan una expresión; la barra vertical aplica un filtro. Aquí, to_nice_json serializa el objeto completo como JSON válido y legible, incluidos los caracteres no ASCII. Evita añadir comillas manualmente a cada valor. Ambos locales utilizan la misma plantilla: branch_name y opening_hours proceden de sus entradas de host respectivas, mientras que menu_items es compartido.

cat > templates/menu.json.j2 <<'JINJA'
{{ {'branch': branch_name, 'hours': opening_hours, 'items': menu_items} | to_nice_json }}
JINJA

Lee las dos fuentes que acabas de escribir para detectar comillas ausentes, sangría incorrecta o delimitadores erróneos antes de ejecutar Ansible:

cat group_vars/all.yml templates/menu.json.j2

El sitio todavía no ha cambiado. Has declarado los datos deseados, pero no los has aplicado. En el siguiente paso, Ansible renderizará esta fuente en el contexto de variables de cada host.

Aplica un playbook a las dos cafeterías

En este paso, previsualizarás y desplegarás la misma declaración en ambos destinos SSH reales y utilizarás sus menús y descargas reales.

Permanece en Controller, en /home/labex/project. Un play selecciona hosts; las tareas declaran el estado administrado. become: true solicita la elevación de privilegios autorizada del destino para que los archivos puedan pertenecer a root. No cambia la cuenta de acceso de LabEx. El módulo file declara el directorio; template renderiza la fuente compartida y sustituye únicamente menu.json. La propiedad explícita y los permisos entre comillas hacen predecibles el acceso al directorio y la lectura pública: 0755 para el directorio y 0644 para el menú.

Los archivos locales local-special.txt, local-notice.txt y el privado staff-notes.txt quedan fuera de tu declaración de menú. No sustituyas el contenido del directorio ni modifiques esos archivos. Conserva sus bytes, su propiedad de root y sus permisos originales: 0644 para la especialidad y el aviso, y 0600 para las notas privadas. El servicio lee menu.json en cada petición, por lo que una actualización de datos no necesita un reinicio ni un handler artificial.

Escribe un playbook completo. Los elementos de listas YAML utilizan - y los espacios anidan los argumentos de cada módulo. Las rutas de src se refieren a fuentes del controlador; dest está en cada destino administrado.

cat > menus.yml <<'YAML'
- name: Keep both branch menus current
  hosts: all
  gather_facts: false
  become: true
  tasks:
    - name: Keep the menu directory available
      ansible.builtin.file:
        path: /srv/branch-menu
        state: directory
        owner: root
        group: root
        mode: "0755"

    - name: Render the shared menu with each branch's inputs
      ansible.builtin.template:
        src: templates/menu.json.j2
        dest: /srv/branch-menu/menu.json
        owner: root
        group: root
        mode: "0644"
YAML

Primero utiliza --syntax-check para validar la sintaxis del playbook sin aplicarlo:

ansible-playbook menus.yml --syntax-check

Si aparece un error YAML, lee el archivo y la línea indicados. Compara la sangría con el bloque completo anterior, vuelve a escribir ese bloque y repite la comprobación. Un error de sintaxis de Ansible no requiere reiniciar la VM.

--check predice los cambios de módulos compatibles; --diff muestra el contenido propuesto antes y después. Es útil para estos archivos sin secretos, pero una previsualización no es una prueba del servicio real. Ejecuta ambas opciones juntas:

ansible-playbook menus.yml --check --diff

Ambos hosts deben predecir un cambio de menú. El diff debe corregir los precios y el horario de Park Café manteniendo distintas las identidades. Ningún archivo del destino ha cambiado. Pasa a Menu Preview, abre o actualiza los locales y confirma que aún aparecen los valores antiguos. Regresa a Controller para aplicar la misma declaración sin opciones de previsualización:

ansible-playbook menus.yml

El resumen de cada host no debe mostrar tareas fallidas ni destinos inaccesibles. Los números exactos de changed pueden diferir porque cada host necesitaba correcciones distintas. Lee los datos reales mediante un comando ad hoc: all selecciona ambos hosts del inventario, -m indica el módulo y -a proporciona sus argumentos. El módulo command ejecuta cat en cada destino, no en el controlador.

ansible all -m ansible.builtin.command -a 'cat /srv/branch-menu/menu.json'

Ambos deben contener las bebidas y precios habituales aprobados. Harbor Café y Park Café deben mantener sus respectivos nombres y horarios.

Ahora cambia a Menu Preview y actualiza cada local. Lee los tres precios, el nombre, el horario, la especialidad y el aviso. Abre Visit y vuelve mediante Menu. Selecciona Download menu y abre el CSV: debe incluir los tres productos aprobados de ese local y su propio nombre en cada fila. Que la página inicial funcione no basta.

Harbor Café muestra los precios compartidos aprobados junto a su horario y especialidad local.

Compara los precios compartidos de la izquierda con la especialidad local de la derecha. Park Café mantiene su horario y especialidad mientras utiliza la misma lista de bebidas aprobada.

Si el navegador muestra un error de menú ausente o no válido, vuelve a Controller, lee la salida y compara tu plantilla JSON con el paso 1. Corrige la fuente del controlador y ejecuta de nuevo el playbook. Si un destino es inaccesible, lee inventory.ini y compáralo con la salida original; no desactives la comprobación de confianza SSH ni cambies cuentas de la plataforma.

Vuelve a Controller. Una repetición sin modificar las entradas no debería tener cambios pendientes:

ansible-playbook menus.yml

Busca las dos filas del resumen:

web1 ... changed=0 ... unreachable=0 ... failed=0 ...
web2 ... changed=0 ... unreachable=0 ... failed=0 ...

Esto es configuración idempotente: los archivos deseados ya coinciden y Ansible no los reescribe. No significa que dejen de producirse peticiones normales o registros del servicio.

Corrige la desviación sin borrar contenido local

En este paso, alterarás deliberadamente un valor del menú administrado y lo restaurarás desde la fuente sin modificar del controlador, conservando el contenido local.

Permanece en Controller. Una desviación de configuración ocurre cuando el estado administrado real deja de coincidir con la intención declarada. Los distintos horarios aprobados no son una desviación; un precio compartido modificado manualmente sí lo es.

Lo siguiente es un fallo deliberado y limitado a web1. -b solicita become para esta tarea ad hoc. content de copy sustituye exactamente el JSON del menú indicado, no su directorio. Mantiene la estructura correcta pero asigna a Espresso el precio no aprobado de 0.01. Este archivo temporal es incorrecto a propósito; no copies su precio a group_vars.

ansible web1 -b -m ansible.builtin.copy -a 'dest=/srv/branch-menu/menu.json content={"branch":"Harbor Café","hours":"07:00–16:00","items":[{"name":"Espresso","price":"0.01"},{"name":"Flat white","price":"4.20"},{"name":"Tea","price":"3.00"}]} owner=root group=root mode=0644'

Cambia a Menu Preview, actualiza First branch y observa el precio incorrecto de Espresso. El segundo local y ambas especialidades deben seguir intactos. Es un cambio real en un archivo del destino, no una luz roja simulada.

Regresa a Controller. No edites las fuentes originales. Previsualiza el estado deseado existente:

ansible-playbook menus.yml --check --diff

Solo web1 debe predecir un cambio. Web2 ya coincide con su estado aprobado. Aplica el mismo playbook para restaurar el menú administrado:

ansible-playbook menus.yml

Pasa a Menu Preview y actualiza ambos locales. Espresso debe volver a costar 3.20. Las especialidades, avisos, horarios y descargas de ambos deben seguir siendo correctos. Tu automatización administra un archivo de configuración, no todos los archivos locales del directorio.

Vuelve a Controller y realiza una última repetición:

ansible-playbook menus.yml

Ambos resúmenes deben volver a mostrar changed=0, unreachable=0 y failed=0. La reparación procede de una intención reutilizable en los datos del controlador y una plantilla compartida, no de corregir manualmente el destino una vez. La misma plantilla debe seguir siendo útil cuando cambie un producto compartido aprobado.

Resumen

Separaste los precios compartidos, las entradas de cada cafetería y el contenido local; previsualizaste y aplicaste una plantilla a dos destinos SSH; utilizaste páginas reales y descargas CSV; y corregiste una desviación real sin borrar diferencias legítimas entre locales. La repetición sin cambios confirmó que los menús declarados habían convergido.