Nutanix

Centos VM Creation on Nutanix Using Ansible

  • Nutanix Prism login credentials
  • Nutanix cluster URL, cluster name, subnet name and disk image name
eCloudControl Engineering Team6 min read
Centos VM Creation on Nutanix Using Ansible

Centos VM Creation on Nutanix Using Ansible

INTRODUCTION

Nutanix Prism is an end-to-end consumer-grade management solution for virtualized datacenter environments. Prism manages the entire stack from the storage and compute infrastructure all the way up to virtual machines (VMs).

Here, we'll discuss how to create a CentOS VM on Nutanix using Ansible playbook. Ansible is a high-level automation engine that automates cloud provisioning, configuration management, application deployment.

PREREQUISITES

  • Nutanix Prism login credentials
  • Nutanix cluster URL, cluster name, subnet name and disk image name

ANSIBLE ON NUTANIX VM CREATION

Ansible roles are sets of Ansible defaults, files, tasks, templates, variables, and other Ansible components that work together. 'nutanix_vm_provisioner' is a basic Ansible role to provision VMs on a Nutanix AHV using APIv3.

Required variables

  • api_version: # add API version, it's best to use v3, if available
  • cluster_url: # IP address where you would normally log into PRISM
  • prism_user: # An account with permissions to provision on the cluster
  • prism_password: # The password to your account
  • cluster_name: # Name of the cluster to provision against
  • subnet_name: # Name of the Subnet to add VMs to
  • image_name: # Name of the disk image or ISO to use
  • vm_defs: # The list of dicts that define the VMs to be created

A single role 'nutanix_vm' is required for the VM creation.

'nutanix_vm' role deals with the creation of a VM with the provided subnet, cluster and the OS image by authenticating with a session cookie for logging into the prism. The required variables are to be placed in 'defaults' folder. 'tasks' for the role is shown step-by-step in the next page.

STEP 1

*(nutanix_vm): *shows how the authentication to the prism is done by creating a session cookie.

- name: Auth to the cluster
   uri:
        url: "{{ api_url_v3 }}/clusters/list"
        body:
           kind: cluster
           sort_order: ASCENDING
           offset: 0
           length: 10
           sort_attribute: ''
       method: POST
       validate_certs: no
       force_basic_auth: yes
       body_format: json
       user: "{{ prism_user }}"
       password: "{{ prism_password }}"
       status_code: 200
       return_content: yes
   register: login
   ignore_errors: yes

- name: Debug | Print Auth Cookie
   debug:
        var: login.set_cookie
   when: global_debug

- name: Set fact for session cookie
   set_fact:
         session_cookie: "{{ login.set_cookie}}"
  register: cookie
- debug: var=cookie.failed

STEP 2

*(nutanix_vm): *shows how to get the cluster lists and uuids to use.

- name: Get clusters list
  uri:
     url: "{{ api_url_v3 }}/clusters/list"
     body:
         kind: cluster
         sort_order: ASCENDING
       offset: 0
         length: 10
         sort_attribute: ''
   method: POST
    validate_certs: no
    body_format: json
    status_code: 200
    headers:
          Cookie: "{{ session_cookie }}"
  register: json_cluster_result
  ignore_errors: yes

- name: Stash the Cluster UUIDs
   set_fact:
         cluster_uuids: "{{ cluster_uuids|default([]) + [{'name': item.spec.name, 'uuid': item.metada.uuid} ] }}"
   with_items: "{{ json_clusters_result.json.entities }}"
   no_log: True

- name: Debug|Printcluster name/UUIDs
  debug:
      var: cluster_uuids
  when: global_debug

STEP 3

*(nutanix_vm): *shows how to get the subnet lists and uuids to use.

- name: Get Subnet List
  uri:
      url: "{{ api_url_v3}}/subnets/list"
      body:
          length: 100
          offset: 0
          filter: ""
    method: POST
    validate_certs: no
    body_format: json
    status_code: 200
    headers:
          Cookie: "{{ session_cookie }}"
  register: json_images_result
  ignore_errors: yes

- debug: var=json_images_result.json.entities.0.status
- debug: var=json_images_result.json.entities.1.status
- debug: var=json_images_result.json.entities.2.status

- name: Stash the subnet UUIDs
  set_fact:
       subnet_uuids: "{{ subnet_uuids|default([]) + [ {'name': item.spec.name, 'uuid': item.metadata.uuid } ] }}"
  with_items: "{{ json_images_result.json.entities }}"
 no_log: True

- name: Debug | Print Subnet name/UUIDs
  debug:
        var: subnet_uuids
  when: global_debug

STEP 4

*(nutanix_vm): *shows how to get the images list and the uuids to use.

- name: Get Images list
  uri:
    url: "{{ api_url_v3 }}/images/list"
    body:
         length: 100
         offset: 0
         filter: ""
    method: POST
    validate_certs: no
    body_format: json
    status_code: 200
    headers:
        Cookie: "{{ session_cookie }}"
  register: json_images_result
  ignore_errors: yes

- name: Stash the image UUIDs
  set_fact:
      image_uuids: "{{ image_uuids | default([]) + [ {'name': item.spec.name, 'uuid': item.metadata.uuid } ] }}"
  with_items: "{{ json_images_result.json.entities }}"
  no_log: True

- name: Debug | Print image name/UUIDs
  debug:
        var: image_uuids
  when: global_debug

STEP 5

*(nutanix_vm): *shows how to define and use the uuids for the VM creation.

- name: Define Cluster UUID to use from name
  set_fact:
       cluster_uuid: "{{ item['uuid'] }}"
  when: "item['name'] == cluster_name"
  loop: "{{ cluster_uuids }}"
  register: cluster_uuid
      - debug: var=cluster_uuid

- name: Define Image UUID to use from name
  set_fact:
       image_uuid: "{{ item['uuid'] }}"
  when: "item['name'] == image_name"
  loop: "{{ image_uuids }}"
  register: image_uuid
- debug: var= image_uuid

- name: Define Subnet UUID to use from name
  set_fact:
       subnet_uuid: "{{ item['uuid'] }}"
  when: "item['name'] == subnet_name"
  loop: "{{ subnet_uuids }}"
  register: subnet_uuid
- debug: var= subnet_uuid

STEP 6

*(nutanix_vm): *shows how to provision a new VM (uses CentOS image here).

- name: Copy python with owner and permissions
  template:
    src: nutanix.py.j2
    dest: /tmp/nutanix.py
    owner: root
    group: root
    mode: u=rwx,g=rx,o=r

- name: Copy  yaml with owner and permissions
  template:
       src: nutanix.yml.j2
       dest: /tmp/nutanix.yml
    owner: root
    group: root
    mode: u=rwx,g=rx,o=r

- name: run python script
  shell:  /tmp/nutanix.py --host {{ vm_name }}
  register: output
- debug: var=output.stdout

- name: Debug | Print VM definitions
  debug:
    var: vm_defs
  when: global_debug
- name: Create fact with VM template contents
  set_fact:
      vm_body: "{{ lookup('template', 'vm-body.yml.j2') | from_yaml }}"
  loop: "{{ vm_defs }}"
  register: templates
  loop_control:
      loop_var: vm

- name: Debug | Print Template lookup result
  debug:
      msg: "{{ item.ansible_facts.vm_body }}"
  when: global_debug
  with_items: "{{ templates.results }}"

- name: Create a VM from a template
  uri:
      url: "{{ api_url_v3 }}/vms"
      body:
          "{{ template.ansible_facts.vm_body }}"
    method: POST
    validate_certs: no
    body_format: json
    headers:
         Cookie: "{{ session_cookie }}"
    status_code: 202
  register: json_create_result
  with_items: "{{ templates.results }}"
  loop_control:
    loop_var: template
  when: 'output.stdout_lines ==  [
            "{}"
        ]'

- name: Debug | Print VM creation result
  debug: msg="{{json_create_result}}"

- name: Debug | Display VM creation response
  debug:
       msg: "{{ item.json.metadata.uuid }}"
  when: 'output.stdout_lines ==  [
            "{}"
        ]'
  with_items: "{{ json_create_result.results }}"

- name: Register the created vm uuid's for future use
  set_fact:
    _uuids: "{{ item.json.metadata.uuid }}"
  with_items: "{{ json_create_result.results }}"
  register: vm_uuids
  when: 'output.stdout_lines ==  [
            "{}"
        ]'
  no_log: True

- name: Debug | Print VM uuids
  debug:
    var: vm_uuids
when: 'output.stdout_lines ==  [
            "{}"
        ]'

'nutanix.py' is a Python script which generates an inventory that Ansible can understand by making API requests to one or more Nutanix clusters. This is placed in the templates folder. You can get a clear idea on this by referring h**ttps://github.com/mattkeeler/ansible-nutanix-inventory

STEP 7

*(nutanix_vm): *template *'nutanix.yml.j2' *is given below.

clusters:
    "{{ cluster_name }}":
        address: "{{ cluster_url }}"
        port: "{{ cluster_port }}"
        username: "{{ prism_user }}"
        password: "{{ prism_password }}"
        verify_ssl: False

caching:
    cache_max_age: 300
    cache_path: '/tmp/'
    cache_base_name: 'ansible-nutanix.cache'

CONCLUSION

Ansible is a simple and efficient tool for automating infrastructure (IaC – Infrastructure as Code). In this tutorial, I used Ansible role *'**nutanix_vm_provisioner' *for the creation of CentOS VM on Nutanix. Ansible can also help in tasks like app deployments, configuration management and wokflow orchestration.

REFERENCES

About The Author

Sreedevi J S

Cloud Dev-Ops Engineer | Cloud Control

Cloud DevOps Engineer with more than three years of experience in supporting, automating, and optimizing deployments to hybrid cloud platforms using DevOps processes, tools, CI/CD, containers and Kubernetes in both Production and Development environments.

On Linked-In