diff --git a/exercises/ansible_rhel/1.1-setup/README.es.md b/exercises/ansible_rhel/1.1-setup/README.es.md index 5d3db94c4..04fcae9a3 100644 --- a/exercises/ansible_rhel/1.1-setup/README.es.md +++ b/exercises/ansible_rhel/1.1-setup/README.es.md @@ -1,98 +1,149 @@ -# Workshop Ejercicio - Validación de los pre-requisitos +# Ejercicio del Taller - Verificar los Prerrequisitos -**Leer esto en otros idiomas**: -
![uk](../../../images/uk.png) [English](README.md), ![japan](../../../images/japan.png)[日本語](README.ja.md), ![brazil](../../../images/brazil.png) [Portugues do Brasil](README.pt-br.md), ![france](../../../images/fr.png) [Française](README.fr.md),![Español](../../../images/col.png) [Español](README.es.md). +**Lee esto en otros idiomas**: +
![uk](../../../images/uk.png) [Inglés](README.md), ![japan](../../../images/japan.png)[日本語](README.ja.md), ![brazil](../../../images/brazil.png) [Português do Brasil](README.pt-br.md), ![france](../../../images/fr.png) [Francés](README.fr.md),![Español](../../../images/col.png) [Español](README.es.md). -## Tabla de contenidos +## Tabla de Contenidos -* [Objetivos](#Objetivos) -* [Guía](#Guía) -* [Su entorno de laboratorio](#Su-entorno-de-laboratorio) -* [Paso 1 - Acceso al entorno](#Paso-1---Acceso-al-entorno) -* [Paso 2 - Trabajar los laboratorios](#Paso-2---Trabajar-los-laboratorios) -* [Paso 3 - Laboratorios de desafío](#Paso-3---Laboratorios-de-desafío) +- [Ejercicio del Taller - Verificar los Prerrequisitos](#ejercicio-del-taller---verificar-los-prerrequisitos) + - [Tabla de Contenidos](#tabla-de-contenidos) + - [Objetivo](#objetivo) + - [Guía](#guía) + - [Tu Entorno de Laboratorio](#tu-entorno-de-laboratorio) + - [Paso 1 - Acceder al Entorno](#paso-1---acceder-al-entorno) + - [Paso 2 - Usando la Terminal](#paso-2---usando-la-terminal) + - [Paso 3 - Examinar los Entornos de Ejecución](#paso-3---examinar-los-entornos-de-ejecución) + - [Paso 4 - Examinar la configuración de ansible-navigator](#paso-4---examinar-la-configuración-de-ansible-navigator) + - [Paso 5 - Labs de Desafío](#paso-5---labs-de-desafío) -# Objetivos +## Objetivos -- Comprender la topología de laboratorio y cómo acceder al entorno. -- Comprender cómo trabajar los ejercicios del taller -- Comprender los laboratorios de desafío +* Entender la Topología del Laboratorio: Familiarízate con el entorno de laboratorio y los métodos de acceso. +* Dominar los Ejercicios del Taller: Adquiere competencia en la navegación y ejecución de las tareas del taller. +* Resolver los desafíos del taller: Aprende a aplicar tus conocimientos en escenarios prácticos -# Guía +## Guía -## Su entorno de laboratorio +La fase inicial de este taller se centra en las utilidades de línea de comandos de Ansible Automation Platform, como: -En este laboratorio se trabaja en un entorno de laboratorio preconfigurado. Tendrá acceso a los siguientes hosts: -| Role | Inventory name | -| ---------------------| ---------------| -| Ansible Control Host | ansible | -| Managed Host 1 | node1 | -| Managed Host 2 | node2 | -| Managed Host 3 | node3 | +- [ansible-navigator](https://github.com/ansible/ansible-navigator) - una Interfaz de Usuario basada en Texto (TUI) para ejecutar y desarrollar contenido de Ansible. +- [ansible-core](https://docs.ansible.com/core.html) - el ejecutable base que proporciona el marco, lenguaje y funciones que sustentan Ansible Automation Platform, incluyendo herramientas de línea de comandos como `ansible`, `ansible-playbook` y `ansible-doc`. +- [Entornos de Ejecución](https://docs.ansible.com/automation-controller/latest/html/userguide/execution_environments.html) - Imágenes de contenedor pre-construidas con colecciones soportadas por Red Hat. +- [ansible-builder](https://github.com/ansible/ansible-builder) - automatiza el proceso de construcción de Entornos de Ejecución. No es un enfoque principal en este taller. -## Paso 1 - Acceso al entorno +Si necesitas más información sobre los nuevos componentes de la Plataforma de Automatización Ansible, guarda esta página principal [https://red.ht/AAP-20](https://red.ht/AAP-20) -Inicie sesión en el host de control a través de SSH: -> **Advertencia** -> -> Reemplace **11.22.33.44** por la **IP** que se le proporciona, y la **X** por student**X** con el número de estudiante que se le proporcionó. +### Tu Entorno de Laboratorio - ssh studentX@11.22.33.44 +Trabajarás en un entorno pre-configurado con los siguientes hosts: -> **Consejo** -> -> La contraseña sera proporcionada por el instructor -Para pasarse a usuario root: +| Rol | Nombre en el inventario | +| ---------------------| -----------------------| +| Host de Control Ansible | ansible-1 | +| Host Gestionado 1 | node1 | +| Host Gestionado 2 | node2 | +| Host Gestionado 3 | node3 | - [student@ansible ~]$ sudo -i +### Paso 1 - Acceder al Entorno -La mayoría de las tareas de requisitos previos ya se han realizado por usted: +Recomendamos usar Visual Studio Code para este taller por su navegador de archivos integrado, editor con resaltado de sintaxis y terminal en el navegador. El acceso directo SSH también está disponible. Consulta este tutorial de YouTube sobre cómo acceder a tu entorno de trabajo. - - Se instala el software Ansible +NOTA: Se proporciona un breve video de YouTube si necesitas claridad adicional: +[Ansible Workshops - Acceder a tu entorno de trabajo](https://youtu.be/Y_Gx4ZBfcuk) - - Conexión SSH y las claves están configuradas - - `sudo` se ha configurado en los hosts administrados para ejecutar comandos que requieren privilegios de root. +1. Conéctate a Visual Studio Code a través de la página de lanzamiento del taller. + ![página de lanzamiento](images/launch_page.png) -Compruebe que Ansible se ha instalado correctamente +2. Ingresa la contraseña proporcionada para iniciar sesión. - [root@ansible ~]# ansible --version - ansible 2.7.0 - [...] + ![inicio de sesión en vs code](images/vscode_login.png) -> **Nota** -> -> Ansible mantiene la administración de la configuración simple. Ansible no requiere base de datos ni demonios en ejecución y puede ejecutarse fácilmente en un portátil. En los hosts administrados no necesita ningún agente en ejecución. -Cierre la sesión de la cuenta root de nuevo: +### Paso 2 - Usando la Terminal - [root@ansible ~]# exit - logout +1. Abre una terminal en Visual Studio Code: -> **Nota** -> ->En todos los ejercicios posteriores, debe trabajar como el usuario student\ en el nodo de control si no se le indica explícitamente de forma diferente. + ![imagen de nueva terminal](images/vscode-new-terminal.png) -## Paso 2 - Trabajar los laboratorios +2. Navega al directorio `rhel-workshop` en la terminal del nodo de control de Ansible. -Es posible que ya haya adivinado que este laboratorio está bastante centrado en la línea de comandos... :-) +```bash +[student@ansible-1 ~]$ cd ~/rhel-workshop/ +[student@ansible-1 rhel-workshop]$ pwd +/home/student/rhel-workshop +``` - - No escriba todo manualmente, utilice copiar y pegar desde el navegador cuando sea apropiado. Pero detente a pensar y entender. +* `~`: atajo para el directorio home `/home/student` +* `cd`: comando para cambiar de directorio +* `pwd`: imprime la ruta completa del directorio de trabajo actual. - - Todos los laboratorios fueron preparados usando **Vim**, pero entendemos que no a todo el mundo le encanta. Siéntase libre de usar editores alternativos. En el entorno de laboratorio que proporcionamos **Midnight Commander** (simplemente ejecute **mc**, se puede acceder a las teclas de función a través de Esc-\, y simplemente haga clic con el ratón) o **Nano** (ejecutar **nano**). Aquí hay un breve [introducción del editor](.. /0.0-support-docs/editor_intro.md). +### Paso 3 - Examinar los Entornos de Ejecución +1. Ejecuta `ansible-navigator images` para ver los Entornos de Ejecución configurados. +2. Usa el número correspondiente para investigar un EE, por ejemplo, presionando 2 para abrir `ee-supported-rhel8` -> **Consejo** -> -> En los comandos de la guía de laboratorio que se supone que debe ejecutar se muestran con o sin la salida esperada, lo que tenga más sentido en el contexto. +```bash +$ ansible-navigator images +``` -## Paso 3 - Laboratorios de desafío +![ansible-navigator images](images/navigator-images.png) + + +> Nota: La salida que veas puede diferir de la salida anterior + + +![menú principal ee](images/navigator-ee-menu.png) + +Seleccionar `2` para `Versión de Ansible y colecciones` nos mostrará todas las Colecciones de Ansible instaladas en ese EE particular, y la versión de `ansible-core`: + +![información ee](images/navigator-ee-collections.png) + +### Paso 4 - Examinar la configuración de ansible-navigator + +1. Visualiza el contenido de `~/.ansible-navigator.yml` usando Visual Studio Code o el comando `cat`. + +```bash +$ cat ~/.ansible-navigator.yml +--- +ansible-navigator: + ansible: + inventory: + entries: + - /home/student/lab_inventory/hosts + + execution-environment: + image: registry.redhat.io/ansible-automation-platform-20-early-access/ee-supported-rhel8:2.0.0 + enabled: true + container-engine: podman + pull: + policy: missing + volume-mounts: + - src: "/etc/ansible/" + dest: "/etc/ansible/" +``` + +2. Observa los siguientes parámetros dentro del archivo `ansible-navigator.yml`: + +* `inventories`: muestra la ubicación del inventario de ansible que se está utilizando +* `execution-environment`: donde se establece el entorno de ejecución predeterminado + +Para una lista completa de cada configuración configurable consulta la [documentación](https://ansible.readthedocs.io/projects/navigator/settings/) + +<<<<<<< HEAD +### Paso 5 - Desafíos del taller + +Cada capítulo del taller viene con un desafío. Estas tareas prueban tu comprensión y aplicación de los conceptos aprendidos. Las soluciones se proporcionan bajo un signo de advertencia para referencia. +======= +### Paso 5 - Labs de Desafío + +Cada capítulo viene con un Lab de Desafío. Estas tareas prueban tu comprensión y aplicación de los conceptos aprendidos. Las soluciones se proporcionan bajo un signo de advertencia para referencia. +>>>>>>> daf03aad826095b4ee06f20aa28c409189bb47b9 -Pronto descubrirá que muchos capítulos de esta guía de laboratorio vienen con una sección de "Laboratorio de desafío". Estos laboratorios están destinados a darle una pequeña tarea para resolver utilizando lo que ha aprendido hasta ahora. La solución de la tarea se muestra debajo de un signo de advertencia. ---- **Navegación** diff --git a/exercises/ansible_rhel/1.3-playbook/README.md b/exercises/ansible_rhel/1.3-playbook/README.md index cf3479a50..caa931353 100644 --- a/exercises/ansible_rhel/1.3-playbook/README.md +++ b/exercises/ansible_rhel/1.3-playbook/README.md @@ -6,488 +6,112 @@ ## Table of Contents - [Workshop Exercise - Writing Your First Playbook](#workshop-exercise---writing-your-first-playbook) - - [Table of Contents](#table-of-contents) - [Objective](#objective) - [Guide](#guide) - [Step 1 - Playbook Basics](#step-1---playbook-basics) - - [Step 2 - Creating a Directory Structure and File for your Playbook](#step-2---creating-a-directory-structure-and-file-for-your-playbook) + - [Step 2 - Creating Your Playbook](#step-2---creating-your-playbook) - [Step 3 - Running the Playbook](#step-3---running-the-playbook) - - [Step 4 - Extend your Playbook: Start \& Enable Apache](#step-4---extend-your-playbook-start--enable-apache) - - [Step 5 - Extend your Playbook: Create an web.html](#step-5---extend-your-playbook-create-an-webhtml) - - [Step 6 - Practice: Apply to Multiple Host](#step-6---practice-apply-to-multiple-host) + - [Step 4 - Checking the Playbook](#step-4---checking-the-playbook) -## Objective -This exercise covers using Ansible to build two Apache web servers on Red Hat Enterprise Linux. This exercise covers the following Ansible fundamentals: +## Objective -* Understanding Ansible module parameters -* Understanding and using the following modules - * [dnf module](https://docs.ansible.com/ansible/latest/modules/dnf_module.html) - * [service module](https://docs.ansible.com/ansible/latest/modules/service_module.html) - * [copy module](https://docs.ansible.com/ansible/latest/modules/copy_module.html) -* Understanding [Idempotence](https://en.wikipedia.org/wiki/Idempotence) and how Ansible modules can be idempotent +In this exercise, you'll use Ansible to conduct basic system setup tasks on a +Red Hat Enterprise Linux server. You will become familiar with fundamental +Ansible modules like `dnf` and `user`, and learn how to create and run +playbooks. ## Guide -Playbooks are files which describe the desired configurations or steps to implement on managed hosts. Playbooks can change lengthy, complex administrative tasks into easily repeatable routines with predictable and successful outcomes. - -A playbook can have multiple plays and a play can have one or multiple tasks. In a task a *module* is called, like the modules in the previous chapter. The goal of a *play* is to map a group of hosts. The goal of a *task* is to implement modules against those hosts. - -> **Tip** -> -> Here is a nice analogy: When Ansible modules are the tools in your workshop, the inventory is the materials and the Playbooks are the instructions. +Playbooks in Ansible are essentially scripts written in YAML format. They are +used to define the tasks and configurations that Ansible will apply to your +servers. ### Step 1 - Playbook Basics +First, create a text file in YAML format for your playbook. Remember: +- Start with three dashes (`---`). +- Use spaces, not tabs, for indentation. -Playbooks are text files written in YAML format and therefore need: - -* to start with three dashes (`---`) - -* proper indentation using spaces and **not** tabs\! - -There are some important concepts: - -* **hosts**: the managed hosts to perform the tasks on - -* **tasks**: the operations to be performed by invoking Ansible modules and passing them the necessary options - -* **become**: privilege escalation in playbooks - -> **Warning** -> -> The ordering of the contents within a Playbook is important, because Ansible executes plays and tasks in the order they are presented. - -A Playbook should be **idempotent**, so if a Playbook is run once to put the hosts in the correct state, it should be safe to run it a second time and it should make no further changes to the hosts. +Key Concepts: +- `hosts`: Specifies the target servers or devices for your playbook to run against. +- `tasks`: The actions Ansible will perform. +- `become`: Allows privilege escalation (running tasks with elevated privileges). -> **Tip** -> -> Most Ansible modules are idempotent, so it is relatively easy to ensure this is true. +> NOTE: An Ansible playbook is designed to be idempotent, meaning if you run it multiple times on the same hosts, it ensures the desired state without making redundant changes. -### Step 2 - Creating a Directory Structure and File for your Playbook - -Enough theory, it’s time to create your first Ansible playbook. In this lab you create a playbook to set up an Apache web server in three steps: - -1. Install httpd package -2. Enable/start httpd service -3. Copy over an web.html file to each web host - -This Playbook makes sure the package containing the Apache web server is installed on `node1`. - -There is a [best practice](https://docs.ansible.com/ansible/latest/user_guide/playbooks_best_practices.html) on the preferred directory structures for playbooks. We strongly encourage you to read and understand these practices as you develop your Ansible ninja skills. That said, our playbook today is very basic and creating a complex structure will just confuse things. - -Instead, we are going to create a very simple directory structure for our playbook, and add just a couple of files to it. - -On your control host **ansible**, create a directory called `ansible-files` in your home directory and change directories into it: +### Step 2 - Creating Your Playbook +Before creating your first playbook, ensure you are in the correct directory by changing to `~/lab_inventory`: ```bash -[student@ansible-1 ~]$ mkdir ansible-files -[student@ansible-1 ~]$ cd ansible-files/ +cd ~/lab_inventory ``` -Add a file called `apache.yml` with the following content. As discussed in the previous exercises, use `vi`/`vim` or, if you are new to editors on the command line, check out the [editor intro](../0.0-support-docs/editor_intro.md) again. - -```yaml ---- -- name: Apache server installed - hosts: node1 - become: yes -``` +Now create a playbook named `system_setup.yml` to perform basic system setup: +- Update all security related packages. +- Create a new user named ‘myuser’. -This shows one of Ansible’s strengths: The Playbook syntax is easy to read and understand. In this Playbook: - -* A name is given for the play via `name:`. -* The host to run the playbook against is defined via `hosts:`. -* We enable user privilege escalation with `become:`. - -> **Tip** -> -> You obviously need to use privilege escalation to install a package or run any other task that requires root permissions. This is done in the Playbook by `become: yes`. - -Now that we've defined the play, let's add a task to get something done. We will add a task in which dnf will ensure that the Apache package is installed in the latest version. Modify the file so that it looks like the following listing: +The basic structure looks as follows: ```yaml --- -- name: Apache server installed +- name: Basic System Setup hosts: node1 - become: yes + become: true tasks: - - - name: Install Apache + - name: Update all security-related packages ansible.builtin.dnf: - name: httpd + name: '*' + state: latest + security: true + + - name: Create a new user + ansible.builtin.user: + name: myuser + state: present + create_home: true ``` -> **Tip** -> -> Since playbooks are written in YAML, alignment of the lines and keywords is crucial. Make sure to vertically align the *t* in `task` with the *b* in `become`. Once you are more familiar with Ansible, make sure to take some time and study a bit the [YAML Syntax](https://docs.ansible.com/ansible/latest/reference_appendices/YAMLSyntax.html). - -In the added lines: +> NOTE: Updating the packages may take a few minutes prior to the Ansible playbook completing. -* We started the tasks part with the keyword `tasks:`. -* A task is named and the module for the task is referenced. Here it uses the `dnf` module. -* Parameters for the module are added: - * `name:` to identify the package name - * `state:` to define the wanted state of the package +* About the `dnf` module: This module is used for package management with DNF (Dandified YUM) on RHEL and other Fedora-based systems. -> **Tip** -> -> The module parameters are individual to each module. If in doubt, look them up again with `ansible-doc`. - -Save your playbook and exit your editor. +* About the `user` module: This module is used to manage user accounts. ### Step 3 - Running the Playbook -With the introduction of Ansible Automation Platform 2, several new key components are being introduced as a part of the overall developer experience. Execution environments have been introduced to provide predictable environments to be used during automation runtime. All collection dependencies are contained within the execution environment to ensure that automation created in development environments runs the same as in production environments. - -What do you find within an execution environment? - -* RHEL UBI 8 -* Ansible 2.9 or Ansible Core 2.11 -* Python 3.8 -* Any content Collections -* Collection python or binary dependencies. - -Why use execution environments? - -They provide a standardized way to define, build and distribute the environments that the automation runs in. In a nutshell, Automation execution environments are container images that allow for easier administration of Ansible by the platform administrator. - -Considering the shift towards containerized execution of automation, automation development workflow and tooling that existed before Ansible Automation Platform 2 have had to be reimagined. In short, `ansible-navigator` replaces `ansible-playbook` and other `ansible-*` command line utilities. - -With this change, Ansible playbooks are executed using the `ansible-navigator` command on the control node. - -The prerequisites and best practices for using `ansible-navigator` have been done for you within this lab. - -These include: -* Installing the `ansible-navigator` package -* Creating a default settings `/home/student/.ansible-navigator.yml` for all your projects (optional) -* All execution environment (EE) logs are stored within `/home/student/.ansible-navigator/logs/ansible-navigator.log` -* Playbook artifacts are saved under `/tmp/artifact.json` - -For more information on the [Ansible navigator settings](https://github.com/ansible/ansible-navigator/blob/main/docs/settings.rst) - -> **Tip** -> -> The parameters for ansible-navigator maybe modified for your specific environment. The current settings use a default `ansible-navigator.yml` for all projects, but a specific `ansible-navigator.yml` can be created for each project and is the recommended practice. - -To run your playbook, use the `ansible-navigator run ` command as follows: +Execute your playbook using the `ansible-navigator` command: ```bash -[student@ansible-1 ansible-files]$ ansible-navigator run apache.yml +[student@ansible-1 lab_inventory]$ ansible-navigator run system_setup.yml -m stdout ``` -> **Tip** -> -> The existing `ansible-navigator.yml` file provides the location of your inventory file. If this was not set within your `ansible-navigator.yml` file, the command to run the playbook would be: `ansible-navigator run apache.yml -i /home/student/lab_inventory/hosts` - -When running the playbook, you'll be displayed a text user interface (TUI) that displays the play name among other information about the playbook that is currently run. - -```bash - PLAY NAME OK CHANGED UNREACHABLE FAILED SKIPPED IGNORED IN PROGRESS TASK COUNT PROGRESS -0│Apache server installed 2 1 0 0 0 0 0 2 COMPLETE -``` +Review the output to ensure each task is completed successfully. -If you notice, prior to the play name `Apache server installed`, you'll see a `0`. By pressing the `0` key on your keyboard, you will be provided a new window view displaying the different tasks that ran for the playbook completion. In this example, those tasks included the "Gathering Facts" and "Install Apache". The "Gathering Facts" is a built-in task that runs automatically at the beginning of each play. It collects information about the managed nodes. Exercises later on will cover this in more detail. The "Install Apache" was the task created within the `apache.yml` file that installed `httpd`. +### Step 4 - Checking the Playbook +Now, let’s create a second playbook for post-configuration checks, named `system_checks.yml`: -The display should look something like this: - -```bash - RESULT HOST NUMBER CHANGED TASK TASK ACTION DURATION -0│OK node1 0 False Gathering Facts gather_facts 1s -1│OK node1 1 True Install Apache dnf 4s -``` - -Taking a closer look, you'll notice that each task is associated with a number. Task 1, "Install Apache", had a change and used the `dnf` module. In this case, the change is the installation of Apache (`httpd` package) on the host `node1`. - -By pressing `0` or `1` on your keyboard, you can see further details of the task being run. If a more traditional output view is desired, type `:st` within the text user interface. - -Once you've completed, reviewing your Ansible playbook, you can exit out of the TUI via the Esc key on your keyboard. - -> **Tip** -> -> The Esc key only takes you back to the previous screen. Once at the main overview screen an additional Esc key will take you back to the terminal window. - - -Once the playbook has completed, connect to `node1` via SSH to make sure Apache has been installed: - -```bash -[student@ansible-1 ansible-files]$ ssh node1 -Last login: Wed May 15 14:03:45 2019 from 44.55.66.77 -Managed by Ansible -``` - -Use the command `rpm -qi httpd` to verify httpd is installed: - -```bash -[ec2-user@node1 ~]$ rpm -qi httpd -Name : httpd -Version : 2.4.37 -[...] -``` - -Log out of `node1` with the command `exit` so that you are back on the control host and verify the installed package with an Ansible playbook labeled `package.yml` - -{% raw %} ```yaml --- -- name: Check packages +- name: System Configuration Checks hosts: node1 become: true - vars: - package: "httpd" - tasks: - - name: Gather the package facts - ansible.builtin.package_facts: - manager: auto - - - name: Check whether a {{ package }} is installed + - name: Check user existence + ansible.builtin.command: + cmd: id myuser + register: user_check + + - name: Report user status ansible.builtin.debug: - msg: "{{ package }} {{ ansible_facts.packages[ package ][0].version }} is installed!" - when: "package in ansible_facts.packages" - -``` -{% endraw %} - - -```bash -[student@ansible-1 ~]$ ansible-navigator run package.yml -m stdout -``` - -```bash - -PLAY [Check packages] ********************************************************** - -TASK [Gathering Facts] ********************************************************* -ok: [ansible] - -TASK [Gather the package facts] ************************************************ -ok: [ansible] - -TASK [Check whether a httpd is installed] ************************************* -ok: [ansible] => { - "msg": "httpd 2.4.37 is installed!" -} - -PLAY RECAP ********************************************************************* -ansible : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 -``` - -Run the the `ansible-navigator run apache.yml` playbook for a second time, and compare the output. The output "CHANGED" now shows `0` instead of `1` and the color changed from yellow to green. This makes it easier to spot when changes have occured when running the Ansible playbook. - -### Step 4 - Extend your Playbook: Start & Enable Apache - -The next part of the Ansible playbook makes sure the Apache application is enabled and started on `node1`. - -On the control host, as your student user, edit the file `~/ansible-files/apache.yml` to add a second task using the `service` module. The Playbook should now look like this: - -```yaml ---- -- name: Apache server installed - hosts: node1 - become: true - tasks: - - - name: Install Apache - ansible.builtin.dnf: - name: httpd - - - name: Apache enabled and running - ansible.builtin.service: - name: httpd - enabled: true - state: started + msg: "User 'myuser' exists." + when: user_check.rc == 0 ``` -What exactly did we do? - -* a second task named "Apache enabled and running" is created -* a module is specified (`service`) -* The module `service` takes the name of the service (`httpd`), if it should be permanently set (`enabled`), and its current state (`started`) - - -Thus with the second task we make sure the Apache server is indeed running on the target machine. Run your extended Playbook: +Run the checks playbook: ```bash -[student@ansible-1 ~]$ ansible-navigator run apache.yml -``` - -Notice in the output, we see the play had `1` "CHANGED" shown in yellow and if we press `0` to enter the play output, you can see that task 2, "Apache enabled and running", was the task that incorporated the latest change by the "CHANGED" value being set to True and highlighted in yellow. - - -* Run the playbook a second time using `ansible-navigator` to get used to the change in the output. - -* Use an Ansible playbook labeled service_state.yml to make sure the Apache (httpd) service is running on `node1`, e.g. with: `systemctl status httpd`. - -{% raw %} -```yaml ---- -- name: Check Status - hosts: node1 - become: true - vars: - package: "httpd" - - tasks: - - name: Check status of {{ package }} service - ansible.builtin.service_facts: - register: service_state - - - ansible.builtin.debug: - var: service_state.ansible_facts.services["{{ package }}.service"].state -``` - -```bash -{% endraw %} - -[student@ansible-1 ~]$ ansible-navigator run service_state.yml +[student@ansible-1 lab_inventory]$ ansible-navigator run system_checks.yml -m stdout ``` -### Step 5 - Extend your Playbook: Create an web.html - -Check that the tasks were executed correctly and Apache is accepting connections: Make an HTTP request using Ansible’s `uri` module in a playbook named check_httpd.yml from the control node to `node1`. - -{% raw %} -```yaml ---- -- name: Check URL - hosts: control - vars: - node: "node1" - - tasks: - - name: Check that you can connect (GET) to a page and it returns a status 200 - ansible.builtin.uri: - url: "http://{{ node }}" - -``` -{% endraw %} - -> **Warning** -> -> **Expect a lot of red lines and a 403 status\!** - -```bash -[student@ansible-1 ~]$ ansible-navigator run check_httpd.yml -m stdout -``` - -There are a lot of red lines and an error: As long as there is not at least an `web.html` file to be served by Apache, it will throw an ugly "HTTP Error 403: Forbidden" status and Ansible will report an error. - -So why not use Ansible to deploy a simple `web.html` file? On the ansible control host, as the `student` user, create the directory `files` to hold file resources in `~/ansible-files/`: - -```bash -[student@ansible-1 ansible-files]$ mkdir files -``` - -Then create the file `~/ansible-files/files/web.html` on the control node: - -```html - -

Apache is running fine

- -``` - -In a previous example, you used Ansible’s `copy` module to write text supplied on the command line into a file. Now you’ll use the module in your playbook to copy a file. - -On the control node as your student user edit the file `~/ansible-files/apache.yml` and add a new task utilizing the `copy` module. It should now look like this: - -```yaml ---- -- name: Apache server installed - hosts: node1 - become: true - tasks: - - - name: Install Apache - ansible.builtin.dnf: - name: httpd - - - name: Apache enabled and running - ansible.builtin.service: - name: httpd - enabled: true - state: started - - - name: Copy index.html - ansible.builtin.copy: - src: web.html - dest: /var/www/html/index.html - mode: '644' -``` - -What does this new copy task do? The new task uses the `copy` module and defines the source and destination options for the copy operation as parameters. - -Run your extended Playbook: - -```bash -[student@ansible-1 ansible-files]$ ansible-navigator run apache.yml -m stdout -``` - -* Have a good look at the output, notice the changes of "CHANGED" and the tasks associated with that change. - -* Run the Ansible playbook check_httpd.yml using the "uri" module from above again to test Apache. The command should now return a friendly green "status: 200" line, amongst other information. - -### Step 6 - Practice: Apply to Multiple Host - -While the above, shows the simplicity of applying changes to a particular host. What about if you want to set changes to many hosts? This is where you'll notice the real power of Ansible as it applies the same set of tasks reliably to many hosts. - -* So what about changing the apache.yml Playbook to run on `node1` **and** `node2` **and** `node3`? - -As you might remember, the inventory lists all nodes as members of the group `web`: - -```ini -[web] -node1 ansible_host=11.22.33.44 -node2 ansible_host=22.33.44.55 -node3 ansible_host=33.44.55.66 -``` - -> **Tip** -> -> The IP addresses shown here are just examples, your nodes will have different IP addresses. - -Change the playbook `hosts` parameter to point to `web` instead of `node1`: - -```yaml ---- -- name: Apache server installed - hosts: web - become: true - tasks: - - - name: Install Apache - ansible.builtin.dnf: - name: httpd - - - name: Apache enabled and running - ansible.builtin.service: - name: httpd - enabled: true - state: started - - - name: Copy index.html - ansible.builtin.copy: - src: web.html - dest: /var/www/html/index.html - mode: '644' - -``` - -Now run the playbook: - -```bash -[student@ansible-1 ansible-files]$ ansible-navigator run apache.yml -m stdout -``` - -Verify if Apache is now running on all web servers (node1, node2, node3). All output should be green. - ---- -**Navigation** -
+Review the output to ensure the user creation was successful. -{% if page.url contains 'ansible_rhel_90' %} -[Previous Exercise](../2-thebasics) - [Next Exercise](../4-variables) -{% else %} -[Previous Exercise](../1.2-thebasics) - [Next Exercise](../1.4-variables) -{% endif %} -

-[Click here to return to the Ansible for Red Hat Enterprise Linux Workshop](../README.md#section-1---ansible-engine-exercises) diff --git a/exercises/ansible_rhel/1.5-handlers/README.md b/exercises/ansible_rhel/1.5-handlers/README.md index 560cc0ac0..19a474eb5 100644 --- a/exercises/ansible_rhel/1.5-handlers/README.md +++ b/exercises/ansible_rhel/1.5-handlers/README.md @@ -1,303 +1,249 @@ - -# Workshop Exercise - Conditionals, Handlers and Loops +# Workshop Exercise - Conditionals, Handlers and Loops **Read this in other languages**:
![uk](../../../images/uk.png) [English](README.md), ![japan](../../../images/japan.png)[日本語](README.ja.md), ![brazil](../../../images/brazil.png) [Portugues do Brasil](README.pt-br.md), ![france](../../../images/fr.png) [Française](README.fr.md),![Español](../../../images/col.png) [Español](README.es.md). - -## Table of Contents +# Workshop Exercises - Using Conditionals, Handlers, and Loops +## Table of Contents - [Objective](#objective) - [Guide](#guide) - - [Step 1 - Conditionals](#step-1---conditionals) - - [Step 2 - Handlers](#step-2---handlers) - - [Step 3 - Simple Loops](#step-3---simple-loops) - - [Step 4 - Loops over hashes](#step-4---loops-over-hashes) + - [Step 1 - Understanding Conditionals, Handlers, and Loops](#step-1---understanding-conditionals-handlers-and-loops) + - [Step 2 - Conditionals](#step-2---conditionals) + - [Step 3 - Handlers](#step-3---handlers) + - [Step 4 - Loops](#step-4---loops) ## Objective -Three foundational Ansible features are: - -* [Conditionals](https://docs.ansible.com/ansible/latest/user_guide/playbooks_conditionals.html) -* [Handlers](https://docs.ansible.com/ansible/latest/user_guide/playbooks_intro.html#handlers-running-operations-on-change) -* [Loops](https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html) +Expanding on Exercise 1.4, this exercise introduces the application of conditionals, handlers, and loops in Ansible playbooks. You'll learn to control task execution with conditionals, manage service responses with handlers, and efficiently handle repetitive tasks using loops. ## Guide -### Step 1 - Conditionals - -Ansible can use conditionals to execute tasks or plays when certain conditions are met. - -To implement a conditional, the `when` statement must be used, followed by the condition to test. The condition is expressed using one of the available operators like e.g. for comparison: - -| | | -| ---- | ---------------------------------------------------------------------- | -| \== | Compares two objects for equality. | -| \!= | Compares two objects for inequality. | -| \> | true if the left hand side is greater than the right hand side. | -| \>= | true if the left hand side is greater or equal to the right hand side. | -| \< | true if the left hand side is lower than the right hand side. | -| \<= | true if the left hand side is lower or equal to the right hand side. | - -For more on this, please refer to the documentation: +Conditionals, handlers, and loops are advanced features in Ansible that enhance control, efficiency, and flexibility in your automation playbooks. -As an example you would like to install an FTP server, but only on hosts that are in the "ftpserver" inventory group. +### Step 1 - Understanding Conditionals, Handlers, and Loops -To do that, first edit the inventory to add another group, and place `node2` in it. The section to add looks like this: +- **Conditionals**: Enable tasks to be executed based on specific conditions. +- **Handlers**: Special tasks triggered by a `notify` directive, typically used for restarting services after changes. +- **Loops**: Used to repeat a task multiple times, particularly useful when the task is similar but needs to be applied to different items. -``` ini -[ftpserver] -node2 -``` - -Edit the inventory `~/lab_inventory/hosts` to add those lines. When you are done, it will look similar to the following listing: - -> **Tip** -> -> The ansible_host variable only needs to be specified once for a node. When adding a node to other groups, you do not need to -> specify the variable again. +### Step 2 - Conditionals -**Important** Do not copy/paste the example below. Just edit the file to add the above lines. +Conditionals in Ansible control whether a task should run based on certain conditions. +Let's add to the system_setup.yml playbook the ability to install the Apache HTTP Server (`httpd`) only on hosts that belong to the `web` group in our inventory. -```ini -[web] -node1 ansible_host=xx.xx.xx.xx -node2 ansible_host=xx.xx.xx.xx -node3 ansible_host=xx.xx.xx.xx - -[ftpserver] -node2 - -[control] -ansible-1 ansible_host=xx.xx.xx.xx -``` - -Next create the file `ftpserver.yml` on your control host in the `~/ansible-files/` directory: +> NOTE: Previous examples had hosts set to node1 but now it is set to all. This means when you run this updated Ansible playbook you will notice updates for the new systems being automated against, the user Roger created on all new systems and the Apache web server package httpd installed on all the hosts within the web group. ```yaml --- -- name: Install vsftpd on ftpservers +- name: Basic System Setup hosts: all become: true + vars: + user_name: 'Roger' + package_name: httpd tasks: - - name: Install FTP server when host in ftpserver group - ansible.builtin.yum: - name: vsftpd + - name: Update all security-related packages + ansible.builtin.dnf: + name: '*' state: latest - when: inventory_hostname in groups["ftpserver"] -``` - -> **Tip** -> -> By now you should know how to run Ansible Playbooks, we’ll start to be less verbose in this guide. Go create and run it. :-) + security: true + update_only: true -Run it and examine the output. The expected outcome: The task is skipped on node1, node3 and the ansible host (your control host) because they are not in the ftpserver group in your inventory file. + - name: Create a new user + ansible.builtin.user: + name: "{{ user_name }}" + state: present + create_home: true -```bash -TASK [Install FTP server when host in ftpserver group] ******************************************* -skipping: [ansible-1] -skipping: [node1] -skipping: [node3] -changed: [node2] + - name: Install Apache on web servers + ansible.builtin.dnf: + name: "{{ package_name }}" + state: present + when: inventory_hostname in groups['web'] ``` -### Step 2 - Handlers - -Sometimes when a task does make a change to the system, an additional task or tasks may need to be run. For example, a change to a service’s configuration file may then require that the service be restarted so that the changed configuration takes effect. - -Here Ansible’s handlers come into play. Handlers can be seen as inactive tasks that only get triggered when explicitly invoked using the "notify" statement. Read more about them in the [Ansible Handlers](http://docs.ansible.com/ansible/latest/playbooks_intro.html#handlers-running-operations-on-change) documentation. +In this example, `inventory_hostname in groups['web']` is the conditional statement. `inventory_hostname` refers to the name of the current host that Ansible is working on in the playbook. The condition checks if this host is part of the `web` group defined in your inventory file. If true, the task will execute and install Apache on that host. -As a an example, let’s write a playbook that: +### Step 3 - Handlers -* manages Apache’s configuration file `/etc/httpd/conf/httpd.conf` on all hosts in the `web` group -* restarts Apache when the file has changed +Handlers are used for tasks that should only run when notified by another task. Typically, they are used to restart services after a configuration change. -First we need the file Ansible will deploy, let’s just take the one from node1. Remember to replace the IP address shown in the listing below with the IP address from your individual `node1`. - -```bash -[student@ansible-1 ansible-files]$ scp node1:/etc/httpd/conf/httpd.conf ~/ansible-files/files/. -httpd.conf -``` +Let's say we want to ensure the firewall is configured correctly on all web servers and then reload the firewall service to apply any new settings. We'll define a handler that reloads the firewall service and is notified by a task that ensures the desired firewall rules are in place: -Next, create the Playbook `httpd_conf.yml`. Make sure that you are in the directory `~/ansible-files`. ```yaml --- -- name: Manage httpd.conf - hosts: web +- name: Basic System Setup + hosts: all become: true - tasks: + . + . + . + - name: Install firewalld + ansible.builtin.dnf: + name: firewalld + state: present - - name: Copy Apache configuration file - ansible.builtin.copy: - src: httpd.conf - dest: /etc/httpd/conf/ - mode: '644' - notify: - - Restart_apache + - name: Ensure firewalld is running + ansible.builtin.service: + name: firewalld + state: started + enabled: true + + - name: Allow HTTPS traffic on web servers + ansible.posix.firewalld: + service: https + permanent: true + state: enabled + when: inventory_hostname in groups['web'] + notify: Reload Firewall handlers: - - name: Restart_apache + - name: Reload Firewall ansible.builtin.service: - name: httpd - state: restarted -``` - -So what’s new here? - -* The "notify" section calls the handler only when the copy task actually changes the file. That way the service is only restarted if needed - and not each time the playbook is run. -* The "handlers" section defines a task that is only run on notification. + name: firewalld + state: reloaded -
+``` -Run the playbook. We didn’t change anything in the file yet so there should not be any `changed` lines in the output and of course the handler shouldn’t have fired. +The handler Restart Apache is triggered only if the task “Allow HTTPS traffic on web servers” makes any changes. -* Now change the `Listen 80` line in `~/ansible-files/files/httpd.conf` to: +> NOTE: Notice how the name of the handler is used within the notify section of the “Reload Firewall” configuration task. This ensures that the proper handler is executed as there can be multiple handlers within an Ansible playbook. -```ini -Listen 8080 ``` +PLAY [Basic System Setup] ****************************************************** -* Run the playbook again. Now the Ansible’s output should be a lot more interesting: - - * httpd.conf should have been copied over - * The handler should have restarted Apache +TASK [Gathering Facts] ********************************************************* +ok: [node1] +ok: [node2] +ok: [ansible-1] +ok: [node3] -Apache should now listen on port 8080. Easy enough to verify: +TASK [Update all security-related packages] ************************************ +ok: [node2] +ok: [node1] +ok: [ansible-1] +ok: [node3] -```bash -[student@ansible-1 ansible-files]$ curl http://node1 -curl: (7) Failed to connect to node1 port 80: Connection refused -[student@ansible-1 ansible-files]$ curl http://node1:8080 - -

Apache is running fine

- -``` +TASK [Create a new user] ******************************************************* +ok: [node1] +ok: [node2] +ok: [ansible-1] +ok: [node3] -Leave the setting for listen on port 8080. We'll use this in a later exercise. +TASK [Install Apache on web servers] ******************************************* +skipping: [ansible-1] +ok: [node2] +ok: [node1] +ok: [node3] -### Step 3 - Simple Loops +TASK [Install firewalld] ******************************************************* +changed: [ansible-1] +changed: [node2] +changed: [node1] +changed: [node3] -Loops enable us to repeat the same task over and over again. For example, lets say you want to create multiple users. By using an Ansible loop, you can do that in a single task. Loops can also iterate over more than just basic lists. For example, if you have a list of users with their coresponding group, loop can iterate over them as well. Find out more about loops in the [Ansible Loops](https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html) documentation. +TASK [Ensure firewalld is running] ********************************************* +changed: [node3] +changed: [ansible-1] +changed: [node2] +changed: [node1] -To show the loops feature we will generate three new users on `node1`. For that, create the file `loop_users.yml` in `~/ansible-files` on your control node as your student user. We will use the `user` module to generate the user accounts. +TASK [Allow HTTPS traffic on web servers] ************************************** +skipping: [ansible-1] +changed: [node2] +changed: [node1] +changed: [node3] - +RUNNING HANDLER [Reload Firewall] ********************************************** +changed: [node2] +changed: [node1] +changed: [node3] -```yaml ---- -- name: Ensure users - hosts: node1 - become: true +PLAY RECAP ********************************************************************* +ansible-1 : ok=5 changed=2 unreachable=0 failed=0 skipped=2 rescued=0 ignored=0 +node1 : ok=8 changed=4 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 +node2 : ok=8 changed=4 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 +node3 : ok=8 changed=4 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 - tasks: - - name: Ensure three users are present - ansible.builtin.user: - name: "{{ item }}" - state: present - loop: - - dev_user - - qa_user - - prod_user ``` - +### Step 4 - Loops -Understand the playbook and the output: +Loops in Ansible allow you to perform a task multiple times with different values. This feature is particularly useful for tasks like creating multiple user accounts in our given example. +In the original system_setup.yml playbook from Exercise 1.4, we had a task for creating a single user: - -* The names are not provided to the user module directly. Instead, there is only a variable called `{{ item }}` for the parameter `name`. -* The `loop` keyword lists the actual user names. Those replace the `{{ item }}` during the actual execution of the playbook. -* During execution the task is only listed once, but there are three changes listed underneath it. - - +```yaml +- name: Create a new user + ansible.builtin.user: + name: "{{ user_name }}" + state: present + create_home: true -### Step 4 - Loops over hashes +``` -As mentioned loops can also be over lists of hashes. Imagine that the users should be assigned to different additional groups: +Now, let's modify this task to create multiple users using a loop: ```yaml -- username: dev_user - groups: ftp -- username: qa_user - groups: ftp -- username: prod_user - groups: apache +- name: Create a new user + ansible.builtin.user: + name: "{{ item }}" + state: present + create_home: true + loop: + - alice + - bob + - carol ``` -The `user` module has the optional parameter `groups` to list additional users. To reference items in a hash, the `{{ item }}` keyword needs to reference the subkey: `{{ item.groups }}` for example. +What Changed? -Let's rewrite the playbook to create the users with additional user rights: +1. Loop Directive: The loop keyword is used to iterate over a list of items. In this case, the list contains the names of users we want to create: alice, bob, and carol. - +2. User Creation with Loop: Instead of creating a single user, the modified task now iterates over each item in the loop list. The `{{ item }}` placeholder is dynamically replaced with each username in the list, so the ansible.builtin.user module creates each user in turn. -```yaml ---- -- name: Ensure users - hosts: node1 - become: true +When you run the updated playbook, this task is executed three times, once for each user specified in the loop. It's an efficient way to handle repetitive tasks with varying input data. - tasks: - - name: Ensure three users are present - ansible.builtin.user: - name: "{{ item.username }}" - state: present - groups: "{{ item.groups }}" - loop: - - { username: 'dev_user', groups: 'ftp' } - - { username: 'qa_user', groups: 'ftp' } - - { username: 'prod_user', groups: 'apache' } +Snippet of the output for creating a new user on all the nodes. ``` +[student@ansible-1 ~lab_inventory]$ ansible-navigator run system_setup.yml -m stdout - +PLAY [Basic System Setup] ****************************************************** -Check the output: - -* Again the task is listed once, but three changes are listed. Each loop with its content is shown. - -Verify that the user `dev_user` was indeed created on `node1` using the following playbook: - -{% raw %} -```yaml ---- -- name: Get user ID - hosts: node1 - vars: - myuser: "dev_user" - tasks: - - name: Get {{ myuser }} info - ansible.builtin.getent: - database: passwd - key: "{{ myuser }}" - - ansible.builtin.debug: - msg: - - "{{ myuser }} uid: {{ getent_passwd[myuser].1 }}" -``` -{% endraw %} +. +. +. -```bash -$ ansible-navigator run user_id.yml -m stdout +TASK [Create a new user] ******************************************************* +changed: [node2] => (item=alice) +changed: [ansible-1] => (item=alice) +changed: [node1] => (item=alice) +changed: [node3] => (item=alice) +changed: [node1] => (item=bob) +changed: [ansible-1] => (item=bob) +changed: [node3] => (item=bob) +changed: [node2] => (item=bob) +changed: [node1] => (item=carol) +changed: [node3] => (item=carol) +changed: [ansible-1] => (item=carol) +changed: [node2] => (item=carol) -PLAY [Get user ID] ************************************************************* +. +. +. -TASK [Gathering Facts] ********************************************************* -ok: [node1] -TASK [Get dev_user info] ******************************************************* -ok: [node1] +PLAY RECAP ********************************************************************* +ansible-1 : ok=5 changed=1 unreachable=0 failed=0 skipped=2 rescued=0 ignored=0 +node1 : ok=7 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 +node2 : ok=7 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 +node3 : ok=7 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 -TASK [debug] ******************************************************************* -ok: [node1] => { - "msg": [ - "dev_user uid: 1002" - ] -} -PLAY RECAP ********************************************************************* -node1 : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 ``` --- **Navigation** diff --git a/exercises/ansible_rhel/1.6-templates/README.md b/exercises/ansible_rhel/1.6-templates/README.md index 3ccb06f1e..d66747077 100644 --- a/exercises/ansible_rhel/1.6-templates/README.md +++ b/exercises/ansible_rhel/1.6-templates/README.md @@ -3,161 +3,126 @@ **Read this in other languages**:
![uk](../../../images/uk.png) [English](README.md), ![japan](../../../images/japan.png)[日本語](README.ja.md), ![brazil](../../../images/brazil.png) [Portugues do Brasil](README.pt-br.md), ![france](../../../images/fr.png) [Française](README.fr.md),![Español](../../../images/col.png) [Español](README.es.md). + ## Table of Contents -* [Objective](#objective) -* [Guide](#guide) -* [Step 1 - Using Templates in Playbooks](#step-1---using-templates-in-playbooks) -* [Step 2 - Challenge Lab](#step-2---challenge-lab) +- [Objective](#objective) +- [Guide](#guide) + - [Step 1 - Introduction to Jinja2 Templating](#step-1---introduction-to-jinja2-templating) + - [Step 2 - Crafting Your First Template](#step-2---crafting-your-first-template) + - [Step 3 - Deploying the Template with a Playbook](#step-3---deploying-the-template-with-a-playbook) + - [Step 4 - Executing the Playbook](#step-4---executing-the-playbook) ## Objective -This exercise will cover Jinja2 templating. Ansible uses Jinja2 templating to modify files before they are distributed to managed hosts. Jinja2 is one of the most used template engines for Python (). +Exercise 1.5 introduces Jinja2 templating within Ansible, a powerful feature for generating dynamic files from templates. You'll learn how to craft templates that incorporate host-specific data, enabling the creation of tailored configuration files for each managed host. ## Guide -### Step 1 - Using Templates in Playbooks +### Step 1 - Introduction to Jinja2 Templating + +Ansible leverages Jinja2, a widely-used templating language for Python, allowing dynamic content generation within files. This capability is particularly useful for configuring files that must differ from host to host. + +### Step 2 - Crafting Your First Template -When a template for a file has been created, it can be deployed to the managed hosts using the `template` module, which supports the transfer of a local file from the control node to the managed hosts. +Templates end with a `.j2` extension and mix static content with dynamic placeholders enclosed in `{{ }}`. -As an example of using templates you will change the motd file to contain host-specific data. +In the following example, let's create a template for the Message of the Day (MOTD) that includes dynamic host information. -First create the directory `templates` to hold template resources in `~/ansible-files/`: +#### Set Up the Template Directory: + +Ensure a templates directory exists within your lab_inventory directory to organize your templates. ```bash -[student@ansible-1 ansible-files]$ mkdir templates +mkdir -p ~/lab_inventory/templates ``` -Then in the `~/ansible-files/templates/` directory create the template file `motd-facts.j2`: +#### Develop the MOTD Template: - +Create a file named `motd.j2` in the templates directory with the following content: -```html+jinja +```jinja Welcome to {{ ansible_hostname }}. -{{ ansible_distribution }} {{ ansible_distribution_version}} -deployed on {{ ansible_architecture }} architecture. +OS: {{ ansible_distribution }} {{ ansible_distribution_version }} +Architecture: {{ ansible_architecture }} ``` - +This template dynamically displays the hostname, OS distribution, version, and architecture of each managed host. + +### Step 3 - Deploying the Template with a Playbook -The template file contains the basic text that will later be copied over. It also contains variables which will be replaced on the target machines individually. +Utilize the `ansible.builtin.template` module in a playbook to distribute and render the template across your managed hosts. -Next we need a playbook to use this template. In the `~/ansible-files/` directory create the Playbook `motd-facts.yml`: +Modify the `system_setup.yml` Playbook with the following content: ```yaml --- -- name: Fill motd file with host data - hosts: node1 +- name: Basic System Setup + hosts: all become: true tasks: - - ansible.builtin.template: - src: motd-facts.j2 +. +. +. + - name: Update MOTD from Jinja2 Template + ansible.builtin.template: + src: templates/motd.j2 dest: /etc/motd - owner: root - group: root - mode: 0644 -``` - -You have done this a couple of times by now: - -* Understand what the Playbook does. -* Execute the Playbook `motd-facts.yml`. -* Login to node1 via SSH and check the message of the day content. -* Log out of node1. - -You should see how Ansible replaces the variables with the facts it discovered from the system. - -### Step 2 - Challenge Lab - -Add a line to the template to list the current kernel of the managed node. - -* Find a fact that contains the kernel version using the commands you learned in the "Ansible Facts" chapter. - -> **Tip** -> -> filter for kernel - -> Run the newly created playbook to find the fact name. - -* Change the template to use the fact you found. - -* Run the motd playbook again. - -* Check motd by logging in to node1 -> **Warning** -> -> **Solution below\!** -* Find the fact: + handlers: + - name: Reload Firewall + ansible.builtin.service: + name: firewalld + state: reloaded -```yaml ---- -- name: Capture Kernel Version - hosts: node1 +``` - tasks: +The `ansible.builtin.template` module takes the `motd.j2` template and generates an `/etc/motd` file on each host, filling in the template's placeholders with the actual host facts. - - name: Collect only kernel facts - ansible.builtin.setup: - filter: - - '*kernel' - register: setup +### Step 4 - Executing the Playbook - - ansible.builtin.debug: - var: setup -``` - -With the wildcard in place, the output shows: +Run the playbook to apply your custom MOTD across all managed hosts: ```bash - -TASK [debug] ******************************************************************* -ok: [node1] => { - "setup": { - "ansible_facts": { - "ansible_kernel": "4.18.0-305.12.1.el8_4.x86_64" - }, - "changed": false, - "failed": false - } -} +[student@ansible-1 lab_inventory]$ ansible-navigator run system_setup.yml -m stdout ``` -With this we can conclude the variable we are looking for is labeled `ansible_kernel`. -Then we can update the motd-facts.j2 template to include `ansible_kernel` as part of its message. +```plaintext +PLAY [Basic System Setup] ****************************************************** +. +. +. -* Modify the template `motd-facts.j2`: +TASK [Update MOTD from Jinja2 Template] **************************************** +changed: [node1] +changed: [node2] +changed: [node3] +changed: [ansible-1] - - -```html+jinja -Welcome to {{ ansible_hostname }}. -{{ ansible_distribution }} {{ ansible_distribution_version}} -deployed on {{ ansible_architecture }} architecture -running kernel {{ ansible_kernel }}. +PLAY RECAP ********************************************************************* +ansible-1 : ok=6 changed=1 unreachable=0 failed=0 skipped=2 rescued=0 ignored=0 +node1 : ok=8 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 +node2 : ok=8 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 +node3 : ok=8 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 ``` - +Verify the changes by SSHing into the node, and you should see the message of the day: -* Run the playbook. - -```bash -[student@ansible-1 ~]$ ansible-navigator run motd-facts.yml -m stdout +```plaintext +[rhel@control ~]$ ssh node1 +``` ``` - -* Verify the new message via SSH login to `node1`. - -```bash -[student@ansible-1 ~]$ ssh node1 Welcome to node1. -RedHat 8.1 -deployed on x86_64 architecture -running kernel 4.18.0-305.12.1.el8_4.x86_64. +OS: RedHat 8.7 +Architecture: x86_64 +Register this system with Red Hat Insights: insights-client --register +Create an account or view all your systems at https://red.ht/insights-dashboard +Last login: Mon Jan 29 16:30:31 2024 from 10.5.1.29 + ``` ---- **Navigation**
[Previous Exercise](../1.5-handlers) - [Next Exercise](../1.7-role) diff --git a/exercises/ansible_rhel/1.7-role/README.md b/exercises/ansible_rhel/1.7-role/README.md index 998cdccbd..628aafcf5 100644 --- a/exercises/ansible_rhel/1.7-role/README.md +++ b/exercises/ansible_rhel/1.7-role/README.md @@ -5,334 +5,254 @@ ## Table of Contents -* [Objective](#objective) -* [Guide](#guide) - * [Step 1 - Understanding the Ansible Role Structure](#step-1---understanding-the-ansible-role-structure) - * [Step 2 - Create a Basic Role Directory Structure](#step-2---create-a-basic-role-directory-structure) - * [Step 3 - Create the Tasks File](#step-3---create-the-tasks-file) - * [Step 4 - Create the handler](#step-4---create-the-handler) - * [Step 5 - Create the web.html and vhost configuration file template](#step-5---create-the-webhtml-and-vhost-configuration-file-template) - * [Step 6 - Test the role](#step-6---test-the-role) -* [Troubleshooting problems](#troubleshooting-problems) +- [Objective](#objective) +- [Guide](#guide) + - [Step 1 - Role Basics](#step-1---role-basics) + - [Step 2 - Cleaning up the Environment](#step-2---cleaning-up-the-environment) + - [Step 3 - Building the Apache Role](#step-3---building-the-apache-role) + - [Step 4 - Role Integration in a Playbook](#step-4---role-integration-in-a-playbook) + - [Step 4 - Role Execution and Validation](#step-4---role-execution-and-validation) + - [Step 5 - Verify the Apache is Running](#step-5---verify-the-apache-is-running) ## Objective -While it is possible to write a playbook in one file as we've done throughout this workshop, eventually you’ll want to reuse files and start to organize things. - -Ansible Roles are the way we do this. When you create a role, you deconstruct your playbook into parts and those parts sit in a directory structure. This is explained in more details in the [Tips and tricks](https://docs.ansible.com/ansible/latest/user_guide/playbooks_best_practices.html) and the [Sample Ansible setup](https://docs.ansible.com/ansible/latest/user_guide/sample_setup.html). - -This exercise will cover: - -* the folder structure of an Ansible Role -* how to build an Ansible Role -* creating an Ansible Play to use and execute a role -* using Ansible to create a Apache VirtualHost on node2 +This exercise builds upon the previous exercises and advances your Ansible skills by guiding you through the creation of a role that configures Apache (httpd). You'll take the knowledge you learned to now integrate variables, handlers, and a template for a custom index.html. This role demonstrates how to encapsulate tasks, variables, templates, and handlers into a reusable structure for efficient automation. ## Guide -### Step 1 - Understanding the Ansible Role Structure - -Roles follow a defined directory structure; a role is named by the top level directory. Some of the subdirectories contain YAML files, named `main.yml`. The files and templates subdirectories can contain objects referenced by the YAML files. - -An example project structure could look like this, the name of the role would be "apache": - -```text -apache/ -├── defaults -│ └── main.yml -├── files -├── handlers -│ └── main.yml -├── meta -│ └── main.yml -├── README.md -├── tasks -│ └── main.yml -├── templates -├── tests -│ ├── inventory -│ └── test.yml -└── vars - └── main.yml -``` +### Step 1 - Role Basics -The various `main.yml` files contain content depending on their location in the directory structure shown above. For instance, `vars/main.yml` references variables, `handlers/main.yaml` describes handlers, and so on. Note that in contrast to playbooks, the `main.yml` files only contain the specific content and not additional playbook information like hosts, `become` or other keywords. +Roles in Ansible organize related automation tasks and resources, such as variables, templates, and handlers, into a structured directory. This exercise focuses on creating an Apache configuration role, emphasizing reusability and modularity. -> **Tip** -> -> There are actually two directories for variables: `vars` and `default`. Default variables, `defaults/main.yml`, have the lowest precedence and usually contain default values set by the role authors and are often used when it is intended that their values will be overridden. Variables set in `vars/main.yml` are for variables not intended to be modified. +### Step 2 - Cleaning up the Environment -Using roles in a Playbook is straight forward: +Building on our previous work with Apache configuration, let's craft an Ansible playbook dedicated to tidying up our environment. This step paves the way for us to introduce a new Apache role, providing a clear view of the adjustments made. Through this process, we'll gain deeper insights into the versatility and reusability afforded by Ansible Roles. + +Run the following Ansible playbook to clean the environment: ```yaml --- -- name: launch roles - hosts: web - roles: - - role1 - - role2 +- name: Cleanup Environment + hosts: all + become: true + vars: + package_name: httpd + tasks: + - name: Remove Apache from web servers + ansible.builtin.dnf: + name: "{{ package_name }}" + state: absent + when: inventory_hostname in groups['web'] + + - name: Remove firewalld + ansible.builtin.dnf: + name: firewalld + state: absent + + - name: Delete created users + ansible.builtin.user: + name: "{{ item }}" + state: absent + remove: true # Use 'remove: true’ to delete home directories + loop: + - alice + - bob + - carol + - Roger + + - name: Reset MOTD to an empty message + ansible.builtin.copy: + dest: /etc/motd + content: '' ``` -For each role, the tasks, handlers and variables of that role will be included in the Playbook, in that order. Any copy, script, template, or include tasks in the role can reference the relevant files, templates, or tasks *without absolute or relative path names*. Ansible will look for them in the role's files, templates, or tasks respectively, based on their -use. +### Step 3 - Building the Apache Role -### Step 2 - Create a Basic Role Directory Structure +We'll develop a role named `apache` to install, configure, and manage Apache. -Ansible looks for roles in a subdirectory called `roles` in the project directory. This can be overridden in the Ansible configuration. Each role has its own directory. To ease creation of a new role the tool `ansible-galaxy` can be used. +1. Generate Role Structure: -> **Tip** -> -> Ansible Galaxy is your hub for finding, reusing and sharing the best Ansible content. `ansible-galaxy` helps to interact with Ansible Galaxy. For now we'll just using it as a helper to build the directory structure. - -Okay, lets start to build a role. We'll build a role that installs and configures Apache to serve a virtual host. Run these commands in your `~/ansible-files` directory: +Create the role using ansible-galaxy, specifying the roles directory for output. ```bash -[student@ansible-1 ansible-files]$ mkdir roles -[student@ansible-1 ansible-files]$ ansible-galaxy init --offline roles/apache_vhost +[student@ansible-1 lab_inventory]$ mkdir roles +[student@ansible-1 lab_inventory]$ ansible-galaxy init --offline roles/apache ``` -Have a look at the role directories and their content: +2. Define Role Variables: -```bash -[student@ansible-1 ansible-files]$ tree roles -``` +Populate `/home/student/lab_inventory/roles/apache/vars/main.yml` with Apache-specific variables: -```text -roles/ -└── apache_vhost - ├── defaults - │ └── main.yml - ├── files - ├── handlers - │ └── main.yml - ├── meta - │ └── main.yml - ├── README.md - ├── tasks - │ └── main.yml - ├── templates - ├── tests - │ ├── inventory - │ └── test.yml - └── vars - └── main.yml +```yaml +--- +# vars file for roles/apache +apache_package_name: httpd +apache_service_name: httpd ``` -### Step 3 - Create the Tasks File - -The `main.yml` file in the tasks subdirectory of the role should do the following: - -* Make sure httpd is installed -* Make sure httpd is started and enabled -* Put HTML content into the Apache document root -* Install the template provided to configure the vhost +3. Configure Role Tasks: -> **WARNING** -> -> **The `main.yml` (and other files possibly included by main.yml) can only contain tasks, *not* complete playbooks!** - -Edit the `roles/apache_vhost/tasks/main.yml` file: +Adjust `/home/student/lab_inventory/roles/apache/tasks/main.yml` to include tasks for Apache installation and service management: ```yaml --- -- name: install httpd - ansible.builtin.yum: - name: httpd - state: latest +# tasks file for ansible-files/roles/apache +- name: Install Apache web server + ansible.builtin.package: + name: "{{ apache_package_name }}" + state: present -- name: start and enable httpd service +- name: Ensure Apache is running and enabled ansible.builtin.service: - name: httpd + name: "{{ apache_service_name }}" state: started enabled: true -``` -Note that here just tasks were added. The details of a playbook are not present. +- name: Install firewalld + ansible.builtin.dnf: + name: firewalld + state: present -The tasks added so far do: +- name: Ensure firewalld is running + ansible.builtin.service: + name: firewalld + state: started + enabled: true -* Install the httpd package using the yum module -* Use the service module to enable and start httpd +- name: Allow HTTPS traffic on web servers + ansible.posix.firewalld: + service: https + permanent: true + state: enabled + when: inventory_hostname in groups['web'] + notify: Reload Firewall +``` -Next we add two more tasks to ensure a vhost directory structure and copy html content: +4. Implement Handlers: - +In `/home/student/lab_inventory/roles/apache/handlers/main.yml`, create a handler to restart firewalld if its configuration changes: ```yaml -- name: ensure vhost directory is present - ansible.builtin.file: - path: "/var/www/vhosts/{{ ansible_hostname }}" - state: directory - -- name: deliver html content - ansible.builtin.copy: - src: web.html - dest: "/var/www/vhosts/{{ ansible_hostname }}/index.html" +--- +# handlers file for ansible-files/roles/apache +- name: Reload Firewall + ansible.builtin.service: + name: firewalld + state: reloaded ``` - +5. Create and Deploy Template: -Note that the vhost directory is created/ensured using the `file` module. +Use a Jinja2 template for a custom `index.html`. Store the template in `templates/index.html.j2`: -The last task we add uses the template module to create the vhost configuration file from a j2-template: - -```yaml -- name: template vhost file - ansible.builtin.template: - src: vhost.conf.j2 - dest: /etc/httpd/conf.d/vhost.conf - owner: root - group: root - mode: 0644 - notify: - - restart_httpd +```html + + +Welcome to {{ ansible_hostname }} + + +

Hello from {{ ansible_hostname }}

+ + ``` -Note it is using a handler to restart httpd after an configuration update. - -The full `tasks/main.yml` file is: - - +6. Update `tasks/main.yml` to deploy this `index.html` template: ```yaml ---- -- name: install httpd - ansible.builtin.yum: - name: httpd - state: latest - -- name: start and enable httpd service - ansible.builtin.service: - name: httpd - state: started - enabled: true - -- name: ensure vhost directory is present - ansible.builtin.file: - path: "/var/www/vhosts/{{ ansible_hostname }}" - state: directory - -- name: deliver html content - ansible.builtin.copy: - src: web.html - dest: "/var/www/vhosts/{{ ansible_hostname }}/index.html" - -- name: template vhost file +- name: Deploy custom index.html ansible.builtin.template: - src: vhost.conf.j2 - dest: /etc/httpd/conf.d/vhost.conf - owner: root - group: root - mode: 0644 - notify: - - restart_httpd + src: index.html.j2 + dest: /var/www/html/index.html ``` - +### Step 4 - Role Integration in a Playbook -### Step 4 - Create the handler - -Create the handler in the file `roles/apache_vhost/handlers/main.yml` to restart httpd when notified by the template task: +Embed the `apache` role in a playbook named `deploy_apache.yml` within `/home/student/lab_inventory` to apply it to your 'web' group hosts (node1, node2, node3). ```yaml ---- -# handlers file for roles/apache_vhost -- name: restart_httpd - ansible.builtin.service: - name: httpd - state: restarted +- name: Setup Apache Web Servers + hosts: web + become: true + roles: + - apache ``` -### Step 5 - Create the web.html and vhost configuration file template +### Step 4 - Role Execution and Validation -Create the HTML content that will be served by the webserver. - -* Create an web.html file in the "src" directory of the role, `files`: +Launch your playbook to configure Apache across the designated web servers: ```bash -#> echo 'simple vhost index' > ~/ansible-files/roles/apache_vhost/files/web.html +ansible-navigator run deploy_apache.yml -m stdout ``` -* Create the `vhost.conf.j2` template file in the role's `templates` subdirectory. - -The contents of the `vhost.conf.j2` template file are found below. - - +#### Output: -```text -# {{ ansible_managed }} +```plaintext +PLAY [Setup Apache Web Servers] ************************************************ - - ServerAdmin webmaster@{{ ansible_fqdn }} - ServerName {{ ansible_fqdn }} - ErrorLog logs/{{ ansible_hostname }}-error.log - CustomLog logs/{{ ansible_hostname }}-common.log common - DocumentRoot /var/www/vhosts/{{ ansible_hostname }}/ +TASK [Gathering Facts] ********************************************************* +ok: [node2] +ok: [node1] +ok: [node3] - - Options +Indexes +FollowSymlinks +Includes - Order allow,deny - Allow from all - - -``` - - - -### Step 6 - Test the role - -You are ready to test the role against `node2`. But since a role cannot be assigned to a node directly, first create a playbook which connects the role and the host. Create the file `test_apache_role.yml` in the directory `~/ansible-files`: +TASK [apache : Install Apache web server] ************************************** +changed: [node1] +changed: [node2] +changed: [node3] -```yaml ---- -- name: use apache_vhost role playbook - hosts: node2 - become: true +TASK [apache : Ensure Apache is running and enabled] *************************** +changed: [node2] +changed: [node1] +changed: [node3] - pre_tasks: - - ansible.builtin.debug: - msg: 'Beginning web server configuration.' +TASK [apache : Deploy custom index.html] *************************************** +changed: [node1] +changed: [node2] +changed: [node3] - roles: - - apache_vhost +RUNNING HANDLER [apache : Reload Firewall] ************************************* +ok: [node2] +ok: [node1] +ok: [node3] - post_tasks: - - ansible.builtin.debug: - msg: 'Web server has been configured.' +PLAY RECAP ********************************************************************* +node1 : ok=5 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 +node2 : ok=5 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 +node3 : ok=5 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 ``` -Note the `pre_tasks` and `post_tasks` keywords. Normally, the tasks of roles execute before the tasks of a playbook. To control order of execution `pre_tasks` are performed before any roles are applied. The `post_tasks` are performed after all the roles have completed. Here we just use them to better highlight when the actual role is executed. +### Step 5 - Verify the Apache is Running -Now you are ready to run your playbook: +Once the playbook has completed, verify that `httpd` is indeed running on all the web nodes. ```bash -[student@ansible-1 ansible-files]$ ansible-navigator run test_apache_role.yml +[rhel@control ~]$ ssh node1 "systemctl status httpd" +● httpd.service - The Apache HTTP Server + Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; vendor preset: disabled) + Active: active (running) since Mon 2024-01-29 16:49:13 UTC; 3min 46s ago ``` -Run a curl command against `node2` to confirm that the role worked: - -```bash -[student@ansible-1 ansible-files]$ curl -s http://node2:8080 -simple vhost index -``` - -Congratulations! You have successfully completed this exercise! - -## Troubleshooting problems - -Did the final curl work? You can see what ports the web server is running by using the ss command: - ```bash -#> sudo ss -tulpn | grep httpd +[rhel@control ~]$ ssh node2 "systemctl status httpd" +● httpd.service - The Apache HTTP Server + Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; vendor preset: disabled) + Active: active (running) since Mon 2024-01-29 16:49:13 UTC; 3min 58s ago ``` -There should be a line like this: +Once `httpd` has been verified it is running, check to see if the Apache webserver is serving the appropriate `index.html` file: ```bash -tcp LISTEN 0 511 *:8080 *:* users:(("httpd",pid=182567,fd=4),("httpd",pid=182566,fd=4),("httpd",pid=182565,fd=4),("httpd",pid=182552,fd=4)) +[student@ansible-1 lab_inventory]$ curl http://node1 + + +Welcome to node1 + + +

Hello from node1

+ + ``` -Pay close attention to the fifth column of the above output. It should be `*:8080`. If it is `*:80` instead or if it is not working, then make sure that the `/etc/httpd/conf/httpd.conf` file has `Listen 8080` in it. This should have been changed by [Exercise 1.5](../1.5-handlers) --- **Navigation** diff --git a/exercises/ansible_rhel/1.8-troubleshoot/README.es.md b/exercises/ansible_rhel/1.8-troubleshoot/README.es.md new file mode 100644 index 000000000..eac154cbe --- /dev/null +++ b/exercises/ansible_rhel/1.8-troubleshoot/README.es.md @@ -0,0 +1,152 @@ + +# Ejercicio del Taller - Depuración y Manejo de Errores + +**Leer esto en otros idiomas**: +
![uk](../../../images/uk.png) [English](README.md), ![japan](../../../images/japan.png)[日本語](README.ja.md), ![brazil](../../../images/brazil.png) [Portugues do Brasil](README.pt-br.md), ![france](../../../images/fr.png) [Française](README.fr.md),![Español](../../../images/col.png) [Español](README.es.md). + +## Tabla de Contenidos + +- [Objetivo](#objetivo) +- [Guía](#guía) + - [Paso 1 - Introducción a la Depuración en Ansible](#paso-1---introducción-a-la-depuración-en-ansible) + - [Paso 2 - Utilizando el Módulo de Depuración](#paso-2---utilizando-el-módulo-de-depuración) + - [Paso 3 - Manejo de Errores con Bloques](#paso-3---manejo-de-errores-con-bloques) + - [Paso 4 - Ejecución en Modo Verbose](#paso-4---ejecución-en-modo-verbose) + - [Resumen](#resumen) + +## Objetivo + +Basándonos en el conocimiento fundamental de ejercicios anteriores, esta sesión se centra en la depuración y el manejo de errores dentro de Ansible. Aprenderás técnicas para solucionar problemas en los playbooks, gestionar errores de manera elegante y asegurar que tu automatización sea robusta y fiable. + +## Guía + +### Paso 1 - Introducción a la Depuración en Ansible + +La depuración es una habilidad crítica para identificar y resolver problemas dentro de tus playbooks de Ansible. Ansible proporciona varios mecanismos para ayudarte a depurar tus scripts de automatización, incluyendo el módulo debug, niveles de verbosidad aumentados y estrategias de manejo de errores. + +### Paso 2 - Utilizando el Módulo de Depuración + +El módulo `debug` es una herramienta simple pero poderosa para imprimir los valores de las variables, lo cual puede ser instrumental para entender el flujo de ejecución del playbook. + +En este ejemplo, añade tareas de depuración a tu rol de Apache en el archivo `tasks/main.yml` para mostrar el valor de las variables o mensajes. + +#### Implementar Tareas de Depuración: + +Inserta tareas de depuración para mostrar los valores de las variables o mensajes personalizados para la solución de problemas: + +```yaml +- name: Display Variable Value + ansible.builtin.debug: + var: apache_service_name + +- name: Display Custom Message + ansible.builtin.debug: + msg: "Apache service name is {{ apache_service_name }}" +``` + +### Paso 3 - Manejo de Errores con Bloques + +Ansible permite agrupar tareas usando `block` y manejar errores con secciones de rescate usando `rescue`, similar a try-catch en la programación tradicional. + +En este ejemplo, añade un bloque para manejar errores potenciales durante la configuración de Apache dentro del archivo `tasks/main.yml`. + +1. Agrupar Tareas y Manejar Errores: + +Envuelve las tareas que podrían fallar potencialmente en un bloque y define una sección de rescate para manejar los errores: + +```yaml +- name: Apache Configuration with Potential Failure Point + block: + - name: Copy Apache configuration + ansible.builtin.copy: + src: "{{ apache_conf_src }}" + dest: "/etc/httpd/conf/httpd.conf" + rescue: + - name: Handle Missing Configuration + ansible.builtin.debug: + msg: "Missing Apache configuration file '{{ apache_conf_src }}'. Using default settings." +``` + +2. Añade una variable `apache_conf_src` dentro de `vars/main.yml` del rol de apache. + +```yaml +apache_conf_src: "files/missing_apache.conf" +``` + +> NOTA: El archivo (`files/missing_apache.conf`) no existe intencionalmente para que podamos activar la sección de rescate de nuestro `tasks/main.yml`. No debe ser creado. + +### Paso 4 - Ejecución en Modo Verbose + +El modo verbose de Ansible (`-v`, `-vv`, `-vvv`, o `-vvvv`) aumenta el detalle de la salida, proporcionando más información sobre la ejecución del playbook y problemas potenciales. + +#### Ejecutar el Playbook en Modo Verbose: + +Ejecuta tu playbook con la opción `-vv` para obtener logs detallados: + +```bash +ansible-navigator run deploy_apache.yml -m stdout -vv +``` + +``` +. +. +. + + +TASK [apache : Display Variable Value] ***************************************** +task path: /home/rhel/ansible-files/roles/apache/tasks/main.yml:20 +ok: [node1] => { + "apache_service_name": "httpd" +} +ok: [node2] => { + "apache_service_name": "httpd" +} +ok: [node3] => { + "apache_service_name": "httpd" +} + +TASK [apache : Display Custom Message] ***************************************** +task path: /home/rhel/ansible-files/roles/apache/tasks/main.yml:24 +ok: [node1] => { + "msg": "Apache service name is httpd" +} +ok: [node2] => { + "msg": "Apache service name is httpd" +} +ok: [node3] => { + "msg": "Apache service name is httpd" +} + +TASK [apache : Copy Apache configuration] ************************************** +task path: /home/rhel/ansible-files/roles/apache/tasks/main.yml:30 +An exception occurred during task execution. To see the full traceback, use -vvv. The error was: If you are using a module and expect the file to exist on the remote, see the remote_src option +fatal: [node3]: FAILED! => {"changed": false, "msg": "Could not find or access 'files/missing_apache.conf'\nSearched in:\n\t/home/student/lab_inventory/roles/apache/files/files/missing_apache.conf\n\t/home/student/lab_inventory/roles/apache/files/missing_apache.conf\n\t/home/student/lab_inventory/roles/apache/tasks/files/files/missing_apache.conf\n\t/home/student/lab_inventory/roles/apache/tasks/files/missing_apache.conf\n\t/home/student/lab_inventory/files/files/missing_apache.conf\n\t/home/student/lab_inventory/files/missing_apache.conf on the Ansible Controller.\nIf you are using a module and expect the file to exist on the remote, see the remote_src option"} +An exception occurred during task execution. To see the full traceback, use -vvv. The error was: If you are using a module and expect the file to exist on the remote, see the remote_src option +fatal: [node1]: FAILED! => {"changed": false, "msg": "Could not find or access 'files/missing_apache.conf'\nSearched in:\n\t/home/student/lab_inventory/roles/apache/files/files/missing_apache.conf\n\t/home/student/lab_inventory/roles/apache/files/missing_apache.conf\n\t/home/student/lab_inventory/roles/apache/tasks/files/files/missing_apache.conf\n\t/home/student/lab_inventory/roles/apache/tasks/files/missing_apache.conf\n\t/home/student/lab_inventory/files/files/missing_apache.conf\n\t/home/student/lab_inventory/files/missing_apache.conf on the Ansible Controller.\nIf you are using a module and expect the file to exist on the remote, see the remote_src option"} +An exception occurred during task execution. To see the full traceback, use -vvv. The error was: If you are using a module and expect the file to exist on the remote, see the remote_src option +fatal: [node2]: FAILED! => {"changed": false, "msg": "Could not find or access 'files/missing_apache.conf'\nSearched in:\n\t/home/student/lab_inventory/roles/apache/files/files/missing_apache.conf\n\t/home/student/lab_inventory/roles/apache/files/missing_apache.conf\n\t/home/student/lab_inventory/roles/apache/tasks/files/files/missing_apache.conf\n\t/home/student/lab_inventory/roles/apache/tasks/files/missing_apache.conf\n\t/home/student/lab_inventory/files/files/missing_apache.conf\n\t/home/student/lab_inventory/files/missing_apache.conf on the Ansible Controller.\nIf you are using a module and expect the file to exist on the remote, see the remote_src option"} + + +TASK [apache : Handle Missing Configuration] *********************************** +task path: /home/rhel/ansible-files/roles/apache/tasks/main.yml:39 +ok: [node1] => { + "msg": "Missing Apache configuration file 'files/missing_apache.conf'. Using default settings." +} +ok: [node2] => { + "msg": "Missing Apache configuration file 'files/missing_apache.conf'. Using default settings." +} +ok: [node3] => { + "msg": "Missing Apache configuration file 'files/missing_apache.conf'. Using default settings." +} + +PLAY RECAP ********************************************************************* +node1 : ok=7 changed=0 unreachable=0 failed=0 skipped=0 rescued=1 ignored=0 +node2 : ok=7 changed=0 unreachable=0 failed=0 skipped=0 rescued=1 ignored=0 +node3 : ok=7 changed=0 unreachable=0 failed=0 skipped=0 rescued=1 ignored=0 + +``` + +Observa cómo el playbook muestra que hubo un error al copiar el archivo de configuración de Apache, pero el playbook pudo manejarlo a través del bloque de rescate que se proporcionó. Si te fijas en la tarea final 'Handle Missing Configuration', detalla que faltaba el archivo y que se utilizarían las configuraciones pred + +## Resumen +En este ejercicio, has explorado técnicas esenciales de depuración y mecanismos de manejo de errores en Ansible. Al incorporar tareas de depuración, utilizar bloques para el manejo de errores y aprovechar el modo detallado (verbose mode), puedes solucionar problemas de manera efectiva y mejorar la fiabilidad de tus playbooks de Ansible. Estas prácticas son fundamentales en el desarrollo de una automatización robusta con Ansible que pueda manejar de forma elegante los problemas inesperados y asegurar resultados consistentes y predecibles. diff --git a/exercises/ansible_rhel/1.8-troubleshoot/README.fr.md b/exercises/ansible_rhel/1.8-troubleshoot/README.fr.md new file mode 100644 index 000000000..e69de29bb diff --git a/exercises/ansible_rhel/1.8-troubleshoot/README.ja.md b/exercises/ansible_rhel/1.8-troubleshoot/README.ja.md new file mode 100644 index 000000000..e69de29bb diff --git a/exercises/ansible_rhel/1.8-troubleshoot/README.md b/exercises/ansible_rhel/1.8-troubleshoot/README.md new file mode 100644 index 000000000..c00ccbeb5 --- /dev/null +++ b/exercises/ansible_rhel/1.8-troubleshoot/README.md @@ -0,0 +1,162 @@ +# Workshop Exercise - Debugging and Error Handling + +**Read this in other languages**: +
![uk](../../../images/uk.png) [English](README.md), ![japan](../../../images/japan.png)[日本語](README.ja.md), ![brazil](../../../images/brazil.png) [Portugues do Brasil](README.pt-br.md), ![france](../../../images/fr.png) [Française](README.fr.md),![Español](../../../images/col.png) [Español](README.es.md). + + +## Table of Contents + +- [Objective](#objective) +- [Guide](#guide) + - [Step 1 - Introduction to Debugging in Ansible](#step-1---introduction-to-debugging-in-ansible) + - [Step 2 - Utilizing the Debug Module](#step-2---utilizing-the-debug-module) + - [Step 3 - Error Handling with Blocks](#step-3---error-handling-with-blocks) + - [Step 4 - Running with Verbose Mode](#step-4---running-with-verbose-mode) + - [Summary](#summary) + +## Objective + +Building on the foundational knowledge from previous exercises, this session focuses on debugging and error handling within Ansible. You'll learn techniques to troubleshoot playbooks, manage errors gracefully, and ensure your automation is robust and reliable. + +## Guide + +### Step 1 - Introduction to Debugging in Ansible + +Debugging is a critical skill for identifying and resolving issues within your Ansible playbooks. Ansible provides several mechanisms to help you debug your automation scripts, including the debug module, increased verbosity levels, and error handling strategies. + +### Step 2 - Utilizing the Debug Module + +The `debug` module is a simple yet powerful tool for printing variable values, which can be instrumental in understanding playbook execution flow. + +In this example, add debug tasks to your Apache role in the `tasks/main.yml` to output the value of variables or messages. + +#### Implement Debug Tasks: + +Insert debug tasks to display the values of variables or custom messages for troubleshooting: + +```yaml +- name: Display Variable Value + ansible.builtin.debug: + var: apache_service_name + +- name: Display Custom Message + ansible.builtin.debug: + msg: "Apache service name is {{ apache_service_name }}" +``` + +### Step 3 - Error Handling with Blocks + +Ansible allows grouping tasks using `block` and handling errors with `rescue` sections, similar to try-catch in traditional programming. + +In this example, add a block to handle potential errors during the Apache configuration within the `tasks/main.yml` file. + +1. Group Tasks and Handle Errors: + +Wrap tasks that could potentially fail in a block and define a rescue section to handle errors: + +```yaml +- name: Apache Configuration with Potential Failure Point + block: + - name: Copy Apache configuration + ansible.builtin.copy: + src: "{{ apache_conf_src }}" + dest: "/etc/httpd/conf/httpd.conf" + rescue: + - name: Handle Missing Configuration + ansible.builtin.debug: + msg: "Missing Apache configuration file '{{ apache_conf_src }}'. Using default settings." +``` + +2. Add an `apache_conf_src` variable within `vars/main.yml` of the apache role. + +```yaml +apache_conf_src: "files/missing_apache.conf" +``` + +> NOTE: This file explicitly does not exist so that we can trigger the rescue portion from our `tasks/main.yml` + +### Step 4 - Running with Verbose Mode + +Ansible's verbose mode (-v, -vv, -vvv, or -vvvv) increases the output detail, providing more insights into playbook execution and potential issues. + +#### Execute Playbook in Verbose Mode: + +Run your playbook with the `-vv` option to get detailed logs: + +```bash +ansible-navigator run deploy_apache.yml -m stdout -vv +``` + +``` +. +. +. + + +TASK [apache : Display Variable Value] ***************************************** +task path: /home/rhel/ansible-files/roles/apache/tasks/main.yml:20 +ok: [node1] => { + "apache_service_name": "httpd" +} +ok: [node2] => { + "apache_service_name": "httpd" +} +ok: [node3] => { + "apache_service_name": "httpd" +} + +TASK [apache : Display Custom Message] ***************************************** +task path: /home/rhel/ansible-files/roles/apache/tasks/main.yml:24 +ok: [node1] => { + "msg": "Apache service name is httpd" +} +ok: [node2] => { + "msg": "Apache service name is httpd" +} +ok: [node3] => { + "msg": "Apache service name is httpd" +} + +TASK [apache : Copy Apache configuration] ************************************** +task path: /home/rhel/ansible-files/roles/apache/tasks/main.yml:30 +An exception occurred during task execution. To see the full traceback, use -vvv. The error was: If you are using a module and expect the file to exist on the remote, see the remote_src option +fatal: [node3]: FAILED! => {"changed": false, "msg": "Could not find or access 'files/missing_apache.conf'\nSearched in:\n\t/home/student/lab_inventory/roles/apache/files/files/missing_apache.conf\n\t/home/student/lab_inventory/roles/apache/files/missing_apache.conf\n\t/home/student/lab_inventory/roles/apache/tasks/files/files/missing_apache.conf\n\t/home/student/lab_inventory/roles/apache/tasks/files/missing_apache.conf\n\t/home/student/lab_inventory/files/files/missing_apache.conf\n\t/home/student/lab_inventory/files/missing_apache.conf on the Ansible Controller.\nIf you are using a module and expect the file to exist on the remote, see the remote_src option"} +An exception occurred during task execution. To see the full traceback, use -vvv. The error was: If you are using a module and expect the file to exist on the remote, see the remote_src option +fatal: [node1]: FAILED! => {"changed": false, "msg": "Could not find or access 'files/missing_apache.conf'\nSearched in:\n\t/home/student/lab_inventory/roles/apache/files/files/missing_apache.conf\n\t/home/student/lab_inventory/roles/apache/files/missing_apache.conf\n\t/home/student/lab_inventory/roles/apache/tasks/files/files/missing_apache.conf\n\t/home/student/lab_inventory/roles/apache/tasks/files/missing_apache.conf\n\t/home/student/lab_inventory/files/files/missing_apache.conf\n\t/home/student/lab_inventory/files/missing_apache.conf on the Ansible Controller.\nIf you are using a module and expect the file to exist on the remote, see the remote_src option"} +An exception occurred during task execution. To see the full traceback, use -vvv. The error was: If you are using a module and expect the file to exist on the remote, see the remote_src option +fatal: [node2]: FAILED! => {"changed": false, "msg": "Could not find or access 'files/missing_apache.conf'\nSearched in:\n\t/home/student/lab_inventory/roles/apache/files/files/missing_apache.conf\n\t/home/student/lab_inventory/roles/apache/files/missing_apache.conf\n\t/home/student/lab_inventory/roles/apache/tasks/files/files/missing_apache.conf\n\t/home/student/lab_inventory/roles/apache/tasks/files/missing_apache.conf\n\t/home/student/lab_inventory/files/files/missing_apache.conf\n\t/home/student/lab_inventory/files/missing_apache.conf on the Ansible Controller.\nIf you are using a module and expect the file to exist on the remote, see the remote_src option"} + + +TASK [apache : Handle Missing Configuration] *********************************** +task path: /home/rhel/ansible-files/roles/apache/tasks/main.yml:39 +ok: [node1] => { + "msg": "Missing Apache configuration file 'files/missing_apache.conf'. Using default settings." +} +ok: [node2] => { + "msg": "Missing Apache configuration file 'files/missing_apache.conf'. Using default settings." +} +ok: [node3] => { + "msg": "Missing Apache configuration file 'files/missing_apache.conf'. Using default settings." +} + +PLAY RECAP ********************************************************************* +node1 : ok=7 changed=0 unreachable=0 failed=0 skipped=0 rescued=1 ignored=0 +node2 : ok=7 changed=0 unreachable=0 failed=0 skipped=0 rescued=1 ignored=0 +node3 : ok=7 changed=0 unreachable=0 failed=0 skipped=0 rescued=1 ignored=0 + +``` + +Notice how the playbook shows there was an error copying the Apache Configuration file but the playbook was able to handle it via the rescue block that was provided. If you notice the final task ‘Handle Missing Configuration’ details that the file was missing and it would use the default settings. + +The final Play Recap shows us that there was a rescued block used via the `rescued=1` per node in the web group. + +## Summary + +In this exercise, you've explored essential debugging techniques and error handling mechanisms in Ansible. By incorporating debugging tasks, using blocks for error handling, and leveraging verbose mode, you can effectively troubleshoot and enhance the reliability of your Ansible playbooks. These practices are fundamental in developing robust Ansible automation that can gracefully handle unexpected issues and ensure consistent, predictable outcomes. + +--- +**Navigation** +
+[Previous Exercise](../1.7-role) - [Next Exercise](../2.1-intro) + +[Click here to return to the Ansible for Red Hat Enterprise Linux Workshop](../README.md#section-1---ansible-engine-exercises) diff --git a/exercises/ansible_rhel/1.8-troubleshoot/README.pt-br.md b/exercises/ansible_rhel/1.8-troubleshoot/README.pt-br.md new file mode 100644 index 000000000..e69de29bb