Skip to content

Commit

Permalink
Phase 1 Changes for ansible ahv support (#1)
Browse files Browse the repository at this point in the history
* Add basic api client and module for vm list call support

* Fix typo

* Use loop instead of with_items

* Cleanup vm info module

* Expose vm sttus and spec directly

* Remove hard coded v3 api endpoint from client

* Add vms array for vm names

* Rename requests response var

* Add request timeout and fix error handling

* Raise caught error along with error message

* Fix typo

* Add environment variable fallback for hostname, username and password

* PC VM create and delete

* Rename api client args

* Update modules and readme to support api client changes

* Fix typo

* handling failure conditions

* Increase timeout to 20 seconds

* Add image info module

* Add nutanix_images module for image control

* Add image delete operation support

* Add image update operation

* added cloud init support

* VM update

* VM list info improvements

* Add dynamic inventory plugin

* Remove unused imports

* Rename image_details to images

* Update vm list example

* Rename nutanix inventory plugin

* Remove shebang for plugin

* Add gitignore

* Invetory plugin fixes after renaming

* Add more inventory file choices

* Add more inventory file choices

* Remove inventory script dependency on api client

* Fix sanity and compile test errors

* Remove exec permission of inventory script

* Lint fixes

* More lint fixes

* Fix missing import

* Add license and update module documentation

* removed asyncio

* update vm if exists

* handle Guest customization cdrom

* added documentatino

* lint fixes

* lint fixes

mend

* fixed ansibledic & pep8

* fixed sanity issues

* fixed sysprep

* Remove f-strings for Python 3.5 compatibility

* sysprep fix

* sysprep fix

mend

* sysprep fix

mend

* Formatting changes

* More cleanup

* pep8 fixes

* Add pagination support for image list operation

* nutanix_images module rewrite

* Rename nutanix_images module to nutanix_image

* Formatting updates and more examples

* Update readme

* Update version

* Fix indentation in nutanix_vm create example

* Fix create_vm example

* Fix image update with image_uuid

* Add github actions for running compile and sanity tests

* Update README.md

* Fix github action syntax

* Remove hard requirement of image_uuid option

* Limit github action push trigger to main branch

Co-authored-by: Balu George <balugeorge@users.noreply.github.com>
Co-authored-by: kumarsarath588 <kumar.sarath588@gmail.com>
  • Loading branch information
3 people authored Jul 13, 2021
1 parent 18aaec9 commit a1e1dee
Show file tree
Hide file tree
Showing 10 changed files with 2,044 additions and 2 deletions.
36 changes: 36 additions & 0 deletions .github/workflows/sanity-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
###### To-do ######
# Fetch namespace, collection and version details dynamically
# Skip tests for python 2.6 and 2.7

name: Run compile and sanity tests

on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
ci:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup Python 3.9
uses: actions/setup-python@v2
with:
python-version: '3.9'
- name: Setup Docker
uses: docker-practice/actions-setup-docker@master
- name: Print docker version
run: |
set -x
docker version
- name: Install ansible
run: pip install ansible
- name: Build and install the collection
run: ansible-galaxy collection build && ansible-galaxy collection install nutanix-nutanix-0.0.1-rc1.tar.gz
- name: Run tests
run: |
cd /home/${USER}/.ansible/collections/ansible_collections/nutanix/nutanix
ansible-test sanity --docker default --python 3.9
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*.tar.gz
*.pyc
45 changes: 43 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,43 @@
# ansible-ahv-provider-plugin-
Ansible plugins to interact with AHV APIs
# ansible-ahv-provider-plugin
Ansible plugin to integrate with Nutanix Enterprise Cloud


# Building and installing the collection locally
```
ansible-galaxy collection build
ansible-galaxy collection install nutanix-nutanix-0.0.1.tar.gz
```
_Add `--force` option for rebuilding or reinstalling to overwrite existing data_

# Included modules
```
nutanix_image_info
nutanix_image
nutanix_vm_info
nutanix_vm
```

# Inventory plugin
`nutanix_vm_inventory`

# Module documentation and examples
```
ansible-doc nutanix.nutanix.<module_name>
```

# Examples
## Playbook to print name of vms in PC
```
- hosts: localhost
collections:
- nutanix.nutanix
tasks:
- nutanix_vm_info:
pc_hostname: {{ pc_hostname }}
pc_username: {{ pc_username }}
pc_password: {{ pc_password }}
validate_certs: False
register: result
- debug:
msg: "{{ result.vms }}"
```
11 changes: 11 additions & 0 deletions galaxy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace: "nutanix"
name: "nutanix"
version: "0.0.1-rc1"
readme: "README.md"
authors:
- "Balu George (@balugeorge)"
- "Sarath Kumar K (@kumarsarath588)"
license:
- GPL-2.0-or-later
tags: [nutanix, ahv]
repository: "https://www.github.com/ideadevice/ansible-ahv-provider-plugin"
155 changes: 155 additions & 0 deletions plugins/inventory/nutanix_vm_inventory.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
# Copyright: (c) 2021, Balu George <balu.george@nutanix.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

from __future__ import (absolute_import, division, print_function)
__metaclass__ = type

DOCUMENTATION = r'''
name: nutanix_vm_inventory
plugin_type: inventory
short_description: Returns nutanix vms ansible inventory
requirements:
- requests
description: Returns nutanix vms ansible inventory
options:
plugin:
description: Name of the plugin
required: true
choices: ['nutanix_vm_inventory', 'nutanix.nutanix.nutanix_vm_inventory']
pc_hostname:
description: PC hostname or IP address
required: true
type: str
env:
- name: PC_HOSTNAME
pc_username:
description: PC username
required: true
type: str
env:
- name: PC_USERNAME
pc_password:
description: PC password
required: true
type: str
env:
- name: PC_PASSWORD
pc_port:
description: PC port
default: 9440
type: str
env:
- name: PC_PORT
validate_certs:
description:
- Set value to C(False) to skip validation for self signed certificates
- This is not recommended for production setup
default: True
type: boolean
env:
- name: VALIDATE_CERTS
'''

try:
import requests
HAS_REQUESTS = True
except ImportError:
HAS_REQUESTS = False

from ansible.errors import AnsibleError
from ansible.plugins.inventory import BaseInventoryPlugin


class InventoryModule(BaseInventoryPlugin):
'''Nutanix VM dynamic invetory parser for ansible'''

NAME = 'nutanix.nutanix.nutanix_vm_inventory'

def __init__(self):
super(InventoryModule, self).__init__()
self.session = None

def _get_create_session(self):
'''Create session'''
if not self.session:
self.session = requests.Session()
if not self.validate_certs:
self.session.verify = self.validate_certs
from urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)

return self.session

def _get_vm_list(self):
'''Get a list of existing VMs'''
api_url = "https://{0}:{1}/api/nutanix/v3/vms/list".format(self.pc_hostname, self.pc_port)
auth = (self.pc_username, self.pc_password)
headers = {'Content-Type': 'application/json', 'Accept': 'application/json'}
payload = '{"offset": 0, "length": 100}'

session = self._get_create_session()
vm_list_response = session.post(url=api_url, auth=auth, headers=headers, data=payload)

return vm_list_response.json()

def _build_inventory(self):
'''Build inventory from API response'''
vars_to_remove = ["disk_list", "vnuma_config", "nic_list", "power_state_mechanism", "host_reference",
"serial_port_list", "gpu_list", "storage_config", "boot_config", "guest_customization"]
vm_list_resp = self._get_vm_list()

for entity in vm_list_resp["entities"]:
nic_count = 0
cluster = entity["status"]["cluster_reference"]["name"]
# self.inventory.add_host(f"{vm_name}-{vm_uuid}")
vm_name = entity["status"]["name"]
vm_uuid = entity["metadata"]["uuid"]

# Get VM IP
for nics in entity["status"]["resources"]["nic_list"]:
if nics["nic_type"] == "NORMAL_NIC" and nic_count == 0:
for endpoint in nics["ip_endpoint_list"]:
if endpoint["type"] == "ASSIGNED":
vm_ip = endpoint["ip"]
nic_count += 1
continue

# Add inventory groups and hosts to inventory groups
self.inventory.add_group(cluster)
self.inventory.add_child('all', cluster)
self.inventory.add_host(vm_name, group=cluster)
self.inventory.set_variable(vm_name, 'ansible_host', vm_ip)
self.inventory.set_variable(vm_name, 'uuid', vm_uuid)

# Add hostvars
for var in vars_to_remove:
try:
del entity["status"]["resources"][var]
except KeyError:
pass
for key, value in entity["status"]["resources"].items():
self.inventory.set_variable(vm_name, key, value)

def verify_file(self, path):
'''Verify inventory configuration file'''
valid = False
if super(InventoryModule, self).verify_file(path):
if path.endswith(('nutanix.yaml', 'nutanix.yml', 'nutanix_host_inventory.yaml', 'nutanix_host_inventory.yml')):
valid = True
return valid

def parse(self, inventory, loader, path, cache):
'''Parse inventory'''
if not HAS_REQUESTS:
raise AnsibleError("Missing python 'requests' package")

super(InventoryModule, self).parse(inventory, loader, path, cache)
self._read_config_data(path)

self.pc_hostname = self.get_option('pc_hostname')
self.pc_username = self.get_option('pc_username')
self.pc_password = self.get_option('pc_password')
self.pc_port = self.get_option('pc_port')
self.validate_certs = self.get_option('validate_certs')

self._build_inventory()
Loading

0 comments on commit a1e1dee

Please sign in to comment.