0

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!

Aaron
  • 3
  • 1
  • 1
    You're already in a jinja templating context. You never need to nest brackets. But `mynames` is a list, while `ansible_hostname` is a string; you're not going to be able to swap one with the other. – larsks Dec 19 '18 at 18:30

1 Answers1

0

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}}
larsks
  • 277,717
  • 41
  • 399
  • 399
  • So far your suggestion is working great, but it has uncovered some inconsistencies in my hostname data. Some of the hostnames returned by the API are FQDN (matching ansible_fqdn), while some are the short name (matching ansible_hostname). Is there a way to match either format or to match ansible_hostname to the leftmost part of the hostname the API returns? (perhaps using regex?). Thanks again! – Aaron Dec 19 '18 at 19:00
  • See my update. If this answer helps you out, don't forget to mark it as "accepted" by clicking the check mark to the left of the answer. – larsks Dec 19 '18 at 19:37
  • Your update worked perfectly - thank you so much for the assistance! – Aaron Dec 19 '18 at 19:45