Search icon CANCEL
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Mastering Ansible, 4th Edition

You're reading from   Mastering Ansible, 4th Edition Automate configuration management and overcome deployment challenges with Ansible

Arrow left icon
Product type Paperback
Published in Dec 2021
Publisher Packt
ISBN-13 9781801818780
Length 540 pages
Edition 4th Edition
Tools
Arrow right icon
Authors (2):
Arrow left icon
Jesse Keating Jesse Keating
Author Profile Icon Jesse Keating
Jesse Keating
James Freeman James Freeman
Author Profile Icon James Freeman
James Freeman
Arrow right icon
View More author details
Toc

Table of Contents (18) Chapters Close

Preface 1. Section 1: Ansible Overview and Fundamentals
2. Chapter 1: The System Architecture and Design of Ansible FREE CHAPTER 3. Chapter 2: Migrating from Earlier Ansible Versions 4. Chapter 3: Protecting Your Secrets with Ansible 5. Chapter 4: Ansible and Windows – Not Just for Linux 6. Chapter 5: Infrastructure Management for Enterprises with AWX 7. Section 2: Writing and Troubleshooting Ansible Playbooks
8. Chapter 6: Unlocking the Power of Jinja2 Templates 9. Chapter 7: Controlling Task Conditions 10. Chapter 8: Composing Reusable Ansible Content with Roles 11. Chapter 9: Troubleshooting Ansible 12. Chapter 10: Extending Ansible 13. Section 3: Orchestration with Ansible
14. Chapter 11: Minimizing Downtime with Rolling Deployments 15. Chapter 12: Infrastructure Provisioning 16. Chapter 13: Network Automation 17. Other Books You May Enjoy

Variable precedence

As you learned in the previous section, there are several major types of variables that can be defined in a myriad of locations. This leads to a very important question: what happens when the same variable name is used in multiple locations? Ansible has a precedence for loading variable data, and thus, it has an order and a definition to decide which variable will win. Variable value overriding is an advanced usage of Ansible, so it is important to fully understand the semantics before attempting such a scenario.

Precedence order

Ansible defines the following precedence order, with those closest to the top of the list winning. Note that this can change from release to release. In fact, it has changed quite significantly since Ansible 2.4 was released, so it is worth reviewing if you are upgrading from an older version of Ansible:

  1. Extra vars (from the command line) always win.
  2. The ansible.builtin.include parameters.
  3. The role (and ansible.builtin.include_role) parameters.
  4. The variables defined with ansible.builtin.set_facts, and those created with the register task directive.
  5. The variables included in a play with ansible.builtin.include_vars.
  6. Task vars (only for the specific task).
  7. Block vars (only for the tasks within the block).
  8. Role vars (defined in main.yml in the vars subdirectory of the role).
  9. Play vars_files.
  10. Play vars_prompt.
  11. Play vars.
  12. The host facts (and also the cached results of ansible.builtin.set_facts).
  13. The host_vars playbook.
  14. The host_vars inventory.
  15. The inventory file (or script)-defined host vars.
  16. The group_vars playbook.
  17. The group_vars inventory.
  18. The group_vars/all playbook.
  19. The group_vars/all inventory.
  20. The inventory file (or script)-defined group vars.
  21. The role defaults.
  22. The command-line values (for example, -u REMOTE_USER).

Ansible releases a porting guide with each release that details the changes you will need to make to your code in order for it to continue functioning as expected. It is important to review these as you upgrade your Ansible environment – the guides can be found at https://docs.ansible.com/ansible/devel/porting_guides/porting_guides.html.

Variable group priority ordering

The previous list of priority ordering is obviously helpful when writing Ansible playbooks, and, in most cases, it is apparent that variables should not clash. For example, a var task clearly wins over a var play, and all tasks and, indeed, plays are unique. Similarly, all hosts in the inventory will be unique; so again, there should be no clash of variables with the inventory either.

There is, however, one exception to this, that is, inventory groups. A one-to-many relationship exists between hosts and groups, and, as such, any given host can be a member of one or more groups. For example, let's suppose that the following code is our inventory file:

[frontend]
host1.example.com
host2.example.com
[web:children]
frontend
[web:vars]
http_port=80
secure=true
[proxy]
host1.example.com
[proxy:vars]
http_port=8080
thread_count=10

Here, we have two hypothetical frontend servers, host1.example.com and host2.example.com, in the frontend group. Both hosts are children of the web group, which means they are assigned the group variable http_port=80 from the inventory. host1.example.com is also a member of the proxy group, which has an identically named variable but a different assignment: http_port=8080.

Both of these variable assignments are at the group_vars inventory level, and so the order of precedence does not define a winner. So, what happens in this scenario?

The answer is, in fact, predictable and deterministic. The group_vars assignments are done in alphabetical order of the group names (as described in the Inventory ordering section), with the last loaded group overriding all preceding variable values that coincide.

This means that any competing variables from mastery2 will win over the other two groups. Those from the mastery11 group will then take precedence of those from the mastery1 group, so please be mindful of this when creating group names!

In our example, when the groups are processed in alphabetical order, web comes after proxy. Therefore, the group_vars assignments from web that coincide with those from any previously processed groups will win. Let's run the previous inventory file through this example playbook to take a look at the behavior:

---
- name: group variable priority ordering example play
  hosts: all
  gather_facts: false
  tasks:
    - name: show assigned group variables
      vars:
        msg: |
             http_port:{{ hostvars[inventory_hostname]['http_port'] }}
             thread_count:{{ hostvars[inventory_hostname]['thread_count'] | default("undefined") }}
             secure:{{ hostvars[inventory_hostname]['secure'] }}
       ansible.builtin.debug:
         msg: "{{ msg.split('\n') }}"

Let's try running the following command:

ansible-playbook -i priority-hosts -c local priorityordering.yaml

We should get the following output:

Figure 1.12 – A playbook run showing how variables can be overridden at the inventory group level

Figure 1.12 – A playbook run showing how variables can be overridden at the inventory group level

As expected, the value assigned to the http_port variable for both hosts in the inventory is 80. However, what if this behavior is not desired? Let's suppose that we want the value of http_port from the proxy group to take priority. It would be painful to have to rename the group and all associated references to it to change the alphanumerical sorting of the groups (although, this would work!). The good news is that Ansible 2.4 introduced the ansible_group_priority group variable, which can be used for just this eventuality. If not explicitly set, this variable defaults to 1, leaving the rest of the inventory file unchanged.

Let's set this as follows:

[proxy:vars]
http_port=8080
thread_count=10
ansible_group_priority=10

Now, when we run the same playbook using the same command as before, pay attention to how the value assigned to http_ort changes, while all variable names that were not coincidental behave exactly as before:

Figure 1.13 – The effect of the ansible_group_priority variable on coincidental group variables

Figure 1.13 – The effect of the ansible_group_priority variable on coincidental group variables

As your inventory grows with your infrastructure, be sure to make use of this feature to gracefully handle any variable assignment collisions between your groups.

Merging hashes

In the previous section, we focused on the precedence with which variables will override each other. The default behavior of Ansible is that any overriding definition for a variable name will completely mask the previous definition of that variable. However, that behavior can be altered for one type of variable: the hash variable. A hash variable (or, in Python terms, a dictionary) is a dataset of keys and values. Values can be of different types for each key and can even be hashes themselves for complex data structures.

In some advanced scenarios, it is preferable to replace just one bit of a hash or add to an existing hash rather than replacing the hash altogether. To unlock this ability, a configuration change is necessary in the Ansible config file. The configuration entry is hash_behavior, which either takes the value replace or merge. A setting of merge will instruct Ansible to merge or blend the values of two hashes when presented with an override scenario rather than assume the default of replace, which will completely replace the old variable data with the new data.

Let's walk through an example of the two behaviors. We will start with a hash loaded with data and simulate a scenario where a different value for the hash is provided as a higher-priority variable.

This is the starting data:

hash_var: 
  fred: 
    home: Seattle 
    transport: Bicycle 

This is the new data loaded via include_vars:

hash_var: 
  fred: 
    transport: Bus 

With the default behavior, the new value for hash_var will be as follows:

hash_var: 
  fred: 
    transport: Bus 

However, if we enable the merge behavior, we will get the following result:

hash_var: 
  fred: 
    home: Seattle 
    transport: Bus 

There are even more nuances and undefined behaviors when using merge, and, as such, it is strongly recommended that you only use this setting if absolutely necessary – it is disabled by default for a good reason!

You have been reading a chapter from
Mastering Ansible, 4th Edition - Fourth Edition
Published in: Dec 2021
Publisher: Packt
ISBN-13: 9781801818780
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at €18.99/month. Cancel anytime