Getting UUID's to pass to Ansible | Nutanix Community
Skip to main content

Hi all,

I’m very new to Nutanix, and pretty new to Ansible. I’ve been tasked with updating / installing guest tools on any machines that need them, and they’d prefer to do it via Ansible.

I’d like to be able to have Ansible use the uri module to grab the UUID of a given VM, or grab a list of UUID’s and the associated VM; however I’m having a lot of trouble parsing this information out in a way that Ansible can actually use it.

Does anyone have experience with this? Or at least can tell me that there’s a better way to be doing this?

Thanks!

I have done this.  The playbook below does it:  :)

It determines the UUID of a VM (myvm) and powers it on.

It also run a couple scripts to start an Oracle database server on the VM which is a Linux host.  f the VM is a Windows server you should use win_command instead of “command”.  win_command is documented on the Ansible site here → https://docs.ansible.com/ansible/latest/modules/list_of_windows_modules.html

 

---

- name: Determine the UUID for VM myvm and power it on

  # nutanixhostname is the name of the nutanix cluster as saved in /etc/ansible/hosts

  hosts: nutanixhostname

  gather_facts: false

  connection: local

  vars:

    # I use the v3 API to get the UUID and the v2 API to power on the VM

    base_urlv2: "https://ntnxb.irea.us:9440/PrismGateway/services/rest/v2.0"

    base_urlv3: "https://ntnxb.irea.us:9440/api/nutanix/v3"

#   Hard-coded Nutanix username and pasword

    username: adminuser

    password: adminoassword

#   ALternatively, best practice is to retrieve the stored username and password

#    username: "{{ lookup('env', 'ANSIBLE_USER') }}"

#    password: "{{ lookup('env', 'ANSIBLE_PASSWORD') }}"

  tasks:

    - name: Query Nutanix to get UUID of VM myvm

      uri:

        url: "{{ base_urlv3 }}/vms/list"

        validate_certs: no

        force_basic_auth: yes

        method: POST

        status_code: 200

        user: "{{ username }}"

        password: "{{ password }}"

        return_content: yes

        body_format: json

        body:

          # Important: "myvm" is case sensitive to be sure to specify the VM name as displayed in Prism ELement

          filter: "vm_name==myvm"

          kind: "vm"

          sort_order: "ASCENDING"

          offset: 0

          length: 1

          sort_attribute: ""

      register: retvalq

    - name: Determine UUID for myvm

      set_fact:

        vm_uuid: "{{ retvalq.json.entities<0].metadata.uuid }}"

    - name: Start the VM

      uri:

        url: "{{ base_urlv2 }}/vms/{{ vm_uuid }}/set_power_state"

        validate_certs: no

        force_basic_auth: yes

        method: POST

        status_code: 200,201

        user: "{{ username }}"

        password: "{{ password }}"

        return_content: no

        body_format: json

        body:

          transition: "ON"

      register: retvalp

    - name: Wait 4 minutes for the VM to boot

      pause:

        seconds: 240

- name: Start the Oracle database

  hosts: myvm

  gather_facts: true

  become: yes

#  If you are using roles ...

#  roles:

#    - oradbhost

  tasks:    

    - name: Start the Oracle listener

      command: "sudo -i -u oracle /oracle/product/11.2.0/dbhome_1/bin/lsnrctl start"

    - name: Start the Oracle database

      command: "sudo -i -u oracle /oracle/localbin/start_db mydatabase"


Hi @PatW 

Have you seen this https://github.com/mattkeeler/ansible-nutanix-inventory/blob/master/nutanix.py ?

It’s a bit old so some adjustments would be needed, of course, but it could be a start?


Thanks for the responses everyone -- @CPatterson , that playbook is incredibly helpful. I was having a lot of trouble figuring out how to have Ansible parse the information being sent back by the API calls.

I’d like to be able to run this against many machines at once, so instead of having it run locally or on the cluster, I run the playbook against a VM inventory and pass the VM name with the magic inventory variable:

body:
filter: "vm_name=={{ inventory_hostname }}"
kind: "vm"
sort_order: "ASCENDING"

Unfortunately though I think I’ll still have to separate VM’s by OS initially; since the connection parameters are different for Windows and Linux. I haven’t yet found a way to enumerate guest OS with Nutanix API’s or powershell cmdlets.

Thanks!


Hey Alona,

I think I just got this script to work; however it seems like it returns what looks like json but is really just one giant string of all the VM’s on the cluster. I know this is really only my own limitations using Ansible; but I can’t figure out how to make sense of the output and have Ansible actually able to use it.


@PatW

Glad to hear there is some progress. Maybe try this post Nutanix dynamic inventory script for Ansible and get in touch with its author for Ansible related questions?


Hello @PatW 

Maybe you can post a snippet of your output here and we can try deciphering and parsing the output. 
Regarding your original task of installing Nutanix guest tools on multiple VM, maybe you can try giving this post a read. 
https://next.nutanix.com/installation-configuration-23/ngt-series-install-ngt-on-multiple-vms-using-prism-central-33591


Not sure if this should go in this post or in another, but I can’t find any information on this error code…

There’s a handful of VM’s that are timing out when I run the above playbook against them. This is the error code:

fatal: >testvm1]: FAILED! => {"changed": false, "content": "", "msg": "Status code was -1 and not a200]: Request failed: <urlopen error timed out>", "redirected": false, "status": -1, "url": "https://vipcluster1.domain.com:9440/api/nutanix/v3/vms/list"}

It seems about 50/50 whether the API call will return successfully or with that error code above. I’m trying to find obvious differences between the ones that work and the ones that don’t, but can’t see anything. 

Any ideas?

Thanks!


I think Ansible is not picking up the embedded inventory_hostname value.  Change your filter as follows and give it a try:

filter: "vm_name==”{{ inventory_hostname }}”"

You might also try the following if that doesn’t work:

filter: vm_name==”{{ inventory_hostname }}”

Also be sure to include the following in the body because they are required by the API:

offset: 0
length: 1
sort_atributes: “”


So since there are some VMs it works for and some it doesn’t, I feel as though it must not be the syntax for the hostname? Just the same, I tried it the ways you suggested and still get the same ‘-1 status code’. Here’s the task in question, and what happens when it’s at that step:

 tasks:
- name: query to get UUID
uri:
url: "{{ base_urlv3 }}/vms/list"
validate_certs: no
force_basic_auth: yes
method: POST
status_code: 200
user: "{{ username }}"
password: "{{ password }}"
return_content: yes
body_format: json
body:
filter: "vm_name=={{ inventory_hostname }}"
kind: "vm"
sort_order: "ASCENDING"
offset: 0
length: 1
sort_attribute: ""
register: retvalq
tags: query
TASK cquery to get UUID] *********************************************************************************************Tuesday 03 December 2019 08:12:22 -0500 (0:00:01.408) 0:00:01.496 ******
ok: ok: fatal: testmachine03]: FAILED! => {"changed": false, "content": "", "msg": "Status code was -1 and not 1200]: Request failed: <urlopen error timed out>", "redirected": false, "status": -1, "url": "https://vipcluster1.vtinfo.com:9440/api/nutanix/v3/vms/list"}

I guess I just don't understand why it would work for some VMs, but not others… is the API call too ‘taxing’ and so it will time out if you try to hit it too many times at once? I also made sure that the case of all VMs match what is in Prism.


Does the host name in /etc/ansible/hosts exactly match the VM name in Nutanix?  Like case?


Yes; I pulled the inventory straight from Nutanix and also double checked in Prism. It’s giving this status code (which I guess is really just a time out?) for specific VMs. I’m guessing there must be something wrong with how these VMs are configured.