I am trying to match hosts using a regex pattern with ansible but it is not working as expected. My inventory is as seen below:
[group1]
hello1
world1
hello2
world2
[group2]
hello3
And my task is:
- debug:
msg: "{{ item }}"
with_inventory_hostnames:
- ~hello*
From their documentation:
Using regexes in patterns
You can specify a pattern as a regular expression by starting the pattern with ~:
~(web|db).*\.example\.com
When I execute the task there is no output. I am a n00b with regex so could it be possible my regex is wrong?
Q: "Could it be possible my regex is wrong?"
A: It's a bug. See inventory_hostnames lookup doesn't support wildcards in patterns #17268. It will be probably fixed in 2.10. But your pattern wouldn't work, I think, because the doc says: "You can use wildcard patterns with FQDNs or IP addresses, as long as the hosts are named in your inventory by FQDN or IP address"
. The hosts in your inventory are neither FQDN nor IP.
Q: "Is there a way to use a regular expression to match hosts in ansible?"
A: Yes. It is. A very convenient way is to create dynamic groups with the module add_host. For example the playbook below
- hosts: localhost
tasks:
- add_host:
name: "{{ item }}"
groups: my_dynamic_group
loop: "{{ groups.all|select('match', my_pattern)|list }}"
vars:
my_pattern: '^hello\d+$'
- hosts: my_dynamic_group
tasks:
- debug:
var: inventory_hostname
gives (abridged)
"inventory_hostname": "hello2"
"inventory_hostname": "hello1"
"inventory_hostname": "hello3"
Update
The next option is the inventory plugin constructed. See
shall> ansible-doc -t inventory ansible.builtin.constructed
shell> tree inventory/
inventory/
├── 01-hosts
└── 02-constructed.yml
0 directories, 2 files
shell> cat inventory/01-hosts
[group1]
hello1
world1
hello2
world2
[group2]
hello3
shell> cat inventory/02-constructed.yml
plugin: ansible.builtin.constructed
groups:
hello_group: inventory_hostname.startswith('hello')
world_group: inventory_hostname.startswith('world')
shell> ansible-inventory -i inventory --graph
@all:
|--@group1:
| |--hello1
| |--hello2
| |--world1
| |--world2
|--@group2:
| |--hello3
|--@hello_group:
| |--hello1
| |--hello2
| |--hello3
|--@ungrouped:
|--@world_group:
| |--world1
| |--world2
You can see that the plugin created two groups: world_group and hello_group.
shell> cat pb.yml
- hosts: hello_group
tasks:
- debug:
var: ansible_play_hosts_all
run_once: true
- hosts: world_group
tasks:
- debug:
var: ansible_play_hosts_all
run_once: true
gives
shell> ansible-playbook -i inventory pb.yml
PLAY [hello_group] ***************************************************************************
TASK [debug] *********************************************************************************
ok: [hello1] =>
ansible_play_hosts_all:
- hello1
- hello2
- hello3
PLAY [world_group] ***************************************************************************
TASK [debug] *********************************************************************************
ok: [world1] =>
ansible_play_hosts_all:
- world1
- world2
PLAY RECAP ***********************************************************************************
hello1: ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
world1: ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0