Ansible Variables

Ansible supports variables that can be used to store values that can be reused throughout files in an entire Ansible project. This can help simplify creation and maintenance of a project and reduce the incidence of errors.

  • Places to define variables:
    • vars, vars_files, and vars_prompt
    • Command line:
    • Roles, blocks, and inventories
  • Essential variable use:
    • - debug: msg="Look! I'm using my variable ({ myVar )) !"
  • A note on quotes:
    • name: "({ package ))"

 

Scope of variables
Variables can be defined in a bewildering variety of places in an Ansible project. However, this can be simplified to three basic scope levels:

  • Global scope:  Variables set from the command line or Ansible configuration
  • Play scope:  Variables set in the play and related structures
  • Host scope:  Variables set on host groups and individual hosts by the inventory, fact gathering, or registered tasks
    If the same variable name is defined at more than one level, the higher wins. So variables defined by the inventory are overridden by variables defined by the playbook, which are overridden by variables defined on the command line.

 

Variables in playbooks

When writing playbooks, administrators can use their own variables and call them in a task. For example, a variable web_package can be defined with a value of httpd and called by the yum module in order to install the httpd package.

It is also possible to define playbook variables in external files. In this case, instead of using vars, the vars_files directive may be used.

The playbook variables are then defined in that file or those files in YAML format:

Once variables have been declared, administrators can use the variables in tasks. Variables are referenced by placing the variable name in double curly braces.

Important
When a variable is used as the first element to start a value, quotes are mandatory. This prevents Ansible from considering the variable as starting a YAML dictionary. The following message appears if quotes are missing:

 

Host variables and group variables
Inventory variables that apply directly to hosts fall into two broad categories:

  • host variables that apply to a specific host
  • group variables that apply to all hosts in a host group or in a group of host groups.

Host variables take precedence over group variables, but variables defined by a playbook take precedence over both. One way to define host variables and group variables is to do it directly in the inventory file. This is an older approach and not preferred, but may be encountered by users:

• This is a host variable, ansible_user, being defined for the host demo.example.com.

• In this example, a group variable user is being defined for the group servers.

• Finally, in this example a group variable user is being defined for the group servers, which happens to consist of two host groups each with two servers.

Among the disadvantages of this approach, it makes the inventory file more difficult to work with, mixes information about hosts and variables in the same file, and uses an obsolete syntax.

Using group_vars and host_vars directories
The preferred approach is to create two directories in the same working directory as the  inventory file or directory,  group_vars and host_vars. These directories contain files defining group variables and host variables, respectively.

Important
The recommended practice is to define inventory variables using host_vars and group_vars directories, and not to define them directly in the inventory file or files.

To define group variables for the group servers, a YAML file named group_vars/servers would be created, and then the contents of that file would set variables to values using the same syntax as a playbook:

Likewise, to define host variables for a particular host, a file with a name matching the host is created in host_vars to contain the host variables.

The following examples illustrate this approach in more detail. Consider the following scenario where there are two data centers to manage that has the following inventory file in ~/project/inventory:

• If a general value needs to be defined for all servers in both datacenters, a group variable can be set for datacenters:

• If the value to define varies for each datacenter, a group variable can be set for each datacenter:

• If the value to be defined varies for each host in every datacenter, using host variables is recommended:

The directory structure for project, if it contained all of the example files above, might look like this:

 

Overriding variables from the command line
Inventory variables are overridden by variables set in a playbook, but both kinds of variables may be overridden through arguments passed to the ansible or ansible-playbook commands on the command line. This can be useful in a case where the defined value for a variable needs to be overridden for a single host for a one-off run of a playbook. For example:

 

Variables and arrays
Instead of assigning a piece of configuration data that relates to the same element (a list of packages, a list of services, a list of users, etc.) to multiple variables, administrators can use arrays. One interesting consequence of this is that an array can be browsed.
For instance, consider the following snippet:

This could be rewritten as an array called users:

Users can then be accessed using the following variables:

Because the variable is defined as a Python dictionary, an alternative syntax is available.

Important
The dot notation can cause problems if the key names are the same as names of Python methods or attributes, such as discard, copy, add, and so on. Using the brackets notation can help avoid errors. Both syntaxes are valid, but to make troubleshooting easier, it is recommended that one syntax used consistently in all files throughout any given Ansible project.

 

Registered variables
Administrators can capture the output of a command by using the register statement. The output is saved into a variable that could be used later for either debugging purposes or in order to achieve something else, such as a particular configuration based on a command’s output. The following playbook demonstrates how to capture the output of a command for debugging purposes:

When the playbook is run, the debug module is used to dump the value of the install_result registered variable to the terminal.

 

Dictionary Variables

  • Yaml formatting allows for python style dictionaries to be used as variables
  • There are two formats to access dictionary values:
    • employee[‚name’]
    • employee.name
  • The bracket syntax is safer as the dot notation can have collisions with python in certain circumstances

 

Magic Variables and Filters

  • Ansible defines several special variables knowns as magic variables
  • You can use the variable hostvars to look at facts about other hosts in the inventory

{{ hostvars['node1']['ansible_distribution'] }}

  • There is also a groups variable that provides inventory information

{{ groups['webservers'] }}

  • Jinja2 filters can be useful in manipulating text format

{{ groups['webservers']|join(' ') }}

  • See

http://jinja.pocoo.org/docs/2.10/templates/#builtin-filters

 

Example 1. of playboook with variables.

The playbook writes to the inv.txt  list of host which belongs to the labservers groups.

We can modificate playbook9 to use jinja filter:

Now the the servers will be listed with spaces:

 

Example 2.

We have a file users.lst in the yaml format:

The plabook below will read the yaml file and write the users to the list file:

We run the playbook ant put the variables from file by adding -e parameter:

After running the playbook10 the content of list file is:

 

Example 3.

In this example you will create a playbook that installs the Apache web server
and opens the ports for the service to be reachable. The playbook queries the web server to ensure it is up and running.

 

Example 4. – Scope of variables.

Look at the inventory file. Notice that there are two host groups, webservers and dbservers, which are children of the larger host group servers. The servers host group has variables set the old way, directly in the inventory file, including one that sets package to httpd.

Createing a new playbook, playbook.yml, for all hosts. Using the yum module, install the package specified by the package variable.

Run the playbook using the ansible-playbook command. Watch the output as Ansible installs the httpd package.

Run an ad hoc command to ensure the httpd package has been successfully installed.

Create the group_vars directory and a new file group_vars/dbservers to set
the variable package to mariadb-server for the dbservers host group in the
recommended way.

Run the playbook again using the ansible-playbook command. Watch Ansible install the mariadb-server package. The package variable for the more specific host group dbservers took precedence over the one for its parent host group servers.

The output indicates the variable defined for the hosts group has been overridden.

Run an ad hoc command to confirm the mariadb-server package has been successfully installed.

For servera.lab.example.com, set the variable package to screen.
Do this by creating a new directory, host_vars, and a file host_vars/
servera.lab.example.com that sets the variable in the recommended way.

Run the playbook again. Watch the output as Ansible installs the screen package. The host-specific value of the package variable overrides any value set by the host’s host groups.

Run an ad hoc command to confirm the screen package has been successfully installed.

Run the ansible-playbook command again, this time using the -e option to override the package variable.

Run an ad hoc command to confirm the mutt package is installed.