I have an Ansible playbook that will be pulling a list of VMs from a Nutanix Prism Central, capture the vm_name
and the UUID, parse the short name of the VM, come up with the FQDN and then replace the vm_name
with the FQDN.
I have issues replacing the vm_name
in the dictionary variable using a loop.
I get:
"The task includes an option with an undefined variable. The error was: str object has no element AnsibleUndefined(hint=None, obj=missing, name='loop')
I have created a minimal reproducible code:
---
- name: Test of value replacement
hosts: all
gather_facts: False
vars:
clone_vm:
- { uuid: "ac1fd960-e19a-48f3-935b-442901ef5fee", vm_name: "server1" }
- { uuid: "f44880f6-49aa-4ba3-8cba-403ff06f1c5e", vm_name: "server2" }
fqdns:
- "mymachine@mycompany.com"
- "myothermachine@mycompany.com"
tasks:
- name: Show variable
debug:
msg:
- "{{ clone_vm }}"
- "{{ fqdns }}"
- name: Replace vm_name with FQDN
set_fact:
clone_vm: "{{ clone_vm | map('combine', [{'vm_name': item[loop.index0]}]) }}"
loop: "{{ fqdns }}"
loop_control:
loop_var: item
- debug:
msg: "{{ clone_vm }}"
If I replace [{'vm_name': item[loop.index0]}]
with [{'vm_name': item.[loop.index0]}]
I get a different error:
template error while templating string: expected name or number. String: {{ clone_vm | map('combine', [{'vm_name': item.[loop.index0]}]) }}. expected name or number
Is there another way to refer to the current value in fqdns
to replace the current value in clone_vm
?
From
- uuid: ac1fd960-e19a-48f3-935b-442901ef5fee
vm_name: server1
- uuid: f44880f6-49aa-4ba3-8cba-403ff06f1c5e
vm_name: server2
My desired output would be:
- uuid: ac1fd960-e19a-48f3-935b-442901ef5fee
vm_name: myserver.mycompany.com
- uuid: f44880f6-49aa-4ba3-8cba-403ff06f1c5e
vm_name: myotherserver.mycompany.com
Thanks to @U880C's answer, I finally got what you are actually trying to do.
You do not need set_fact
nor extended loop vars to achieve your goal (although you can use them, see example at bottom). The following self-explanatory playbook is an example that meets your requirement. You can run it with -v
to get intermediate debugging to study the solution. Feel free to drop the intermediate vars to bring it down to a single jinja2 expression if you need.
---
- name: Test of value replacement
hosts: localhost
gather_facts: False
vars:
clone_vm:
- { uuid: "ac1fd960-e19a-48f3-935b-442901ef5fee", vm_name: "vrtstart001.hs.local_clone1" }
- { uuid: "f44880f6-49aa-4ba3-8cba-403ff06f1c5e", vm_name: "vrtstsrs001.hs.local_clone1" }
fqdns:
- "vrtstart001.nadex.co"
- "vrtstsrs001.nadex.co"
_fqdns_dict_list: "{{ ['vm_name: '] | product(fqdns) | map('join') | map('from_yaml') }}"
_synchronized_list: "{{ clone_vm | zip(_fqdns_dict_list) }}"
clone_vm_transformed: "{{ _synchronized_list | map('combine') }}"
tasks:
- name: "Intermediate result: fqdns as a list of dicts"
ansible.builtin.debug:
var: _fqdns_dict_list
verbosity: 1
- name: "Intermediate result: synchronized list"
ansible.builtin.debug:
var: _synchronized_list
verbosity: 1
- name: "Final result: dict list with replaced vm_name"
ansible.builtin.debug:
var: clone_vm_transformed
Playbook demo run:
PLAY [Test of value replacement] ********************************************************************************************************************************************************************************************
TASK [Intermediate result: fqdns as a list of dicts] ************************************************************************************************************************************************************************
skipping: [localhost]
TASK [Intermediate result: synchonized list] ********************************************************************************************************************************************************************************
skipping: [localhost]
TASK [Final result: dict list with replaced vm_name] ************************************************************************************************************************************************************************
ok: [localhost] => {
"clone_vm_transformed": [
{
"uuid": "ac1fd960-e19a-48f3-935b-442901ef5fee",
"vm_name": "vrtstart001.nadex.co"
},
{
"uuid": "f44880f6-49aa-4ba3-8cba-403ff06f1c5e",
"vm_name": "vrtstsrs001.nadex.co"
}
]
}
PLAY RECAP ******************************************************************************************************************************************************************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=2 rescued=0 ignored=0
For completeness and learning sake, here is an example using your original approach. This will create an unnecessary task running in a loop and possibly for every host in your play loop (although this last point can be optimized). So I consider this a bad practice in this situation and the goal below is just to show it is feasible.
The following playbook:
---
- name: Test of value replacement
hosts: localhost
gather_facts: False
vars:
clone_vm:
- { uuid: "ac1fd960-e19a-48f3-935b-442901ef5fee", vm_name: "vrtstart001.hs.local_clone1" }
- { uuid: "f44880f6-49aa-4ba3-8cba-403ff06f1c5e", vm_name: "vrtstsrs001.hs.local_clone1" }
fqdns:
- "vrtstart001.nadex.co"
- "vrtstsrs001.nadex.co"
tasks:
- name: Replace vm_name with FQDN
vars:
current_name:
vm_name: "{{ item }}"
ansible.builtin.set_fact:
clone_vm_transformed: "{{ clone_vm_transformed | d([]) + [clone_vm[ansible_loop.index0] | combine(current_name)] }}"
loop: "{{ fqdns }}"
loop_control:
extended: true
- name: Show replacement result
ansible.builtin.debug:
var: clone_vm_transformed
gives:
PLAY [Test of value replacement] ********************************************************************************************************************************************************************************************
TASK [Replace vm_name with FQDN] ********************************************************************************************************************************************************************************************
ok: [localhost] => (item=vrtstart001.nadex.co)
ok: [localhost] => (item=vrtstsrs001.nadex.co)
TASK [Show replacement result] **********************************************************************************************************************************************************************************************
ok: [localhost] => {
"clone_vm_transformed": [
{
"uuid": "ac1fd960-e19a-48f3-935b-442901ef5fee",
"vm_name": "vrtstart001.nadex.co"
},
{
"uuid": "f44880f6-49aa-4ba3-8cba-403ff06f1c5e",
"vm_name": "vrtstsrs001.nadex.co"
}
]
}
PLAY RECAP ******************************************************************************************************************************************************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0