I am trying to use the JSON response from an API to lookup the UUID of a VM I am trying to back up using the hostname. The API returns a list of hashes which include the hostnames and UUID of that hostname. I'd like to get Ansible to return the UUID of a machine when I feed it the hostname.
Here is an example of the response from the API, which I am storing in networker_vms
{
"networker_vms.json.vms": [
{
"hostname": ""
},
{
"hostname": ""
},
{
"hostname": "server1.company.com",
"uuid": "1ef92350-a5e3-8df3-6106-208a88aad352"
},
{
"hostname": "server2.company.com",
"uuid": "5003006d-23f4-a515-3722-181238489896"
},
{
"hostname": "server3.company.com",
"uuid": "50640076-07ae-571d-5e69-2183db42d2ee"
},
{
"hostname": "server4.company.com",
"uuid": "500410b1-505a-7539-5efd-89131d671b0a"
},
{
"hostname": "server5.company.com",
"uuid": "5024014b-e788-12a9-bcf6-5475ae50bf7c"
},
{
"hostname": "server6.company.com",
"uuid": "51462200-1abf-1c09-5007-fa72f76854fc"
}
],
}
I am able to get the UUID that coincides with a hostname with the following Ansible snippet, however I cannot get the code to work when switching the "mynames" variable to something like {{ ansible_hostname }} - I get the error "unexpected failure during module execution". I'm guessing it has to do with the stacking of the curly-braces, but am not sure....
- name: debug my_uuid
debug:
msg: "{{ mynames | map('extract', dict(networker_vms.json | json_query('vms[].[hostname,uuid]'))) }}"
vars:
mynames:
- server2.company.com
What is the best way for me to search the results of the API call for a specific hostname and get Ansible to put the corresponding uuid into a fact or variable for me?
Thanks!
It sounds like you want to extract the UUID for the current host, as identified by the ansible_hostname
variable. You could do that like this:
- name: debug using ansible_hostname
debug:
msg: >-
{{ [ansible_hostname] |
map('extract', dict(networker_vms.json |
json_query('vms[].[hostname,uuid]'))) | first }}
This simply replaces mynames
in your example, which is a list, with [ansible_hostname]
, which is also a list (consisting of a single value, the contents of ansible_hostname
). This provides the list context necessary for the map
filter.
However, if you have a single value, you don't need to use the map
filter; you can instead just do this:
- name: debug using ansible_hostname
debug:
msg: >-
{{ (networker_vms.json.vms |
selectattr('hostname', 'eq', ansible_hostname)|first).uuid }}
Update
If you have a mix of qualified and unqualified hostnames, you could do something like this:
- name: get my uuid
set_fact:
my_uuid: "{{ host_to_addr[item] }}"
when: my_uuid is not defined and item in host_to_addr
vars:
host_to_addr: "{{ dict(networker_vms.json | json_query('vms[].[hostname,uuid]')) }}"
loop:
- "{{ ansible_hostname }}"
- "{{ ansible_fqdn }}"
- debug:
var: my_uuid
This will loop over a list of hostnames and will set the my_uuid
fact to whichever one matches first.
You could also write a slightly more complex expression for the json_query
filter:
- name: get my uuid
debug:
msg: >-
{{ networker_vms.json.vms |
json_query('[?hostname == `%s` || hostname == `%s`].[uuid]|[]' % (
ansible_hostname, ansible_fqdn))|
first}}