Exercise 1.3 - Using Variables, Loops, and Handlers

Return to Workshop

Exercise Description

In previous exercises, we showed you the basics of the Ansible core. In the next few exercises, we are going to teach some more advanced Ansible skills that will add flexibility and power to your playbooks.

Ansible exists to make tasks simple and repeatable. We also know that not all systems are exactly alike and often require some slight customization to the way an Ansible playbook is run. Variables, loops and handlers make customization easier.

Variables are used to address differences between your systems, enabling you to account for a change in port, IP address or directory.

Loops enable us to repeat the same task over and over again. For example, lets say you want to install 10 packages. By using an Ansible loop, you can do that in a single task.

Handlers are the way in which we restart services. Did you just deploy a new config file, install a new package? If so, you may need to restart a service, for those changes to take effect. We do that with a handler.

For a full understanding of variables, loops, and handlers; check out our Ansible documentation on these subjects.
Ansible Variables
Ansible Loops
Ansible Handlers

Section 1: Running the playbook

To begin, we are going to create a new playbook, but it should look very familiar to the one you created in Exercise 1.2

We are now going to run your brand-new playbook, on your two web nodes. To do this, you are going to use the ansible-playbook command.

Step 1: Create a new project and playbook

Navigate to the '~' directory create a new project and playbook.

cd ~/
mkdir apache-basic-playbook
cd apache-basic-playbook
vim site.yml

Step 2: Add a play definition and variables

Add a play definition and some variables to your playbook. These include additional packages that your playbook will install on your web servers, plus some web server-specific configurations.

---
- hosts: web
  name: This is a play within a playbook
  become: yes
  vars:
    httpd_packages:
      - httpd
      - python3-mod_wsgi
    apache_test_message: This is a test message
    apache_webserver_port: 80

Step 3: Add a task

Add a new task called install httpd packages.

  tasks:
    - name: install httpd packages
      package:
        name: "{{ item }}"
        state: present
      with_items: "{{ httpd_packages }}"
      notify: restart apache service

Explanation of the install httpd packages task actions.

  • vars: You’ve told Ansible the next thing it sees will be a variable name

  • httpd_packages You are defining a list-type variable called httpd_packages. What follows is a list of those packages

  • {{ item }} You are telling Ansible that this will expand into a list item like httpd and python3-mod_wsgi.

  • with_items: "{{ httpd_packages }} This is your loop, which is instructing Ansible to perform this task on every item in httpd_packages

  • notify: restart apache service This statement is a handler, so we’ll come back to it in Section 3.

Section 2: Deploying files and starting a service

When you need to do pretty much anything with files and directories, use one of the Ansible Files modules. In this case, we’ll leverage the file and template modules.

After that, you will define a task to start the apache service.

Step 1: Create a template directory

Create a templates directory in your project directory and download two files.

mkdir templates
cd templates
curl -O https://raw.githubusercontent.com/ansible/lightbulb/master/examples/apache-basic-playbook/templates/httpd.conf.j2
curl -O https://raw.githubusercontent.com/ansible/lightbulb/master/examples/apache-basic-playbook/templates/index.html.j2

Step 2: Add file and service tasks

Add some file tasks and a service task to your playbook.

    - name: site-enabled directory is present
      file:
        name: /etc/httpd/conf/sites-enabled
        state: directory

    - name: copy httpd.conf
      template:
        src: templates/httpd.conf.j2
        dest: /etc/httpd/conf/httpd.conf
      notify: restart apache service

    - name: copy index.html
      template:
        src: templates/index.html.j2
        dest: /var/www/html/index.html

    - name: httpd is started and enabled
      service:
        name: httpd
        state: started
        enabled: yes

What actions are performed by the playbook we just wrote?

  • file: This module is used to create, modify, delete files, directories, and symlinks.

  • template: This module specifies that a jinja2 template is being used and deployed. template is part of the Files module family and we encourage you to check out all of the other file-management modules here.

  • jinja-who? - Not to be confused with 2013’s blockbuster "Ninja II - Shadow of a Tear", jinja2 is used in Ansible to transform data inside a template expression, i.e. filters.

  • service - The Service module starts/stops/restarts services.

Section 3: Defining and using handlers

Often, we may find ourselves needing to restart a service or process. Reasons may include the deployment of a configuration file, installation of a new package, etc. Here, we are going to learn about using handlers in this situation.

There are really two parts to this Section; adding a handler to the playbook and calling the handler after the a task. We will start with the former.

Step 1: Define a handler

  handlers:
    - name: restart apache service
      service:
        name: httpd
        state: restarted
        enabled: yes
  • handler: This is telling the play that the tasks: are over, and now we are defining handlers:. Everything below that looks the same as any other task, i.e. you give it a name, a module, and the options for that module. This is the definition of a handler.

Step 2: Calling the handlers

You can’t have a former if you don’t mention the latter.

  • notify: restart apache service …​and here is your latter. Finally! The notify statement is the invocation of a handler by name. Quite the reveal, we know. You already noticed that you’ve added a notify statement to the copy httpd.conf task, now you know why.

Section 4: Review

Your new, improved playbook is done! But don’t run it just yet, we’ll do that in our next exercise. For now, let’s take a second look to make sure everything looks the way you intended. If not, now is the time to fix it up. The figure below shows line counts and spacing.

---
- hosts: web
  name: This is a play within a playbook
  become: yes
  vars:
    httpd_packages:
      - httpd
      - python3-mod_wsgi
    apache_test_message: This is a test message
    apache_webserver_port: 80

  tasks:
    - name: httpd packages are present
      package:
        name: "{{ item }}"
        state: present
      with_items: "{{ httpd_packages }}"
      notify: restart apache service

    - name: site-enabled directory is present
      file:
        name: /etc/httpd/conf/sites-enabled
        state: directory

    - name: copy httpd.conf
      template:
        src: templates/httpd.conf.j2
        dest: /etc/httpd/conf/httpd.conf
      notify: restart apache service

    - name: copy index.html
      template:
        src: templates/index.html.j2
        dest: /var/www/html/index.html

    - name: httpd is started and enabled
      service:
        name: httpd
        state: started
        enabled: yes

  handlers:
    - name: restart apache service
      service:
        name: httpd
        state: restarted
        enabled: yes

Workshop Details

Domain Red Hat Logo
Workshop
Student ID

Return to Workshop