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.