Chapter 7: Managing Complex Plays and Playbooks
Exercise: Selecting hosts with host patterns
You will point one small play at two example inventories and change only its hosts: line, fourteen times, to see exactly what each kind of pattern selects. Predict each result before you run it. Nothing in this exercise connects to a managed host.
The project ~/projects-host has an ansible.cfg, two inventories and a playbook. Most hosts in inventory1 do not exist. That does not matter: the play does not gather facts, and its only task, debug, runs on the control node, so Ansible never tries to connect. It just shows which hosts the pattern matched.
Selecting hosts with host patterns
- Use names, groups, wildcards, lists, exclusions and intersections to select hosts from an inventory.
Prerequisites: Complete control-node setup and the preceding lessons in this chapter. Run commands as student on workstation unless a step names another machine.
From the project directory, run the relevant home-lab check. For an exercise with several checkpoints, grade each state before changing or removing it:
lab grade projects-hostThe grader reads project files and host state. A passing report covers the listed checks; also perform the task’s independent connection, repeat-run, and reboot checks where requested.
Find hosts in London that are not databases. Predict their names before testing your pattern.
Record the published result first. The grader checks the original requirements, so a changed name or value may intentionally fail those checks.
Predict and verify host selection without altering any systems. Use the two supplied inventories and playbook.yml.
- In
inventory1, select a single named host, a listed IP, all hosts, names ending inexample.com, and that domain excludinglab.example.com. - Select exactly
lb1.lab.example.com,s1.lab.example.com, anddb1.example.com; then select addresses beginning172.25.. - Compare a wildcard that matches
stagewith one that matches individual host names. Select the union of production, addresses beginning172, and names containinglab; then the intersection of database and London hosts. - In
inventory2, verify London, Europe, ungrouped, and the missing Australia group. Explain why a missing group can produce a successful run that performs no work.
Look at the project
[student@workstation ~]$ cd ~/projects-host
[student@workstation projects-host]$ ls
ansible.cfg inventory1 inventory2 playbook.ymlRead inventory1. It has four hosts outside any group, groups by function (web, db, lb), by city (boston, london) and by environment (dev, stage, prod, new), and three layers of parent groups. Some hosts are in lab.example.com, some directly in example.com, and new lists three IP addresses.
[web]
jupiter.lab.example.com
saturn.example.com
[db]
db1.example.com
db2.example.com
db3.example.com
[lb]
lb1.lab.example.com
lb2.lab.example.com
[boston]
db1.example.com
jupiter.lab.example.com
lb2.lab.example.com
[london]
db2.example.com
db3.example.com
file1.lab.example.com
lb1.lab.example.com
[dev]
web1.lab.example.com
db3.example.com
[stage]
file2.example.com
db2.example.com
[prod]
lb2.lab.example.com
db1.example.com
jupiter.lab.example.com
[function:children]
web
db
lb
city
[city:children]
boston
london
environments
[environments:children]
dev
stage
prod
new
[new]
172.25.252.23
172.25.252.44
172.25.252.32inventory2 is much smaller: workstation.lab.example.com outside any group, one server in each of london, berlin, tokyo and atlanta, and a parent group europe made of london and berlin.
The playbook prints the name of each host it matches:
---
- name: Resolve host patterns
hosts: db1.example.com
gather_facts: false
tasks:
- name: Display managed hosts matching the host pattern
ansible.builtin.debug:
msg: "{{ inventory_hostname }}"One host by name
Run the playbook against inventory1 as it is:
[student@workstation projects-host]$ ansible-navigator run \
> -m stdout playbook.yml -i inventory1
PLAY [Resolve host patterns] ***************************************************
TASK [Display managed hosts matching the host pattern] *************************
ok: [db1.example.com] => {
"msg": "db1.example.com"
}
PLAY RECAP *********************************************************************
db1.example.com : ok=1 changed=0 unreachable=0 failed=0 ...For the rest of the exercise, only change the hosts: line and run the same command. The outputs below show just the ok: line of each matched host.
One host by IP address
Set hosts: 172.25.252.44.
ok: [172.25.252.44]This works only because the inventory lists that address. An address that merely resolves to an inventory host, or a DNS name that the inventory does not contain, matches nothing.
Every host
Set hosts: all. All seventeen hosts are listed: the four without a group, the ten named hosts in groups, and the three addresses.
A domain, with a wildcard
Set hosts: '*example.com', with the quotes.
ok: [srv1.example.com]
ok: [srv2.example.com]
ok: [s1.lab.example.com]
ok: [s2.lab.example.com]
ok: [jupiter.lab.example.com]
ok: [saturn.example.com]
ok: [db1.example.com]
ok: [db2.example.com]
ok: [db3.example.com]
ok: [lb1.lab.example.com]
ok: [lb2.lab.example.com]
ok: [file1.lab.example.com]
ok: [web1.lab.example.com]
ok: [file2.example.com]Fourteen hosts: every name that ends in example.com, including those in lab.example.com. Only the three IP addresses are left out.
Leave out a subdomain
Keep the hosts in example.com but drop everything in lab.example.com:
hosts: '*.example.com, !*.lab.example.com'ok: [srv1.example.com]
ok: [srv2.example.com]
ok: [saturn.example.com]
ok: [db1.example.com]
ok: [db2.example.com]
ok: [db3.example.com]
ok: [file2.example.com]A list of hosts
Without using any group, select exactly lb1.lab.example.com, s1.lab.example.com and db1.example.com.
hosts: lb1.lab.example.com,s1.lab.example.com,db1.example.comok: [lb1.lab.example.com]
ok: [s1.lab.example.com]
ok: [db1.example.com]Addresses by prefix
Select every host whose address starts with 172.25.
hosts: '172.25.*'ok: [172.25.252.23]
ok: [172.25.252.44]
ok: [172.25.252.32]A wildcard that matches a group
Set hosts: 's*' and predict the result before you run it.
ok: [file2.example.com]
ok: [db2.example.com]
ok: [srv1.example.com]
ok: [srv2.example.com]
ok: [s1.lab.example.com]
ok: [s2.lab.example.com]
ok: [saturn.example.com]file2 and db2 do not start with s. They are here because they are in the group stage, which does. A wildcard is matched against host names and group names, and it cannot tell them apart.
Mix groups and wildcards
In one pattern, select the hosts in prod, every address that starts with 172, and every host with lab in its name.
hosts: 'prod,172*,*lab*'ok: [lb2.lab.example.com]
ok: [db1.example.com]
ok: [jupiter.lab.example.com]
ok: [172.25.252.23]
ok: [172.25.252.44]
ok: [172.25.252.32]
ok: [s1.lab.example.com]
ok: [s2.lab.example.com]
ok: [lb1.lab.example.com]
ok: [file1.lab.example.com]
ok: [web1.lab.example.com]Each host appears once, even when several terms match it.
Hosts in two groups at once
Select the hosts that are in both db and london.
hosts: db,&londonok: [db2.example.com]
ok: [db3.example.com]db1 is in db but in boston, so the intersection drops it.
Groups and nested groups in inventory2
Switch to the second inventory and try three patterns, running with -i inventory2:
[student@workstation projects-host]$ ansible-navigator run \
> -m stdout playbook.yml -i inventory2hosts: | Matches |
|---|---|
london | servera.lab.example.com |
europe | servera.lab.example.com, serverb.lab.example.com |
ungrouped | workstation.lab.example.com |
europe has no hosts of its own; it contains the hosts of its child groups. ungrouped is a built-in group of the hosts that are in no other group.
A group that does not exist
Set hosts: australia and run against inventory2:
[student@workstation projects-host]$ ansible-navigator run \
> -m stdout playbook.yml -i inventory2
[WARNING]: Could not match supplied host pattern, ignoring: australia
PLAY [Resolve host patterns] ***************************************************
skipping: no hosts matched
PLAY RECAP *********************************************************************Not an error: a warning, and a play that does nothing. A misspelled group name behaves exactly like this, which is why the warning is worth reading.
Finish
Check your work with lab grade projects-host, then put the exercise away with lab finish projects-host.
Try it again, differently
Without running anything first, write down the hosts each pattern selects from inventory1, then check with ansible 'PATTERN' -i inventory1 --list-hosts: 'city,!london', 'environments,&*.lab.example.com', 'd*', 'all,!function'.