Jackson
Jackson

Reputation: 83

Is there a way to use a regular expression to match hosts in ansible?

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?

Upvotes: 4

Views: 11552

Answers (1)

Vladimir Botka
Vladimir Botka

Reputation: 68384

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
  1. Create the inventory
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')
  1. Test the inventory
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.

  1. Use the groups. For example,
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

Upvotes: 4

Related Questions