Defining variables

In this section, we will cover the topic of variables and how they can be defined in Ansible. You will learn how variables should be defined step by step and understand how to work with them in Ansible.

Although automation removes much of the repetition from previously manual tasks, not every single system is identical. If two systems differ in some minor way, you could write two unique playbooks—one for each system. However, this would be inefficient and wasteful, as well as difficult to manage as time goes on (for example, if the code in one playbook is changed, how can you ensure that it is updated in the second variant?). 

Equally, you might need to use a value from one system in another—perhaps you need to obtain the hostname of a database server and make it available to another. All of these issues can be addressed with variables as they allow the same automation code to run with parameter variations, as well as values to pass from one system to another (although this must be handled with some care).

Let's get started with a practical look at defining variables in Ansible.

Variables in Ansible should have well-formatted names that adhere to the following rules:

  • The name of the variable must only include letters, underscores, and numbers—spaces are not allowed.
  • The name of the variable can only begin with a letter—they can contain numbers, but cannot start with one.

For example, the following are good variable names:

  • external_svc_port
  • internal_hostname_ap1

The following examples are all invalid, however, and cannot be used:

  • appserver-zone-na
  • cache server ip
  • dbms.server.port
  • 01appserver

As discussed in the Learning the YAML syntax section, variables can be defined in a dictionary structure, such as the following. All values are declared in key-value pairs:

region:
east: app
west: frontend
central: cache

In order to retrieve a specific field from the preceding dictionary structure, you can use either one of the following notations:

# bracket notation
region['east']

# dot notation
region.east

There are some exceptions to this; for example, you should use bracket notation if the variable name starts and ends with two underscores (for example, __variable__) or contains known public attributes, such as the following:

  • as_integer_ratio
  • symmetric_difference

You can find more information on this at https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#creating-valid-variable-names.

This dictionary structure is valuable when defining host variables; although earlier in this chapter we worked with a fictional set of employee records defined as an Ansible variables file, you could use this to specify something, such as some redis server parameters:

---
redis:
- server: cacheserver01.example.com
port: 6379
slaveof: cacheserver02.example.com

These could then be applied through your playbook and one common playbook could be used for all redis servers, regardless of their configuration, as changeable parameters such as the port and master servers are all contained in the variables.

You can also pass set variables directly in a playbook, and even pass them to roles that you call. For example, the following playbook code calls four hypothetical roles and each assigns a different value to the username variable for each one. These roles could be used to set up various administration roles on a server (or multiple servers), with each passing a changing list of usernames as people come and go from the company:

roles:
- role: dbms_admin
vars:
username: James
- role: system_admin
vars:
username: John
- role: security_amdin
vars:
username: Rock
- role: app_admin
vars:
username: Daniel

To access variables from within a playbook, you simply place the variable name inside quoted pairs of curly braces. Consider the following example playbook (based loosely on our previous redis example):

---
- name: Display redis variables
hosts: all

vars:
redis:
server: cacheserver01.example.com
port: 6379
slaveof: cacheserver02.example.com

tasks:
- name: Display the redis port
debug:
msg: "The redis port for {{ redis.server }} is {{ redis.port }}"

Here, we define a variable in the playbook itself called redis. This variable is a dictionary, containing a number of parameters that might be important for our server. To access the contents of these variables, we use pairs of curly braces around them (as described previously) and the entire string is encased in quotation marks, which means we don't have to individually quote the variables. If you run the playbook on a local machine, you should see an output that looks as follows:

$ ansible-playbook -i localhost, redis-playbook.yml

PLAY [Display redis variables] *************************************************

TASK [Gathering Facts] *********************************************************
ok: [localhost]

TASK [Display the redis port] **************************************************
ok: [localhost] => {
"msg": "The redis port for cacheserver01.example.com is 6379"
}

PLAY RECAP *********************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

Although we are accessing these variables here to print them in a debug message, you could use the same curly brace notation to assign them to module parameters, or for any other purpose that your playbook requires them for.

Ansible, just like many languages, has specially reserved variables that take on particular meaning in playbooks. In Ansible, these are known as magic variables and you can find a full list of them at https://docs.ansible.com/ansible/latest/reference_appendices/special_variables.html. Needless to say, you should not attempt to use any magic variable names for your own variables. Some common magic variables you might come across are as follows:

  • inventory_hostname: The hostname for the current host that is iterated over in the play
  • groups: A dictionary of the host groups in the inventory, along with the host membership of each group
  • group_names: A list of the groups the current host (specified by inventory_hostname) is part of
  • hostvars: A dictionary of all the hosts in the inventory and the variables assigned to each of them

For example, the host variables for all the hosts can be accessed at any point in the playbook using hostvars, even if you are only operating on one particular host. Magic variables are surprisingly useful in playbooks and you will rapidly start to find yourself using them, so it is important to be aware of their existence.

You should also note that you can specify Ansible variables in multiple locations. Ansible has a strict order of variable precedence and you can take advantage of this by setting default values for variables in a place that has low precedence and then overriding them later in the play. This is useful for a variety of reasons, especially where an undefined variable could cause havoc when a playbook is run (or even when the playbook would fail as a result of this). We have not yet discussed all of the places that variables can be stored, so the full list of variable precedence order is not given here.

In addition, it can change between Ansible releases, so it is important that you refer to the documentation when working with and understanding variable precedence—go to https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#variable-precedence-where-should-i-put-a-variable for more information.

That concludes our brief overview of variables in Ansible, although we will see them used again in later examples in this book. Let's now round off this chapter with a look at Jinja2 filters, which add a whole world of power to your variable definitions.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.221.53.5