Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sanity and python fix #46

Merged
merged 16 commits into from
Feb 1, 2022
1 change: 1 addition & 0 deletions galaxy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ authors:
- "Balu George (@balugeorge)"
- "Sarath Kumar K (@kumarsarath588)"
- "Prem Karat (@premkarat)"
- "Gevorg Khachatryan (@Gevorg-Khachatryan-97)"
description: Ansible collection for v3 Nutanix APIs https://www.nutanix.dev/api-reference-v3/
license_file: 'LICENSE'
tags: [nutanix, prism, ahv]
Expand Down
Binary file added nutanix-ncp-1.0.0.tar.gz
Binary file not shown.
11 changes: 5 additions & 6 deletions plugins/inventory/ntnx_prism_vm_inventory.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-

# Copyright: (c) 2021 [Balu George, Prem Karat]
Expand Down Expand Up @@ -66,12 +65,12 @@
requirements: "null"
"""

import json
import tempfile
from ansible.errors import AnsibleError
from ansible.plugins.inventory import BaseInventoryPlugin
import json # noqa: E402
import tempfile # noqa: E402

from ..module_utils.prism import vms
from ansible.plugins.inventory import BaseInventoryPlugin # noqa: E402

from ..module_utils.prism import vms # noqa: E402


class Mock_Module:
Expand Down
3 changes: 1 addition & 2 deletions plugins/module_utils/base_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause )
from __future__ import absolute_import, division, print_function

from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.basic import env_fallback
from ansible.module_utils.basic import AnsibleModule, env_fallback

__metaclass__ = type

Expand Down
31 changes: 19 additions & 12 deletions plugins/module_utils/entity.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
# This file is part of Ansible
# 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

import json
from ansible.module_utils.urls import fetch_url
from ansible.module_utils._text import to_text
from base64 import b64encode
from urllib.parse import urlparse, parse_qsl, urlencode, urlunparse

from ansible.module_utils._text import to_text
from ansible.module_utils.urls import fetch_url

try:
from urllib.parse import parse_qsl, urlencode, urlparse, urlunparse
except ImportError:
from urlparse import urlparse # python2


class Entity(object):
Expand All @@ -35,7 +39,7 @@ def create(self, data=None, endpoint=None, query=None, timeout=30):
def read(self, uuid=None, endpoint=None, query=None, timeout=30):
url = self.base_url + "/{0}".format(uuid) if uuid else self.base_url
if endpoint:
url = url + "/{}".format(endpoint)
url = url + "/{0}".format(endpoint)
if query:
url = self._build_url_with_query(url, query)
return self._fetch_url(url, method="GET", timeout=timeout)
Expand Down Expand Up @@ -63,8 +67,8 @@ def list(self, data=None, endpoint=None, use_base_url=False, timeout=30):
return self._fetch_url(url, method="POST", data=data, timeout=timeout)

def get_uuid(self, name):
data = {"filter": f"name=={name}", "length": 1}
resp, _ = self.list(data)
data = {"filter": "name=={0}".format(name), "length": 1}
resp, status = self.list(data)
if resp and resp.get("entities"):
return resp["entities"][0]["metadata"]["uuid"]
return None
Expand All @@ -74,11 +78,11 @@ def _build_url(self, module, scheme, resource_type):
url = "{proto}://{host}".format(proto=scheme, host=host)
port = module.params.get("nutanix_port")
if port:
url += ":{port}".format(port=port)
url += ":{0}".format(port)
if resource_type.startswith("/"):
url += resource_type
else:
url += "/{resource_type}".format(resource_type=resource_type)
url += "/{0}".format(resource_type)
return url

def _build_headers(self, module, additional_headers):
Expand All @@ -88,8 +92,11 @@ def _build_headers(self, module, additional_headers):
usr = module.params.get("nutanix_username")
pas = module.params.get("nutanix_password")
if usr and pas:
cred = f"{usr}:{pas}".format(usr=usr, pas=pas)
encoded_cred = b64encode(bytes(cred, encoding="ascii")).decode("ascii")
cred = "{0}:{1}".format(usr, pas)
try:
encoded_cred = b64encode(bytes(cred, encoding="ascii")).decode("ascii")
except BaseException:
encoded_cred = b64encode(bytes(cred).encode("ascii")).decode("ascii")
auth_header = "Basic " + encoded_cred
headers.update({"Authorization": auth_header})
return headers
Expand Down Expand Up @@ -126,7 +133,7 @@ def _fetch_url(self, url, method, data=None, timeout=30):
else:
err = info.get("msg", "Status code != 2xx")
self.module.fail_json(
msg="Failed fetching URL: {}".format(url),
msg="Failed fetching URL: {0}".format(url),
status_code=status_code,
error=err,
response=resp_json,
Expand Down
5 changes: 4 additions & 1 deletion plugins/module_utils/prism/clusters.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
# This file is part of Ansible
# 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

from .prism import Prism


class Cluster(Prism):
def __init__(self, module):
resource_type = "/clusters"
super().__init__(module, resource_type=resource_type)
super(Cluster, self).__init__(module, resource_type=resource_type)
7 changes: 5 additions & 2 deletions plugins/module_utils/prism/groups.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
# This file is part of Ansible
# 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

from .prism import Prism


class Groups(Prism):
def __init__(self, module):
resource_type = "/groups"
super().__init__(module, resource_type=resource_type)
super(Groups, self).__init__(module, resource_type=resource_type)

def get_uuid(self, entity_type, filter):
data = {"entity_type": entity_type, "filter_criteria": filter}
resp, _ = self.list(data, use_base_url=True)
resp, status = self.list(data, use_base_url=True)
if resp.get("group_results"):
return resp["group_results"][0]["entity_results"][0]["entity_id"]
return None
5 changes: 4 additions & 1 deletion plugins/module_utils/prism/images.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
# This file is part of Ansible
# 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

from .prism import Prism


class Image(Prism):
def __init__(self, module):
resource_type = "/images"
super().__init__(module, resource_type=resource_type)
super(Image, self).__init__(module, resource_type=resource_type)
2 changes: 1 addition & 1 deletion plugins/module_utils/prism/prism.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ class Prism(Entity):

def __init__(self, module, resource_type):
resource_type = self.__BASEURL__ + resource_type
super().__init__(module, resource_type)
super(Prism, self).__init__(module, resource_type)
5 changes: 4 additions & 1 deletion plugins/module_utils/prism/projects.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
# This file is part of Ansible
# 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

from .prism import Prism


class Project(Prism):
def __init__(self, module):
resource_type = "/projects"
super().__init__(module, resource_type=resource_type)
super(Project, self).__init__(module, resource_type=resource_type)
5 changes: 4 additions & 1 deletion plugins/module_utils/prism/subnets.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
# This file is part of Ansible
# 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

from .prism import Prism


class Subnet(Prism):
def __init__(self, module):
resource_type = "/subnets"
super().__init__(module, resource_type=resource_type)
super(Subnet, self).__init__(module, resource_type=resource_type)
6 changes: 4 additions & 2 deletions plugins/module_utils/prism/tasks.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
# This file is part of Ansible
# 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

from os import stat
import time

from .prism import Prism
Expand All @@ -10,7 +12,7 @@
class Task(Prism):
def __init__(self, module):
resource_type = "/tasks"
super().__init__(module, resource_type=resource_type)
super(Task, self).__init__(module, resource_type=resource_type)

def create(self, data=None, endpoint=None, query=None, timeout=30):
raise NotImplementedError("Create not permitted")
Expand Down
56 changes: 25 additions & 31 deletions plugins/module_utils/prism/vms.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
# This file is part of Ansible
# 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

from copy import deepcopy
__metaclass__ = type

import base64
import os
from copy import deepcopy

from .clusters import Cluster
from .groups import Groups
from .images import Image
from .prism import Prism
from .projects import Project
from .subnets import Subnet
from .groups import Groups
from .images import Image


class VM(Prism):
def __init__(self, module):
resource_type = "/vms"
super().__init__(module, resource_type=resource_type)
super(VM, self).__init__(module, resource_type=resource_type)
self.build_spec_methods = {
"name": self._build_spec_name,
"desc": self._build_spec_desc,
Expand All @@ -41,7 +41,7 @@ def get_spec(self):
for ansible_param, ansible_value in self.module.params.items():
build_spec_method = self.build_spec_methods.get(ansible_param)
if build_spec_method and ansible_value:
_, error = build_spec_method(spec, ansible_value)
spec, error = build_spec_method(spec, ansible_value)
if error:
return None, error
return spec, None
Expand Down Expand Up @@ -113,7 +113,8 @@ def _build_spec_project(self, payload, param):
name = param["name"]
uuid = project.get_uuid(name)
if not uuid:
error = "Project {} not found.".format(name)

error = "Project {0} not found.".format(name)
return None, error

elif "uuid" in param:
Expand All @@ -130,7 +131,8 @@ def _build_spec_cluster(self, payload, param):
name = param["name"]
uuid = cluster.get_uuid(name)
if not uuid:
error = "Cluster {} not found.".format(name)

error = "Cluster {0} not found.".format(name)
return None, error

elif "uuid" in param:
Expand Down Expand Up @@ -165,7 +167,7 @@ def _build_spec_networks(self, payload, networks):
name = network["subnet"]["name"]
uuid = subnet.get_uuid(name)
if not uuid:
error = "Subnet {} not found.".format(name)
error = "Subnet {0} not found.".format(name)
return None, error

elif network.get("subnet", {}).get("uuid"):
Expand All @@ -180,30 +182,24 @@ def _build_spec_networks(self, payload, networks):

def _build_spec_disks(self, payload, vdisks):
disks = []
scsi_index = sata_index = pci_index = ide_index = 0
device_indexes = {}

for vdisk in vdisks:
disk = self._get_default_disk_spec()

if "type" in vdisk:
if vdisk.get("type"):
disk["device_properties"]["device_type"] = vdisk["type"]

if "bus" in vdisk:
if vdisk["bus"] == "SCSI":
device_index = scsi_index
scsi_index += 1
elif vdisk["bus"] == "SATA":
device_index = sata_index
sata_index += 1
elif vdisk["bus"] == "PCI":
device_index = pci_index
pci_index += 1
elif vdisk["bus"] == "IDE":
device_index = ide_index
ide_index += 1
if vdisk.get("bus"):
if device_indexes.get(vdisk["bus"]):
device_indexes[vdisk["bus"]] += 1
else:
device_indexes[vdisk["bus"]] = 0

disk["device_properties"]["disk_address"]["adapter_type"] = vdisk["bus"]
disk["device_properties"]["disk_address"]["device_index"] = device_index
disk["device_properties"]["disk_address"][
"device_index"
] = device_indexes[vdisk["bus"]]

if vdisk.get("empty_cdrom"):
disk.pop("disk_size_bytes")
Expand All @@ -220,12 +216,10 @@ def _build_spec_disks(self, payload, vdisks):
name = vdisk["storage_container"]["name"]
uuid = groups.get_uuid(
entity_type="storage_container",
filter=f"container_name=={name}",
filter="container_name=={0}".format(name),
)
if not uuid:
error = "Storage container {} not found.".format(
name
)
error = "Storage container {0} not found.".format(name)
return None, error

elif "uuid" in vdisk["storage_container"]:
Expand All @@ -239,7 +233,7 @@ def _build_spec_disks(self, payload, vdisks):
name = vdisk["clone_image"]["name"]
uuid = image.get_uuid(name)
if not uuid:
error = "Image {} not found.".format(name)
error = "Image {0} not found.".format(name)
return None, error

elif "uuid" in vdisk["clone_image"]:
Expand Down Expand Up @@ -281,7 +275,7 @@ def _build_spec_gc(self, payload, param):
fpath = param["script_path"]

if not os.path.exists(fpath):
error = "File not found: {}".format(fpath)
error = "File not found: {0}".format(fpath)
return None, error

with open(fpath, "rb") as f:
Expand Down
Loading