From 70c4f5a3a38df67371669dd9188e90be1b30490e Mon Sep 17 00:00:00 2001 From: Gevorg-Khachatryaan Date: Mon, 17 Oct 2022 12:31:51 +0400 Subject: [PATCH 01/48] volume groups module --- plugins/module_utils/prism/volume_groups.py | 93 +++++++++ plugins/modules/ntnx_volume_groups.py | 208 ++++++++++++++++++++ 2 files changed, 301 insertions(+) create mode 100644 plugins/module_utils/prism/volume_groups.py create mode 100644 plugins/modules/ntnx_volume_groups.py diff --git a/plugins/module_utils/prism/volume_groups.py b/plugins/module_utils/prism/volume_groups.py new file mode 100644 index 000000000..bec37b34e --- /dev/null +++ b/plugins/module_utils/prism/volume_groups.py @@ -0,0 +1,93 @@ +# 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 copy import deepcopy + +from .clusters import get_cluster_uuid +from .prism import Prism + + +class VolumeGroup(Prism): + __BASEURL__ = "/api/storage/v4.0.a2/config" + + def __init__(self, module): + resource_type = "/volume-groups" + super(VolumeGroup, self).__init__(module, resource_type=resource_type) + self.build_spec_methods = { + "name": self._build_spec_name, + "desc": self._build_spec_desc, + "cluster": self._build_spec_cluster, + "target_prefix": self._build_spec_target_prefix, + "load_balance": self._build_spec_load_balance, + } + + # def get_uuid(self, value, key="name", raise_error=True, no_response=False): + # data = {"filter": "{0}=={1}".format(key, value)} + # resp = self.list(data, raise_error=raise_error, no_response=no_response) + # entities = resp.get("entities") if resp else None + # if entities: + # for entity in entities: + # if entity["service_group"]["name"] == value: + # return entity["uuid"] + # return None + + def _get_default_spec(self): + return deepcopy( + { + "name": "", + "description": "", + "loadBalanceVmAttachments": False, + "sharingStatus": "SHARED", + "iscsiTargetPrefix": "", + "clusterReference": None, + "usageType": "USER", + } + ) + + def _build_spec_name(self, payload, value): + payload["name"] = value + return payload, None + + def _build_spec_desc(self, payload, value): + payload["description"] = value + return payload, None + + def _build_spec_target_prefix(self, payload, value): + payload["iscsiTargetPrefix"] = value + return payload, None + + def _build_spec_load_balance(self, payload, value): + payload["loadBalanceVmAttachments"] = value + return payload, None + + def _build_spec_cluster(self, payload, param): + uuid, err = get_cluster_uuid(param, self.module) + if err: + return None, err + payload["clusterReference"] = uuid + return payload, None + +# Helper functions + + +class VGDisks(): + pass + +def get_volume_group_uuid(config, module): + if "name" in config: + service_group = VolumeGroup(module) + name = config["name"] + uuid = service_group.get_uuid(name) + if not uuid: + error = "Volume Group {0} not found.".format(name) + return None, error + elif "uuid" in config: + uuid = config["uuid"] + else: + error = "Config {0} doesn't have name or uuid key".format(config) + return None, error + + return uuid, None diff --git a/plugins/modules/ntnx_volume_groups.py b/plugins/modules/ntnx_volume_groups.py new file mode 100644 index 000000000..d3f8243a5 --- /dev/null +++ b/plugins/modules/ntnx_volume_groups.py @@ -0,0 +1,208 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2021, Prem Karat +# 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""" +--- +module: ntnx_volume_groups +short_description: volume_groups module which suports volume_groups CRUD operations +version_added: 1.4.0 +description: 'Create, Update, Delete volume_group' +options: + state: + description: + - Specify state of volume_groups + - If C(state) is set to C(present) then volume_groups is created. + - >- + If C(state) is set to C(absent) and if the volume_groups exists, then + volume_groups is removed. + choices: + - present + - absent + type: str + default: present + wait: + description: Wait for volume_groups CRUD operation to complete. + type: bool + required: false + default: True + name: + description: volume_groups Name + required: False + type: str + volume_group_uuid: + description: volume_group UUID + type: str + desc: + description: volume_groups description + type: str + + ...............TODO + +extends_documentation_fragment: + - nutanix.ncp.ntnx_credentials + - nutanix.ncp.ntnx_operations +author: + - Prem Karat (@premkarat) + - Gevorg Khachatryan (@Gevorg-Khachatryan-97) + - Alaa Bishtawi (@alaa-bish) +""" + +EXAMPLES = r""" + +""" + +RETURN = r""" + +""" + +from ..module_utils.base_module import BaseModule # noqa: E402 +from ..module_utils.prism.volume_groups import VolumeGroup # noqa: E402 +from ..module_utils.utils import remove_param_with_none_value # noqa: E402 + + +def get_module_spec(): + mutually_exclusive = [("name", "uuid")] + + entity_by_spec = dict(name=dict(type="str"), uuid=dict(type="str")) + + disk_spec = dict( + size_gb=dict(type="int"), + storage_container=dict( + type="dict", options=entity_by_spec, mutually_exclusive=mutually_exclusive + ), + ) + + module_args = dict( + name=dict(type="str"), + desc=dict(type="str"), + cluster=dict( + type="dict", options=entity_by_spec, mutually_exclusive=mutually_exclusive + ), + target_prefix=dict(type="str"), + volume_group_uuid=dict(type="str"), + flash_mode=dict(type="bool", default=False), + disks=dict(type="list", elements="dict", options=disk_spec), + vms=dict(type="list", elements="str"), + load_balance=dict(type="bool", default=False), + clients=dict(type="list", elements="str"), + CHAP_auth=dict(type="bool", default=False), + target_password=dict(type="str", no_log=True), + + ) + + return module_args + + +def create_volume_group(module, result): + volume_group = VolumeGroup(module) + spec, error = volume_group.get_spec() + if error: + result["error"] = error + module.fail_json(msg="Failed generating volume_groups spec", **result) + + if module.check_mode: + result["response"] = spec + return + + # attach disks + # VGDisks + # attach vms + + # attach clients + + resp = volume_group.create(spec) + # volume_group_uuid = resp["uuid"] + result["changed"] = True + result["response"] = resp + # result["volume_group_uuid"] = volume_group_uuid + + +# def update_volume_group(module, result): +# volume_group = VolumeGroup(module) +# volume_group_uuid = module.params.get("volume_group_uuid") +# if not volume_group_uuid: +# result["error"] = "Missing parameter volume_group_uuid in playbook" +# module.fail_json(msg="Failed updating volume_group", **result) +# result["volume_group_uuid"] = volume_group_uuid +# +# # read the current state of volume_group +# resp = volume_group.read(volume_group_uuid) +# resp = resp.get("volume_group") +# +# # new spec for updating volume_group +# update_spec, error = volume_group.get_spec(resp) +# if error: +# result["error"] = error +# module.fail_json(msg="Failed generating volume_group update spec", **result) +# +# # check for idempotency +# if resp == update_spec: +# result["skipped"] = True +# module.exit_json( +# msg="Nothing to change. Refer docs to check for fields which can be updated" +# ) +# +# if module.check_mode: +# result["response"] = update_spec +# return +# +# # update volume_group +# volume_group.update(update_spec, uuid=volume_group_uuid, no_response=True) +# +# resp = volume_group.read(volume_group_uuid) +# +# result["changed"] = True +# result["response"] = resp + + +# def delete_volume_group(module, result): +# volume_group_uuid = module.params["volume_group_uuid"] +# if not volume_group_uuid: +# result["error"] = "Missing parameter volume_group_uuid in playbook" +# module.fail_json(msg="Failed deleting volume_groups", **result) +# +# volume_group = VolumeGroup(module) +# resp = volume_group.delete(volume_group_uuid, no_response=True) +# result["changed"] = True +# result["response"] = resp +# result["volume_group_uuid"] = volume_group_uuid + + +def run_module(): + module = BaseModule( + argument_spec=get_module_spec(), + supports_check_mode=True, + required_if=[ + ("state", "present", ("name", "volume_group_uuid"), True), + ("state", "absent", ("volume_group_uuid",)), + ], + ) + remove_param_with_none_value(module.params) + result = { + "changed": False, + "error": None, + "response": None, + "volume_group_uuid": None, + } + state = module.params["state"] + if state == "absent": + delete_volume_group(module, result) + elif module.params.get("volume_group_uuid"): + update_volume_group(module, result) + else: + create_volume_group(module, result) + module.exit_json(**result) + + +def main(): + run_module() + + +if __name__ == "__main__": + main() From 500583a469bd2023d92f0430b55883128b185672 Mon Sep 17 00:00:00 2001 From: alaa-bish Date: Wed, 19 Oct 2022 09:40:00 +0300 Subject: [PATCH 02/48] black fix --- meta/runtime.yml | 1 + plugins/module_utils/prism/volume_groups.py | 4 +++- plugins/modules/ntnx_volume_groups.py | 3 +-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/meta/runtime.yml b/meta/runtime.yml index 12e2e3f84..6b78b0afe 100644 --- a/meta/runtime.yml +++ b/meta/runtime.yml @@ -63,3 +63,4 @@ action_groups: - ntnx_karbon_clusters_info - ntnx_karbon_registries - ntnx_karbon_registries_info + - ntnx_volume_groups diff --git a/plugins/module_utils/prism/volume_groups.py b/plugins/module_utils/prism/volume_groups.py index bec37b34e..a858edb44 100644 --- a/plugins/module_utils/prism/volume_groups.py +++ b/plugins/module_utils/prism/volume_groups.py @@ -70,12 +70,14 @@ def _build_spec_cluster(self, payload, param): payload["clusterReference"] = uuid return payload, None + # Helper functions -class VGDisks(): +class VGDisks: pass + def get_volume_group_uuid(config, module): if "name" in config: service_group = VolumeGroup(module) diff --git a/plugins/modules/ntnx_volume_groups.py b/plugins/modules/ntnx_volume_groups.py index d3f8243a5..dea2c3afe 100644 --- a/plugins/modules/ntnx_volume_groups.py +++ b/plugins/modules/ntnx_volume_groups.py @@ -42,7 +42,7 @@ description: volume_groups description type: str - ...............TODO + # ...............TODO extends_documentation_fragment: - nutanix.ncp.ntnx_credentials @@ -93,7 +93,6 @@ def get_module_spec(): clients=dict(type="list", elements="str"), CHAP_auth=dict(type="bool", default=False), target_password=dict(type="str", no_log=True), - ) return module_args From 6149e8939bdad89fc1b22a9d208851d9ca540d33 Mon Sep 17 00:00:00 2001 From: Gevorg-Khachatryaan Date: Wed, 19 Oct 2022 14:13:35 +0400 Subject: [PATCH 03/48] volume groups module, disks --- plugins/module_utils/entity.py | 3 +- plugins/module_utils/prism/vdisks.py | 57 +++++++++++++++++++++ plugins/module_utils/prism/volume_groups.py | 3 -- plugins/modules/ntnx_volume_groups.py | 37 ++++++++++--- 4 files changed, 88 insertions(+), 12 deletions(-) create mode 100644 plugins/module_utils/prism/vdisks.py diff --git a/plugins/module_utils/entity.py b/plugins/module_utils/entity.py index ba1d0642c..6aafe8755 100644 --- a/plugins/module_utils/entity.py +++ b/plugins/module_utils/entity.py @@ -85,6 +85,7 @@ def update( self, data=None, uuid=None, + method="PUT", endpoint=None, query=None, raise_error=True, @@ -98,7 +99,7 @@ def update( url = self._build_url_with_query(url, query) return self._fetch_url( url, - method="PUT", + method=method, data=data, raise_error=raise_error, no_response=no_response, diff --git a/plugins/module_utils/prism/vdisks.py b/plugins/module_utils/prism/vdisks.py new file mode 100644 index 000000000..28e0f7105 --- /dev/null +++ b/plugins/module_utils/prism/vdisks.py @@ -0,0 +1,57 @@ +# 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 copy import deepcopy + +from .clusters import get_cluster_uuid +from .groups import get_entity_uuid +from .prism import Prism + + +class VDisks: + + def get_spec(self, module, vdisk): + payload = self._get_default_spec() + spec, error = self._build_spec_vdisk(module, payload, vdisk) + if error: + return None, error + return spec, None + + @staticmethod + def _get_default_spec(): + return deepcopy( + { + "diskSizeBytes": None, + "diskDataSourceReference": { + "$objectType": "common.v1.config.EntityReference", + "$reserved": { + "$fqObjectType": "common.v1.r0.a3.config.EntityReference" + }, + "$unknownFields": {}, + "extId": None, + "entityType": "STORAGE_CONTAINER" + } + } + ) + + @staticmethod + def _build_spec_vdisk(module, payload, vdisk): + + disk_size_bytes = vdisk["size_gb"] * 1024 * 1024 * 1024 + + payload["diskSizeBytes"] = disk_size_bytes + uuid, error = get_entity_uuid( + vdisk["storage_container"], + module, + key="container_name", + entity_type="storage_container", + ) + if error: + return None, error + + payload["diskDataSourceReference"]["extId"] = uuid + + return payload, None diff --git a/plugins/module_utils/prism/volume_groups.py b/plugins/module_utils/prism/volume_groups.py index bec37b34e..1b8503815 100644 --- a/plugins/module_utils/prism/volume_groups.py +++ b/plugins/module_utils/prism/volume_groups.py @@ -73,9 +73,6 @@ def _build_spec_cluster(self, payload, param): # Helper functions -class VGDisks(): - pass - def get_volume_group_uuid(config, module): if "name" in config: service_group = VolumeGroup(module) diff --git a/plugins/modules/ntnx_volume_groups.py b/plugins/modules/ntnx_volume_groups.py index d3f8243a5..f511465f1 100644 --- a/plugins/modules/ntnx_volume_groups.py +++ b/plugins/modules/ntnx_volume_groups.py @@ -63,6 +63,8 @@ from ..module_utils.base_module import BaseModule # noqa: E402 from ..module_utils.prism.volume_groups import VolumeGroup # noqa: E402 +from ..module_utils.prism.vdisks import VDisks # noqa: E402 +from ..module_utils.prism.tasks import Task # noqa: E402 from ..module_utils.utils import remove_param_with_none_value # noqa: E402 @@ -110,17 +112,28 @@ def create_volume_group(module, result): result["response"] = spec return - # attach disks - # VGDisks - # attach vms - - # attach clients - resp = volume_group.create(spec) - # volume_group_uuid = resp["uuid"] + task_uuid = resp["data"]["extId"][-36:] result["changed"] = True result["response"] = resp - # result["volume_group_uuid"] = volume_group_uuid + result["task_uuid"] = task_uuid + wait_for_task_completion(module, result) + + volume_group_uuid = result["volume_group_uuid"] + resp = volume_group.read(volume_group_uuid) + result["response"] = resp + if module.params.get("disks"): + vdisk = VDisks() + disks_response = [] + for disk in module.params["disks"]: + spec, _ = vdisk.get_spec(module, disk) + resp = volume_group.update(spec, volume_group_uuid, method="POST", endpoint="disks") + disks_response.append(resp) + result["response"]["disks"] = disks_response + + # attach vms + + # attach clients # def update_volume_group(module, result): @@ -174,6 +187,14 @@ def create_volume_group(module, result): # result["volume_group_uuid"] = volume_group_uuid +def wait_for_task_completion(module, result): + task = Task(module) + task_uuid = result["task_uuid"] + resp = task.wait_for_completion(task_uuid) + result["response"] = resp + result["volume_group_uuid"] = resp["entity_reference_list"][0]["uuid"] + + def run_module(): module = BaseModule( argument_spec=get_module_spec(), From 524592556fd2d611c1945bb231054a92c3ae8975 Mon Sep 17 00:00:00 2001 From: Gevorg-Khachatryaan Date: Wed, 19 Oct 2022 14:14:13 +0400 Subject: [PATCH 04/48] volume groups module, default spec --- plugins/module_utils/prism/volume_groups.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/plugins/module_utils/prism/volume_groups.py b/plugins/module_utils/prism/volume_groups.py index 1b8503815..6fd5a722d 100644 --- a/plugins/module_utils/prism/volume_groups.py +++ b/plugins/module_utils/prism/volume_groups.py @@ -38,10 +38,8 @@ def _get_default_spec(self): return deepcopy( { "name": "", - "description": "", "loadBalanceVmAttachments": False, "sharingStatus": "SHARED", - "iscsiTargetPrefix": "", "clusterReference": None, "usageType": "USER", } From ab90fd949bcabda2a721aaf865554b005d7155ef Mon Sep 17 00:00:00 2001 From: alaa-bish Date: Wed, 19 Oct 2022 13:55:19 +0300 Subject: [PATCH 05/48] sanity fix --- plugins/module_utils/prism/vdisks.py | 7 ++----- plugins/modules/ntnx_volume_groups.py | 10 +++++----- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/plugins/module_utils/prism/vdisks.py b/plugins/module_utils/prism/vdisks.py index 28e0f7105..ac5870cf8 100644 --- a/plugins/module_utils/prism/vdisks.py +++ b/plugins/module_utils/prism/vdisks.py @@ -6,13 +6,10 @@ from copy import deepcopy -from .clusters import get_cluster_uuid from .groups import get_entity_uuid -from .prism import Prism class VDisks: - def get_spec(self, module, vdisk): payload = self._get_default_spec() spec, error = self._build_spec_vdisk(module, payload, vdisk) @@ -32,8 +29,8 @@ def _get_default_spec(): }, "$unknownFields": {}, "extId": None, - "entityType": "STORAGE_CONTAINER" - } + "entityType": "STORAGE_CONTAINER", + }, } ) diff --git a/plugins/modules/ntnx_volume_groups.py b/plugins/modules/ntnx_volume_groups.py index e53d9e036..7b6fb2b59 100644 --- a/plugins/modules/ntnx_volume_groups.py +++ b/plugins/modules/ntnx_volume_groups.py @@ -41,9 +41,7 @@ desc: description: volume_groups description type: str - # ...............TODO - extends_documentation_fragment: - nutanix.ncp.ntnx_credentials - nutanix.ncp.ntnx_operations @@ -62,9 +60,9 @@ """ from ..module_utils.base_module import BaseModule # noqa: E402 -from ..module_utils.prism.volume_groups import VolumeGroup # noqa: E402 -from ..module_utils.prism.vdisks import VDisks # noqa: E402 from ..module_utils.prism.tasks import Task # noqa: E402 +from ..module_utils.prism.vdisks import VDisks # noqa: E402 +from ..module_utils.prism.volume_groups import VolumeGroup # noqa: E402 from ..module_utils.utils import remove_param_with_none_value # noqa: E402 @@ -126,7 +124,9 @@ def create_volume_group(module, result): disks_response = [] for disk in module.params["disks"]: spec, _ = vdisk.get_spec(module, disk) - resp = volume_group.update(spec, volume_group_uuid, method="POST", endpoint="disks") + resp = volume_group.update( + spec, volume_group_uuid, method="POST", endpoint="disks" + ) disks_response.append(resp) result["response"]["disks"] = disks_response From 8c93b896b9589dd0d4616095c7f52d232ef88dc4 Mon Sep 17 00:00:00 2001 From: Gevorg-Khachatryaan Date: Wed, 19 Oct 2022 19:45:40 +0400 Subject: [PATCH 06/48] volume groups module, vms, clients --- plugins/module_utils/prism/volume_groups.py | 39 ++++++++++++++++++++- plugins/modules/ntnx_volume_groups.py | 34 ++++++++++++++++-- 2 files changed, 70 insertions(+), 3 deletions(-) diff --git a/plugins/module_utils/prism/volume_groups.py b/plugins/module_utils/prism/volume_groups.py index 812de4c93..7a2374fac 100644 --- a/plugins/module_utils/prism/volume_groups.py +++ b/plugins/module_utils/prism/volume_groups.py @@ -8,7 +8,7 @@ from .clusters import get_cluster_uuid from .prism import Prism - +from .vms import get_vm_uuid class VolumeGroup(Prism): __BASEURL__ = "/api/storage/v4.0.a2/config" @@ -22,6 +22,7 @@ def __init__(self, module): "cluster": self._build_spec_cluster, "target_prefix": self._build_spec_target_prefix, "load_balance": self._build_spec_load_balance, + "flash_mode": self._build_spec_flash_mode, } # def get_uuid(self, value, key="name", raise_error=True, no_response=False): @@ -61,6 +62,28 @@ def _build_spec_load_balance(self, payload, value): payload["loadBalanceVmAttachments"] = value return payload, None + def _build_spec_flash_mode(self, payload, value): + payload["storageFeatures"] = { + "$objectType": "storage.v4.config.StorageFeatures", + "$reserved": { + "$fqObjectType": "storage.v4.r0.a2.config.StorageFeatures" + }, + "$unknownFields": { + + }, + "flashMode": { + "$objectType": "storage.v4.config.FlashMode", + "$reserved": { + "$fqObjectType": "storage.v4.r0.a2.config.FlashMode" + }, + "$unknownFields": { + + }, + "isEnabled": True + } + } + return payload, None + def _build_spec_cluster(self, payload, param): uuid, err = get_cluster_uuid(param, self.module) if err: @@ -68,7 +91,21 @@ def _build_spec_cluster(self, payload, param): payload["clusterReference"] = uuid return payload, None + def get_vm_spec(self, vm): + uuid, error = get_vm_uuid(vm, self.module) + if error: + return None, error + spec = {"extId": uuid} + return spec, None + + def get_client_spec(self, client): + # uuid, error = get_client_uuid(client, self.module) + # if error: + # return None, error + spec = {"extId": client["uuid"]} + return spec, None +# {"extId":"42a59a22-d821-4db2-b0b9-68f420589bc1"} # Helper functions diff --git a/plugins/modules/ntnx_volume_groups.py b/plugins/modules/ntnx_volume_groups.py index 7b6fb2b59..53f2c09d1 100644 --- a/plugins/modules/ntnx_volume_groups.py +++ b/plugins/modules/ntnx_volume_groups.py @@ -88,9 +88,19 @@ def get_module_spec(): volume_group_uuid=dict(type="str"), flash_mode=dict(type="bool", default=False), disks=dict(type="list", elements="dict", options=disk_spec), - vms=dict(type="list", elements="str"), + vms=dict( + type="list", + elements="dict", + options=entity_by_spec, + mutually_exclusive=mutually_exclusive + ), load_balance=dict(type="bool", default=False), - clients=dict(type="list", elements="str"), + clients=dict( + type="list", + elements="dict", + options=entity_by_spec, + mutually_exclusive=mutually_exclusive + ), CHAP_auth=dict(type="bool", default=False), target_password=dict(type="str", no_log=True), ) @@ -119,6 +129,8 @@ def create_volume_group(module, result): volume_group_uuid = result["volume_group_uuid"] resp = volume_group.read(volume_group_uuid) result["response"] = resp + + # create disks if module.params.get("disks"): vdisk = VDisks() disks_response = [] @@ -131,8 +143,26 @@ def create_volume_group(module, result): result["response"]["disks"] = disks_response # attach vms + if module.params.get("vms"): + vms_response = [] + for vm in module.params["vms"]: + spec, _ = volume_group.get_vm_spec(vm) + resp = volume_group.update( + spec, volume_group_uuid, method="POST", endpoint="$actions/attach-vm" + ) + vms_response.append(resp) + result["response"]["vms"] = vms_response # attach clients + if module.params.get("clients"): + clients_response = [] + for client in module.params["clients"]: + spec, _ = volume_group.get_client_spec(client) + resp = volume_group.update( + spec, volume_group_uuid, method="POST", endpoint="/$actions/attach-iscsi-client" + ) + clients_response.append(resp) + result["response"]["clients"] = clients_response # def update_volume_group(module, result): From efe2aecb07833a042be7d4fb4fbe1f70eade1a31 Mon Sep 17 00:00:00 2001 From: Gevorg-Khachatryaan Date: Sat, 22 Oct 2022 23:36:02 +0400 Subject: [PATCH 07/48] volume groups module, clients --- plugins/module_utils/entity.py | 1 - plugins/module_utils/prism/iscsi_clients.py | 88 +++++++++++++++++++++ plugins/module_utils/prism/volume_groups.py | 2 +- plugins/modules/ntnx_volume_groups.py | 14 +++- 4 files changed, 101 insertions(+), 4 deletions(-) create mode 100644 plugins/module_utils/prism/iscsi_clients.py diff --git a/plugins/module_utils/entity.py b/plugins/module_utils/entity.py index 17c44c2a4..aad30c40d 100644 --- a/plugins/module_utils/entity.py +++ b/plugins/module_utils/entity.py @@ -85,7 +85,6 @@ def update( self, data=None, uuid=None, - method="PUT", endpoint=None, query=None, raise_error=True, diff --git a/plugins/module_utils/prism/iscsi_clients.py b/plugins/module_utils/prism/iscsi_clients.py new file mode 100644 index 000000000..812fec6db --- /dev/null +++ b/plugins/module_utils/prism/iscsi_clients.py @@ -0,0 +1,88 @@ +# 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 copy import deepcopy + +from .groups import get_entity_uuid + + +class Clients: + + @classmethod + def get_spec(cls, iscsi_client, chap_auth=False): + payload = cls._get_default_spec() + spec, error = cls._build_spec_iscsi_client(payload, iscsi_client, chap_auth) + if error: + return None, error + return spec, None + + @staticmethod + def _get_default_spec(): + return deepcopy( + { + #for iqn + "iscsiInitiatorName": "", + #for ip + "iscsiInitiatorNetworkId": { + "$objectType": "common.v1.config.IPAddressOrFQDN", + "$reserved": { + "$fqObjectType": "common.v1.r0.a3.config.IPAddressOrFQDN" + }, + "$unknownFields": { + + }, + "ipv4": { + "$objectType": "common.v1.config.IPv4Address", + "$reserved": { + "$fqObjectType": "common.v1.r0.a3.config.IPv4Address" + }, + "$unknownFields": { + + }, + "value": "10.10.20.5" + } + }, + #for uuid + "extId": "d70626f2-7575-4773-a5fb-ded32dd208e2", + "clientSecret": "", + "enabledAuthentications": "NONE" # CHAP/NONE + } + ) + + @staticmethod + def _build_spec_iscsi_client(payload, iscsi_client, chap_auth): + + if iscsi_client.get("uuid"): + payload["extId"] = iscsi_client["uuid"] + elif iscsi_client.get("iscsi_iqn"): + payload["iscsiInitiatorName"] = iscsi_client["iscsi_iqn"] + elif iscsi_client.get("iscsi_ip"): + payload["iscsiInitiatorNetworkId"] = { + "$objectType": "common.v1.config.IPAddressOrFQDN", + "$reserved": { + "$fqObjectType": "common.v1.r0.a3.config.IPAddressOrFQDN" + }, + "$unknownFields": { + + }, + "ipv4": { + "$objectType": "common.v1.config.IPv4Address", + "$reserved": { + "$fqObjectType": "common.v1.r0.a3.config.IPv4Address" + }, + "$unknownFields": { + + }, + "value": iscsi_client["iscsi_ip"] + } + } + if chap_auth and iscsi_client.get("client_password"): + payload["clientSecret"] = iscsi_client["client_password"] + + # if iscsi_client.get("CHAP_auth"): + payload["enabledAuthentications"] = "CHAP" + + return payload, None diff --git a/plugins/module_utils/prism/volume_groups.py b/plugins/module_utils/prism/volume_groups.py index 7a2374fac..9a461b833 100644 --- a/plugins/module_utils/prism/volume_groups.py +++ b/plugins/module_utils/prism/volume_groups.py @@ -10,6 +10,7 @@ from .prism import Prism from .vms import get_vm_uuid + class VolumeGroup(Prism): __BASEURL__ = "/api/storage/v4.0.a2/config" @@ -105,7 +106,6 @@ def get_client_spec(self, client): spec = {"extId": client["uuid"]} return spec, None -# {"extId":"42a59a22-d821-4db2-b0b9-68f420589bc1"} # Helper functions diff --git a/plugins/modules/ntnx_volume_groups.py b/plugins/modules/ntnx_volume_groups.py index 53f2c09d1..ad47c3566 100644 --- a/plugins/modules/ntnx_volume_groups.py +++ b/plugins/modules/ntnx_volume_groups.py @@ -63,6 +63,7 @@ from ..module_utils.prism.tasks import Task # noqa: E402 from ..module_utils.prism.vdisks import VDisks # noqa: E402 from ..module_utils.prism.volume_groups import VolumeGroup # noqa: E402 +from ..module_utils.prism.iscsi_clients import Clients # noqa: E402 from ..module_utils.utils import remove_param_with_none_value # noqa: E402 @@ -78,6 +79,15 @@ def get_module_spec(): ), ) + client_spec = dict( + name=dict(type="str"), + uuid=dict(type="str"), + iqn=dict(type="str"), + ip=dict(type="str"), + # CHAP_auth=dict(type="bool", default=False),? + client_password=dict(type="str", no_log=True), + ) + module_args = dict( name=dict(type="str"), desc=dict(type="str"), @@ -98,7 +108,7 @@ def get_module_spec(): clients=dict( type="list", elements="dict", - options=entity_by_spec, + options=client_spec, mutually_exclusive=mutually_exclusive ), CHAP_auth=dict(type="bool", default=False), @@ -157,7 +167,7 @@ def create_volume_group(module, result): if module.params.get("clients"): clients_response = [] for client in module.params["clients"]: - spec, _ = volume_group.get_client_spec(client) + spec, _ = Clients.get_spec(client, module.params.get("CHAP_auth")) resp = volume_group.update( spec, volume_group_uuid, method="POST", endpoint="/$actions/attach-iscsi-client" ) From 03e2cd7f610df27890404cc9570f8e14a5766712 Mon Sep 17 00:00:00 2001 From: alaa-bish Date: Sun, 23 Oct 2022 09:55:54 +0300 Subject: [PATCH 08/48] sanity fix --- plugins/module_utils/prism/iscsi_clients.py | 53 ++++++++------------- plugins/module_utils/prism/volume_groups.py | 21 +++----- plugins/modules/ntnx_volume_groups.py | 17 ++++--- 3 files changed, 38 insertions(+), 53 deletions(-) diff --git a/plugins/module_utils/prism/iscsi_clients.py b/plugins/module_utils/prism/iscsi_clients.py index 812fec6db..148b8b85f 100644 --- a/plugins/module_utils/prism/iscsi_clients.py +++ b/plugins/module_utils/prism/iscsi_clients.py @@ -6,11 +6,8 @@ from copy import deepcopy -from .groups import get_entity_uuid - class Clients: - @classmethod def get_spec(cls, iscsi_client, chap_auth=False): payload = cls._get_default_spec() @@ -23,32 +20,28 @@ def get_spec(cls, iscsi_client, chap_auth=False): def _get_default_spec(): return deepcopy( { - #for iqn + # for iqn "iscsiInitiatorName": "", - #for ip + # for ip "iscsiInitiatorNetworkId": { "$objectType": "common.v1.config.IPAddressOrFQDN", "$reserved": { "$fqObjectType": "common.v1.r0.a3.config.IPAddressOrFQDN" }, - "$unknownFields": { - - }, + "$unknownFields": {}, "ipv4": { "$objectType": "common.v1.config.IPv4Address", "$reserved": { "$fqObjectType": "common.v1.r0.a3.config.IPv4Address" }, - "$unknownFields": { - - }, - "value": "10.10.20.5" - } + "$unknownFields": {}, + "value": "10.10.20.5", + }, }, - #for uuid + # for uuid "extId": "d70626f2-7575-4773-a5fb-ded32dd208e2", "clientSecret": "", - "enabledAuthentications": "NONE" # CHAP/NONE + "enabledAuthentications": "NONE", # CHAP/NONE } ) @@ -61,28 +54,24 @@ def _build_spec_iscsi_client(payload, iscsi_client, chap_auth): payload["iscsiInitiatorName"] = iscsi_client["iscsi_iqn"] elif iscsi_client.get("iscsi_ip"): payload["iscsiInitiatorNetworkId"] = { - "$objectType": "common.v1.config.IPAddressOrFQDN", + "$objectType": "common.v1.config.IPAddressOrFQDN", + "$reserved": { + "$fqObjectType": "common.v1.r0.a3.config.IPAddressOrFQDN" + }, + "$unknownFields": {}, + "ipv4": { + "$objectType": "common.v1.config.IPv4Address", "$reserved": { - "$fqObjectType": "common.v1.r0.a3.config.IPAddressOrFQDN" + "$fqObjectType": "common.v1.r0.a3.config.IPv4Address" }, - "$unknownFields": { - - }, - "ipv4": { - "$objectType": "common.v1.config.IPv4Address", - "$reserved": { - "$fqObjectType": "common.v1.r0.a3.config.IPv4Address" - }, - "$unknownFields": { - - }, - "value": iscsi_client["iscsi_ip"] - } - } + "$unknownFields": {}, + "value": iscsi_client["iscsi_ip"], + }, + } if chap_auth and iscsi_client.get("client_password"): payload["clientSecret"] = iscsi_client["client_password"] - # if iscsi_client.get("CHAP_auth"): + # if iscsi_client.get("CHAP_auth"): payload["enabledAuthentications"] = "CHAP" return payload, None diff --git a/plugins/module_utils/prism/volume_groups.py b/plugins/module_utils/prism/volume_groups.py index 9a461b833..9f9e3b72e 100644 --- a/plugins/module_utils/prism/volume_groups.py +++ b/plugins/module_utils/prism/volume_groups.py @@ -66,22 +66,14 @@ def _build_spec_load_balance(self, payload, value): def _build_spec_flash_mode(self, payload, value): payload["storageFeatures"] = { "$objectType": "storage.v4.config.StorageFeatures", - "$reserved": { - "$fqObjectType": "storage.v4.r0.a2.config.StorageFeatures" - }, - "$unknownFields": { - - }, + "$reserved": {"$fqObjectType": "storage.v4.r0.a2.config.StorageFeatures"}, + "$unknownFields": {}, "flashMode": { "$objectType": "storage.v4.config.FlashMode", - "$reserved": { - "$fqObjectType": "storage.v4.r0.a2.config.FlashMode" - }, - "$unknownFields": { - - }, - "isEnabled": True - } + "$reserved": {"$fqObjectType": "storage.v4.r0.a2.config.FlashMode"}, + "$unknownFields": {}, + "isEnabled": True, + }, } return payload, None @@ -106,6 +98,7 @@ def get_client_spec(self, client): spec = {"extId": client["uuid"]} return spec, None + # Helper functions diff --git a/plugins/modules/ntnx_volume_groups.py b/plugins/modules/ntnx_volume_groups.py index ad47c3566..56078e6ae 100644 --- a/plugins/modules/ntnx_volume_groups.py +++ b/plugins/modules/ntnx_volume_groups.py @@ -60,10 +60,10 @@ """ from ..module_utils.base_module import BaseModule # noqa: E402 +from ..module_utils.prism.iscsi_clients import Clients # noqa: E402 from ..module_utils.prism.tasks import Task # noqa: E402 from ..module_utils.prism.vdisks import VDisks # noqa: E402 from ..module_utils.prism.volume_groups import VolumeGroup # noqa: E402 -from ..module_utils.prism.iscsi_clients import Clients # noqa: E402 from ..module_utils.utils import remove_param_with_none_value # noqa: E402 @@ -102,14 +102,14 @@ def get_module_spec(): type="list", elements="dict", options=entity_by_spec, - mutually_exclusive=mutually_exclusive + mutually_exclusive=mutually_exclusive, ), load_balance=dict(type="bool", default=False), clients=dict( type="list", elements="dict", options=client_spec, - mutually_exclusive=mutually_exclusive + mutually_exclusive=mutually_exclusive, ), CHAP_auth=dict(type="bool", default=False), target_password=dict(type="str", no_log=True), @@ -145,7 +145,7 @@ def create_volume_group(module, result): vdisk = VDisks() disks_response = [] for disk in module.params["disks"]: - spec, _ = vdisk.get_spec(module, disk) + spec, err = vdisk.get_spec(module, disk) resp = volume_group.update( spec, volume_group_uuid, method="POST", endpoint="disks" ) @@ -156,7 +156,7 @@ def create_volume_group(module, result): if module.params.get("vms"): vms_response = [] for vm in module.params["vms"]: - spec, _ = volume_group.get_vm_spec(vm) + spec, err = volume_group.get_vm_spec(vm) resp = volume_group.update( spec, volume_group_uuid, method="POST", endpoint="$actions/attach-vm" ) @@ -167,9 +167,12 @@ def create_volume_group(module, result): if module.params.get("clients"): clients_response = [] for client in module.params["clients"]: - spec, _ = Clients.get_spec(client, module.params.get("CHAP_auth")) + spec, err = Clients.get_spec(client, module.params.get("CHAP_auth")) resp = volume_group.update( - spec, volume_group_uuid, method="POST", endpoint="/$actions/attach-iscsi-client" + spec, + volume_group_uuid, + method="POST", + endpoint="/$actions/attach-iscsi-client", ) clients_response.append(resp) result["response"]["clients"] = clients_response From 280fdbcfd380d6e31eebe6d0352b03726c90f536 Mon Sep 17 00:00:00 2001 From: Gevorg-Khachatryaan Date: Mon, 24 Oct 2022 20:30:45 +0400 Subject: [PATCH 09/48] volume groups delete, clients detaching --- plugins/module_utils/prism/iscsi_clients.py | 32 +--------- plugins/module_utils/prism/volume_groups.py | 6 ++ plugins/modules/ntnx_volume_groups.py | 69 ++++++++++++--------- 3 files changed, 47 insertions(+), 60 deletions(-) diff --git a/plugins/module_utils/prism/iscsi_clients.py b/plugins/module_utils/prism/iscsi_clients.py index 812fec6db..aed1bb6c9 100644 --- a/plugins/module_utils/prism/iscsi_clients.py +++ b/plugins/module_utils/prism/iscsi_clients.py @@ -6,8 +6,6 @@ from copy import deepcopy -from .groups import get_entity_uuid - class Clients: @@ -22,34 +20,7 @@ def get_spec(cls, iscsi_client, chap_auth=False): @staticmethod def _get_default_spec(): return deepcopy( - { - #for iqn - "iscsiInitiatorName": "", - #for ip - "iscsiInitiatorNetworkId": { - "$objectType": "common.v1.config.IPAddressOrFQDN", - "$reserved": { - "$fqObjectType": "common.v1.r0.a3.config.IPAddressOrFQDN" - }, - "$unknownFields": { - - }, - "ipv4": { - "$objectType": "common.v1.config.IPv4Address", - "$reserved": { - "$fqObjectType": "common.v1.r0.a3.config.IPv4Address" - }, - "$unknownFields": { - - }, - "value": "10.10.20.5" - } - }, - #for uuid - "extId": "d70626f2-7575-4773-a5fb-ded32dd208e2", - "clientSecret": "", - "enabledAuthentications": "NONE" # CHAP/NONE - } + {"enabledAuthentications": "NONE"} ) @staticmethod @@ -82,7 +53,6 @@ def _build_spec_iscsi_client(payload, iscsi_client, chap_auth): if chap_auth and iscsi_client.get("client_password"): payload["clientSecret"] = iscsi_client["client_password"] - # if iscsi_client.get("CHAP_auth"): payload["enabledAuthentications"] = "CHAP" return payload, None diff --git a/plugins/module_utils/prism/volume_groups.py b/plugins/module_utils/prism/volume_groups.py index 9a461b833..429858bc6 100644 --- a/plugins/module_utils/prism/volume_groups.py +++ b/plugins/module_utils/prism/volume_groups.py @@ -22,6 +22,7 @@ def __init__(self, module): "desc": self._build_spec_desc, "cluster": self._build_spec_cluster, "target_prefix": self._build_spec_target_prefix, + "target_password": self._build_spec_target_password, "load_balance": self._build_spec_load_balance, "flash_mode": self._build_spec_flash_mode, } @@ -59,6 +60,11 @@ def _build_spec_target_prefix(self, payload, value): payload["iscsiTargetPrefix"] = value return payload, None + def _build_spec_target_password(self, payload, value): + payload["targetSecret"] = value + payload["enabledAuthentications"] = "CHAP" + return payload, None + def _build_spec_load_balance(self, payload, value): payload["loadBalanceVmAttachments"] = value return payload, None diff --git a/plugins/modules/ntnx_volume_groups.py b/plugins/modules/ntnx_volume_groups.py index ad47c3566..d6e65cee1 100644 --- a/plugins/modules/ntnx_volume_groups.py +++ b/plugins/modules/ntnx_volume_groups.py @@ -80,11 +80,9 @@ def get_module_spec(): ) client_spec = dict( - name=dict(type="str"), uuid=dict(type="str"), - iqn=dict(type="str"), - ip=dict(type="str"), - # CHAP_auth=dict(type="bool", default=False),? + iscsi_iqn=dict(type="str"), + iscsi_ip=dict(type="str"), client_password=dict(type="str", no_log=True), ) @@ -134,9 +132,9 @@ def create_volume_group(module, result): result["changed"] = True result["response"] = resp result["task_uuid"] = task_uuid - wait_for_task_completion(module, result) - - volume_group_uuid = result["volume_group_uuid"] + resp = wait_for_task_completion(module, result) + volume_group_uuid = resp["entity_reference_list"][0]["uuid"] + result["volume_group_uuid"] = volume_group_uuid resp = volume_group.read(volume_group_uuid) result["response"] = resp @@ -154,26 +152,23 @@ def create_volume_group(module, result): # attach vms if module.params.get("vms"): - vms_response = [] for vm in module.params["vms"]: spec, _ = volume_group.get_vm_spec(vm) - resp = volume_group.update( + volume_group.update( spec, volume_group_uuid, method="POST", endpoint="$actions/attach-vm" ) - vms_response.append(resp) - result["response"]["vms"] = vms_response + result["response"]["vms"] = volume_group.read(volume_group_uuid, endpoint="/vm-attachments") # attach clients if module.params.get("clients"): - clients_response = [] for client in module.params["clients"]: spec, _ = Clients.get_spec(client, module.params.get("CHAP_auth")) - resp = volume_group.update( + volume_group.update( spec, volume_group_uuid, method="POST", endpoint="/$actions/attach-iscsi-client" ) - clients_response.append(resp) - result["response"]["clients"] = clients_response - + result["response"]["clients"] = volume_group.read( + volume_group_uuid, endpoint="/iscsi-client-attachments" + ) # def update_volume_group(module, result): # volume_group = VolumeGroup(module) @@ -213,25 +208,41 @@ def create_volume_group(module, result): # result["response"] = resp -# def delete_volume_group(module, result): -# volume_group_uuid = module.params["volume_group_uuid"] -# if not volume_group_uuid: -# result["error"] = "Missing parameter volume_group_uuid in playbook" -# module.fail_json(msg="Failed deleting volume_groups", **result) -# -# volume_group = VolumeGroup(module) -# resp = volume_group.delete(volume_group_uuid, no_response=True) -# result["changed"] = True -# result["response"] = resp -# result["volume_group_uuid"] = volume_group_uuid +def delete_volume_group(module, result): + + def detach_iscsi_clients(): + clients_resp = volume_group.read( + volume_group_uuid, endpoint="/iscsi-client-attachments" + ) + detached_clients = [] + for client in clients_resp["data"]: + client_uuid = client["extId"] + endpoint = "$actions/detach-iscsi-client/{0}".format(client_uuid) + detach_resp = volume_group.update(uuid=volume_group_uuid, method="post", endpoint=endpoint) + task_uuid = detach_resp["data"]["extId"][-36:] + wait_for_task_completion(module, {"task_uuid": task_uuid}) + detached_clients.append(client_uuid) + result["detached_clients"] = detached_clients + + volume_group_uuid = module.params["volume_group_uuid"] + if not volume_group_uuid: + result["error"] = "Missing parameter volume_group_uuid in playbook" + module.fail_json(msg="Failed deleting volume_groups", **result) + + volume_group = VolumeGroup(module) + detach_iscsi_clients() + resp = volume_group.delete(volume_group_uuid) + resp.pop("metadata") + result["changed"] = True + result["response"] = resp + result["volume_group_uuid"] = volume_group_uuid def wait_for_task_completion(module, result): task = Task(module) task_uuid = result["task_uuid"] resp = task.wait_for_completion(task_uuid) - result["response"] = resp - result["volume_group_uuid"] = resp["entity_reference_list"][0]["uuid"] + return resp def run_module(): From 6b40e915296c53546ef841933cdf5c629a28923e Mon Sep 17 00:00:00 2001 From: Gevorg-Khachatryaan Date: Tue, 25 Oct 2022 14:11:34 +0400 Subject: [PATCH 10/48] volume groups delete, vms detaching --- plugins/modules/ntnx_volume_groups.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/plugins/modules/ntnx_volume_groups.py b/plugins/modules/ntnx_volume_groups.py index 7fff6a814..339a4ddc4 100644 --- a/plugins/modules/ntnx_volume_groups.py +++ b/plugins/modules/ntnx_volume_groups.py @@ -215,7 +215,7 @@ def detach_iscsi_clients(): volume_group_uuid, endpoint="/iscsi-client-attachments" ) detached_clients = [] - for client in clients_resp["data"]: + for client in clients_resp.get("data", []): client_uuid = client["extId"] endpoint = "$actions/detach-iscsi-client/{0}".format(client_uuid) detach_resp = volume_group.update(uuid=volume_group_uuid, method="post", endpoint=endpoint) @@ -224,6 +224,20 @@ def detach_iscsi_clients(): detached_clients.append(client_uuid) result["detached_clients"] = detached_clients + def detach_vms(): + vms_resp = volume_group.read( + volume_group_uuid, endpoint="/vm-attachments" + ) + detached_vms = [] + for vm in vms_resp.get("data", []): + vm_uuid = vm["extId"] + endpoint = "$actions/detach-vm/{0}".format(vm_uuid) + detach_resp = volume_group.update(uuid=volume_group_uuid, method="post", endpoint=endpoint) + task_uuid = detach_resp["data"]["extId"][-36:] + wait_for_task_completion(module, {"task_uuid": task_uuid}) + detached_vms.append(vm_uuid) + result["detached_vms"] = detached_vms + volume_group_uuid = module.params["volume_group_uuid"] if not volume_group_uuid: result["error"] = "Missing parameter volume_group_uuid in playbook" @@ -231,6 +245,7 @@ def detach_iscsi_clients(): volume_group = VolumeGroup(module) detach_iscsi_clients() + detach_vms() resp = volume_group.delete(volume_group_uuid) resp.pop("metadata") result["changed"] = True From a22a5edcfcd452d4c888b4d52757f7489f8c59b0 Mon Sep 17 00:00:00 2001 From: Gevorg-Khachatryaan Date: Wed, 26 Oct 2022 14:03:51 +0400 Subject: [PATCH 11/48] vms fixes, requirements --- plugins/module_utils/prism/vdisks.py | 8 +++-- plugins/module_utils/prism/volume_groups.py | 10 ------ plugins/modules/ntnx_volume_groups.py | 35 +++++++++++++-------- 3 files changed, 27 insertions(+), 26 deletions(-) diff --git a/plugins/module_utils/prism/vdisks.py b/plugins/module_utils/prism/vdisks.py index ac5870cf8..5befbe2fb 100644 --- a/plugins/module_utils/prism/vdisks.py +++ b/plugins/module_utils/prism/vdisks.py @@ -10,9 +10,11 @@ class VDisks: - def get_spec(self, module, vdisk): - payload = self._get_default_spec() - spec, error = self._build_spec_vdisk(module, payload, vdisk) + + @classmethod + def get_spec(cls, module, vdisk): + payload = cls._get_default_spec() + spec, error = cls._build_spec_vdisk(module, payload, vdisk) if error: return None, error return spec, None diff --git a/plugins/module_utils/prism/volume_groups.py b/plugins/module_utils/prism/volume_groups.py index 003258225..0e0753ae7 100644 --- a/plugins/module_utils/prism/volume_groups.py +++ b/plugins/module_utils/prism/volume_groups.py @@ -27,16 +27,6 @@ def __init__(self, module): "flash_mode": self._build_spec_flash_mode, } - # def get_uuid(self, value, key="name", raise_error=True, no_response=False): - # data = {"filter": "{0}=={1}".format(key, value)} - # resp = self.list(data, raise_error=raise_error, no_response=no_response) - # entities = resp.get("entities") if resp else None - # if entities: - # for entity in entities: - # if entity["service_group"]["name"] == value: - # return entity["uuid"] - # return None - def _get_default_spec(self): return deepcopy( { diff --git a/plugins/modules/ntnx_volume_groups.py b/plugins/modules/ntnx_volume_groups.py index 339a4ddc4..f5edd567d 100644 --- a/plugins/modules/ntnx_volume_groups.py +++ b/plugins/modules/ntnx_volume_groups.py @@ -125,6 +125,7 @@ def create_volume_group(module, result): if module.check_mode: result["response"] = spec + result["response"]["vms"] = module.params["vms"] return resp = volume_group.create(spec) @@ -136,39 +137,43 @@ def create_volume_group(module, result): volume_group_uuid = resp["entity_reference_list"][0]["uuid"] result["volume_group_uuid"] = volume_group_uuid resp = volume_group.read(volume_group_uuid) - result["response"] = resp + result["response"] = resp.get("data") # create disks if module.params.get("disks"): - vdisk = VDisks() - disks_response = [] for disk in module.params["disks"]: - spec, err = vdisk.get_spec(module, disk) - resp = volume_group.update( + spec, err = VDisks.get_spec(module, disk) + update_resp = volume_group.update( spec, volume_group_uuid, method="POST", endpoint="disks" ) - disks_response.append(resp) - result["response"]["disks"] = disks_response + task_uuid = update_resp["data"]["extId"][-36:] + wait_for_task_completion(module, {"task_uuid": task_uuid}) + disks = volume_group.read(volume_group_uuid, endpoint="/disks") + result["response"]["disks"] = disks.get("data") # attach vms if module.params.get("vms"): for vm in module.params["vms"]: spec, err = volume_group.get_vm_spec(vm) - volume_group.update( + update_resp = volume_group.update( spec, volume_group_uuid, method="POST", endpoint="$actions/attach-vm" ) - result["response"]["vms"] = volume_group.read(volume_group_uuid, endpoint="/vm-attachments") + task_uuid = update_resp["data"]["extId"][-36:] + wait_for_task_completion(module, {"task_uuid": task_uuid}) + vms = volume_group.read(volume_group_uuid, endpoint="/vm-attachments") + result["response"]["vms"] = vms.get("data") # attach clients if module.params.get("clients"): for client in module.params["clients"]: spec, err = Clients.get_spec(client, module.params.get("CHAP_auth")) - volume_group.update( + update_resp = volume_group.update( spec, volume_group_uuid, method="POST", endpoint="/$actions/attach-iscsi-client" ) - result["response"]["clients"] = volume_group.read( - volume_group_uuid, endpoint="/iscsi-client-attachments" - ) + task_uuid = update_resp["data"]["extId"][-36:] + wait_for_task_completion(module, {"task_uuid": task_uuid}) + clients = volume_group.read(volume_group_uuid, endpoint="/iscsi-client-attachments") + result["response"]["clients"] = clients.get("data") # def update_volume_group(module, result): # volume_group = VolumeGroup(module) @@ -267,6 +272,10 @@ def run_module(): required_if=[ ("state", "present", ("name", "volume_group_uuid"), True), ("state", "absent", ("volume_group_uuid",)), + ("CHAP_auth", True, ("target_password",)), + ], + mutually_exclusive=[ + ("vms", "clients") ], ) remove_param_with_none_value(module.params) From 4aacccff0d97514375f1c0565c7fadccf75d637f Mon Sep 17 00:00:00 2001 From: alaa-bish Date: Sun, 30 Oct 2022 13:55:24 +0200 Subject: [PATCH 12/48] doc fix --- plugins/module_utils/prism/iscsi_clients.py | 5 +- plugins/module_utils/prism/vdisks.py | 1 - plugins/modules/ntnx_volume_groups.py | 116 +++++++++++++++++--- 3 files changed, 104 insertions(+), 18 deletions(-) diff --git a/plugins/module_utils/prism/iscsi_clients.py b/plugins/module_utils/prism/iscsi_clients.py index 6838799a9..4406bb8a1 100644 --- a/plugins/module_utils/prism/iscsi_clients.py +++ b/plugins/module_utils/prism/iscsi_clients.py @@ -8,7 +8,6 @@ class Clients: - @classmethod def get_spec(cls, iscsi_client, chap_auth=False): payload = cls._get_default_spec() @@ -19,9 +18,7 @@ def get_spec(cls, iscsi_client, chap_auth=False): @staticmethod def _get_default_spec(): - return deepcopy( - {"enabledAuthentications": "NONE"} - ) + return deepcopy({"enabledAuthentications": "NONE"}) @staticmethod def _build_spec_iscsi_client(payload, iscsi_client, chap_auth): diff --git a/plugins/module_utils/prism/vdisks.py b/plugins/module_utils/prism/vdisks.py index 5befbe2fb..e3700f535 100644 --- a/plugins/module_utils/prism/vdisks.py +++ b/plugins/module_utils/prism/vdisks.py @@ -10,7 +10,6 @@ class VDisks: - @classmethod def get_spec(cls, module, vdisk): payload = cls._get_default_spec() diff --git a/plugins/modules/ntnx_volume_groups.py b/plugins/modules/ntnx_volume_groups.py index f5edd567d..08869f022 100644 --- a/plugins/modules/ntnx_volume_groups.py +++ b/plugins/modules/ntnx_volume_groups.py @@ -41,7 +41,92 @@ desc: description: volume_groups description type: str - # ...............TODO + cluster: + description: write + type: dict + suboptions: + name: + description: + - Cluster Name + - Mutually exclusive with C(uuid) + type: str + uuid: + description: + - Cluster UUID + - Mutually exclusive with C(name) + type: str + target_prefix: + description: write + type: str + flash_mode: + description: write + type: bool + default: false + disks: + description: write + type: list + elements: dict + suboptions: + size_gb: + description: write + type: int + storage_container: + description: write + type: dict + suboptions: + name: + description: + - Mutually exclusive with C(uuid) + type: str + uuid: + description: + - Mutually exclusive with C(name) + type: str + vms: + description: write + type: list + elements: dict + suboptions: + name: + description: + - Mutually exclusive with C(uuid) + type: str + uuid: + description: + - Mutually exclusive with C(name) + type: str + load_balance: + description: write + type: bool + default: false + clients: + description: write + type: list + elements: dict + suboptions: + iscsi_iqn: + description: + - write + type: str + uuid: + description: + - write + type: str + iscsi_ip: + description: + - write + type: str + client_password: + description: + - write + type: str + CHAP_auth: + description: write + type: bool + default: false + target_password: + description: write + type: str extends_documentation_fragment: - nutanix.ncp.ntnx_credentials - nutanix.ncp.ntnx_operations @@ -107,7 +192,7 @@ def get_module_spec(): type="list", elements="dict", options=client_spec, - mutually_exclusive=mutually_exclusive, + # mutually_exclusive=mutually_exclusive, ), CHAP_auth=dict(type="bool", default=False), target_password=dict(type="str", no_log=True), @@ -168,13 +253,19 @@ def create_volume_group(module, result): for client in module.params["clients"]: spec, err = Clients.get_spec(client, module.params.get("CHAP_auth")) update_resp = volume_group.update( - spec, volume_group_uuid, method="POST", endpoint="/$actions/attach-iscsi-client" + spec, + volume_group_uuid, + method="POST", + endpoint="/$actions/attach-iscsi-client", ) task_uuid = update_resp["data"]["extId"][-36:] wait_for_task_completion(module, {"task_uuid": task_uuid}) - clients = volume_group.read(volume_group_uuid, endpoint="/iscsi-client-attachments") + clients = volume_group.read( + volume_group_uuid, endpoint="/iscsi-client-attachments" + ) result["response"]["clients"] = clients.get("data") + # def update_volume_group(module, result): # volume_group = VolumeGroup(module) # volume_group_uuid = module.params.get("volume_group_uuid") @@ -214,7 +305,6 @@ def create_volume_group(module, result): def delete_volume_group(module, result): - def detach_iscsi_clients(): clients_resp = volume_group.read( volume_group_uuid, endpoint="/iscsi-client-attachments" @@ -223,21 +313,23 @@ def detach_iscsi_clients(): for client in clients_resp.get("data", []): client_uuid = client["extId"] endpoint = "$actions/detach-iscsi-client/{0}".format(client_uuid) - detach_resp = volume_group.update(uuid=volume_group_uuid, method="post", endpoint=endpoint) + detach_resp = volume_group.update( + uuid=volume_group_uuid, method="post", endpoint=endpoint + ) task_uuid = detach_resp["data"]["extId"][-36:] wait_for_task_completion(module, {"task_uuid": task_uuid}) detached_clients.append(client_uuid) result["detached_clients"] = detached_clients def detach_vms(): - vms_resp = volume_group.read( - volume_group_uuid, endpoint="/vm-attachments" - ) + vms_resp = volume_group.read(volume_group_uuid, endpoint="/vm-attachments") detached_vms = [] for vm in vms_resp.get("data", []): vm_uuid = vm["extId"] endpoint = "$actions/detach-vm/{0}".format(vm_uuid) - detach_resp = volume_group.update(uuid=volume_group_uuid, method="post", endpoint=endpoint) + detach_resp = volume_group.update( + uuid=volume_group_uuid, method="post", endpoint=endpoint + ) task_uuid = detach_resp["data"]["extId"][-36:] wait_for_task_completion(module, {"task_uuid": task_uuid}) detached_vms.append(vm_uuid) @@ -274,9 +366,7 @@ def run_module(): ("state", "absent", ("volume_group_uuid",)), ("CHAP_auth", True, ("target_password",)), ], - mutually_exclusive=[ - ("vms", "clients") - ], + mutually_exclusive=[("vms", "clients")], ) remove_param_with_none_value(module.params) result = { From 6c2ac7a0c49532547f0178f5e0bd6d6e12803812 Mon Sep 17 00:00:00 2001 From: Gevorg-Khachatryaan Date: Mon, 31 Oct 2022 12:34:56 +0400 Subject: [PATCH 13/48] attachment fixes --- plugins/module_utils/prism/volume_groups.py | 51 +++++++++++++++------ plugins/modules/ntnx_volume_groups.py | 41 ++++++++++------- 2 files changed, 62 insertions(+), 30 deletions(-) diff --git a/plugins/module_utils/prism/volume_groups.py b/plugins/module_utils/prism/volume_groups.py index 0e0753ae7..c08c55da1 100644 --- a/plugins/module_utils/prism/volume_groups.py +++ b/plugins/module_utils/prism/volume_groups.py @@ -27,6 +27,32 @@ def __init__(self, module): "flash_mode": self._build_spec_flash_mode, } + def attach_vm(self, spec, volume_group_uuid, method="POST", endpoint="$actions/attach-vm"): + + resp = self.update(spec, volume_group_uuid, method=method, endpoint=endpoint) + resp["task_uuid"] = resp["data"]["extId"][-36:] + return resp + + def attach_iscsi_client(self, spec, volume_group_uuid, method="POST", endpoint="/$actions/attach-iscsi-client"): + + resp = self.update(spec, volume_group_uuid, method=method, endpoint=endpoint) + resp["task_uuid"] = resp["data"]["extId"][-36:] + return resp + + def detach_vm(self, volume_group_uuid, vm, method="POST"): + vm_uuid = vm["extId"] + endpoint = "$actions/detach-vm/{0}".format(vm_uuid) + resp = self.update(uuid=volume_group_uuid, method=method, endpoint=endpoint) + resp["task_uuid"] = resp["data"]["extId"][-36:] + return resp + + def detach_iscsi_client(self, volume_group_uuid, client, method="POST"): + client_uuid = client["extId"] + endpoint = "$actions/detach-iscsi-client/{0}".format(client_uuid) + resp = self.update(uuid=volume_group_uuid, method=method, endpoint=endpoint) + resp["task_uuid"] = resp["data"]["extId"][-36:] + return resp + def _get_default_spec(self): return deepcopy( { @@ -60,17 +86,19 @@ def _build_spec_load_balance(self, payload, value): return payload, None def _build_spec_flash_mode(self, payload, value): - payload["storageFeatures"] = { - "$objectType": "storage.v4.config.StorageFeatures", - "$reserved": {"$fqObjectType": "storage.v4.r0.a2.config.StorageFeatures"}, - "$unknownFields": {}, - "flashMode": { - "$objectType": "storage.v4.config.FlashMode", - "$reserved": {"$fqObjectType": "storage.v4.r0.a2.config.FlashMode"}, + + if value: + payload["storageFeatures"] = { + "$objectType": "storage.v4.config.StorageFeatures", + "$reserved": {"$fqObjectType": "storage.v4.r0.a2.config.StorageFeatures"}, "$unknownFields": {}, - "isEnabled": True, - }, - } + "flashMode": { + "$objectType": "storage.v4.config.FlashMode", + "$reserved": {"$fqObjectType": "storage.v4.r0.a2.config.FlashMode"}, + "$unknownFields": {}, + "isEnabled": True, + }, + } return payload, None def _build_spec_cluster(self, payload, param): @@ -88,9 +116,6 @@ def get_vm_spec(self, vm): return spec, None def get_client_spec(self, client): - # uuid, error = get_client_uuid(client, self.module) - # if error: - # return None, error spec = {"extId": client["uuid"]} return spec, None diff --git a/plugins/modules/ntnx_volume_groups.py b/plugins/modules/ntnx_volume_groups.py index f5edd567d..159dc5e5f 100644 --- a/plugins/modules/ntnx_volume_groups.py +++ b/plugins/modules/ntnx_volume_groups.py @@ -154,24 +154,27 @@ def create_volume_group(module, result): # attach vms if module.params.get("vms"): for vm in module.params["vms"]: + spec, err = volume_group.get_vm_spec(vm) - update_resp = volume_group.update( - spec, volume_group_uuid, method="POST", endpoint="$actions/attach-vm" - ) - task_uuid = update_resp["data"]["extId"][-36:] + attach_resp = volume_group.attach_vm(spec, volume_group_uuid) + + task_uuid = attach_resp["task_uuid"] wait_for_task_completion(module, {"task_uuid": task_uuid}) + vms = volume_group.read(volume_group_uuid, endpoint="/vm-attachments") + result["response"]["vms"] = vms.get("data") # attach clients if module.params.get("clients"): for client in module.params["clients"]: + spec, err = Clients.get_spec(client, module.params.get("CHAP_auth")) - update_resp = volume_group.update( - spec, volume_group_uuid, method="POST", endpoint="/$actions/attach-iscsi-client" - ) - task_uuid = update_resp["data"]["extId"][-36:] + attach_resp = volume_group.attach_iscsi_client(spec, volume_group_uuid) + + task_uuid = attach_resp["task_uuid"] wait_for_task_completion(module, {"task_uuid": task_uuid}) + clients = volume_group.read(volume_group_uuid, endpoint="/iscsi-client-attachments") result["response"]["clients"] = clients.get("data") @@ -221,12 +224,13 @@ def detach_iscsi_clients(): ) detached_clients = [] for client in clients_resp.get("data", []): - client_uuid = client["extId"] - endpoint = "$actions/detach-iscsi-client/{0}".format(client_uuid) - detach_resp = volume_group.update(uuid=volume_group_uuid, method="post", endpoint=endpoint) + + detach_resp = volume_group.detach_iscsi_client(volume_group_uuid, client) + task_uuid = detach_resp["data"]["extId"][-36:] wait_for_task_completion(module, {"task_uuid": task_uuid}) - detached_clients.append(client_uuid) + detached_clients.append(client["extId"]) + result["detached_clients"] = detached_clients def detach_vms(): @@ -235,12 +239,13 @@ def detach_vms(): ) detached_vms = [] for vm in vms_resp.get("data", []): - vm_uuid = vm["extId"] - endpoint = "$actions/detach-vm/{0}".format(vm_uuid) - detach_resp = volume_group.update(uuid=volume_group_uuid, method="post", endpoint=endpoint) - task_uuid = detach_resp["data"]["extId"][-36:] + + detach_resp = volume_group.detach_vm(volume_group_uuid, vm) + + task_uuid = detach_resp["task_uuid"] wait_for_task_completion(module, {"task_uuid": task_uuid}) - detached_vms.append(vm_uuid) + detached_vms.append(vm["extId"]) + result["detached_vms"] = detached_vms volume_group_uuid = module.params["volume_group_uuid"] @@ -249,8 +254,10 @@ def detach_vms(): module.fail_json(msg="Failed deleting volume_groups", **result) volume_group = VolumeGroup(module) + detach_iscsi_clients() detach_vms() + resp = volume_group.delete(volume_group_uuid) resp.pop("metadata") result["changed"] = True From 73e3ee608a9c161aedc7f1d1b7bf58d938c8498b Mon Sep 17 00:00:00 2001 From: alaa-bish Date: Mon, 31 Oct 2022 13:26:20 +0200 Subject: [PATCH 14/48] doc fix --- plugins/modules/ntnx_volume_groups.py | 28 +++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/plugins/modules/ntnx_volume_groups.py b/plugins/modules/ntnx_volume_groups.py index 08869f022..2699de12d 100644 --- a/plugins/modules/ntnx_volume_groups.py +++ b/plugins/modules/ntnx_volume_groups.py @@ -42,7 +42,7 @@ description: volume_groups description type: str cluster: - description: write + description: Name or UUID of the cluster on which the volume group will be placed type: dict suboptions: name: @@ -56,31 +56,33 @@ - Mutually exclusive with C(name) type: str target_prefix: - description: write + description: iSCSI target prefix-name. type: str flash_mode: - description: write + description: if enabled all volume disks of the VG will be pinned to SSD tier. type: bool default: false disks: - description: write + description: Volume group disk specification. type: list elements: dict suboptions: size_gb: - description: write + description: The Disk Size in GB. type: int storage_container: - description: write + description: Container on which to create the disk. type: dict suboptions: name: description: - - Mutually exclusive with C(uuid) + - Storage containter Name + - Mutually exclusive with C(uuid) type: str uuid: description: - - Mutually exclusive with C(name) + - Storage container UUID + - Mutually exclusive with C(name) type: str vms: description: write @@ -89,11 +91,13 @@ suboptions: name: description: - - Mutually exclusive with C(uuid) + - VM name + - Mutually exclusive with C(uuid) type: str uuid: description: - - Mutually exclusive with C(name) + - VM UUID + - Mutually exclusive with C(name) type: str load_balance: description: write @@ -121,11 +125,11 @@ - write type: str CHAP_auth: - description: write + description: Use Challenge-Handshake Authentication Protocol type: bool default: false target_password: - description: write + description: CHAP secret type: str extends_documentation_fragment: - nutanix.ncp.ntnx_credentials From db02f439e567a4419af277b7ed339ccaaf5ee400 Mon Sep 17 00:00:00 2001 From: alaa-bish Date: Mon, 31 Oct 2022 13:27:35 +0200 Subject: [PATCH 15/48] black fix --- plugins/module_utils/prism/volume_groups.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/plugins/module_utils/prism/volume_groups.py b/plugins/module_utils/prism/volume_groups.py index c08c55da1..f6c405be0 100644 --- a/plugins/module_utils/prism/volume_groups.py +++ b/plugins/module_utils/prism/volume_groups.py @@ -27,13 +27,21 @@ def __init__(self, module): "flash_mode": self._build_spec_flash_mode, } - def attach_vm(self, spec, volume_group_uuid, method="POST", endpoint="$actions/attach-vm"): + def attach_vm( + self, spec, volume_group_uuid, method="POST", endpoint="$actions/attach-vm" + ): resp = self.update(spec, volume_group_uuid, method=method, endpoint=endpoint) resp["task_uuid"] = resp["data"]["extId"][-36:] return resp - def attach_iscsi_client(self, spec, volume_group_uuid, method="POST", endpoint="/$actions/attach-iscsi-client"): + def attach_iscsi_client( + self, + spec, + volume_group_uuid, + method="POST", + endpoint="/$actions/attach-iscsi-client", + ): resp = self.update(spec, volume_group_uuid, method=method, endpoint=endpoint) resp["task_uuid"] = resp["data"]["extId"][-36:] @@ -90,7 +98,9 @@ def _build_spec_flash_mode(self, payload, value): if value: payload["storageFeatures"] = { "$objectType": "storage.v4.config.StorageFeatures", - "$reserved": {"$fqObjectType": "storage.v4.r0.a2.config.StorageFeatures"}, + "$reserved": { + "$fqObjectType": "storage.v4.r0.a2.config.StorageFeatures" + }, "$unknownFields": {}, "flashMode": { "$objectType": "storage.v4.config.FlashMode", From 4b4c23b046f7e269d78f55f94cd1c0719b08e427 Mon Sep 17 00:00:00 2001 From: Gevorg-Khachatryaan Date: Tue, 1 Nov 2022 13:09:28 +0400 Subject: [PATCH 16/48] disks, requirements --- plugins/module_utils/prism/volume_groups.py | 8 ++++++++ plugins/modules/ntnx_volume_groups.py | 11 +++++------ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/plugins/module_utils/prism/volume_groups.py b/plugins/module_utils/prism/volume_groups.py index f6c405be0..669ca9eb0 100644 --- a/plugins/module_utils/prism/volume_groups.py +++ b/plugins/module_utils/prism/volume_groups.py @@ -27,6 +27,14 @@ def __init__(self, module): "flash_mode": self._build_spec_flash_mode, } + def create_vdisk( + self, spec, volume_group_uuid, method="POST", endpoint="disks" + ): + + resp = self.update(spec, volume_group_uuid, method=method, endpoint=endpoint) + resp["task_uuid"] = resp["data"]["extId"][-36:] + return resp + def attach_vm( self, spec, volume_group_uuid, method="POST", endpoint="$actions/attach-vm" ): diff --git a/plugins/modules/ntnx_volume_groups.py b/plugins/modules/ntnx_volume_groups.py index 6b7c6eb73..ee66d1f54 100644 --- a/plugins/modules/ntnx_volume_groups.py +++ b/plugins/modules/ntnx_volume_groups.py @@ -196,7 +196,7 @@ def get_module_spec(): type="list", elements="dict", options=client_spec, - # mutually_exclusive=mutually_exclusive, + mutually_exclusive=[("uuid", "iscsi_iqn", "iscsi_ip")], ), CHAP_auth=dict(type="bool", default=False), target_password=dict(type="str", no_log=True), @@ -232,11 +232,11 @@ def create_volume_group(module, result): if module.params.get("disks"): for disk in module.params["disks"]: spec, err = VDisks.get_spec(module, disk) - update_resp = volume_group.update( - spec, volume_group_uuid, method="POST", endpoint="disks" - ) - task_uuid = update_resp["data"]["extId"][-36:] + vdisk_resp = volume_group.create_vdisk(spec, volume_group_uuid) + + task_uuid = vdisk_resp["task_uuid"] wait_for_task_completion(module, {"task_uuid": task_uuid}) + disks = volume_group.read(volume_group_uuid, endpoint="/disks") result["response"]["disks"] = disks.get("data") @@ -251,7 +251,6 @@ def create_volume_group(module, result): wait_for_task_completion(module, {"task_uuid": task_uuid}) vms = volume_group.read(volume_group_uuid, endpoint="/vm-attachments") - result["response"]["vms"] = vms.get("data") # attach clients From 56dc34513225749063d22fea2cd4bab68cf929e2 Mon Sep 17 00:00:00 2001 From: alaa-bish Date: Tue, 1 Nov 2022 11:18:00 +0200 Subject: [PATCH 17/48] black fix --- plugins/module_utils/prism/volume_groups.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/plugins/module_utils/prism/volume_groups.py b/plugins/module_utils/prism/volume_groups.py index 669ca9eb0..a8a8e665e 100644 --- a/plugins/module_utils/prism/volume_groups.py +++ b/plugins/module_utils/prism/volume_groups.py @@ -27,9 +27,7 @@ def __init__(self, module): "flash_mode": self._build_spec_flash_mode, } - def create_vdisk( - self, spec, volume_group_uuid, method="POST", endpoint="disks" - ): + def create_vdisk(self, spec, volume_group_uuid, method="POST", endpoint="disks"): resp = self.update(spec, volume_group_uuid, method=method, endpoint=endpoint) resp["task_uuid"] = resp["data"]["extId"][-36:] From 7dd12fcfce337da807f59e70f54e268ff2b95c1b Mon Sep 17 00:00:00 2001 From: Gevorg-Khachatryaan Date: Tue, 1 Nov 2022 14:45:37 +0400 Subject: [PATCH 18/48] chap auth validation --- plugins/module_utils/prism/iscsi_clients.py | 13 ++++++++----- plugins/modules/ntnx_volume_groups.py | 19 ++++++++++++++++++- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/plugins/module_utils/prism/iscsi_clients.py b/plugins/module_utils/prism/iscsi_clients.py index 4406bb8a1..07391549b 100644 --- a/plugins/module_utils/prism/iscsi_clients.py +++ b/plugins/module_utils/prism/iscsi_clients.py @@ -43,9 +43,12 @@ def _build_spec_iscsi_client(payload, iscsi_client, chap_auth): "value": iscsi_client["iscsi_ip"], }, } - if chap_auth and iscsi_client.get("client_password"): - payload["clientSecret"] = iscsi_client["client_password"] - - payload["enabledAuthentications"] = "CHAP" - + if iscsi_client.get("client_password"): + if chap_auth: + payload["clientSecret"] = iscsi_client["client_password"] + + payload["enabledAuthentications"] = "CHAP" + else: + error = "parameters are required together: CHAP_auth, client_password" + return None, error return payload, None diff --git a/plugins/modules/ntnx_volume_groups.py b/plugins/modules/ntnx_volume_groups.py index ee66d1f54..810ae5a5a 100644 --- a/plugins/modules/ntnx_volume_groups.py +++ b/plugins/modules/ntnx_volume_groups.py @@ -214,7 +214,9 @@ def create_volume_group(module, result): if module.check_mode: result["response"] = spec - result["response"]["vms"] = module.params["vms"] + result["response"]["disks"] = module.params.get("disks") + result["response"]["vms"] = module.params.get("vms") + result["response"]["clients"] = module.params.get("clients") return resp = volume_group.create(spec) @@ -232,6 +234,11 @@ def create_volume_group(module, result): if module.params.get("disks"): for disk in module.params["disks"]: spec, err = VDisks.get_spec(module, disk) + if err: + result["warning"] = "Disk is not created. Error: {0}".format(err) + result["skipped"] = True + continue + vdisk_resp = volume_group.create_vdisk(spec, volume_group_uuid) task_uuid = vdisk_resp["task_uuid"] @@ -245,6 +252,11 @@ def create_volume_group(module, result): for vm in module.params["vms"]: spec, err = volume_group.get_vm_spec(vm) + if err: + result["warning"] = "VM is not attached. Error: {0}".format(err) + result["skipped"] = True + continue + attach_resp = volume_group.attach_vm(spec, volume_group_uuid) task_uuid = attach_resp["task_uuid"] @@ -258,6 +270,11 @@ def create_volume_group(module, result): for client in module.params["clients"]: spec, err = Clients.get_spec(client, module.params.get("CHAP_auth")) + if err: + result["warning"] = "Client is not attached. Error: {0}".format(err) + result["skipped"] = True + continue + attach_resp = volume_group.attach_iscsi_client(spec, volume_group_uuid) task_uuid = attach_resp["task_uuid"] From dd7fd23ed16e100915bdb2b3f0cfc3d9126763a2 Mon Sep 17 00:00:00 2001 From: Gevorg-Khachatryaan Date: Thu, 3 Nov 2022 14:21:50 +0400 Subject: [PATCH 19/48] optimizing --- plugins/module_utils/prism/volume_groups.py | 53 +++-- plugins/modules/ntnx_volume_groups.py | 218 +++++++++++++------- 2 files changed, 173 insertions(+), 98 deletions(-) diff --git a/plugins/module_utils/prism/volume_groups.py b/plugins/module_utils/prism/volume_groups.py index a8a8e665e..c63914ddf 100644 --- a/plugins/module_utils/prism/volume_groups.py +++ b/plugins/module_utils/prism/volume_groups.py @@ -27,43 +27,47 @@ def __init__(self, module): "flash_mode": self._build_spec_flash_mode, } - def create_vdisk(self, spec, volume_group_uuid, method="POST", endpoint="disks"): + def get_vdisks(self, volume_group_uuid): + endpoint = "/disks" + return self.read(volume_group_uuid, endpoint=endpoint) - resp = self.update(spec, volume_group_uuid, method=method, endpoint=endpoint) - resp["task_uuid"] = resp["data"]["extId"][-36:] - return resp + def get_vms(self, volume_group_uuid): + endpoint = "/vm-attachments" + return self.read(volume_group_uuid, endpoint=endpoint) - def attach_vm( - self, spec, volume_group_uuid, method="POST", endpoint="$actions/attach-vm" - ): + def get_clients(self, volume_group_uuid): + endpoint = "/iscsi-client-attachments" + return self.read(volume_group_uuid, endpoint=endpoint) - resp = self.update(spec, volume_group_uuid, method=method, endpoint=endpoint) + def create_vdisk(self, spec, volume_group_uuid): + endpoint = "disks" + resp = self.update(spec, volume_group_uuid, method="POST", endpoint=endpoint) resp["task_uuid"] = resp["data"]["extId"][-36:] return resp - def attach_iscsi_client( - self, - spec, - volume_group_uuid, - method="POST", - endpoint="/$actions/attach-iscsi-client", - ): + def attach_vm(self, spec, volume_group_uuid): + endpoint = "$actions/attach-vm" + resp = self.update(spec, volume_group_uuid, method="POST", endpoint=endpoint) + resp["task_uuid"] = resp["data"]["extId"][-36:] + return resp - resp = self.update(spec, volume_group_uuid, method=method, endpoint=endpoint) + def attach_iscsi_client(self, spec, volume_group_uuid): + endpoint = "/$actions/attach-iscsi-client" + resp = self.update(spec, volume_group_uuid, method="POST", endpoint=endpoint) resp["task_uuid"] = resp["data"]["extId"][-36:] return resp - def detach_vm(self, volume_group_uuid, vm, method="POST"): + def detach_vm(self, volume_group_uuid, vm): vm_uuid = vm["extId"] endpoint = "$actions/detach-vm/{0}".format(vm_uuid) - resp = self.update(uuid=volume_group_uuid, method=method, endpoint=endpoint) + resp = self.update(uuid=volume_group_uuid, method="POST", endpoint=endpoint) resp["task_uuid"] = resp["data"]["extId"][-36:] return resp - def detach_iscsi_client(self, volume_group_uuid, client, method="POST"): + def detach_iscsi_client(self, volume_group_uuid, client): client_uuid = client["extId"] endpoint = "$actions/detach-iscsi-client/{0}".format(client_uuid) - resp = self.update(uuid=volume_group_uuid, method=method, endpoint=endpoint) + resp = self.update(uuid=volume_group_uuid, method="POST", endpoint=endpoint) resp["task_uuid"] = resp["data"]["extId"][-36:] return resp @@ -71,13 +75,18 @@ def _get_default_spec(self): return deepcopy( { "name": "", - "loadBalanceVmAttachments": False, "sharingStatus": "SHARED", - "clusterReference": None, "usageType": "USER", } ) + def get_update_spec(self): + + return self.get_spec({ + "extId": self.module.params["volume_group_uuid"], + "sharingStatus": "SHARED", + }) + def _build_spec_name(self, payload, value): payload["name"] = value return payload, None diff --git a/plugins/modules/ntnx_volume_groups.py b/plugins/modules/ntnx_volume_groups.py index 810ae5a5a..2c223e824 100644 --- a/plugins/modules/ntnx_volume_groups.py +++ b/plugins/modules/ntnx_volume_groups.py @@ -207,6 +207,10 @@ def get_module_spec(): def create_volume_group(module, result): volume_group = VolumeGroup(module) + vg_disks = module.params.get("disks") + vg_vms = module.params.get("vms") + vg_clients = module.params.get("clients") + spec, error = volume_group.get_spec() if error: result["error"] = error @@ -214,9 +218,9 @@ def create_volume_group(module, result): if module.check_mode: result["response"] = spec - result["response"]["disks"] = module.params.get("disks") - result["response"]["vms"] = module.params.get("vms") - result["response"]["clients"] = module.params.get("clients") + result["response"]["disks"] = vg_disks + result["response"]["vms"] = vg_vms + result["response"]["clients"] = vg_clients return resp = volume_group.create(spec) @@ -231,8 +235,8 @@ def create_volume_group(module, result): result["response"] = resp.get("data") # create disks - if module.params.get("disks"): - for disk in module.params["disks"]: + if vg_disks: + for disk in vg_disks: spec, err = VDisks.get_spec(module, disk) if err: result["warning"] = "Disk is not created. Error: {0}".format(err) @@ -244,12 +248,12 @@ def create_volume_group(module, result): task_uuid = vdisk_resp["task_uuid"] wait_for_task_completion(module, {"task_uuid": task_uuid}) - disks = volume_group.read(volume_group_uuid, endpoint="/disks") - result["response"]["disks"] = disks.get("data") + disks_resp = volume_group.get_vdisks(volume_group_uuid) + result["response"]["disks"] = disks_resp.get("data") # attach vms - if module.params.get("vms"): - for vm in module.params["vms"]: + if vg_vms: + for vm in vg_vms: spec, err = volume_group.get_vm_spec(vm) if err: @@ -262,12 +266,12 @@ def create_volume_group(module, result): task_uuid = attach_resp["task_uuid"] wait_for_task_completion(module, {"task_uuid": task_uuid}) - vms = volume_group.read(volume_group_uuid, endpoint="/vm-attachments") - result["response"]["vms"] = vms.get("data") + vms_resp = volume_group.get_vms(volume_group_uuid) + result["response"]["vms"] = vms_resp.get("data") # attach clients - if module.params.get("clients"): - for client in module.params["clients"]: + if vg_clients: + for client in vg_clients: spec, err = Clients.get_spec(client, module.params.get("CHAP_auth")) if err: @@ -280,79 +284,109 @@ def create_volume_group(module, result): task_uuid = attach_resp["task_uuid"] wait_for_task_completion(module, {"task_uuid": task_uuid}) - clients = volume_group.read( - volume_group_uuid, endpoint="/iscsi-client-attachments" - ) - result["response"]["clients"] = clients.get("data") - - -# def update_volume_group(module, result): -# volume_group = VolumeGroup(module) -# volume_group_uuid = module.params.get("volume_group_uuid") -# if not volume_group_uuid: -# result["error"] = "Missing parameter volume_group_uuid in playbook" -# module.fail_json(msg="Failed updating volume_group", **result) -# result["volume_group_uuid"] = volume_group_uuid -# -# # read the current state of volume_group -# resp = volume_group.read(volume_group_uuid) -# resp = resp.get("volume_group") -# -# # new spec for updating volume_group -# update_spec, error = volume_group.get_spec(resp) -# if error: -# result["error"] = error -# module.fail_json(msg="Failed generating volume_group update spec", **result) -# -# # check for idempotency -# if resp == update_spec: -# result["skipped"] = True -# module.exit_json( -# msg="Nothing to change. Refer docs to check for fields which can be updated" -# ) -# -# if module.check_mode: -# result["response"] = update_spec -# return -# -# # update volume_group -# volume_group.update(update_spec, uuid=volume_group_uuid, no_response=True) -# -# resp = volume_group.read(volume_group_uuid) -# -# result["changed"] = True -# result["response"] = resp + clients_resp = volume_group.get_clients(volume_group_uuid) + result["response"]["clients"] = clients_resp.get("data") -def delete_volume_group(module, result): - def detach_iscsi_clients(): - clients_resp = volume_group.read( - volume_group_uuid, endpoint="/iscsi-client-attachments" - ) - detached_clients = [] - for client in clients_resp.get("data", []): +def update_volume_group(module, result): + volume_group = VolumeGroup(module) + volume_group_uuid = module.params.get("volume_group_uuid") + vg_disks = module.params.get("disks") + vg_vms = module.params.get("vms") + vg_clients = module.params.get("clients") + if not volume_group_uuid: + result["error"] = "Missing parameter volume_group_uuid in playbook" + module.fail_json(msg="Failed updating volume_group", **result) + result["volume_group_uuid"] = volume_group_uuid + + # read the current state of volume_group + resp = volume_group.read(volume_group_uuid) + resp = resp.get("data") - detach_resp = volume_group.detach_iscsi_client(volume_group_uuid, client) + # new spec for updating volume_group + update_spec, error = volume_group.get_update_spec() + if error: + result["error"] = error + module.fail_json(msg="Failed generating volume_group update spec", **result) + + # check for idempotency + # def check_volume_groups_idempotency() + # if resp == update_spec: + # result["skipped"] = True + # module.exit_json( + # msg="Nothing to change. Refer docs to check for fields which can be updated" + # ) + + if module.check_mode: + result["response"] = update_spec + result["response"]["disks"] = vg_disks + result["response"]["vms"] = vg_vms + result["response"]["clients"] = vg_clients + return + + # update volume_group + resp = volume_group.update(update_spec, uuid=volume_group_uuid, method="PATCH") + # result["response"] = resp + resp = volume_group.read(volume_group_uuid) - task_uuid = detach_resp["data"]["extId"][-36:] + result["changed"] = True + result["response"] = resp.get("data") + + # update disks + if vg_disks: + for disk in vg_disks: + spec, err = VDisks.get_spec(module, disk) + if err: + result["warning"] = "Disk is not created. Error: {0}".format(err) + result["skipped"] = True + continue + + vdisk_resp = volume_group.create_vdisk(spec, volume_group_uuid) + + task_uuid = vdisk_resp["task_uuid"] wait_for_task_completion(module, {"task_uuid": task_uuid}) - detached_clients.append(client["extId"]) - result["detached_clients"] = detached_clients + disks_resp = volume_group.get_vdisks(volume_group_uuid) + result["response"]["disks"] = disks_resp.get("data") - def detach_vms(): - vms_resp = volume_group.read(volume_group_uuid, endpoint="/vm-attachments") - detached_vms = [] - for vm in vms_resp.get("data", []): + # update vms + if vg_vms: + for vm in vg_vms: - detach_resp = volume_group.detach_vm(volume_group_uuid, vm) + spec, err = volume_group.get_vm_spec(vm) + if err: + result["warning"] = "VM is not attached. Error: {0}".format(err) + result["skipped"] = True + continue + + attach_resp = volume_group.attach_vm(spec, volume_group_uuid) + + task_uuid = attach_resp["task_uuid"] + wait_for_task_completion(module, {"task_uuid": task_uuid}) + + vms_resp = volume_group.get_vms(volume_group_uuid) + result["response"]["vms"] = vms_resp.get("data") + + # update clients + if vg_clients: + for client in vg_clients: + + spec, err = Clients.get_spec(client, module.params.get("CHAP_auth")) + if err: + result["warning"] = "Client is not attached. Error: {0}".format(err) + result["skipped"] = True + continue - task_uuid = detach_resp["task_uuid"] + attach_resp = volume_group.attach_iscsi_client(spec, volume_group_uuid) + + task_uuid = attach_resp["task_uuid"] wait_for_task_completion(module, {"task_uuid": task_uuid}) - detached_vms.append(vm["extId"]) - result["detached_vms"] = detached_vms + clients_resp = volume_group.get_clients(volume_group_uuid) + result["response"]["clients"] = clients_resp.get("data") + +def delete_volume_group(module, result): volume_group_uuid = module.params["volume_group_uuid"] if not volume_group_uuid: result["error"] = "Missing parameter volume_group_uuid in playbook" @@ -360,8 +394,29 @@ def detach_vms(): volume_group = VolumeGroup(module) - detach_iscsi_clients() - detach_vms() + # detach iscsi_clients + clients_resp = volume_group.get_clients(volume_group_uuid) + detached_clients = [] + for client in clients_resp.get("data", []): + detach_resp = volume_group.detach_iscsi_client(volume_group_uuid, client) + + task_uuid = detach_resp["task_uuid"] + wait_for_task_completion(module, {"task_uuid": task_uuid}) + detached_clients.append(client["extId"]) + + result["detached_clients"] = detached_clients + + # detach vms + vms_resp = volume_group.get_vms(volume_group_uuid) + detached_vms = [] + for vm in vms_resp.get("data", []): + detach_resp = volume_group.detach_vm(volume_group_uuid, vm) + + task_uuid = detach_resp["task_uuid"] + wait_for_task_completion(module, {"task_uuid": task_uuid}) + detached_vms.append(vm["extId"]) + + result["detached_vms"] = detached_vms resp = volume_group.delete(volume_group_uuid) resp.pop("metadata") @@ -370,6 +425,17 @@ def detach_vms(): result["volume_group_uuid"] = volume_group_uuid +def check_volume_groups_idempotency(old_spec, update_spec): + + if old_spec["spec"]["name"] != update_spec["spec"]["name"]: + return False + + if old_spec["spec"].get("description") != update_spec["spec"].get("description"): + return False + + return True + + def wait_for_task_completion(module, result): task = Task(module) task_uuid = result["task_uuid"] From 0cb8659d537c5042af1dfd82a52a208fd9228919 Mon Sep 17 00:00:00 2001 From: Gevorg-Khachatryaan Date: Fri, 4 Nov 2022 16:01:23 +0400 Subject: [PATCH 20/48] vg base spec idempotency --- plugins/modules/ntnx_volume_groups.py | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/plugins/modules/ntnx_volume_groups.py b/plugins/modules/ntnx_volume_groups.py index 2c223e824..42ab989a5 100644 --- a/plugins/modules/ntnx_volume_groups.py +++ b/plugins/modules/ntnx_volume_groups.py @@ -310,12 +310,11 @@ def update_volume_group(module, result): module.fail_json(msg="Failed generating volume_group update spec", **result) # check for idempotency - # def check_volume_groups_idempotency() - # if resp == update_spec: - # result["skipped"] = True - # module.exit_json( - # msg="Nothing to change. Refer docs to check for fields which can be updated" - # ) + if check_volume_groups_idempotency(resp, update_spec): + result["skipped"] = True + module.exit_json( + msg="Nothing to change. Refer docs to check for fields which can be updated" + ) if module.check_mode: result["response"] = update_spec @@ -427,11 +426,9 @@ def delete_volume_group(module, result): def check_volume_groups_idempotency(old_spec, update_spec): - if old_spec["spec"]["name"] != update_spec["spec"]["name"]: - return False - - if old_spec["spec"].get("description") != update_spec["spec"].get("description"): - return False + for key, value in update_spec.items(): + if old_spec.get(key) != value: + return False return True From f2585bff4c0950563a26560d4b10b5e02614216f Mon Sep 17 00:00:00 2001 From: alaa-bish Date: Mon, 7 Nov 2022 11:16:12 +0200 Subject: [PATCH 21/48] black fix --- plugins/module_utils/prism/volume_groups.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/plugins/module_utils/prism/volume_groups.py b/plugins/module_utils/prism/volume_groups.py index c63914ddf..8e6785e51 100644 --- a/plugins/module_utils/prism/volume_groups.py +++ b/plugins/module_utils/prism/volume_groups.py @@ -82,10 +82,12 @@ def _get_default_spec(self): def get_update_spec(self): - return self.get_spec({ - "extId": self.module.params["volume_group_uuid"], - "sharingStatus": "SHARED", - }) + return self.get_spec( + { + "extId": self.module.params["volume_group_uuid"], + "sharingStatus": "SHARED", + } + ) def _build_spec_name(self, payload, value): payload["name"] = value From c5dba9725d3bb2bbbd5e7bdc0f547d5e5ee815dc Mon Sep 17 00:00:00 2001 From: Gevorg-Khachatryaan Date: Tue, 8 Nov 2022 15:58:02 +0400 Subject: [PATCH 22/48] vg disks update --- plugins/module_utils/prism/vdisks.py | 39 ++++---- plugins/module_utils/prism/volume_groups.py | 21 +++- plugins/modules/ntnx_volume_groups.py | 105 ++++++++++++++++---- 3 files changed, 123 insertions(+), 42 deletions(-) diff --git a/plugins/module_utils/prism/vdisks.py b/plugins/module_utils/prism/vdisks.py index e3700f535..8603c1633 100644 --- a/plugins/module_utils/prism/vdisks.py +++ b/plugins/module_utils/prism/vdisks.py @@ -23,15 +23,6 @@ def _get_default_spec(): return deepcopy( { "diskSizeBytes": None, - "diskDataSourceReference": { - "$objectType": "common.v1.config.EntityReference", - "$reserved": { - "$fqObjectType": "common.v1.r0.a3.config.EntityReference" - }, - "$unknownFields": {}, - "extId": None, - "entityType": "STORAGE_CONTAINER", - }, } ) @@ -41,15 +32,27 @@ def _build_spec_vdisk(module, payload, vdisk): disk_size_bytes = vdisk["size_gb"] * 1024 * 1024 * 1024 payload["diskSizeBytes"] = disk_size_bytes - uuid, error = get_entity_uuid( - vdisk["storage_container"], - module, - key="container_name", - entity_type="storage_container", - ) - if error: - return None, error - payload["diskDataSourceReference"]["extId"] = uuid + if vdisk.get("storage_container"): + uuid, error = get_entity_uuid( + vdisk["storage_container"], + module, + key="container_name", + entity_type="storage_container", + ) + if error: + return None, error + + payload["diskDataSourceReference"] = { + "$objectType": "common.v1.config.EntityReference", + "$reserved": { + "$fqObjectType": "common.v1.r0.a3.config.EntityReference" + }, + "$unknownFields": {}, + "extId": uuid, + "entityType": "STORAGE_CONTAINER", + }, + elif vdisk.get("uuid"): + payload["extId"] = vdisk["uuid"] return payload, None diff --git a/plugins/module_utils/prism/volume_groups.py b/plugins/module_utils/prism/volume_groups.py index c63914ddf..8805e888b 100644 --- a/plugins/module_utils/prism/volume_groups.py +++ b/plugins/module_utils/prism/volume_groups.py @@ -57,12 +57,29 @@ def attach_iscsi_client(self, spec, volume_group_uuid): resp["task_uuid"] = resp["data"]["extId"][-36:] return resp + def update_disk(self, spec, volume_group_uuid, disk_uuid): + endpoint = "disks/{0}".format(disk_uuid) + resp = self.update(spec, uuid=volume_group_uuid, method="PATCH", endpoint=endpoint) + resp["task_uuid"] = resp["data"]["extId"][-36:] + return resp + + def delete_disk(self, volume_group_uuid, disk_uuid): + endpoint = "disks/{0}".format(disk_uuid) + resp = self.delete(uuid=volume_group_uuid, endpoint=endpoint) + resp["task_uuid"] = resp["data"]["extId"][-36:] + return resp + def detach_vm(self, volume_group_uuid, vm): - vm_uuid = vm["extId"] + if not vm.get("extId"): + vm_uuid, error = get_vm_uuid(vm, self.module) + if error: + return None, error + else: + vm_uuid = vm["extId"] endpoint = "$actions/detach-vm/{0}".format(vm_uuid) resp = self.update(uuid=volume_group_uuid, method="POST", endpoint=endpoint) resp["task_uuid"] = resp["data"]["extId"][-36:] - return resp + return resp, None def detach_iscsi_client(self, volume_group_uuid, client): client_uuid = client["extId"] diff --git a/plugins/modules/ntnx_volume_groups.py b/plugins/modules/ntnx_volume_groups.py index 42ab989a5..ebacad919 100644 --- a/plugins/modules/ntnx_volume_groups.py +++ b/plugins/modules/ntnx_volume_groups.py @@ -162,13 +162,22 @@ def get_module_spec(): entity_by_spec = dict(name=dict(type="str"), uuid=dict(type="str")) disk_spec = dict( + state=dict(type="str", choices=["absent"]), + uuid=dict(type="str"), size_gb=dict(type="int"), storage_container=dict( type="dict", options=entity_by_spec, mutually_exclusive=mutually_exclusive ), ) + vm_spec = dict( + state=dict(type="str", choices=["absent"]), + name=dict(type="str"), + uuid=dict(type="str"), + ) + client_spec = dict( + state=dict(type="str", choices=["absent"]), uuid=dict(type="str"), iscsi_iqn=dict(type="str"), iscsi_ip=dict(type="str"), @@ -184,11 +193,20 @@ def get_module_spec(): target_prefix=dict(type="str"), volume_group_uuid=dict(type="str"), flash_mode=dict(type="bool", default=False), - disks=dict(type="list", elements="dict", options=disk_spec), + disks=dict( + type="list", + elements="dict", + options=disk_spec, + mutually_exclusive=[ + ("uuid", "storage_container"), + ("state", "size_gb"), + ], + required_if=[("state", "absent", ("uuid",))], + ), vms=dict( type="list", elements="dict", - options=entity_by_spec, + options=vm_spec, mutually_exclusive=mutually_exclusive, ), load_balance=dict(type="bool", default=False), @@ -310,7 +328,7 @@ def update_volume_group(module, result): module.fail_json(msg="Failed generating volume_group update spec", **result) # check for idempotency - if check_volume_groups_idempotency(resp, update_spec): + if check_volume_groups_idempotency(resp, update_spec, volume_group): result["skipped"] = True module.exit_json( msg="Nothing to change. Refer docs to check for fields which can be updated" @@ -334,13 +352,27 @@ def update_volume_group(module, result): # update disks if vg_disks: for disk in vg_disks: - spec, err = VDisks.get_spec(module, disk) - if err: - result["warning"] = "Disk is not created. Error: {0}".format(err) - result["skipped"] = True - continue - - vdisk_resp = volume_group.create_vdisk(spec, volume_group_uuid) + if disk.get("uuid"): + disk_uuid = disk["uuid"] + if disk.get("state") == "absent": + vdisk_resp = volume_group.delete_disk(volume_group_uuid, disk_uuid) + + else: + spec, err = VDisks.get_spec(module, disk) + if err: + result["warning"].append("Disk is not updated. Error: {0}".format(err)) + result["skipped"] = True + continue + vdisk_resp = volume_group.update_disk(spec, volume_group_uuid, disk_uuid) + + else: + spec, err = VDisks.get_spec(module, disk) + if err: + result["warning"].append("Disk is not created. Error: {0}".format(err)) + result["skipped"] = True + continue + + vdisk_resp = volume_group.create_vdisk(spec, volume_group_uuid) task_uuid = vdisk_resp["task_uuid"] wait_for_task_completion(module, {"task_uuid": task_uuid}) @@ -351,16 +383,22 @@ def update_volume_group(module, result): # update vms if vg_vms: for vm in vg_vms: - - spec, err = volume_group.get_vm_spec(vm) - if err: - result["warning"] = "VM is not attached. Error: {0}".format(err) - result["skipped"] = True - continue - - attach_resp = volume_group.attach_vm(spec, volume_group_uuid) - - task_uuid = attach_resp["task_uuid"] + if vm.get("state") == "absent": + vm_resp, err = volume_group.detach_vm(volume_group_uuid, vm) + if err: + result["warning"].append("VM is not detached. Error: {0}".format(err)) + result["skipped"] = True + continue + else: + spec, err = volume_group.get_vm_spec(vm) + if err: + result["warning"].append("VM is not attached. Error: {0}".format(err)) + result["skipped"] = True + continue + + vm_resp = volume_group.attach_vm(spec, volume_group_uuid) + + task_uuid = vm_resp["task_uuid"] wait_for_task_completion(module, {"task_uuid": task_uuid}) vms_resp = volume_group.get_vms(volume_group_uuid) @@ -372,7 +410,7 @@ def update_volume_group(module, result): spec, err = Clients.get_spec(client, module.params.get("CHAP_auth")) if err: - result["warning"] = "Client is not attached. Error: {0}".format(err) + result["warning"].append("Client is not attached. Error: {0}".format(err)) result["skipped"] = True continue @@ -424,11 +462,33 @@ def delete_volume_group(module, result): result["volume_group_uuid"] = volume_group_uuid -def check_volume_groups_idempotency(old_spec, update_spec): +def check_volume_groups_idempotency(old_spec, update_spec, volume_group): for key, value in update_spec.items(): if old_spec.get(key) != value: return False + volume_group_uuid = volume_group.module.params.get("volume_group_uuid") + updated_disks = volume_group.module.params.get("disks") + updated_vms = volume_group.module.params.get("vms") + updated_clients = volume_group.module.params.get("clients") + + if updated_disks: + # vg_disks = volume_group.get_vdisks(volume_group_uuid).get("data") + # for disk in updated_disks: + # if disk not in vg_disks: + return False + + if updated_vms: + vg_vms = volume_group.get_vms(volume_group_uuid).get("data") + for vm in updated_vms: + if vm not in vg_vms: + return False + + if updated_clients: + vg_clients = volume_group.get_clients(volume_group_uuid).get("data") + for client in updated_disks: + if client not in vg_clients: + return False return True @@ -457,6 +517,7 @@ def run_module(): "error": None, "response": None, "volume_group_uuid": None, + "warning": [] } state = module.params["state"] if state == "absent": From e952ed68e8b1e4ae7aea3d4b3dcef8ac5c630804 Mon Sep 17 00:00:00 2001 From: alaa-bish Date: Tue, 8 Nov 2022 14:19:39 +0200 Subject: [PATCH 23/48] sanity fix --- plugins/module_utils/prism/vdisks.py | 4 +- plugins/module_utils/prism/volume_groups.py | 4 +- plugins/modules/ntnx_volume_groups.py | 51 ++++++++++++++++----- 3 files changed, 46 insertions(+), 13 deletions(-) diff --git a/plugins/module_utils/prism/vdisks.py b/plugins/module_utils/prism/vdisks.py index 8603c1633..e419cfc58 100644 --- a/plugins/module_utils/prism/vdisks.py +++ b/plugins/module_utils/prism/vdisks.py @@ -43,7 +43,8 @@ def _build_spec_vdisk(module, payload, vdisk): if error: return None, error - payload["diskDataSourceReference"] = { + payload["diskDataSourceReference"] = ( + { "$objectType": "common.v1.config.EntityReference", "$reserved": { "$fqObjectType": "common.v1.r0.a3.config.EntityReference" @@ -52,6 +53,7 @@ def _build_spec_vdisk(module, payload, vdisk): "extId": uuid, "entityType": "STORAGE_CONTAINER", }, + ) elif vdisk.get("uuid"): payload["extId"] = vdisk["uuid"] diff --git a/plugins/module_utils/prism/volume_groups.py b/plugins/module_utils/prism/volume_groups.py index cea2a3c4c..0f62a4c47 100644 --- a/plugins/module_utils/prism/volume_groups.py +++ b/plugins/module_utils/prism/volume_groups.py @@ -59,7 +59,9 @@ def attach_iscsi_client(self, spec, volume_group_uuid): def update_disk(self, spec, volume_group_uuid, disk_uuid): endpoint = "disks/{0}".format(disk_uuid) - resp = self.update(spec, uuid=volume_group_uuid, method="PATCH", endpoint=endpoint) + resp = self.update( + spec, uuid=volume_group_uuid, method="PATCH", endpoint=endpoint + ) resp["task_uuid"] = resp["data"]["extId"][-36:] return resp diff --git a/plugins/modules/ntnx_volume_groups.py b/plugins/modules/ntnx_volume_groups.py index ebacad919..a71d4c7d4 100644 --- a/plugins/modules/ntnx_volume_groups.py +++ b/plugins/modules/ntnx_volume_groups.py @@ -70,6 +70,13 @@ size_gb: description: The Disk Size in GB. type: int + state: + description: write + type: str + choices: ["absent"] + uuid: + description: write + type: str storage_container: description: Container on which to create the disk. type: dict @@ -99,6 +106,11 @@ - VM UUID - Mutually exclusive with C(name) type: str + state: + description: + - write + type: str + choices: ["absent"] load_balance: description: write type: bool @@ -108,6 +120,11 @@ type: list elements: dict suboptions: + state: + description: + - write + type: str + choices: ["absent"] iscsi_iqn: description: - write @@ -360,15 +377,21 @@ def update_volume_group(module, result): else: spec, err = VDisks.get_spec(module, disk) if err: - result["warning"].append("Disk is not updated. Error: {0}".format(err)) + result["warning"].append( + "Disk is not updated. Error: {0}".format(err) + ) result["skipped"] = True continue - vdisk_resp = volume_group.update_disk(spec, volume_group_uuid, disk_uuid) + vdisk_resp = volume_group.update_disk( + spec, volume_group_uuid, disk_uuid + ) else: spec, err = VDisks.get_spec(module, disk) if err: - result["warning"].append("Disk is not created. Error: {0}".format(err)) + result["warning"].append( + "Disk is not created. Error: {0}".format(err) + ) result["skipped"] = True continue @@ -386,13 +409,17 @@ def update_volume_group(module, result): if vm.get("state") == "absent": vm_resp, err = volume_group.detach_vm(volume_group_uuid, vm) if err: - result["warning"].append("VM is not detached. Error: {0}".format(err)) + result["warning"].append( + "VM is not detached. Error: {0}".format(err) + ) result["skipped"] = True continue else: spec, err = volume_group.get_vm_spec(vm) if err: - result["warning"].append("VM is not attached. Error: {0}".format(err)) + result["warning"].append( + "VM is not attached. Error: {0}".format(err) + ) result["skipped"] = True continue @@ -410,7 +437,9 @@ def update_volume_group(module, result): spec, err = Clients.get_spec(client, module.params.get("CHAP_auth")) if err: - result["warning"].append("Client is not attached. Error: {0}".format(err)) + result["warning"].append( + "Client is not attached. Error: {0}".format(err) + ) result["skipped"] = True continue @@ -473,10 +502,10 @@ def check_volume_groups_idempotency(old_spec, update_spec, volume_group): updated_clients = volume_group.module.params.get("clients") if updated_disks: - # vg_disks = volume_group.get_vdisks(volume_group_uuid).get("data") - # for disk in updated_disks: - # if disk not in vg_disks: - return False + # vg_disks = volume_group.get_vdisks(volume_group_uuid).get("data") + # for disk in updated_disks: + # if disk not in vg_disks: + return False if updated_vms: vg_vms = volume_group.get_vms(volume_group_uuid).get("data") @@ -517,7 +546,7 @@ def run_module(): "error": None, "response": None, "volume_group_uuid": None, - "warning": [] + "warning": [], } state = module.params["state"] if state == "absent": From cbc18a335f684d4e2652e770d5af571d5caaaa4f Mon Sep 17 00:00:00 2001 From: Gevorg-Khachatryaan Date: Tue, 8 Nov 2022 16:45:23 +0400 Subject: [PATCH 24/48] vg disks update, fix --- plugins/module_utils/prism/vdisks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/module_utils/prism/vdisks.py b/plugins/module_utils/prism/vdisks.py index 8603c1633..556bf825c 100644 --- a/plugins/module_utils/prism/vdisks.py +++ b/plugins/module_utils/prism/vdisks.py @@ -51,7 +51,7 @@ def _build_spec_vdisk(module, payload, vdisk): "$unknownFields": {}, "extId": uuid, "entityType": "STORAGE_CONTAINER", - }, + } elif vdisk.get("uuid"): payload["extId"] = vdisk["uuid"] From d0b910d93efff25dce2c0e7843ef5a9bec737eac Mon Sep 17 00:00:00 2001 From: alaa-bish Date: Tue, 8 Nov 2022 14:52:21 +0200 Subject: [PATCH 25/48] black fix --- plugins/module_utils/prism/vdisks.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/plugins/module_utils/prism/vdisks.py b/plugins/module_utils/prism/vdisks.py index 556bf825c..f87e7f4ce 100644 --- a/plugins/module_utils/prism/vdisks.py +++ b/plugins/module_utils/prism/vdisks.py @@ -44,14 +44,14 @@ def _build_spec_vdisk(module, payload, vdisk): return None, error payload["diskDataSourceReference"] = { - "$objectType": "common.v1.config.EntityReference", - "$reserved": { - "$fqObjectType": "common.v1.r0.a3.config.EntityReference" - }, - "$unknownFields": {}, - "extId": uuid, - "entityType": "STORAGE_CONTAINER", - } + "$objectType": "common.v1.config.EntityReference", + "$reserved": { + "$fqObjectType": "common.v1.r0.a3.config.EntityReference" + }, + "$unknownFields": {}, + "extId": uuid, + "entityType": "STORAGE_CONTAINER", + } elif vdisk.get("uuid"): payload["extId"] = vdisk["uuid"] From 734b0dd10e711b932830d2d84f1518e4ae1b419a Mon Sep 17 00:00:00 2001 From: Gevorg-Khachatryaan Date: Tue, 8 Nov 2022 16:58:33 +0400 Subject: [PATCH 26/48] vg disks update, fix --- plugins/modules/ntnx_volume_groups.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/modules/ntnx_volume_groups.py b/plugins/modules/ntnx_volume_groups.py index a71d4c7d4..37fd62316 100644 --- a/plugins/modules/ntnx_volume_groups.py +++ b/plugins/modules/ntnx_volume_groups.py @@ -476,7 +476,7 @@ def delete_volume_group(module, result): vms_resp = volume_group.get_vms(volume_group_uuid) detached_vms = [] for vm in vms_resp.get("data", []): - detach_resp = volume_group.detach_vm(volume_group_uuid, vm) + detach_resp, _ = volume_group.detach_vm(volume_group_uuid, vm) task_uuid = detach_resp["task_uuid"] wait_for_task_completion(module, {"task_uuid": task_uuid}) From 120bf5c618179327f43d27b8c818b8ac0afd5bc5 Mon Sep 17 00:00:00 2001 From: Gevorg-Khachatryaan Date: Wed, 9 Nov 2022 18:39:33 +0400 Subject: [PATCH 27/48] vg disks idempotency --- plugins/module_utils/prism/volume_groups.py | 7 +- plugins/modules/ntnx_volume_groups.py | 81 ++++++++++----------- 2 files changed, 43 insertions(+), 45 deletions(-) diff --git a/plugins/module_utils/prism/volume_groups.py b/plugins/module_utils/prism/volume_groups.py index 0f62a4c47..a4f80a414 100644 --- a/plugins/module_utils/prism/volume_groups.py +++ b/plugins/module_utils/prism/volume_groups.py @@ -27,8 +27,11 @@ def __init__(self, module): "flash_mode": self._build_spec_flash_mode, } - def get_vdisks(self, volume_group_uuid): - endpoint = "/disks" + def get_vdisks(self, volume_group_uuid, disk_uuid=None): + if disk_uuid: + endpoint = "/disks/{0}".format(disk_uuid) + else: + endpoint = "/disks" return self.read(volume_group_uuid, endpoint=endpoint) def get_vms(self, volume_group_uuid): diff --git a/plugins/modules/ntnx_volume_groups.py b/plugins/modules/ntnx_volume_groups.py index 37fd62316..7961706d1 100644 --- a/plugins/modules/ntnx_volume_groups.py +++ b/plugins/modules/ntnx_volume_groups.py @@ -324,6 +324,7 @@ def create_volume_group(module, result): def update_volume_group(module, result): + nothing_to_change = True volume_group = VolumeGroup(module) volume_group_uuid = module.params.get("volume_group_uuid") vg_disks = module.params.get("disks") @@ -345,26 +346,23 @@ def update_volume_group(module, result): module.fail_json(msg="Failed generating volume_group update spec", **result) # check for idempotency - if check_volume_groups_idempotency(resp, update_spec, volume_group): - result["skipped"] = True - module.exit_json( - msg="Nothing to change. Refer docs to check for fields which can be updated" - ) - - if module.check_mode: - result["response"] = update_spec - result["response"]["disks"] = vg_disks - result["response"]["vms"] = vg_vms - result["response"]["clients"] = vg_clients - return - - # update volume_group - resp = volume_group.update(update_spec, uuid=volume_group_uuid, method="PATCH") - # result["response"] = resp - resp = volume_group.read(volume_group_uuid) - - result["changed"] = True - result["response"] = resp.get("data") + if not check_for_idempotency(resp, update_spec): + + if module.check_mode: + result["response"] = update_spec + result["response"]["disks"] = vg_disks + result["response"]["vms"] = vg_vms + result["response"]["clients"] = vg_clients + return + + # update volume_group + nothing_to_change = False + resp = volume_group.update(update_spec, uuid=volume_group_uuid, method="PATCH") + # result["response"] = resp + resp = volume_group.read(volume_group_uuid) + resp.get("data") + result["changed"] = True + result["response"] = resp # update disks if vg_disks: @@ -372,21 +370,32 @@ def update_volume_group(module, result): if disk.get("uuid"): disk_uuid = disk["uuid"] if disk.get("state") == "absent": + nothing_to_change = False vdisk_resp = volume_group.delete_disk(volume_group_uuid, disk_uuid) else: + vdisk = volume_group.get_vdisks(volume_group_uuid, disk_uuid).get("data") spec, err = VDisks.get_spec(module, disk) if err: + nothing_to_change = False result["warning"].append( "Disk is not updated. Error: {0}".format(err) ) result["skipped"] = True continue + elif check_for_idempotency(vdisk, spec): + result["warning"].append( + "Nothing to change. Disk: {0}".format(disk_uuid) + ) + result["skipped"] = True + continue + nothing_to_change = False vdisk_resp = volume_group.update_disk( spec, volume_group_uuid, disk_uuid ) else: + nothing_to_change = False spec, err = VDisks.get_spec(module, disk) if err: result["warning"].append( @@ -407,6 +416,7 @@ def update_volume_group(module, result): if vg_vms: for vm in vg_vms: if vm.get("state") == "absent": + nothing_to_change = False vm_resp, err = volume_group.detach_vm(volume_group_uuid, vm) if err: result["warning"].append( @@ -423,6 +433,7 @@ def update_volume_group(module, result): result["skipped"] = True continue + nothing_to_change = False vm_resp = volume_group.attach_vm(spec, volume_group_uuid) task_uuid = vm_resp["task_uuid"] @@ -435,6 +446,7 @@ def update_volume_group(module, result): if vg_clients: for client in vg_clients: + nothing_to_change = False spec, err = Clients.get_spec(client, module.params.get("CHAP_auth")) if err: result["warning"].append( @@ -443,6 +455,7 @@ def update_volume_group(module, result): result["skipped"] = True continue + nothing_to_change = False attach_resp = volume_group.attach_iscsi_client(spec, volume_group_uuid) task_uuid = attach_resp["task_uuid"] @@ -450,6 +463,10 @@ def update_volume_group(module, result): clients_resp = volume_group.get_clients(volume_group_uuid) result["response"]["clients"] = clients_resp.get("data") + if nothing_to_change: + module.exit_json( + msg="Nothing to change. Refer docs to check for fields which can be updated" + ) def delete_volume_group(module, result): @@ -491,33 +508,11 @@ def delete_volume_group(module, result): result["volume_group_uuid"] = volume_group_uuid -def check_volume_groups_idempotency(old_spec, update_spec, volume_group): +def check_for_idempotency(old_spec, update_spec): for key, value in update_spec.items(): if old_spec.get(key) != value: return False - volume_group_uuid = volume_group.module.params.get("volume_group_uuid") - updated_disks = volume_group.module.params.get("disks") - updated_vms = volume_group.module.params.get("vms") - updated_clients = volume_group.module.params.get("clients") - - if updated_disks: - # vg_disks = volume_group.get_vdisks(volume_group_uuid).get("data") - # for disk in updated_disks: - # if disk not in vg_disks: - return False - - if updated_vms: - vg_vms = volume_group.get_vms(volume_group_uuid).get("data") - for vm in updated_vms: - if vm not in vg_vms: - return False - - if updated_clients: - vg_clients = volume_group.get_clients(volume_group_uuid).get("data") - for client in updated_disks: - if client not in vg_clients: - return False return True From fcab4eb7711d8f454cd85930a1069e7689267abb Mon Sep 17 00:00:00 2001 From: alaa-bish Date: Thu, 10 Nov 2022 09:41:01 +0200 Subject: [PATCH 28/48] black fix --- plugins/modules/ntnx_volume_groups.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/modules/ntnx_volume_groups.py b/plugins/modules/ntnx_volume_groups.py index 7961706d1..5bf1bcb1c 100644 --- a/plugins/modules/ntnx_volume_groups.py +++ b/plugins/modules/ntnx_volume_groups.py @@ -374,7 +374,9 @@ def update_volume_group(module, result): vdisk_resp = volume_group.delete_disk(volume_group_uuid, disk_uuid) else: - vdisk = volume_group.get_vdisks(volume_group_uuid, disk_uuid).get("data") + vdisk = volume_group.get_vdisks(volume_group_uuid, disk_uuid).get( + "data" + ) spec, err = VDisks.get_spec(module, disk) if err: nothing_to_change = False From 88453b636984ecd99a8be11bc2aabdd551798af5 Mon Sep 17 00:00:00 2001 From: Gevorg-Khachatryaan Date: Wed, 16 Nov 2022 15:01:03 +0400 Subject: [PATCH 29/48] vg vms and clients update --- plugins/module_utils/prism/iscsi_clients.py | 47 +++- plugins/module_utils/prism/volume_groups.py | 11 +- plugins/modules/ntnx_volume_groups.py | 240 ++++++++++++-------- 3 files changed, 195 insertions(+), 103 deletions(-) diff --git a/plugins/module_utils/prism/iscsi_clients.py b/plugins/module_utils/prism/iscsi_clients.py index 07391549b..c4dcc5657 100644 --- a/plugins/module_utils/prism/iscsi_clients.py +++ b/plugins/module_utils/prism/iscsi_clients.py @@ -6,12 +6,49 @@ from copy import deepcopy +from .prism import Prism -class Clients: - @classmethod - def get_spec(cls, iscsi_client, chap_auth=False): - payload = cls._get_default_spec() - spec, error = cls._build_spec_iscsi_client(payload, iscsi_client, chap_auth) + +class Clients(Prism): + __BASEURL__ = "/api/storage/v4.0.a2/config" + + def __init__(self, module): + resource_type = "/iscsi-clients" + super(Clients, self).__init__(module, resource_type=resource_type) + self.build_spec_methods = {} + + def update( + self, + data=None, + uuid=None, + endpoint=None, + query=None, + raise_error=True, + no_response=False, + timeout=30, + method="PATCH", + ): + resp = super(Clients, self).update( + data, + uuid, + endpoint, + query, + raise_error, + no_response, + timeout, + method, + ) + resp["task_uuid"] = resp["data"]["extId"].split(":")[1] + return resp + + def get_client_spec(self, iscsi_client, old_spec={}): + payload = self._get_default_spec() + if self.module.params.get("CHAP_auth") == "enable" or old_spec.get("enabledAuthentications"): + chap_auth = True + else: + chap_auth = False + + spec, error = self._build_spec_iscsi_client(payload, iscsi_client, chap_auth) if error: return None, error return spec, None diff --git a/plugins/module_utils/prism/volume_groups.py b/plugins/module_utils/prism/volume_groups.py index a4f80a414..47cf8a8f4 100644 --- a/plugins/module_utils/prism/volume_groups.py +++ b/plugins/module_utils/prism/volume_groups.py @@ -22,6 +22,7 @@ def __init__(self, module): "desc": self._build_spec_desc, "cluster": self._build_spec_cluster, "target_prefix": self._build_spec_target_prefix, + "CHAP_auth": self._build_spec_chap_auth, "target_password": self._build_spec_target_password, "load_balance": self._build_spec_load_balance, "flash_mode": self._build_spec_flash_mode, @@ -45,7 +46,7 @@ def get_clients(self, volume_group_uuid): def create_vdisk(self, spec, volume_group_uuid): endpoint = "disks" resp = self.update(spec, volume_group_uuid, method="POST", endpoint=endpoint) - resp["task_uuid"] = resp["data"]["extId"][-36:] + resp["task_uuid"] = resp["data"]["extId"].split(":")[1] return resp def attach_vm(self, spec, volume_group_uuid): @@ -125,7 +126,13 @@ def _build_spec_target_prefix(self, payload, value): def _build_spec_target_password(self, payload, value): payload["targetSecret"] = value - payload["enabledAuthentications"] = "CHAP" + return payload, None + + def _build_spec_chap_auth(self, payload, value): + if value == "enable": + payload["enabledAuthentications"] = "CHAP" + else: + payload["enabledAuthentications"] = "NONE" return payload, None def _build_spec_load_balance(self, payload, value): diff --git a/plugins/modules/ntnx_volume_groups.py b/plugins/modules/ntnx_volume_groups.py index 5bf1bcb1c..d2b963133 100644 --- a/plugins/modules/ntnx_volume_groups.py +++ b/plugins/modules/ntnx_volume_groups.py @@ -233,7 +233,7 @@ def get_module_spec(): options=client_spec, mutually_exclusive=[("uuid", "iscsi_iqn", "iscsi_ip")], ), - CHAP_auth=dict(type="bool", default=False), + CHAP_auth=dict(type="str", choices=["enable", "disable"]), target_password=dict(type="str", no_log=True), ) @@ -306,9 +306,10 @@ def create_volume_group(module, result): # attach clients if vg_clients: - for client in vg_clients: + client = Clients(module) + for vg_client in vg_clients: - spec, err = Clients.get_spec(client, module.params.get("CHAP_auth")) + spec, err = client.get_client_spec(vg_client) if err: result["warning"] = "Client is not attached. Error: {0}".format(err) result["skipped"] = True @@ -324,7 +325,6 @@ def create_volume_group(module, result): def update_volume_group(module, result): - nothing_to_change = True volume_group = VolumeGroup(module) volume_group_uuid = module.params.get("volume_group_uuid") vg_disks = module.params.get("disks") @@ -345,6 +345,13 @@ def update_volume_group(module, result): result["error"] = error module.fail_json(msg="Failed generating volume_group update spec", **result) + if module.check_mode: + result["response"] = update_spec + result["response"]["disks"] = vg_disks + result["response"]["vms"] = vg_vms + result["response"]["clients"] = vg_clients + return + # check for idempotency if not check_for_idempotency(resp, update_spec): @@ -356,119 +363,36 @@ def update_volume_group(module, result): return # update volume_group - nothing_to_change = False + result["nothing_to_change"] = False resp = volume_group.update(update_spec, uuid=volume_group_uuid, method="PATCH") # result["response"] = resp resp = volume_group.read(volume_group_uuid) resp.get("data") - result["changed"] = True result["response"] = resp # update disks if vg_disks: - for disk in vg_disks: - if disk.get("uuid"): - disk_uuid = disk["uuid"] - if disk.get("state") == "absent": - nothing_to_change = False - vdisk_resp = volume_group.delete_disk(volume_group_uuid, disk_uuid) - - else: - vdisk = volume_group.get_vdisks(volume_group_uuid, disk_uuid).get( - "data" - ) - spec, err = VDisks.get_spec(module, disk) - if err: - nothing_to_change = False - result["warning"].append( - "Disk is not updated. Error: {0}".format(err) - ) - result["skipped"] = True - continue - elif check_for_idempotency(vdisk, spec): - result["warning"].append( - "Nothing to change. Disk: {0}".format(disk_uuid) - ) - result["skipped"] = True - continue - nothing_to_change = False - vdisk_resp = volume_group.update_disk( - spec, volume_group_uuid, disk_uuid - ) - - else: - nothing_to_change = False - spec, err = VDisks.get_spec(module, disk) - if err: - result["warning"].append( - "Disk is not created. Error: {0}".format(err) - ) - result["skipped"] = True - continue - - vdisk_resp = volume_group.create_vdisk(spec, volume_group_uuid) - - task_uuid = vdisk_resp["task_uuid"] - wait_for_task_completion(module, {"task_uuid": task_uuid}) - + update_volume_group_disks(module, volume_group, vg_disks, volume_group_uuid, result) disks_resp = volume_group.get_vdisks(volume_group_uuid) result["response"]["disks"] = disks_resp.get("data") # update vms if vg_vms: - for vm in vg_vms: - if vm.get("state") == "absent": - nothing_to_change = False - vm_resp, err = volume_group.detach_vm(volume_group_uuid, vm) - if err: - result["warning"].append( - "VM is not detached. Error: {0}".format(err) - ) - result["skipped"] = True - continue - else: - spec, err = volume_group.get_vm_spec(vm) - if err: - result["warning"].append( - "VM is not attached. Error: {0}".format(err) - ) - result["skipped"] = True - continue - - nothing_to_change = False - vm_resp = volume_group.attach_vm(spec, volume_group_uuid) - - task_uuid = vm_resp["task_uuid"] - wait_for_task_completion(module, {"task_uuid": task_uuid}) - + update_volume_group_vms(module, volume_group, vg_vms, volume_group_uuid, result) vms_resp = volume_group.get_vms(volume_group_uuid) result["response"]["vms"] = vms_resp.get("data") # update clients if vg_clients: - for client in vg_clients: - - nothing_to_change = False - spec, err = Clients.get_spec(client, module.params.get("CHAP_auth")) - if err: - result["warning"].append( - "Client is not attached. Error: {0}".format(err) - ) - result["skipped"] = True - continue - - nothing_to_change = False - attach_resp = volume_group.attach_iscsi_client(spec, volume_group_uuid) - - task_uuid = attach_resp["task_uuid"] - wait_for_task_completion(module, {"task_uuid": task_uuid}) - + update_volume_group_clients(module, volume_group, vg_clients, volume_group_uuid, result) clients_resp = volume_group.get_clients(volume_group_uuid) result["response"]["clients"] = clients_resp.get("data") - if nothing_to_change: + + if result.pop("nothing_to_change"): module.exit_json( msg="Nothing to change. Refer docs to check for fields which can be updated" ) + result["changed"] = True def delete_volume_group(module, result): @@ -510,10 +434,133 @@ def delete_volume_group(module, result): result["volume_group_uuid"] = volume_group_uuid +def update_volume_group_disks(module, volume_group, vg_disks, volume_group_uuid, result): + for disk in vg_disks: + if disk.get("uuid"): + disk_uuid = disk["uuid"] + if disk.get("state") == "absent": + result["nothing_to_change"] = False + vdisk_resp = volume_group.delete_disk(volume_group_uuid, disk_uuid) + + else: + vdisk = volume_group.get_vdisks(volume_group_uuid, disk_uuid).get("data") + spec, err = VDisks.get_spec(module, disk) + if err: + result["nothing_to_change"] = False + result["warning"].append( + "Disk is not updated. Error: {0}".format(err) + ) + result["skipped"] = True + continue + elif check_for_idempotency(vdisk, spec): + result["warning"].append( + "Nothing to change. Disk: {0}".format(disk_uuid) + ) + result["skipped"] = True + continue + result["nothing_to_change"] = False + vdisk_resp = volume_group.update_disk( + spec, volume_group_uuid, disk_uuid + ) + + else: + result["nothing_to_change"] = False + spec, err = VDisks.get_spec(module, disk) + if err: + result["warning"].append( + "Disk is not created. Error: {0}".format(err) + ) + result["skipped"] = True + continue + vdisk_resp = volume_group.create_vdisk(spec, volume_group_uuid) + + task_uuid = vdisk_resp["task_uuid"] + wait_for_task_completion(module, {"task_uuid": task_uuid}) + + disks_resp = volume_group.get_vdisks(volume_group_uuid) + result["response"]["disks"] = disks_resp.get("data") + + +def update_volume_group_vms(module, volume_group, vg_vms, volume_group_uuid, result): + for vm in vg_vms: + if vm.get("state") == "absent": + result["nothing_to_change"] = False + vm_resp, err = volume_group.detach_vm(volume_group_uuid, vm) + if err: + result["warning"].append( + "VM is not detached. Error: {0}".format(err) + ) + result["skipped"] = True + continue + else: + spec, err = volume_group.get_vm_spec(vm) + if err: + result["warning"].append( + "VM is not attached. Error: {0}".format(err) + ) + result["skipped"] = True + continue + + result["nothing_to_change"] = False + vm_resp = volume_group.attach_vm(spec, volume_group_uuid) + + task_uuid = vm_resp["task_uuid"] + wait_for_task_completion(module, {"task_uuid": task_uuid}) + + +def update_volume_group_clients(module, volume_group, vg_clients, volume_group_uuid, result): + client = Clients(module) + for vg_client in vg_clients: + + if vg_client.get("uuid"): + client_uuid = vg_client["uuid"] + if vg_client.get("state") == "absent": + result["nothing_to_change"] = False + client_resp = volume_group.detach_iscsi_client(volume_group_uuid, client_uuid) + + else: + resp = client.read(client_uuid).get("data") + spec, err = client.get_client_spec(vg_client, resp) + if err: + result["nothing_to_change"] = False + result["warning"].append( + "Client is not updated. Error: {0}".format(err) + ) + result["skipped"] = True + continue + elif check_for_idempotency(resp, spec): + result["warning"].append( + "Nothing to change. Client: {0}".format(client_uuid) + ) + result["skipped"] = True + continue + result["nothing_to_change"] = False + client_resp = client.update( + spec, client_uuid, method="PATCH" + ) + + else: + result["nothing_to_change"] = False + spec, err = client.get_client_spec(vg_client) + if err: + result["warning"].append( + "Client is not created. Error: {0}".format(err) + ) + result["skipped"] = True + continue + client_resp = volume_group.attach_iscsi_client(spec, volume_group_uuid) + + task_uuid = client_resp["task_uuid"] + wait_for_task_completion(module, {"task_uuid": task_uuid}) + + def check_for_idempotency(old_spec, update_spec): for key, value in update_spec.items(): - if old_spec.get(key) != value: + if key == "enabledAuthentications" and value != "NONE": + if old_spec.get(key): + False + elif old_spec.get(key) != value: return False return True @@ -533,7 +580,7 @@ def run_module(): required_if=[ ("state", "present", ("name", "volume_group_uuid"), True), ("state", "absent", ("volume_group_uuid",)), - ("CHAP_auth", True, ("target_password",)), + ("CHAP_auth", "enable", ("target_password",)), ], mutually_exclusive=[("vms", "clients")], ) @@ -544,6 +591,7 @@ def run_module(): "response": None, "volume_group_uuid": None, "warning": [], + "nothing_to_change": True } state = module.params["state"] if state == "absent": From 6442d44bdb1fd4f1cddfe31734e7b486d34390a5 Mon Sep 17 00:00:00 2001 From: alaa-bish Date: Wed, 16 Nov 2022 13:15:31 +0200 Subject: [PATCH 30/48] sanity fix --- plugins/module_utils/prism/iscsi_clients.py | 22 +++++----- plugins/modules/ntnx_volume_groups.py | 46 +++++++++++---------- 2 files changed, 37 insertions(+), 31 deletions(-) diff --git a/plugins/module_utils/prism/iscsi_clients.py b/plugins/module_utils/prism/iscsi_clients.py index c4dcc5657..3267c6c44 100644 --- a/plugins/module_utils/prism/iscsi_clients.py +++ b/plugins/module_utils/prism/iscsi_clients.py @@ -18,15 +18,15 @@ def __init__(self, module): self.build_spec_methods = {} def update( - self, - data=None, - uuid=None, - endpoint=None, - query=None, - raise_error=True, - no_response=False, - timeout=30, - method="PATCH", + self, + data=None, + uuid=None, + endpoint=None, + query=None, + raise_error=True, + no_response=False, + timeout=30, + method="PATCH", ): resp = super(Clients, self).update( data, @@ -43,7 +43,9 @@ def update( def get_client_spec(self, iscsi_client, old_spec={}): payload = self._get_default_spec() - if self.module.params.get("CHAP_auth") == "enable" or old_spec.get("enabledAuthentications"): + if self.module.params.get("CHAP_auth") == "enable" or old_spec.get( + "enabledAuthentications" + ): chap_auth = True else: chap_auth = False diff --git a/plugins/modules/ntnx_volume_groups.py b/plugins/modules/ntnx_volume_groups.py index d2b963133..71cfdf719 100644 --- a/plugins/modules/ntnx_volume_groups.py +++ b/plugins/modules/ntnx_volume_groups.py @@ -143,8 +143,8 @@ type: str CHAP_auth: description: Use Challenge-Handshake Authentication Protocol - type: bool - default: false + type: str + choices: ["enable", "disable"] target_password: description: CHAP secret type: str @@ -372,7 +372,9 @@ def update_volume_group(module, result): # update disks if vg_disks: - update_volume_group_disks(module, volume_group, vg_disks, volume_group_uuid, result) + update_volume_group_disks( + module, volume_group, vg_disks, volume_group_uuid, result + ) disks_resp = volume_group.get_vdisks(volume_group_uuid) result["response"]["disks"] = disks_resp.get("data") @@ -384,7 +386,9 @@ def update_volume_group(module, result): # update clients if vg_clients: - update_volume_group_clients(module, volume_group, vg_clients, volume_group_uuid, result) + update_volume_group_clients( + module, volume_group, vg_clients, volume_group_uuid, result + ) clients_resp = volume_group.get_clients(volume_group_uuid) result["response"]["clients"] = clients_resp.get("data") @@ -434,7 +438,9 @@ def delete_volume_group(module, result): result["volume_group_uuid"] = volume_group_uuid -def update_volume_group_disks(module, volume_group, vg_disks, volume_group_uuid, result): +def update_volume_group_disks( + module, volume_group, vg_disks, volume_group_uuid, result +): for disk in vg_disks: if disk.get("uuid"): disk_uuid = disk["uuid"] @@ -443,7 +449,9 @@ def update_volume_group_disks(module, volume_group, vg_disks, volume_group_uuid, vdisk_resp = volume_group.delete_disk(volume_group_uuid, disk_uuid) else: - vdisk = volume_group.get_vdisks(volume_group_uuid, disk_uuid).get("data") + vdisk = volume_group.get_vdisks(volume_group_uuid, disk_uuid).get( + "data" + ) spec, err = VDisks.get_spec(module, disk) if err: result["nothing_to_change"] = False @@ -467,9 +475,7 @@ def update_volume_group_disks(module, volume_group, vg_disks, volume_group_uuid, result["nothing_to_change"] = False spec, err = VDisks.get_spec(module, disk) if err: - result["warning"].append( - "Disk is not created. Error: {0}".format(err) - ) + result["warning"].append("Disk is not created. Error: {0}".format(err)) result["skipped"] = True continue vdisk_resp = volume_group.create_vdisk(spec, volume_group_uuid) @@ -487,17 +493,13 @@ def update_volume_group_vms(module, volume_group, vg_vms, volume_group_uuid, res result["nothing_to_change"] = False vm_resp, err = volume_group.detach_vm(volume_group_uuid, vm) if err: - result["warning"].append( - "VM is not detached. Error: {0}".format(err) - ) + result["warning"].append("VM is not detached. Error: {0}".format(err)) result["skipped"] = True continue else: spec, err = volume_group.get_vm_spec(vm) if err: - result["warning"].append( - "VM is not attached. Error: {0}".format(err) - ) + result["warning"].append("VM is not attached. Error: {0}".format(err)) result["skipped"] = True continue @@ -508,7 +510,9 @@ def update_volume_group_vms(module, volume_group, vg_vms, volume_group_uuid, res wait_for_task_completion(module, {"task_uuid": task_uuid}) -def update_volume_group_clients(module, volume_group, vg_clients, volume_group_uuid, result): +def update_volume_group_clients( + module, volume_group, vg_clients, volume_group_uuid, result +): client = Clients(module) for vg_client in vg_clients: @@ -516,7 +520,9 @@ def update_volume_group_clients(module, volume_group, vg_clients, volume_group_u client_uuid = vg_client["uuid"] if vg_client.get("state") == "absent": result["nothing_to_change"] = False - client_resp = volume_group.detach_iscsi_client(volume_group_uuid, client_uuid) + client_resp = volume_group.detach_iscsi_client( + volume_group_uuid, client_uuid + ) else: resp = client.read(client_uuid).get("data") @@ -535,9 +541,7 @@ def update_volume_group_clients(module, volume_group, vg_clients, volume_group_u result["skipped"] = True continue result["nothing_to_change"] = False - client_resp = client.update( - spec, client_uuid, method="PATCH" - ) + client_resp = client.update(spec, client_uuid, method="PATCH") else: result["nothing_to_change"] = False @@ -591,7 +595,7 @@ def run_module(): "response": None, "volume_group_uuid": None, "warning": [], - "nothing_to_change": True + "nothing_to_change": True, } state = module.params["state"] if state == "absent": From 0bf05ff7cb475f629c88fa09a388cc420e2aa900 Mon Sep 17 00:00:00 2001 From: Gevorg-Khachatryaan Date: Wed, 16 Nov 2022 21:16:38 +0400 Subject: [PATCH 31/48] vg vms and clients update --- plugins/module_utils/prism/iscsi_clients.py | 4 ++-- plugins/modules/ntnx_volume_groups.py | 9 +++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/plugins/module_utils/prism/iscsi_clients.py b/plugins/module_utils/prism/iscsi_clients.py index 3267c6c44..f5e73c299 100644 --- a/plugins/module_utils/prism/iscsi_clients.py +++ b/plugins/module_utils/prism/iscsi_clients.py @@ -41,9 +41,9 @@ def update( resp["task_uuid"] = resp["data"]["extId"].split(":")[1] return resp - def get_client_spec(self, iscsi_client, old_spec={}): + def get_client_spec(self, iscsi_client, old_spec=None): payload = self._get_default_spec() - if self.module.params.get("CHAP_auth") == "enable" or old_spec.get( + if self.module.params.get("CHAP_auth") == "enable" or old_spec and old_spec.get( "enabledAuthentications" ): chap_auth = True diff --git a/plugins/modules/ntnx_volume_groups.py b/plugins/modules/ntnx_volume_groups.py index 71cfdf719..21245d58d 100644 --- a/plugins/modules/ntnx_volume_groups.py +++ b/plugins/modules/ntnx_volume_groups.py @@ -423,8 +423,13 @@ def delete_volume_group(module, result): vms_resp = volume_group.get_vms(volume_group_uuid) detached_vms = [] for vm in vms_resp.get("data", []): - detach_resp, _ = volume_group.detach_vm(volume_group_uuid, vm) - + detach_resp, err = volume_group.detach_vm(volume_group_uuid, vm) + if err: + result["warning"].append( + "VM is not detached. Error: {0}".format(err) + ) + result["skipped"] = True + continue task_uuid = detach_resp["task_uuid"] wait_for_task_completion(module, {"task_uuid": task_uuid}) detached_vms.append(vm["extId"]) From 760417c66b327d4c8525cda08e726fff48b5ec7d Mon Sep 17 00:00:00 2001 From: Gevorg-Khachatryaan Date: Wed, 16 Nov 2022 21:19:45 +0400 Subject: [PATCH 32/48] response fixes --- plugins/modules/ntnx_volume_groups.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/modules/ntnx_volume_groups.py b/plugins/modules/ntnx_volume_groups.py index 21245d58d..d02a2828c 100644 --- a/plugins/modules/ntnx_volume_groups.py +++ b/plugins/modules/ntnx_volume_groups.py @@ -364,10 +364,10 @@ def update_volume_group(module, result): # update volume_group result["nothing_to_change"] = False - resp = volume_group.update(update_spec, uuid=volume_group_uuid, method="PATCH") - # result["response"] = resp + volume_group.update(update_spec, uuid=volume_group_uuid, method="PATCH") + resp = volume_group.read(volume_group_uuid) - resp.get("data") + resp = resp.get("data") result["response"] = resp # update disks From 7e2c148c0561290e9b61a3ad5ab7f03b8972f136 Mon Sep 17 00:00:00 2001 From: alaa-bish Date: Thu, 17 Nov 2022 08:47:33 +0200 Subject: [PATCH 33/48] black fix --- plugins/module_utils/prism/iscsi_clients.py | 6 ++++-- plugins/modules/ntnx_volume_groups.py | 4 +--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/module_utils/prism/iscsi_clients.py b/plugins/module_utils/prism/iscsi_clients.py index f5e73c299..6ddb49646 100644 --- a/plugins/module_utils/prism/iscsi_clients.py +++ b/plugins/module_utils/prism/iscsi_clients.py @@ -43,8 +43,10 @@ def update( def get_client_spec(self, iscsi_client, old_spec=None): payload = self._get_default_spec() - if self.module.params.get("CHAP_auth") == "enable" or old_spec and old_spec.get( - "enabledAuthentications" + if ( + self.module.params.get("CHAP_auth") == "enable" + or old_spec + and old_spec.get("enabledAuthentications") ): chap_auth = True else: diff --git a/plugins/modules/ntnx_volume_groups.py b/plugins/modules/ntnx_volume_groups.py index d02a2828c..a0c7b4e67 100644 --- a/plugins/modules/ntnx_volume_groups.py +++ b/plugins/modules/ntnx_volume_groups.py @@ -425,9 +425,7 @@ def delete_volume_group(module, result): for vm in vms_resp.get("data", []): detach_resp, err = volume_group.detach_vm(volume_group_uuid, vm) if err: - result["warning"].append( - "VM is not detached. Error: {0}".format(err) - ) + result["warning"].append("VM is not detached. Error: {0}".format(err)) result["skipped"] = True continue task_uuid = detach_resp["task_uuid"] From d30d29397d4606eab6d9f5799d706e5340821029 Mon Sep 17 00:00:00 2001 From: Gevorg-Khachatryaan Date: Thu, 17 Nov 2022 15:25:18 +0400 Subject: [PATCH 34/48] fixes --- plugins/module_utils/prism/volume_groups.py | 12 ++++++------ plugins/modules/ntnx_volume_groups.py | 15 +-------------- 2 files changed, 7 insertions(+), 20 deletions(-) diff --git a/plugins/module_utils/prism/volume_groups.py b/plugins/module_utils/prism/volume_groups.py index 47cf8a8f4..814974406 100644 --- a/plugins/module_utils/prism/volume_groups.py +++ b/plugins/module_utils/prism/volume_groups.py @@ -52,13 +52,13 @@ def create_vdisk(self, spec, volume_group_uuid): def attach_vm(self, spec, volume_group_uuid): endpoint = "$actions/attach-vm" resp = self.update(spec, volume_group_uuid, method="POST", endpoint=endpoint) - resp["task_uuid"] = resp["data"]["extId"][-36:] + resp["task_uuid"] = resp["data"]["extId"].split(":")[1] return resp def attach_iscsi_client(self, spec, volume_group_uuid): endpoint = "/$actions/attach-iscsi-client" resp = self.update(spec, volume_group_uuid, method="POST", endpoint=endpoint) - resp["task_uuid"] = resp["data"]["extId"][-36:] + resp["task_uuid"] = resp["data"]["extId"].split(":")[1] return resp def update_disk(self, spec, volume_group_uuid, disk_uuid): @@ -66,13 +66,13 @@ def update_disk(self, spec, volume_group_uuid, disk_uuid): resp = self.update( spec, uuid=volume_group_uuid, method="PATCH", endpoint=endpoint ) - resp["task_uuid"] = resp["data"]["extId"][-36:] + resp["task_uuid"] = resp["data"]["extId"].split(":")[1] return resp def delete_disk(self, volume_group_uuid, disk_uuid): endpoint = "disks/{0}".format(disk_uuid) resp = self.delete(uuid=volume_group_uuid, endpoint=endpoint) - resp["task_uuid"] = resp["data"]["extId"][-36:] + resp["task_uuid"] = resp["data"]["extId"].split(":")[1] return resp def detach_vm(self, volume_group_uuid, vm): @@ -84,14 +84,14 @@ def detach_vm(self, volume_group_uuid, vm): vm_uuid = vm["extId"] endpoint = "$actions/detach-vm/{0}".format(vm_uuid) resp = self.update(uuid=volume_group_uuid, method="POST", endpoint=endpoint) - resp["task_uuid"] = resp["data"]["extId"][-36:] + resp["task_uuid"] = resp["data"]["extId"].split(":")[1] return resp, None def detach_iscsi_client(self, volume_group_uuid, client): client_uuid = client["extId"] endpoint = "$actions/detach-iscsi-client/{0}".format(client_uuid) resp = self.update(uuid=volume_group_uuid, method="POST", endpoint=endpoint) - resp["task_uuid"] = resp["data"]["extId"][-36:] + resp["task_uuid"] = resp["data"]["extId"].split(":")[1] return resp def _get_default_spec(self): diff --git a/plugins/modules/ntnx_volume_groups.py b/plugins/modules/ntnx_volume_groups.py index a0c7b4e67..ba725e15a 100644 --- a/plugins/modules/ntnx_volume_groups.py +++ b/plugins/modules/ntnx_volume_groups.py @@ -253,13 +253,10 @@ def create_volume_group(module, result): if module.check_mode: result["response"] = spec - result["response"]["disks"] = vg_disks - result["response"]["vms"] = vg_vms - result["response"]["clients"] = vg_clients return resp = volume_group.create(spec) - task_uuid = resp["data"]["extId"][-36:] + task_uuid = resp["data"]["extId"].split(":")[1] result["changed"] = True result["response"] = resp result["task_uuid"] = task_uuid @@ -347,21 +344,11 @@ def update_volume_group(module, result): if module.check_mode: result["response"] = update_spec - result["response"]["disks"] = vg_disks - result["response"]["vms"] = vg_vms - result["response"]["clients"] = vg_clients return # check for idempotency if not check_for_idempotency(resp, update_spec): - if module.check_mode: - result["response"] = update_spec - result["response"]["disks"] = vg_disks - result["response"]["vms"] = vg_vms - result["response"]["clients"] = vg_clients - return - # update volume_group result["nothing_to_change"] = False volume_group.update(update_spec, uuid=volume_group_uuid, method="PATCH") From cd12727b6a3259e2708de71bf4cab02745016612 Mon Sep 17 00:00:00 2001 From: Gevorg-Khachatryaan Date: Fri, 18 Nov 2022 15:01:42 +0400 Subject: [PATCH 35/48] fixes --- plugins/module_utils/prism/volume_groups.py | 3 +-- plugins/modules/ntnx_volume_groups.py | 6 ++++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/plugins/module_utils/prism/volume_groups.py b/plugins/module_utils/prism/volume_groups.py index 814974406..128d350b8 100644 --- a/plugins/module_utils/prism/volume_groups.py +++ b/plugins/module_utils/prism/volume_groups.py @@ -87,8 +87,7 @@ def detach_vm(self, volume_group_uuid, vm): resp["task_uuid"] = resp["data"]["extId"].split(":")[1] return resp, None - def detach_iscsi_client(self, volume_group_uuid, client): - client_uuid = client["extId"] + def detach_iscsi_client(self, volume_group_uuid, client_uuid): endpoint = "$actions/detach-iscsi-client/{0}".format(client_uuid) resp = self.update(uuid=volume_group_uuid, method="POST", endpoint=endpoint) resp["task_uuid"] = resp["data"]["extId"].split(":")[1] diff --git a/plugins/modules/ntnx_volume_groups.py b/plugins/modules/ntnx_volume_groups.py index ba725e15a..a8c0ccfc7 100644 --- a/plugins/modules/ntnx_volume_groups.py +++ b/plugins/modules/ntnx_volume_groups.py @@ -232,6 +232,7 @@ def get_module_spec(): elements="dict", options=client_spec, mutually_exclusive=[("uuid", "iscsi_iqn", "iscsi_ip")], + required_if=[("state", "absent", ("uuid",))], ), CHAP_auth=dict(type="str", choices=["enable", "disable"]), target_password=dict(type="str", no_log=True), @@ -398,11 +399,12 @@ def delete_volume_group(module, result): clients_resp = volume_group.get_clients(volume_group_uuid) detached_clients = [] for client in clients_resp.get("data", []): - detach_resp = volume_group.detach_iscsi_client(volume_group_uuid, client) + client_uuid = client["extId"] + detach_resp = volume_group.detach_iscsi_client(volume_group_uuid, client_uuid) task_uuid = detach_resp["task_uuid"] wait_for_task_completion(module, {"task_uuid": task_uuid}) - detached_clients.append(client["extId"]) + detached_clients.append(client_uuid) result["detached_clients"] = detached_clients From 5185789f614ad03506ba4105d28b332c2beb6539 Mon Sep 17 00:00:00 2001 From: Gevorg-Khachatryaan Date: Fri, 18 Nov 2022 16:02:50 +0400 Subject: [PATCH 36/48] fixes --- plugins/modules/ntnx_volume_groups.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/plugins/modules/ntnx_volume_groups.py b/plugins/modules/ntnx_volume_groups.py index a8c0ccfc7..17cd50171 100644 --- a/plugins/modules/ntnx_volume_groups.py +++ b/plugins/modules/ntnx_volume_groups.py @@ -363,22 +363,25 @@ def update_volume_group(module, result): update_volume_group_disks( module, volume_group, vg_disks, volume_group_uuid, result ) - disks_resp = volume_group.get_vdisks(volume_group_uuid) - result["response"]["disks"] = disks_resp.get("data") + + disks_resp = volume_group.get_vdisks(volume_group_uuid) + result["response"]["disks"] = disks_resp.get("data") # update vms if vg_vms: update_volume_group_vms(module, volume_group, vg_vms, volume_group_uuid, result) - vms_resp = volume_group.get_vms(volume_group_uuid) - result["response"]["vms"] = vms_resp.get("data") + + vms_resp = volume_group.get_vms(volume_group_uuid) + result["response"]["vms"] = vms_resp.get("data") # update clients if vg_clients: update_volume_group_clients( module, volume_group, vg_clients, volume_group_uuid, result ) - clients_resp = volume_group.get_clients(volume_group_uuid) - result["response"]["clients"] = clients_resp.get("data") + + clients_resp = volume_group.get_clients(volume_group_uuid) + result["response"]["clients"] = clients_resp.get("data") if result.pop("nothing_to_change"): module.exit_json( From 91f3eb09683afd7649a2a82ebcaa903f5b382212 Mon Sep 17 00:00:00 2001 From: Gevorg-Khachatryaan Date: Tue, 14 Mar 2023 12:59:44 +0400 Subject: [PATCH 37/48] volume group's info module --- plugins/modules/ntnx_volume_groups_info.py | 294 +++++++++++++++++++++ 1 file changed, 294 insertions(+) create mode 100644 plugins/modules/ntnx_volume_groups_info.py diff --git a/plugins/modules/ntnx_volume_groups_info.py b/plugins/modules/ntnx_volume_groups_info.py new file mode 100644 index 000000000..8e87a2ad7 --- /dev/null +++ b/plugins/modules/ntnx_volume_groups_info.py @@ -0,0 +1,294 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2021, Prem Karat +# 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""" +--- +module: ntnx_volume_groups_info +short_description: volume_group info module +version_added: 1.0.0 +description: 'Get volume_group info' +options: + kind: + description: + - The kind name + type: str + default: volume_group + volume_group_uuid: + description: + - volume_group UUID + type: str +extends_documentation_fragment: + - nutanix.ncp.ntnx_credentials + - nutanix.ncp.ntnx_info +author: + - Prem Karat (@premkarat) + - Gevorg Khachatryan (@Gevorg-Khachatryan-97) + - Alaa Bishtawi (@alaa-bish) +""" +EXAMPLES = r""" + - name: List volume_group using name filter criteria + ntnx_volume_groups_info: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: False + filter: + name: "{{ volume_group.name }}" + kind: volume_group + register: result + + - name: List volume_group using length, offset, sort order and name sort attribute + ntnx_volume_groups_info: + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: False + length: 10 + offset: 1 + sort_order: "ASCENDING" + sort_attribute: "name" + register: result +""" +RETURN = r""" +metadata: + description: Metadata for volume_group list output + returned: always + type: dict + sample: {} +entities: + description: volume_group intent response + returned: always + type: list + sample: { + "entities": [ + { + "status": { + "description": "string", + "state": "string", + "message_list": [ + { + "message": "string", + "reason": "string", + "details": { + "additionalProp1": "string", + "additionalProp2": "string", + "additionalProp3": "string" + } + } + ], + "cluster_reference": { + "kind": "cluster", + "name": "string", + "uuid": "string" + }, + "resources": { + "flash_mode": "string", + "iscsi_target_name": "string", + "enabled_authentications": "string", + "attachment_list": [ + { + "iscsi_initiator_network_id": "string", + "enabled_authentications": "string", + "vm_reference": { + "kind": "vm", + "name": "string", + "uuid": "string" + }, + "iscsi_initiator_name": "string" + } + ], + "created_by": "string", + "parent_reference": { + "url": "string", + "kind": "string", + "uuid": "string", + "name": "string" + }, + "sharing_status": "string", + "disk_list": [ + { + "index": 0, + "storage_container_uuid": "string", + "disk_size_mib": 0, + "disk_size_bytes": 0, + "uuid": "string" + } + ], + "size_bytes": 0, + "usage_type": "string", + "load_balance_vm_attachments": true, + "is_hidden": true, + "size_mib": 0, + "iscsi_target_prefix": "string" + }, + "name": "string" + }, + "spec": { + "name": "string", + "description": "string", + "resources": { + "flash_mode": "string", + "load_balance_vm_attachments": true, + "created_by": "string", + "iscsi_target_prefix": "string", + "parent_reference": { + "url": "string", + "kind": "string", + "uuid": "string", + "name": "string" + }, + "sharing_status": "string", + "attachment_list": [ + { + "iscsi_initiator_network_id": "string", + "client_secret": "string", + "vm_reference": { + "kind": "vm", + "name": "string", + "uuid": "string" + }, + "iscsi_initiator_name": "string" + } + ], + "usage_type": "string", + "target_secret": "string", + "is_hidden": true, + "disk_list": [ + { + "index": 16383, + "data_source_reference": { + "url": "string", + "kind": "string", + "uuid": "string", + "name": "string" + }, + "disk_size_mib": 0, + "disk_size_bytes": 0, + "storage_container_uuid": "string" + } + ] + }, + "cluster_reference": { + "kind": "cluster", + "name": "string", + "uuid": "string" + } + }, + "api_version": "3.1.0", + "metadata": { + "last_update_time": "2023-03-13T11:41:16.626Z", + "use_categories_mapping": false, + "kind": "volume_group", + "uuid": "string", + "project_reference": { + "kind": "project", + "name": "string", + "uuid": "string" + }, + "creation_time": "2023-03-13T11:41:16.626Z", + "spec_version": 0, + "spec_hash": "string", + "categories_mapping": { + "additionalProp1": [ + "string" + ], + "additionalProp2": [ + "string" + ], + "additionalProp3": [ + "string" + ] + }, + "should_force_translate": true, + "entity_version": "string", + "owner_reference": { + "kind": "user", + "name": "string", + "uuid": "string" + }, + "categories": { + "additionalProp1": "string", + "additionalProp2": "string", + "additionalProp3": "string" + }, + "name": "string" + } + } + ], + "api_version": "3.1.0", + "metadata": { + "kind": "volume_group", + "total_matches": 0, + "sort_attribute": "string", + "filter": "string", + "length": 0, + "sort_order": "string", + "offset": 0 + } +} +""" + +from ..module_utils.base_info_module import BaseInfoModule # noqa: E402 +from ..module_utils.prism.volume_groups import VolumeGroup # noqa: E402 +from ..module_utils.utils import remove_param_with_none_value # noqa: E402 + + +def get_module_spec(): + + module_args = dict( + volume_group_uuid=dict(type="str"), + # kind=dict(type="str", default="volume_group"), + # sort_order=dict(type="str"), + # sort_attribute=dict(type="str"), + # offset=dict(type="int", default=0), + # length=dict(type="int", default=10), + ) + + return module_args + + +def get_volume_group(module, result): + volume_group = VolumeGroup(module) + volume_group_uuid = module.params.get("volume_group_uuid") + resp = volume_group.read(volume_group_uuid) + + result["response"] = resp + + +def get_volume_groups(module, result): + volume_group = VolumeGroup(module) + spec, error = volume_group.get_info_spec() + + # resp = volume_group.list(spec) + resp = volume_group.read() + + result["response"] = resp + + +def run_module(): + module = BaseInfoModule( + argument_spec=get_module_spec(), + supports_check_mode=False, + # required_together=[("sort_order", "sort_attribute")], + ) + remove_param_with_none_value(module.params) + result = {"changed": False, "error": None, "response": None} + if module.params.get("volume_group_uuid"): + get_volume_group(module, result) + else: + get_volume_groups(module, result) + module.exit_json(**result) + + +def main(): + run_module() + + +if __name__ == "__main__": + main() From 4905add901adaf4e144a3674b0bccefe961c3b2e Mon Sep 17 00:00:00 2001 From: Gevorg-Khachatryaan Date: Tue, 14 Mar 2023 13:05:52 +0400 Subject: [PATCH 38/48] volume group's info module fix --- plugins/modules/ntnx_volume_groups_info.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/plugins/modules/ntnx_volume_groups_info.py b/plugins/modules/ntnx_volume_groups_info.py index 8e87a2ad7..e23a53ecb 100644 --- a/plugins/modules/ntnx_volume_groups_info.py +++ b/plugins/modules/ntnx_volume_groups_info.py @@ -243,11 +243,6 @@ def get_module_spec(): module_args = dict( volume_group_uuid=dict(type="str"), - # kind=dict(type="str", default="volume_group"), - # sort_order=dict(type="str"), - # sort_attribute=dict(type="str"), - # offset=dict(type="int", default=0), - # length=dict(type="int", default=10), ) return module_args @@ -263,9 +258,7 @@ def get_volume_group(module, result): def get_volume_groups(module, result): volume_group = VolumeGroup(module) - spec, error = volume_group.get_info_spec() - # resp = volume_group.list(spec) resp = volume_group.read() result["response"] = resp From 667d438afec4c7bf20d236eb75cf1cb8fc86e150 Mon Sep 17 00:00:00 2001 From: alaa-bish Date: Tue, 14 Mar 2023 11:27:19 +0200 Subject: [PATCH 39/48] sanity fix --- meta/runtime.yml | 1 + plugins/modules/ntnx_volume_groups.py | 2 +- plugins/modules/ntnx_volume_groups_info.py | 10 ++-------- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/meta/runtime.yml b/meta/runtime.yml index c94168437..702ca6c04 100644 --- a/meta/runtime.yml +++ b/meta/runtime.yml @@ -96,3 +96,4 @@ action_groups: - ntnx_ndb_maintenance_windows_info - ntnx_ndb_slas - ntnx_volume_groups + - ntnx_volume_groups_info diff --git a/plugins/modules/ntnx_volume_groups.py b/plugins/modules/ntnx_volume_groups.py index 17cd50171..5cf2f1f51 100644 --- a/plugins/modules/ntnx_volume_groups.py +++ b/plugins/modules/ntnx_volume_groups.py @@ -11,7 +11,7 @@ --- module: ntnx_volume_groups short_description: volume_groups module which suports volume_groups CRUD operations -version_added: 1.4.0 +version_added: 1.9.0 description: 'Create, Update, Delete volume_group' options: state: diff --git a/plugins/modules/ntnx_volume_groups_info.py b/plugins/modules/ntnx_volume_groups_info.py index e23a53ecb..dcc6ef660 100644 --- a/plugins/modules/ntnx_volume_groups_info.py +++ b/plugins/modules/ntnx_volume_groups_info.py @@ -11,21 +11,16 @@ --- module: ntnx_volume_groups_info short_description: volume_group info module -version_added: 1.0.0 +version_added: 1.9.0 description: 'Get volume_group info' options: - kind: - description: - - The kind name - type: str - default: volume_group volume_group_uuid: description: - volume_group UUID type: str extends_documentation_fragment: - nutanix.ncp.ntnx_credentials - - nutanix.ncp.ntnx_info + # - nutanix.ncp.ntnx_info author: - Prem Karat (@premkarat) - Gevorg Khachatryan (@Gevorg-Khachatryan-97) @@ -268,7 +263,6 @@ def run_module(): module = BaseInfoModule( argument_spec=get_module_spec(), supports_check_mode=False, - # required_together=[("sort_order", "sort_attribute")], ) remove_param_with_none_value(module.params) result = {"changed": False, "error": None, "response": None} From 61a64986c3f3c20e98e49de5198b5d064d1edc89 Mon Sep 17 00:00:00 2001 From: Gevorg-Khachatryaan Date: Tue, 14 Mar 2023 13:26:21 +0400 Subject: [PATCH 40/48] volume group's module fix --- plugins/modules/ntnx_volume_groups.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/plugins/modules/ntnx_volume_groups.py b/plugins/modules/ntnx_volume_groups.py index 5cf2f1f51..967e298e2 100644 --- a/plugins/modules/ntnx_volume_groups.py +++ b/plugins/modules/ntnx_volume_groups.py @@ -328,6 +328,7 @@ def update_volume_group(module, result): vg_disks = module.params.get("disks") vg_vms = module.params.get("vms") vg_clients = module.params.get("clients") + result["nothing_to_change"] = True if not volume_group_uuid: result["error"] = "Missing parameter volume_group_uuid in playbook" module.fail_json(msg="Failed updating volume_group", **result) @@ -558,7 +559,7 @@ def check_for_idempotency(old_spec, update_spec): for key, value in update_spec.items(): if key == "enabledAuthentications" and value != "NONE": if old_spec.get(key): - False + return False elif old_spec.get(key) != value: return False @@ -590,7 +591,7 @@ def run_module(): "response": None, "volume_group_uuid": None, "warning": [], - "nothing_to_change": True, + "nothing_to_change": False, } state = module.params["state"] if state == "absent": From ceb9cc4f243353178c6c8abc5a252325f1636a3e Mon Sep 17 00:00:00 2001 From: Gevorg-Khachatryaan Date: Wed, 15 Mar 2023 12:38:06 +0400 Subject: [PATCH 41/48] volume group's module fix, clients attaching by uuid --- plugins/modules/ntnx_volume_groups.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/modules/ntnx_volume_groups.py b/plugins/modules/ntnx_volume_groups.py index 967e298e2..d0a8dc3f5 100644 --- a/plugins/modules/ntnx_volume_groups.py +++ b/plugins/modules/ntnx_volume_groups.py @@ -512,7 +512,7 @@ def update_volume_group_clients( client = Clients(module) for vg_client in vg_clients: - if vg_client.get("uuid"): + if vg_client.get("uuid") and (vg_client.get("state") or vg_client.get("client_password")): client_uuid = vg_client["uuid"] if vg_client.get("state") == "absent": result["nothing_to_change"] = False From 465e19f71d757d265ef77311e553c499f85e8596 Mon Sep 17 00:00:00 2001 From: Gevorg-Khachatryaan Date: Wed, 15 Mar 2023 14:33:25 +0400 Subject: [PATCH 42/48] volume group's module fix, clients requirements --- plugins/module_utils/prism/iscsi_clients.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/module_utils/prism/iscsi_clients.py b/plugins/module_utils/prism/iscsi_clients.py index 6ddb49646..38491399e 100644 --- a/plugins/module_utils/prism/iscsi_clients.py +++ b/plugins/module_utils/prism/iscsi_clients.py @@ -45,8 +45,8 @@ def get_client_spec(self, iscsi_client, old_spec=None): payload = self._get_default_spec() if ( self.module.params.get("CHAP_auth") == "enable" - or old_spec - and old_spec.get("enabledAuthentications") + or (old_spec + and old_spec.get("enabledAuthentications")) ): chap_auth = True else: From 74bc2d347d4103ff07cec4026f27caf7169097e3 Mon Sep 17 00:00:00 2001 From: Gevorg-Khachatryaan Date: Wed, 15 Mar 2023 15:43:23 +0400 Subject: [PATCH 43/48] volume group's module fix, clients requirements --- plugins/module_utils/prism/iscsi_clients.py | 5 ++--- plugins/modules/ntnx_volume_groups.py | 9 +++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/plugins/module_utils/prism/iscsi_clients.py b/plugins/module_utils/prism/iscsi_clients.py index 38491399e..c134130a1 100644 --- a/plugins/module_utils/prism/iscsi_clients.py +++ b/plugins/module_utils/prism/iscsi_clients.py @@ -41,12 +41,11 @@ def update( resp["task_uuid"] = resp["data"]["extId"].split(":")[1] return resp - def get_client_spec(self, iscsi_client, old_spec=None): + def get_client_spec(self, iscsi_client, authentication_is_enabled=False): payload = self._get_default_spec() if ( self.module.params.get("CHAP_auth") == "enable" - or (old_spec - and old_spec.get("enabledAuthentications")) + or authentication_is_enabled ): chap_auth = True else: diff --git a/plugins/modules/ntnx_volume_groups.py b/plugins/modules/ntnx_volume_groups.py index d0a8dc3f5..d7a25d658 100644 --- a/plugins/modules/ntnx_volume_groups.py +++ b/plugins/modules/ntnx_volume_groups.py @@ -377,8 +377,9 @@ def update_volume_group(module, result): # update clients if vg_clients: + authentication_is_enabled = True if resp.get("enabledAuthentications") else False update_volume_group_clients( - module, volume_group, vg_clients, volume_group_uuid, result + module, volume_group, vg_clients, volume_group_uuid, result, authentication_is_enabled ) clients_resp = volume_group.get_clients(volume_group_uuid) @@ -507,7 +508,7 @@ def update_volume_group_vms(module, volume_group, vg_vms, volume_group_uuid, res def update_volume_group_clients( - module, volume_group, vg_clients, volume_group_uuid, result + module, volume_group, vg_clients, volume_group_uuid, result, authentication_is_enabled ): client = Clients(module) for vg_client in vg_clients: @@ -522,7 +523,7 @@ def update_volume_group_clients( else: resp = client.read(client_uuid).get("data") - spec, err = client.get_client_spec(vg_client, resp) + spec, err = client.get_client_spec(vg_client, authentication_is_enabled) if err: result["nothing_to_change"] = False result["warning"].append( @@ -541,7 +542,7 @@ def update_volume_group_clients( else: result["nothing_to_change"] = False - spec, err = client.get_client_spec(vg_client) + spec, err = client.get_client_spec(vg_client, authentication_is_enabled) if err: result["warning"].append( "Client is not created. Error: {0}".format(err) From 4854a9804fd1a1fa67c7c567314aee6fdd0b4712 Mon Sep 17 00:00:00 2001 From: Gevorg-Khachatryaan Date: Wed, 15 Mar 2023 16:01:34 +0400 Subject: [PATCH 44/48] volume group's module fix, result status fix --- plugins/modules/ntnx_volume_groups.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/plugins/modules/ntnx_volume_groups.py b/plugins/modules/ntnx_volume_groups.py index d7a25d658..e0c100bac 100644 --- a/plugins/modules/ntnx_volume_groups.py +++ b/plugins/modules/ntnx_volume_groups.py @@ -355,6 +355,8 @@ def update_volume_group(module, result): result["nothing_to_change"] = False volume_group.update(update_spec, uuid=volume_group_uuid, method="PATCH") + result["changed"] = True + resp = volume_group.read(volume_group_uuid) resp = resp.get("data") result["response"] = resp @@ -389,7 +391,6 @@ def update_volume_group(module, result): module.exit_json( msg="Nothing to change. Refer docs to check for fields which can be updated" ) - result["changed"] = True def delete_volume_group(module, result): @@ -444,6 +445,7 @@ def update_volume_group_disks( if disk.get("state") == "absent": result["nothing_to_change"] = False vdisk_resp = volume_group.delete_disk(volume_group_uuid, disk_uuid) + result["changed"] = True else: vdisk = volume_group.get_vdisks(volume_group_uuid, disk_uuid).get( @@ -467,7 +469,7 @@ def update_volume_group_disks( vdisk_resp = volume_group.update_disk( spec, volume_group_uuid, disk_uuid ) - + result["changed"] = True else: result["nothing_to_change"] = False spec, err = VDisks.get_spec(module, disk) @@ -477,6 +479,8 @@ def update_volume_group_disks( continue vdisk_resp = volume_group.create_vdisk(spec, volume_group_uuid) + result["changed"] = True + task_uuid = vdisk_resp["task_uuid"] wait_for_task_completion(module, {"task_uuid": task_uuid}) @@ -493,6 +497,8 @@ def update_volume_group_vms(module, volume_group, vg_vms, volume_group_uuid, res result["warning"].append("VM is not detached. Error: {0}".format(err)) result["skipped"] = True continue + result["changed"] = True + else: spec, err = volume_group.get_vm_spec(vm) if err: @@ -503,6 +509,8 @@ def update_volume_group_vms(module, volume_group, vg_vms, volume_group_uuid, res result["nothing_to_change"] = False vm_resp = volume_group.attach_vm(spec, volume_group_uuid) + result["changed"] = True + task_uuid = vm_resp["task_uuid"] wait_for_task_completion(module, {"task_uuid": task_uuid}) @@ -521,6 +529,8 @@ def update_volume_group_clients( volume_group_uuid, client_uuid ) + result["changed"] = True + else: resp = client.read(client_uuid).get("data") spec, err = client.get_client_spec(vg_client, authentication_is_enabled) @@ -540,6 +550,8 @@ def update_volume_group_clients( result["nothing_to_change"] = False client_resp = client.update(spec, client_uuid, method="PATCH") + result["changed"] = True + else: result["nothing_to_change"] = False spec, err = client.get_client_spec(vg_client, authentication_is_enabled) @@ -551,6 +563,8 @@ def update_volume_group_clients( continue client_resp = volume_group.attach_iscsi_client(spec, volume_group_uuid) + result["changed"] = True + task_uuid = client_resp["task_uuid"] wait_for_task_completion(module, {"task_uuid": task_uuid}) From 68108e52a4879aed489bf848060b6ce6aca84ac2 Mon Sep 17 00:00:00 2001 From: Gevorg-Khachatryaan Date: Wed, 22 Mar 2023 12:28:58 +0400 Subject: [PATCH 45/48] sub tusks messages --- plugins/module_utils/prism/volume_groups.py | 35 ++++-- plugins/modules/ntnx_volume_groups.py | 128 +++++++++++++------- 2 files changed, 111 insertions(+), 52 deletions(-) diff --git a/plugins/module_utils/prism/volume_groups.py b/plugins/module_utils/prism/volume_groups.py index 128d350b8..9cc4c5e18 100644 --- a/plugins/module_utils/prism/volume_groups.py +++ b/plugins/module_utils/prism/volume_groups.py @@ -45,51 +45,64 @@ def get_clients(self, volume_group_uuid): def create_vdisk(self, spec, volume_group_uuid): endpoint = "disks" - resp = self.update(spec, volume_group_uuid, method="POST", endpoint=endpoint) + resp = self.update(spec, volume_group_uuid, method="POST", endpoint=endpoint, raise_error=False) resp["task_uuid"] = resp["data"]["extId"].split(":")[1] return resp def attach_vm(self, spec, volume_group_uuid): endpoint = "$actions/attach-vm" - resp = self.update(spec, volume_group_uuid, method="POST", endpoint=endpoint) + + resp = self.update(spec, volume_group_uuid, method="POST", endpoint=endpoint, raise_error=False) + if resp.get("data") and resp["data"].get("error"): + err = resp["data"]["error"] + if isinstance(err, list): + err = err[0] + if err.get("message"): + err = err["message"] + return None, err + resp["task_uuid"] = resp["data"]["extId"].split(":")[1] - return resp + return resp, None def attach_iscsi_client(self, spec, volume_group_uuid): endpoint = "/$actions/attach-iscsi-client" - resp = self.update(spec, volume_group_uuid, method="POST", endpoint=endpoint) + resp = self.update(spec, volume_group_uuid, method="POST", endpoint=endpoint, raise_error=False) resp["task_uuid"] = resp["data"]["extId"].split(":")[1] return resp def update_disk(self, spec, volume_group_uuid, disk_uuid): endpoint = "disks/{0}".format(disk_uuid) resp = self.update( - spec, uuid=volume_group_uuid, method="PATCH", endpoint=endpoint + spec, uuid=volume_group_uuid, method="PATCH", endpoint=endpoint, raise_error=False ) resp["task_uuid"] = resp["data"]["extId"].split(":")[1] return resp def delete_disk(self, volume_group_uuid, disk_uuid): endpoint = "disks/{0}".format(disk_uuid) - resp = self.delete(uuid=volume_group_uuid, endpoint=endpoint) + resp = self.delete(uuid=volume_group_uuid, endpoint=endpoint, raise_error=False) resp["task_uuid"] = resp["data"]["extId"].split(":")[1] return resp def detach_vm(self, volume_group_uuid, vm): if not vm.get("extId"): - vm_uuid, error = get_vm_uuid(vm, self.module) - if error: - return None, error + vm_uuid, err = get_vm_uuid(vm, self.module) + if err: + if isinstance(err, list): + err = err[0] + if err.get("message"): + err = err["message"] + return None, err else: vm_uuid = vm["extId"] endpoint = "$actions/detach-vm/{0}".format(vm_uuid) - resp = self.update(uuid=volume_group_uuid, method="POST", endpoint=endpoint) + resp = self.update(uuid=volume_group_uuid, method="POST", endpoint=endpoint, raise_error=False) resp["task_uuid"] = resp["data"]["extId"].split(":")[1] return resp, None def detach_iscsi_client(self, volume_group_uuid, client_uuid): endpoint = "$actions/detach-iscsi-client/{0}".format(client_uuid) - resp = self.update(uuid=volume_group_uuid, method="POST", endpoint=endpoint) + resp = self.update(uuid=volume_group_uuid, method="POST", endpoint=endpoint, raise_error=False) resp["task_uuid"] = resp["data"]["extId"].split(":")[1] return resp diff --git a/plugins/modules/ntnx_volume_groups.py b/plugins/modules/ntnx_volume_groups.py index e0c100bac..0af39b086 100644 --- a/plugins/modules/ntnx_volume_groups.py +++ b/plugins/modules/ntnx_volume_groups.py @@ -258,10 +258,11 @@ def create_volume_group(module, result): resp = volume_group.create(spec) task_uuid = resp["data"]["extId"].split(":")[1] - result["changed"] = True result["response"] = resp result["task_uuid"] = task_uuid - resp = wait_for_task_completion(module, result) + resp, err = wait_for_task_completion(module, result) + + result["changed"] = True volume_group_uuid = resp["entity_reference_list"][0]["uuid"] result["volume_group_uuid"] = volume_group_uuid resp = volume_group.read(volume_group_uuid) @@ -279,8 +280,11 @@ def create_volume_group(module, result): vdisk_resp = volume_group.create_vdisk(spec, volume_group_uuid) task_uuid = vdisk_resp["task_uuid"] - wait_for_task_completion(module, {"task_uuid": task_uuid}) - + vdisk_resp, err = wait_for_task_completion(module, {"task_uuid": task_uuid}, raise_error=False) + if err: + result["warning"].append("Disk creating task is failed. Error: {0}".format(err)) + result["skipped"] = True + continue disks_resp = volume_group.get_vdisks(volume_group_uuid) result["response"]["disks"] = disks_resp.get("data") @@ -297,7 +301,11 @@ def create_volume_group(module, result): attach_resp = volume_group.attach_vm(spec, volume_group_uuid) task_uuid = attach_resp["task_uuid"] - wait_for_task_completion(module, {"task_uuid": task_uuid}) + attach_resp, err = wait_for_task_completion(module, {"task_uuid": task_uuid}, raise_error=False) + if err: + result["warning"].append("VM attaching task is failed. Error: {0}".format(err)) + result["skipped"] = True + continue vms_resp = volume_group.get_vms(volume_group_uuid) result["response"]["vms"] = vms_resp.get("data") @@ -316,7 +324,11 @@ def create_volume_group(module, result): attach_resp = volume_group.attach_iscsi_client(spec, volume_group_uuid) task_uuid = attach_resp["task_uuid"] - wait_for_task_completion(module, {"task_uuid": task_uuid}) + attach_resp, err = wait_for_task_completion(module, {"task_uuid": task_uuid}, raise_error=False) + if err: + result["warning"].append("Client attaching task is failed. Error: {0}".format(err)) + result["skipped"] = True + continue clients_resp = volume_group.get_clients(volume_group_uuid) result["response"]["clients"] = clients_resp.get("data") @@ -372,6 +384,7 @@ def update_volume_group(module, result): # update vms if vg_vms: + detach_volume_group_clients(module, volume_group, volume_group_uuid, result) update_volume_group_vms(module, volume_group, vg_vms, volume_group_uuid, result) vms_resp = volume_group.get_vms(volume_group_uuid) @@ -380,6 +393,7 @@ def update_volume_group(module, result): # update clients if vg_clients: authentication_is_enabled = True if resp.get("enabledAuthentications") else False + detach_volume_group_vms(module, volume_group, volume_group_uuid, result) update_volume_group_clients( module, volume_group, vg_clients, volume_group_uuid, result, authentication_is_enabled ) @@ -402,32 +416,10 @@ def delete_volume_group(module, result): volume_group = VolumeGroup(module) # detach iscsi_clients - clients_resp = volume_group.get_clients(volume_group_uuid) - detached_clients = [] - for client in clients_resp.get("data", []): - client_uuid = client["extId"] - detach_resp = volume_group.detach_iscsi_client(volume_group_uuid, client_uuid) - - task_uuid = detach_resp["task_uuid"] - wait_for_task_completion(module, {"task_uuid": task_uuid}) - detached_clients.append(client_uuid) - - result["detached_clients"] = detached_clients + detach_volume_group_clients(module, volume_group, volume_group_uuid, result) # detach vms - vms_resp = volume_group.get_vms(volume_group_uuid) - detached_vms = [] - for vm in vms_resp.get("data", []): - detach_resp, err = volume_group.detach_vm(volume_group_uuid, vm) - if err: - result["warning"].append("VM is not detached. Error: {0}".format(err)) - result["skipped"] = True - continue - task_uuid = detach_resp["task_uuid"] - wait_for_task_completion(module, {"task_uuid": task_uuid}) - detached_vms.append(vm["extId"]) - - result["detached_vms"] = detached_vms + detach_volume_group_vms(module, volume_group, volume_group_uuid, result) resp = volume_group.delete(volume_group_uuid) resp.pop("metadata") @@ -507,12 +499,21 @@ def update_volume_group_vms(module, volume_group, vg_vms, volume_group_uuid, res continue result["nothing_to_change"] = False - vm_resp = volume_group.attach_vm(spec, volume_group_uuid) - - result["changed"] = True + vm_resp, err = volume_group.attach_vm(spec, volume_group_uuid) + if err: + result["warning"].append("VM is not attached. Error: {0}".format(err)) + result["skipped"] = True + continue task_uuid = vm_resp["task_uuid"] - wait_for_task_completion(module, {"task_uuid": task_uuid}) + resp, err = wait_for_task_completion(module, {"task_uuid": task_uuid}, raise_error=False) + + if err: + result["warning"].append("VM update task is failed. Error: {0}".format(err)) + result["skipped"] = True + continue + + result["changed"] = True def update_volume_group_clients( @@ -532,12 +533,12 @@ def update_volume_group_clients( result["changed"] = True else: - resp = client.read(client_uuid).get("data") + resp = client.read(client_uuid, raise_error=False).get("data") spec, err = client.get_client_spec(vg_client, authentication_is_enabled) - if err: + if err or resp.get("error"): result["nothing_to_change"] = False result["warning"].append( - "Client is not updated. Error: {0}".format(err) + "Client is not updated. Error: {0}".format(resp.get("error") or err) ) result["skipped"] = True continue @@ -566,7 +567,49 @@ def update_volume_group_clients( result["changed"] = True task_uuid = client_resp["task_uuid"] - wait_for_task_completion(module, {"task_uuid": task_uuid}) + resp, err = wait_for_task_completion(module, {"task_uuid": task_uuid}, raise_error=False) + if err: + result["warning"].append("Client update task is failed. Error: {0}".format(err)) + result["skipped"] = True + continue + + +def detach_volume_group_clients(module, volume_group, volume_group_uuid, result): + clients_resp = volume_group.get_clients(volume_group_uuid) + detached_clients = [] + for client in clients_resp.get("data", []): + client_uuid = client["extId"] + detach_resp = volume_group.detach_iscsi_client(volume_group_uuid, client_uuid) + + task_uuid = detach_resp["task_uuid"] + resp, err = wait_for_task_completion(module, {"task_uuid": task_uuid}, raise_error=False) + if err: + result["warning"].append("Client detaching task is failed. Error: {0}".format(err)) + result["skipped"] = True + continue + detached_clients.append(client_uuid) + + result["detached_clients"] = detached_clients + + +def detach_volume_group_vms(module, volume_group, volume_group_uuid, result): + vms_resp = volume_group.get_vms(volume_group_uuid) + detached_vms = [] + for vm in vms_resp.get("data", []): + detach_resp, err = volume_group.detach_vm(volume_group_uuid, vm) + if err: + result["warning"].append("VM is not detached. Error: {0}".format(err)) + result["skipped"] = True + continue + task_uuid = detach_resp["task_uuid"] + resp, err = wait_for_task_completion(module, {"task_uuid": task_uuid}, raise_error=False) + if err: + result["warning"].append("VM detaching task is failed. Error: {0}".format(err)) + result["skipped"] = True + continue + detached_vms.append(vm["extId"]) + + result["detached_vms"] = detached_vms def check_for_idempotency(old_spec, update_spec): @@ -581,11 +624,14 @@ def check_for_idempotency(old_spec, update_spec): return True -def wait_for_task_completion(module, result): +def wait_for_task_completion(module, result, raise_error=True): task = Task(module) task_uuid = result["task_uuid"] - resp = task.wait_for_completion(task_uuid) - return resp + resp = task.wait_for_completion(task_uuid, raise_error=raise_error) + if resp.get("status") == "FAILED": + err = resp.get("error_detail") + return None, err + return resp, None def run_module(): From df88adf5f185be4eb42cbbac66896a78ed7a1741 Mon Sep 17 00:00:00 2001 From: alaa-bish Date: Wed, 22 Mar 2023 11:03:42 +0200 Subject: [PATCH 46/48] black fix --- plugins/module_utils/prism/iscsi_clients.py | 5 +- plugins/module_utils/prism/volume_groups.py | 26 +++++-- plugins/modules/ntnx_volume_groups.py | 78 ++++++++++++++++----- 3 files changed, 81 insertions(+), 28 deletions(-) diff --git a/plugins/module_utils/prism/iscsi_clients.py b/plugins/module_utils/prism/iscsi_clients.py index c134130a1..cd18aa21e 100644 --- a/plugins/module_utils/prism/iscsi_clients.py +++ b/plugins/module_utils/prism/iscsi_clients.py @@ -43,10 +43,7 @@ def update( def get_client_spec(self, iscsi_client, authentication_is_enabled=False): payload = self._get_default_spec() - if ( - self.module.params.get("CHAP_auth") == "enable" - or authentication_is_enabled - ): + if self.module.params.get("CHAP_auth") == "enable" or authentication_is_enabled: chap_auth = True else: chap_auth = False diff --git a/plugins/module_utils/prism/volume_groups.py b/plugins/module_utils/prism/volume_groups.py index 9cc4c5e18..179ceadf8 100644 --- a/plugins/module_utils/prism/volume_groups.py +++ b/plugins/module_utils/prism/volume_groups.py @@ -45,14 +45,18 @@ def get_clients(self, volume_group_uuid): def create_vdisk(self, spec, volume_group_uuid): endpoint = "disks" - resp = self.update(spec, volume_group_uuid, method="POST", endpoint=endpoint, raise_error=False) + resp = self.update( + spec, volume_group_uuid, method="POST", endpoint=endpoint, raise_error=False + ) resp["task_uuid"] = resp["data"]["extId"].split(":")[1] return resp def attach_vm(self, spec, volume_group_uuid): endpoint = "$actions/attach-vm" - resp = self.update(spec, volume_group_uuid, method="POST", endpoint=endpoint, raise_error=False) + resp = self.update( + spec, volume_group_uuid, method="POST", endpoint=endpoint, raise_error=False + ) if resp.get("data") and resp["data"].get("error"): err = resp["data"]["error"] if isinstance(err, list): @@ -66,14 +70,20 @@ def attach_vm(self, spec, volume_group_uuid): def attach_iscsi_client(self, spec, volume_group_uuid): endpoint = "/$actions/attach-iscsi-client" - resp = self.update(spec, volume_group_uuid, method="POST", endpoint=endpoint, raise_error=False) + resp = self.update( + spec, volume_group_uuid, method="POST", endpoint=endpoint, raise_error=False + ) resp["task_uuid"] = resp["data"]["extId"].split(":")[1] return resp def update_disk(self, spec, volume_group_uuid, disk_uuid): endpoint = "disks/{0}".format(disk_uuid) resp = self.update( - spec, uuid=volume_group_uuid, method="PATCH", endpoint=endpoint, raise_error=False + spec, + uuid=volume_group_uuid, + method="PATCH", + endpoint=endpoint, + raise_error=False, ) resp["task_uuid"] = resp["data"]["extId"].split(":")[1] return resp @@ -96,13 +106,17 @@ def detach_vm(self, volume_group_uuid, vm): else: vm_uuid = vm["extId"] endpoint = "$actions/detach-vm/{0}".format(vm_uuid) - resp = self.update(uuid=volume_group_uuid, method="POST", endpoint=endpoint, raise_error=False) + resp = self.update( + uuid=volume_group_uuid, method="POST", endpoint=endpoint, raise_error=False + ) resp["task_uuid"] = resp["data"]["extId"].split(":")[1] return resp, None def detach_iscsi_client(self, volume_group_uuid, client_uuid): endpoint = "$actions/detach-iscsi-client/{0}".format(client_uuid) - resp = self.update(uuid=volume_group_uuid, method="POST", endpoint=endpoint, raise_error=False) + resp = self.update( + uuid=volume_group_uuid, method="POST", endpoint=endpoint, raise_error=False + ) resp["task_uuid"] = resp["data"]["extId"].split(":")[1] return resp diff --git a/plugins/modules/ntnx_volume_groups.py b/plugins/modules/ntnx_volume_groups.py index 0af39b086..52286d67c 100644 --- a/plugins/modules/ntnx_volume_groups.py +++ b/plugins/modules/ntnx_volume_groups.py @@ -280,9 +280,13 @@ def create_volume_group(module, result): vdisk_resp = volume_group.create_vdisk(spec, volume_group_uuid) task_uuid = vdisk_resp["task_uuid"] - vdisk_resp, err = wait_for_task_completion(module, {"task_uuid": task_uuid}, raise_error=False) + vdisk_resp, err = wait_for_task_completion( + module, {"task_uuid": task_uuid}, raise_error=False + ) if err: - result["warning"].append("Disk creating task is failed. Error: {0}".format(err)) + result["warning"].append( + "Disk creating task is failed. Error: {0}".format(err) + ) result["skipped"] = True continue disks_resp = volume_group.get_vdisks(volume_group_uuid) @@ -301,9 +305,13 @@ def create_volume_group(module, result): attach_resp = volume_group.attach_vm(spec, volume_group_uuid) task_uuid = attach_resp["task_uuid"] - attach_resp, err = wait_for_task_completion(module, {"task_uuid": task_uuid}, raise_error=False) + attach_resp, err = wait_for_task_completion( + module, {"task_uuid": task_uuid}, raise_error=False + ) if err: - result["warning"].append("VM attaching task is failed. Error: {0}".format(err)) + result["warning"].append( + "VM attaching task is failed. Error: {0}".format(err) + ) result["skipped"] = True continue @@ -324,9 +332,13 @@ def create_volume_group(module, result): attach_resp = volume_group.attach_iscsi_client(spec, volume_group_uuid) task_uuid = attach_resp["task_uuid"] - attach_resp, err = wait_for_task_completion(module, {"task_uuid": task_uuid}, raise_error=False) + attach_resp, err = wait_for_task_completion( + module, {"task_uuid": task_uuid}, raise_error=False + ) if err: - result["warning"].append("Client attaching task is failed. Error: {0}".format(err)) + result["warning"].append( + "Client attaching task is failed. Error: {0}".format(err) + ) result["skipped"] = True continue @@ -392,10 +404,17 @@ def update_volume_group(module, result): # update clients if vg_clients: - authentication_is_enabled = True if resp.get("enabledAuthentications") else False + authentication_is_enabled = ( + True if resp.get("enabledAuthentications") else False + ) detach_volume_group_vms(module, volume_group, volume_group_uuid, result) update_volume_group_clients( - module, volume_group, vg_clients, volume_group_uuid, result, authentication_is_enabled + module, + volume_group, + vg_clients, + volume_group_uuid, + result, + authentication_is_enabled, ) clients_resp = volume_group.get_clients(volume_group_uuid) @@ -506,7 +525,9 @@ def update_volume_group_vms(module, volume_group, vg_vms, volume_group_uuid, res continue task_uuid = vm_resp["task_uuid"] - resp, err = wait_for_task_completion(module, {"task_uuid": task_uuid}, raise_error=False) + resp, err = wait_for_task_completion( + module, {"task_uuid": task_uuid}, raise_error=False + ) if err: result["warning"].append("VM update task is failed. Error: {0}".format(err)) @@ -517,12 +538,19 @@ def update_volume_group_vms(module, volume_group, vg_vms, volume_group_uuid, res def update_volume_group_clients( - module, volume_group, vg_clients, volume_group_uuid, result, authentication_is_enabled + module, + volume_group, + vg_clients, + volume_group_uuid, + result, + authentication_is_enabled, ): client = Clients(module) for vg_client in vg_clients: - if vg_client.get("uuid") and (vg_client.get("state") or vg_client.get("client_password")): + if vg_client.get("uuid") and ( + vg_client.get("state") or vg_client.get("client_password") + ): client_uuid = vg_client["uuid"] if vg_client.get("state") == "absent": result["nothing_to_change"] = False @@ -538,7 +566,9 @@ def update_volume_group_clients( if err or resp.get("error"): result["nothing_to_change"] = False result["warning"].append( - "Client is not updated. Error: {0}".format(resp.get("error") or err) + "Client is not updated. Error: {0}".format( + resp.get("error") or err + ) ) result["skipped"] = True continue @@ -567,9 +597,13 @@ def update_volume_group_clients( result["changed"] = True task_uuid = client_resp["task_uuid"] - resp, err = wait_for_task_completion(module, {"task_uuid": task_uuid}, raise_error=False) + resp, err = wait_for_task_completion( + module, {"task_uuid": task_uuid}, raise_error=False + ) if err: - result["warning"].append("Client update task is failed. Error: {0}".format(err)) + result["warning"].append( + "Client update task is failed. Error: {0}".format(err) + ) result["skipped"] = True continue @@ -582,9 +616,13 @@ def detach_volume_group_clients(module, volume_group, volume_group_uuid, result) detach_resp = volume_group.detach_iscsi_client(volume_group_uuid, client_uuid) task_uuid = detach_resp["task_uuid"] - resp, err = wait_for_task_completion(module, {"task_uuid": task_uuid}, raise_error=False) + resp, err = wait_for_task_completion( + module, {"task_uuid": task_uuid}, raise_error=False + ) if err: - result["warning"].append("Client detaching task is failed. Error: {0}".format(err)) + result["warning"].append( + "Client detaching task is failed. Error: {0}".format(err) + ) result["skipped"] = True continue detached_clients.append(client_uuid) @@ -602,9 +640,13 @@ def detach_volume_group_vms(module, volume_group, volume_group_uuid, result): result["skipped"] = True continue task_uuid = detach_resp["task_uuid"] - resp, err = wait_for_task_completion(module, {"task_uuid": task_uuid}, raise_error=False) + resp, err = wait_for_task_completion( + module, {"task_uuid": task_uuid}, raise_error=False + ) if err: - result["warning"].append("VM detaching task is failed. Error: {0}".format(err)) + result["warning"].append( + "VM detaching task is failed. Error: {0}".format(err) + ) result["skipped"] = True continue detached_vms.append(vm["extId"]) From df9cdf59c665071a3c4102b5e5c7ede4cf211429 Mon Sep 17 00:00:00 2001 From: Gevorg-Khachatryaan Date: Wed, 22 Mar 2023 14:12:15 +0400 Subject: [PATCH 47/48] sub tasks messages --- plugins/modules/ntnx_volume_groups.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/plugins/modules/ntnx_volume_groups.py b/plugins/modules/ntnx_volume_groups.py index 0af39b086..020dbdb11 100644 --- a/plugins/modules/ntnx_volume_groups.py +++ b/plugins/modules/ntnx_volume_groups.py @@ -273,7 +273,7 @@ def create_volume_group(module, result): for disk in vg_disks: spec, err = VDisks.get_spec(module, disk) if err: - result["warning"] = "Disk is not created. Error: {0}".format(err) + result["warning"].append("Disk is not created. Error: {0}".format(err)) result["skipped"] = True continue @@ -294,11 +294,15 @@ def create_volume_group(module, result): spec, err = volume_group.get_vm_spec(vm) if err: - result["warning"] = "VM is not attached. Error: {0}".format(err) + result["warning"].append("VM is not attached. Error: {0}".format(err)) result["skipped"] = True continue - attach_resp = volume_group.attach_vm(spec, volume_group_uuid) + attach_resp, err = volume_group.attach_vm(spec, volume_group_uuid) + if err: + result["warning"].append("VM is not attached. Error: {0}".format(err)) + result["skipped"] = True + continue task_uuid = attach_resp["task_uuid"] attach_resp, err = wait_for_task_completion(module, {"task_uuid": task_uuid}, raise_error=False) @@ -317,7 +321,7 @@ def create_volume_group(module, result): spec, err = client.get_client_spec(vg_client) if err: - result["warning"] = "Client is not attached. Error: {0}".format(err) + result["warning"].append("Client is not attached. Error: {0}".format(err)) result["skipped"] = True continue From 892624ed637286d4b00b7f9bf9043033a9a4f316 Mon Sep 17 00:00:00 2001 From: Gevorg-Khachatryaan Date: Wed, 22 Mar 2023 16:56:14 +0400 Subject: [PATCH 48/48] sub tasks failing fixes --- plugins/module_utils/prism/volume_groups.py | 9 ++++++++- plugins/modules/ntnx_volume_groups.py | 14 ++++++++++---- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/plugins/module_utils/prism/volume_groups.py b/plugins/module_utils/prism/volume_groups.py index 179ceadf8..9723a79b2 100644 --- a/plugins/module_utils/prism/volume_groups.py +++ b/plugins/module_utils/prism/volume_groups.py @@ -48,8 +48,15 @@ def create_vdisk(self, spec, volume_group_uuid): resp = self.update( spec, volume_group_uuid, method="POST", endpoint=endpoint, raise_error=False ) + if resp.get("data") and resp["data"].get("error"): + err = resp["data"]["error"] + if isinstance(err, list): + err = err[0] + if err.get("message"): + err = err["message"] + return None, err resp["task_uuid"] = resp["data"]["extId"].split(":")[1] - return resp + return resp, None def attach_vm(self, spec, volume_group_uuid): endpoint = "$actions/attach-vm" diff --git a/plugins/modules/ntnx_volume_groups.py b/plugins/modules/ntnx_volume_groups.py index afe9e934c..1f271a6b6 100644 --- a/plugins/modules/ntnx_volume_groups.py +++ b/plugins/modules/ntnx_volume_groups.py @@ -277,8 +277,11 @@ def create_volume_group(module, result): result["skipped"] = True continue - vdisk_resp = volume_group.create_vdisk(spec, volume_group_uuid) - + vdisk_resp, err = volume_group.create_vdisk(spec, volume_group_uuid) + if err: + result["warning"].append("Disk is not created. Error: {0}".format(err)) + result["skipped"] = True + continue task_uuid = vdisk_resp["task_uuid"] vdisk_resp, err = wait_for_task_completion( module, {"task_uuid": task_uuid}, raise_error=False @@ -492,8 +495,11 @@ def update_volume_group_disks( result["warning"].append("Disk is not created. Error: {0}".format(err)) result["skipped"] = True continue - vdisk_resp = volume_group.create_vdisk(spec, volume_group_uuid) - + vdisk_resp, err = volume_group.create_vdisk(spec, volume_group_uuid) + if err: + result["warning"].append("Disk is not created. Error: {0}".format(err)) + result["skipped"] = True + continue result["changed"] = True task_uuid = vdisk_resp["task_uuid"]