Start here: validate the inputs before creating a VM
This revised example uses nutanix.ncp 2.5.0 and requires explicit opt-in before creation. Prove read-only access first, verify the resource IDs, and plan for an ambiguous or partially completed request.
Jump to project setup, the guarded playbook, validation and execution, or readiness checks.
Introduction
This is a guarded lab example for creating one AHV VM from an existing, prepared disk image through Prism Central. Complete the read-only Ansible foundations exercise first. Use the same project-local nutanix.ncp 2.5.0 collection, Python/Ansible environment, and installed SDK dependencies. Check the release compatibility table against your actual AOS and Prism Central versions. This example is not a production-certified deployment role.
My Personal Repository on GitHub
Diagram: VM Deployment Workflow

Step 1: Define Inventory
Place inventory.yml, nutanix_credentials.yml, vm_spec.yml, and deploy_vm.yml together beside the project-local collections directory from Part 1. The local interpreter below keeps module execution in the same Python environment as Ansible.
all:
hosts:
localhost:
ansible_connection: local
ansible_python_interpreter: "{{ ansible_playbook_python }}"
Step 2: Define Credentials File
Reuse the encrypted Vault file from Part 1, or create it with ansible-vault create nutanix_credentials.yml. Enter the placeholders below inside the editor, replace them there, and use ansible-vault edit for later changes. Keep passwords out of source control, command arguments, and logs. The approved account needs inventory visibility and the permissions required for VM creation; read access alone is insufficient.
nutanix_pc_hostname: "prism-central.example.com" nutanix_pc_port: "9440" nutanix_username: "REPLACE_WITH_APPROVED_ACCOUNT" nutanix_password: "REPLACE_INSIDE_VAULT_EDITOR"
Step 3: Create Your VM Deployment Playbook
Create vm_spec.yml with the inputs below. Resolve each UUID in the intended Prism Central environment and verify that the subnet belongs to the chosen placement and the prepared UEFI disk image is available there. UUID syntax alone does not prove that a resource exists, is visible, or is compatible. The image must contain the guest drivers and customization needed for your workload.
vm_name: "lab-app-01" cluster_ext_id: "REPLACE_WITH_CLUSTER_UUID" subnet_ext_id: "REPLACE_WITH_SUBNET_UUID" image_ext_id: "REPLACE_WITH_IMAGE_UUID"
Save this as deploy_vm.yml. It uses ntnx_vms_v2, assigns 2 vCPUs and 8 GiB RAM, clones the image without requesting a disk resize, and leaves the NIC disconnected. It does not request power-on. Validate the guest and network identity before separately approving connection and startup.
- name: Create one approved AHV lab VM
hosts: localhost
gather_facts: false
vars_files:
- nutanix_credentials.yml
- vm_spec.yml
vars:
allow_create: false
uuid_pattern: '^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$'
tasks:
- name: Require explicit creation approval and a normal run
ansible.builtin.assert:
that:
- allow_create | bool
- not ansible_check_mode
fail_msg: "Creation is disabled. Review the lab change before opting in; check mode is not supported by this workflow."
- name: Validate the supplied name and reference formats
ansible.builtin.assert:
that:
- vm_name is match('^[A-Za-z0-9][A-Za-z0-9_-]{0,62}$')
- cluster_ext_id is match(uuid_pattern)
- subnet_ext_id is match(uuid_pattern)
- image_ext_id is match(uuid_pattern)
fail_msg: "Replace every reference with a verified UUID and use a simple, approved VM name."
- name: Look for an existing visible VM with this name
nutanix.ncp.ntnx_vms_info_v2:
nutanix_host: "{{ nutanix_pc_hostname }}"
nutanix_port: "{{ nutanix_pc_port }}"
nutanix_username: "{{ nutanix_username }}"
nutanix_password: "{{ nutanix_password }}"
validate_certs: true
filter: "name eq '{{ vm_name }}'"
limit: 1
register: vm_lookup
no_log: true
- name: Stop if the name is already in use
ansible.builtin.assert:
that:
- vm_lookup.response is defined
- vm_lookup.response is sequence
- vm_lookup.response is not string
- vm_lookup.response is not mapping
- vm_lookup.response | length == 0
fail_msg: "A VM already exists or discovery did not return an empty list. Review Prism Central before proceeding."
no_log: true
- name: Create the VM from the approved UEFI disk image
nutanix.ncp.ntnx_vms_v2:
nutanix_host: "{{ nutanix_pc_hostname }}"
nutanix_port: "{{ nutanix_pc_port }}"
nutanix_username: "{{ nutanix_username }}"
nutanix_password: "{{ nutanix_password }}"
validate_certs: true
state: present
wait: true
name: "{{ vm_name }}"
description: "Approved Ansible lab deployment"
cluster:
ext_id: "{{ cluster_ext_id }}"
num_sockets: 1
num_cores_per_socket: 2
memory_size_bytes: 8589934592
boot_config:
uefi_boot:
boot_order:
- DISK
disks:
- disk_address:
bus_type: SCSI
index: 0
backing_info:
vm_disk:
data_source:
reference:
image_reference:
image_ext_id: "{{ image_ext_id }}"
nics:
- nic_backing_info:
virtual_ethernet_nic:
model: VIRTIO
is_connected: false
nic_network_info:
virtual_ethernet_nic_network_info:
nic_type: NORMAL_NIC
subnet:
ext_id: "{{ subnet_ext_id }}"
register: created_vm
no_log: true
- name: Require a returned VM identifier
ansible.builtin.assert:
that:
- created_vm.ext_id is defined
- created_vm.ext_id is string
- created_vm.ext_id | length > 0
fail_msg: "Creation may have succeeded, but the VM ID is missing. Inspect Prism Central; do not retry blindly."
no_log: true
- name: Record only the non-secret identifier in the change record
ansible.builtin.debug:
msg: "Created VM external ID: {{ created_vm.ext_id }}"
Retry boundary: creation without ext_id is not name-based reconciliation. The name check is only a guard against visible duplicates, not a lock; two concurrent runs or restricted inventory visibility can defeat it. Allow one authorized run, retain the returned ID, and inspect the task and VM in Prism Central after any ambiguous failure before considering another attempt. Updates and deletion need separate, reviewed workflows.
Step 4: Add Extra Configs (Optional)
- Add optional fields only after checking
ansible-doc nutanix.ncp.ntnx_vms_v2for the installed release. - Categories use a list of category
ext_idreferences in this module. Do not copy the earlier name/value or arbitrary metadata fragment into this schema. - Treat guest customization, network connection, power actions, and backup assignment as separate changes with their own acceptance checks. A created VM is not automatically a configured or protected application.
Step 5: Run the Playbook
Keep creation disabled while preparing the files. The final command below deliberately enables a real VM-creation request; it is not a dry run. Do not use --check as a substitute: the information module used by this workflow does not support check mode.
# Inspect the installed module before editing or running the playbook.
ANSIBLE_COLLECTIONS_PATH=./collections ansible-doc nutanix.ncp.ntnx_vms_v2
# Local syntax validation; this does not prove permissions or API compatibility.
ansible-playbook -i inventory.yml deploy_vm.yml --syntax-check --ask-vault-pass
# WRITES to Prism Central: run once, only after approval in the intended lab.
ansible-playbook -i inventory.yml deploy_vm.yml --ask-vault-pass --extra-vars '{"allow_create":true}'
Tips for Production Readiness
- Approve the target Prism Central, placement, subnet, prepared image, resource sizing, and account scope. Use an isolated lab network first.
- Validate certificate trust instead of disabling it. Keep secret-bearing tasks under
no_log: true, and protect the Vault password and editor temporary files. - Serialize creation runs. Check for existing or partially created VMs after any timeout, and preserve the VM/task identifiers in the change record.
- Confirm the actual CPU, RAM, cloned disk, boot configuration, NIC state, and power state before allowing the guest onto a network.
- Test guest uniqueness, application health, backup enrollment, and a separately approved cleanup procedure before turning the lab recipe into a deployment role.
Summary
This recipe prepares a controlled, version-specific AHV creation request—not a claim of production readiness. A successful API task must still be followed by configuration and guest validation. Keep lifecycle actions, concurrent-run protection, secret management, backup enrollment, and recovery procedures explicit before expanding beyond a single lab VM.
External Documentation:
- Nutanix 2.5.0 compatibility and dependencies
- Nutanix VM creation/update schema and behavior
- Nutanix VM information module
- Nutanix connection and certificate options
- Ansible assertion checks
- Ansible Vault guidance
Quick start: prove read access before provisioning Begin with a read-only AHV inventory query through Prism Central. This revision replaces the earlier...