Skip to content

Instantly share code, notes, and snippets.

@halberom
Created May 17, 2017 09:35
Show Gist options
  • Save halberom/9bfe009c9a3df5d64c7bb505a7700430 to your computer and use it in GitHub Desktop.
Save halberom/9bfe009c9a3df5d64c7bb505a7700430 to your computer and use it in GitHub Desktop.
ansible - example of using map + regex_replace to modify all items in a list
---
- hosts: localhost
connection: local
gather_facts: False
vars:
mylist:
- group_1
- group_2
tasks:
- debug:
msg: "{{ mylist | map('regex_replace', '(.*)', '\\1_foo') | list }}"
PLAY [localhost] **********************************************************************************************************************
TASK [debug] **************************************************************************************************************************
ok: [localhost] => {
"changed": false,
"msg": [
"group_1_foo",
"group_2_foo"
]
}
PLAY RECAP ****************************************************************************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0
@Infiniverse
Copy link

Looks good. I was hoping that this might work:

   - debug: msg="YYY {{ groups['all'] | map('regex_replace', '(.*)', hostvars['\1'].ansible_ssh_host) | list }}"

but I get an error:

fatal: [neptune]: FAILED! => {"failed": true, "msg": "the field 'args' has an invalid value, which appears to include a variable
that is undefined. The error was: 'ansible.vars.hostvars.HostVars object' has no attribute '\\\\1'\n\n
The error appears to have been in 'playbook-test.yml': line 9, column 7, but may\nbe elsewhere in the file depending
on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n
    - debug: msg=\"YYY {{ groups['all'] | map('regex_replace', '(.*)', hostvars['\\1'].ansible_ssh_host) | list }}\"\n
^ here\nWe could be wrong, but this one looks like it might be an issue with\nmissing quotes.  Always quote template expression brackets when they\nstart a value.
For instance:\n\n    with_items:\n      - {{ foo }}\n\nShould be written as:\n\n    with_items:\n      - \"{{ foo }}\"\n"}

@Infiniverse
Copy link

The \ doesn't appear to make a difference. I tried '\', but that didn't happen.

Another approach should be:

    - debug: msg="YYY {{ groups['all'] | map('regex_replace', '(.*)', "hostvars[\1].ansible_ssh_host") | list }}"

which correctly outputs:

ok: [neptune] => {
    "changed": false, 
    "msg": "YYY [u'hostvars[unifi-controller-office].ansible_ssh_host', u'hostvars[neptune].ansible_ssh_host']"
}

So the question is, how do we evaluate those strings to get them replaced by the variable values.

@halberom
Copy link
Author

this is a method for modifying all items in a list, it's not suitable for pulling out elements from a nested structure.

As pointed out in chan,

{{ groups['all'] | map('extract', hostvars, 'ansible_ssh_host' }}

is the way to do that

@ReSearchITEng
Copy link

if you need to both add a prefix and a suffix, as well as making everything a list, take a look at the below:

  set_fact:
    extended_etcd_endpoints_list: "{{ groups['etcd'] | map('extract', hostvars, ['ansible_default_ipv4','address']) | map('regex_replace', '^(.*)$','https://\\1:2379') | list  }}"

it takes the list of all machines in the group etcd, extracts the ipv4, adds an 'https://' in front and an ':2379' at the end.
Finally, everything is transformed in a list.

@gobenji
Copy link

gobenji commented Mar 13, 2020

Indeed, I got strange results if the regex was not achored at the beginning: "^..."
Other than that, thanks for this useful pattern.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment