Introduction to Ansible 2 – vol.2

Ansible

Going fordward with Ansible

Variables

The last post shown how a playbook was able to install and configure an Apache server and also to open needed ports on the firewall. If we wanted to install a FTP server we should create a new playbook or duplicate a task, but thanks to variables we are going to see how to reuse the same task on the same playbook.

This is the original playbook:

$ cat playbooks/prepare-WebServers.yaml
---
- name: Install and configure webservers services
  hosts: webservers
  remote_user: centos
  become: True
  tasks:

  - block:
    - name: Install Apache package
      yum:
        name: httpd 
        state: installed
    - name: Install Firewalld package
      yum:
        name: firewalld
        state: installed

  - block:
    - name: Start and enable Apache service
      service:
        name: httpd
        enabled: true
        state: started
    - name: Start and enable Firewalld service
      service:
        name: firewalld
        enabled: true
        state: started

  - block:
    - name: Enable firewall rules for Apache
      firewalld:
        state: enabled
        service: http
        permanent: true
        immediate: true

  - block:
    - name: create index file
      shell: echo 'Hello World!' > /var/www/html/index.html
...

VARIABLES

Thanks to variables usage we can set some values outside the playbook. e.g. it is possible to install NGING instead of Apache web server.

The variables can be defined through different levels, shown from lower to higher precedence order. NODE: there are more levels, but here are most usual.

  • inventory_dir/group_vars/all
  • playbook_dir/group_vars/all
  • inventory_dir/group_vars/*
  • playbook_dir/group_vars/*
  • inventory_dir/host_vars/*
  • playbook_dir/host_vars/*
  • play vars
  • play vars_files
  • role vars
  • block vars
  • task vars
  • include_vars
  • extra vars (option –extra-vars|-e in command line)
GROUP_VARS and HOST_VARS

The group_vars and host_vars, defined at inventory or playbook level, allow to define a set of variables to use  on hosts or hosts groups. Ansible sets as a good practice:

A lot of folks may ask about how variables override another. Ultimately it’s Ansible’s philosophy that it’s better you know where to put a variable, and then you have to think about it a lot less.

Avoid defining the variable “x” in 47 places and then ask the question “which x gets used”. Why? Because that’s not Ansible’s Zen philosophy of doing things.

There is only one Empire State Building. One Mona Lisa, etc. Figure out where to define a variable, and don’t make it complicated.

So lets configure our webserver package in a variable to be able to change their value without modify the playbook.

$ cat playbooks/group_vars/webservers.yaml
---
packages: nginx
services: http
...
$ cat playbooks/prepare-WebServers.yaml
---
- name: Install and configure webservers services
  hosts: webservers
  remote_user: centos
  become: True
  tasks:

  - block:
    - name: Install WebServer package
      yum:
        name: "{{ package }}"
        state: installed
    - name: Install Firewalld package
      yum:
        name: firewalld
        state: installed

  - block:
    - name: Start and enable Apache service
      service:
        name: "{{ services }}"
        enabled: true
        state: started
    - name: Start and enable Firewalld service
      service:
        name: firewalld
        enabled: true
        state: started

  - block:
    - name: Enable firewall rules for Apache
      firewalld:
        state: enabled
        service: http
        permanent: true
        immediate: true

  - block:
    - name: create index file
      shell: echo 'Hello World!' > /var/www/html/index.html
...

Basic loops

Another feature we can find on the Ansible playbooks is the loops, that allow us to run a task n times with different values. For that we will use the keyword with_items that will receive a list to loop over, and will generate a variable called item, with a task scope that will have the value of the loop.

In the next example I will take the install packages task and I will do a loop with the packages httpd and firewalld. Because of this we avoid to repeat a task, making easier to read and configure the playbook.

    - name: Install packages
      yum:
        name: "{{ item }}"
        state: installed
      with_items:
        - httpd
        - firewalld

You can also pass the variables as elements on the loop:

$ cat playbooks/group_vars/webservers
---
packages:
  - httpd
  - firewalld
...

$ cat playbooks/prepare-WebServers.yaml
    - name: Install packages
      yum: 
        name: "{{ item }}" 
        state: installed 
      with_items: 
        - "{{ packages }}"

Registering variables

Ansible allows to register the return values from a task, so we can work with them on another task. Depending the ansible module used, the variable will contain different types. The keyword is register

Lets take a look and later analyze the next example.

$ cat playbooks/test-Register.yaml
 tasks:
 - block:
   - name: Register date
     command: date
     register: date_registered
 
 - block:
   - name: Check
     debug:
       var: date_registered

The result will be:

ok: [localhost] => {
"date_registered": {
"changed": true,
"cmd": [
"date"
],
"delta": "0:00:00.106724",
"end": "2017-04-07 08:03:11.264052",
"rc": 0,
"start": "2017-04-07 08:03:11.157328",
"stderr": "",
"stdout": "Fri Apr 7 08:03:11 UTC 2017",
"stdout_lines": [
"Fri Apr 7 08:03:11 UTC 2017"
],
"warnings": []
}
}

If you take a look to the result, you can use the values in another tasks, as these are defined as elements inside an object.

A simple example would be to show the system date, so I will use the stdout_lines element from the date_registered object.

$ cat playbooks/test-Register.yaml
 tasks:
 - block:
   - name: Register date
     command: date
     register: date_registered
 
 - block:
   - name: Check
     debug:
       var: date_registered.stdout_lines

Conditions

We can not only use variables as parameter form some elements in the tasks but we also can use the variables to conditionally run another tasks. The keyword is when

As example we can define a task that creates the index.html file only if the package httpd is installed.

$ cat playbooks/group_vars/webservers
---
packages:
  - httpd
  - firewalld
...
$ cat playbooks/prepare-WebServers.yaml
    - name: Create index.html if httpd is in packages
      copy: 
        dest: /var/www/html/index.html
        force: no
        content: |
          <html>
            <body>
              <h1>Hello World!</h1>
            </body>
          </html> 
      with_items: "{{ packages }}"
      when: item == 'httpd'

Up to this point. I think that to be Volume 2 of this tutorial, I have advanced a lot. See you!!

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.