From 0bc4af7d6b9be1d895b4529685cc7947e9844ecb Mon Sep 17 00:00:00 2001 From: Gevorg Khachatryan Date: Wed, 25 Oct 2023 14:13:50 +0400 Subject: [PATCH 01/41] example fix (#420) Co-authored-by: Gevorg-Khachatryaan --- examples/vm_operations.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/vm_operations.yml b/examples/vm_operations.yml index 7c4743734..50a977bae 100644 --- a/examples/vm_operations.yml +++ b/examples/vm_operations.yml @@ -20,9 +20,8 @@ - name: hard power off the vm ntnx_vms: - state: present + state: hard_poweroff vm_uuid: "{{ vm_uuid }}" - operation: hard_poweroff register: result ignore_errors: true From 73e846b3671b35e8a7197e9f5d15b7ddaa7bc894 Mon Sep 17 00:00:00 2001 From: Pradeepsingh Bhati Date: Wed, 25 Oct 2023 15:47:55 +0530 Subject: [PATCH 02/41] Add cluster URL to response only when there is cluster creation (#402) * Create cluster url when it is required * Minor fix --- plugins/modules/ntnx_foundation.py | 4 +- .../tasks/image_nodes.yml | 37 +++++++++++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/plugins/modules/ntnx_foundation.py b/plugins/modules/ntnx_foundation.py index 9b2abd41e..f5b7a3d15 100644 --- a/plugins/modules/ntnx_foundation.py +++ b/plugins/modules/ntnx_foundation.py @@ -15,7 +15,7 @@ description: 'Nutanix module to image nodes and optionally create clusters' options: hypervisor_nameserver: - description: to-write + description: name server for hypervisors type: str required: false cvm_gateway: @@ -1244,7 +1244,7 @@ def image_nodes(module, result): # add cluster urls if any cluster created cluster_urls = [] - if spec["clusters"]: + if spec.get("clusters"): for cluster in spec["clusters"]: cluster_urls.append( { diff --git a/tests/integration/targets/ntnx_foundation_sanity/tasks/image_nodes.yml b/tests/integration/targets/ntnx_foundation_sanity/tasks/image_nodes.yml index 49e4b651b..5705fb3a1 100644 --- a/tests/integration/targets/ntnx_foundation_sanity/tasks/image_nodes.yml +++ b/tests/integration/targets/ntnx_foundation_sanity/tasks/image_nodes.yml @@ -116,6 +116,43 @@ fail_msg: " Fail : unable to create spec for imaging nodes" success_msg: "Succes: spec generated successfully" + - name: Image nodes without cluster creation + ntnx_foundation: + timeout: 4500 + cvm_gateway: "{{cvm_gateway}}" + cvm_netmask: "{{cvm_netmask}}" + hypervisor_gateway: "{{hypervisor_gateway}}" + hypervisor_netmask: "{{hypervisor_netmask}}" + default_ipmi_user: "{{default_ipmi_user}}" + current_cvm_vlan_tag: "{{nodes.current_cvm_vlan_tag}}" + nos_package: "{{images.aos_packages[0]}}" + blocks: + - block_id: "{{nodes.block_id}}" + nodes: + - manual_mode: + cvm_ip: "{{nodes.node2.cvm_ip}}" + cvm_gb_ram: 50 + hypervisor_hostname: "{{nodes.node2.hypervisor_hostname}}" + ipmi_netmask: "{{nodes.node2.ipmi_netmask}}" + ipmi_gateway: "{{nodes.node2.ipmi_gateway}}" + ipmi_ip: "{{nodes.node2.ipmi_ip}}" + ipmi_password: "{{nodes.node2.ipmi_password}}" + hypervisor: "{{nodes.node2.hypervisor}}" + hypervisor_ip: "{{nodes.node2.hypervisor_ip}}" + node_position: "{{nodes.node2.node_position}}" + register: result + no_log: true + ignore_errors: True + + - name: Creation Status + assert: + that: + - result.response is defined + - result.failed==false + - result.changed==true + fail_msg: " Fail : unable to image nodes" + success_msg: "Succes: node imaging done successfully" + - name: Image nodes and create cluster out of it ntnx_foundation: timeout: 4500 From e3629ff5c0211c451db25a12612d969c8ca01b5d Mon Sep 17 00:00:00 2001 From: Gevorg Khachatryan Date: Wed, 25 Oct 2023 14:46:58 +0400 Subject: [PATCH 03/41] fiql string in filtering (#423) * fiql string in filtering * fix * Add Tests * example for filter string --------- Co-authored-by: Gevorg-Khachatryaan Co-authored-by: Alaa Bishtawi --- examples/vm_info.yml | 8 +++- plugins/doc_fragments/ntnx_info.py | 8 +++- plugins/module_utils/base_info_module.py | 9 ++++ plugins/module_utils/entity.py | 10 ++-- .../nutanix_vms_info/tasks/list_vms.yml | 48 +++++++++++++++++++ 5 files changed, 77 insertions(+), 6 deletions(-) diff --git a/examples/vm_info.yml b/examples/vm_info.yml index 53e1e01ea..53d2928cb 100644 --- a/examples/vm_info.yml +++ b/examples/vm_info.yml @@ -22,7 +22,13 @@ kind: vm register: result ignore_errors: True - + + - name: List vms using FIQL filter string + ntnx_vms_info: + filter_string: "vm_name=={{vm.name}};power_state==off" + register: result + ignore_errors: True + - name: List vms using length, offset and ascending vm_name sorting ntnx_vms_info: length: 10 diff --git a/plugins/doc_fragments/ntnx_info.py b/plugins/doc_fragments/ntnx_info.py index bc0be2293..387d503b5 100644 --- a/plugins/doc_fragments/ntnx_info.py +++ b/plugins/doc_fragments/ntnx_info.py @@ -31,10 +31,14 @@ class ModuleDocFragment(object): type: int filter: description: - - The filter in FIQL syntax used for the results + - The filter in key-value syntax used for the results type: dict custom_filter: description: - - The filter in FIQL syntax used for the results + - The filter in key-value syntax used for the results type: dict + filter_string: + description: + - The filter in FIQL syntax used for the results + type: str """ diff --git a/plugins/module_utils/base_info_module.py b/plugins/module_utils/base_info_module.py index 14c4f1849..5adefc4ea 100644 --- a/plugins/module_utils/base_info_module.py +++ b/plugins/module_utils/base_info_module.py @@ -15,12 +15,21 @@ class BaseInfoModule(BaseModule): length=dict(type="int"), filter=dict(type="dict"), custom_filter=dict(type="dict"), + filter_string=dict(type="str"), ) + info_args_mutually_exclusive = [ + ("filter", "filter_string"), + ] + def __init__(self, skip_info_args=False, **kwargs): self.argument_spec = deepcopy(BaseModule.argument_spec) self.argument_spec.pop("state") self.argument_spec.pop("wait") if not skip_info_args: self.argument_spec.update(self.info_argument_spec) + info_args_mutually_exclusive = deepcopy(self.info_args_mutually_exclusive) + if kwargs.get("mutually_exclusive"): + info_args_mutually_exclusive.extend(kwargs["mutually_exclusive"]) + kwargs["mutually_exclusive"] = info_args_mutually_exclusive super(BaseInfoModule, self).__init__(**kwargs) diff --git a/plugins/module_utils/entity.py b/plugins/module_utils/entity.py index a1dc79461..2bbc97f54 100644 --- a/plugins/module_utils/entity.py +++ b/plugins/module_utils/entity.py @@ -283,10 +283,14 @@ def get_info_spec(self): else: spec.pop(key) - if params.get("filter", {}).get("name") and params.get("kind") == "vm": - spec["filter"]["vm_name"] = spec["filter"].pop("name") + if params.get("filter"): + if params.get("filter", {}).get("name") and params.get("kind") == "vm": + spec["filter"]["vm_name"] = spec["filter"].pop("name") - spec["filter"] = self._parse_filters(params.get("filter", {})) + spec["filter"] = self._parse_filters(params.get("filter", {})) + + elif params.get("filter_string"): + spec["filter"] = params["filter_string"] return spec, None diff --git a/tests/integration/targets/nutanix_vms_info/tasks/list_vms.yml b/tests/integration/targets/nutanix_vms_info/tasks/list_vms.yml index 1b758596b..991d25733 100644 --- a/tests/integration/targets/nutanix_vms_info/tasks/list_vms.yml +++ b/tests/integration/targets/nutanix_vms_info/tasks/list_vms.yml @@ -1,3 +1,43 @@ +- set_fact: + todelete: [] + +- name: Creat anohter VM with same name + ntnx_vms: + name: "{{ vm.name }}" + cluster: + name: "{{ cluster.name }}" + state: "power_off" + register: output + ignore_errors: true + +- name: Creation Status + assert: + that: + - output.response is defined + - output.response.status.state == 'COMPLETE' + fail_msg: ' Unable to create VM with minimum requiremnts ' + success_msg: ' VM with minimum requiremnts created successfully ' + +- set_fact: + todelete: '{{ todelete + [ output["response"]["metadata"]["uuid"] ] }}' + when: output.response.status.state == 'COMPLETE' +################################################## +- name: List vms using filter_string + ntnx_vms_info: + filter_string: vm_name=={{vm.name}};power_state==off + register: result + ignore_errors: True + +- name: Listing Status + assert: + that: + - result.response is defined + - result.response.entities[0].metadata.uuid == '{{output["response"]["metadata"]["uuid"]}}' + - result.response.metadata.kind == "vm" + - result.response.metadata.total_matches == 1 + fail_msg: " Unable to list vms using filter_string" + success_msg: " VMs listed successfully using filter_string " +################################################## - name: List vms using name filter criteria ntnx_vms_info: filter: @@ -44,3 +84,11 @@ fail_msg: " Unable to list vms " success_msg: " VMs listed successfully " #################################################### +- name: Delete all Created VMs + ntnx_vms: + state: absent + vm_uuid: '{{ item }}' + register: result + loop: '{{ todelete }}' +- set_fact: + todelete: [] \ No newline at end of file From d1a0016b2954d0f7e89834bccb5de5eb8c392116 Mon Sep 17 00:00:00 2001 From: alaa-bish Date: Wed, 25 Oct 2023 13:48:41 +0300 Subject: [PATCH 04/41] Bug/issue#383 (#411) * Fix Jekyll Build * fix --- .../ntnx_ndb_databases_sanity/tasks/tests.yml | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/tests/integration/targets/ntnx_ndb_databases_sanity/tasks/tests.yml b/tests/integration/targets/ntnx_ndb_databases_sanity/tasks/tests.yml index 6e8240cf9..f6229a439 100644 --- a/tests/integration/targets/ntnx_ndb_databases_sanity/tasks/tests.yml +++ b/tests/integration/targets/ntnx_ndb_databases_sanity/tasks/tests.yml @@ -274,12 +274,22 @@ - set_fact: db_uuid: "{{result.db_uuid}}" -- name: create properties map - set_fact: - properties: "{{ properties | default({}) | combine ({ item['name'] : item['value'] }) }}" - loop: "{{result.response.properties}}" +- name: Ensure properties is defined + set_fact: + properties: "{}" + when: properties is undefined + +- name: Combine properties + block: + - set_fact: + temp_dict: "{ '{{' }} item['name']: item['value'] {{ '}}' }}" + - set_fact: + properties: "{{ properties | combine(temp_dict) }}" + loop: "{{ result.response.properties }}" no_log: true + + - name: Creation Status assert: that: From 0054cc95131dbc172496b3df7689fd1490e4af90 Mon Sep 17 00:00:00 2001 From: Pradeepsingh Bhati Date: Wed, 25 Oct 2023 16:23:21 +0530 Subject: [PATCH 05/41] Fix #391 and #418 (#419) * Create cluster url when it is required * Minor fix * Change api url for fetching time machine using name to get complete info same as uuid * Add attribute in clone modules in ndb for creation or refresh using latestSnapshot * Minor typo fix * Minor typo fix --- plugins/module_utils/ndb/database_clones.py | 8 ++++++-- plugins/module_utils/ndb/time_machines.py | 7 +++++-- plugins/modules/ntnx_ndb_database_clone_refresh.py | 5 +++-- plugins/modules/ntnx_ndb_database_clones.py | 3 ++- plugins/modules/ntnx_ndb_time_machines_info.py | 2 +- 5 files changed, 17 insertions(+), 8 deletions(-) diff --git a/plugins/module_utils/ndb/database_clones.py b/plugins/module_utils/ndb/database_clones.py index 721bfddd0..8493faa80 100644 --- a/plugins/module_utils/ndb/database_clones.py +++ b/plugins/module_utils/ndb/database_clones.py @@ -200,10 +200,12 @@ def get_clone_refresh_spec(self): payload["snapshotId"] = self.module.params.get("snapshot_uuid") elif self.module.params.get("pitr_timestamp"): payload["userPitrTimestamp"] = self.module.params.get("pitr_timestamp") + elif self.module.params.get("latest_snapshot", False): + payload["latestSnapshot"] = True else: return ( None, - "snapshot_uuid or pitr_timestamp is required for database clone refresh", + "One of snapshot_uuid, pitr_timestamp or latest_snapshot is required for database clone refresh", ) payload["timeZone"] = self.module.params.get("timezone") @@ -237,10 +239,12 @@ def _build_spec_time_machine(self, payload, time_machine): payload["snapshotId"] = time_machine.get("snapshot_uuid") elif time_machine.get("pitr_timestamp"): payload["userPitrTimestamp"] = time_machine.get("pitr_timestamp") + elif time_machine.get("latest_snapshot", False): + payload["latestSnapshot"] = True else: return ( None, - "Required snapshot_uuid or pitr_timestamp for source of db clone", + "Required one of snapshot_uuid, pitr_timestamp or latest_snapshot for source of db clone", ) payload["timeZone"] = time_machine.get("timezone") diff --git a/plugins/module_utils/ndb/time_machines.py b/plugins/module_utils/ndb/time_machines.py index dc54b0dc0..7f78858c7 100644 --- a/plugins/module_utils/ndb/time_machines.py +++ b/plugins/module_utils/ndb/time_machines.py @@ -37,8 +37,11 @@ def get_time_machine(self, uuid=None, name=None, query=None): if uuid: resp = self.read(uuid=uuid, query=query) elif name: - endpoint = "{0}/{1}".format("name", name) - resp = self.read(endpoint=endpoint, query=query) + if not query: + query = {} + query["value_type"] = "name" + query["value"] = name + resp = self.read(query=query) if isinstance(resp, list): if not resp: return None, "Time machine with name {0} not found".format(name) diff --git a/plugins/modules/ntnx_ndb_database_clone_refresh.py b/plugins/modules/ntnx_ndb_database_clone_refresh.py index 687145e37..8b0934c23 100644 --- a/plugins/modules/ntnx_ndb_database_clone_refresh.py +++ b/plugins/modules/ntnx_ndb_database_clone_refresh.py @@ -301,6 +301,7 @@ def get_module_spec(): snapshot_uuid=dict(type="str", required=False), timezone=dict(type="str", default="Asia/Calcutta", required=False), pitr_timestamp=dict(type="str", required=False), + latest_snapshot=dict(type="bool", required=False) ) return module_args @@ -340,12 +341,12 @@ def refresh_clone(module, result): def run_module(): mutually_exclusive_list = [ - ("snapshot_uuid", "pitr_timestamp"), + ("snapshot_uuid", "pitr_timestamp", "latest_snapshot"), ] module = NdbBaseModule( argument_spec=get_module_spec(), supports_check_mode=True, - required_if=[("state", "present", ("snapshot_uuid", "pitr_timestamp"), True)], + required_if=[("state", "present", ("snapshot_uuid", "pitr_timestamp", "latest_snapshot"), True)], mutually_exclusive=mutually_exclusive_list, ) remove_param_with_none_value(module.params) diff --git a/plugins/modules/ntnx_ndb_database_clones.py b/plugins/modules/ntnx_ndb_database_clones.py index a6485ee76..cfaa38451 100644 --- a/plugins/modules/ntnx_ndb_database_clones.py +++ b/plugins/modules/ntnx_ndb_database_clones.py @@ -652,6 +652,7 @@ def get_module_spec(): uuid=dict(type="str", required=False), snapshot_uuid=dict(type="str", required=False), pitr_timestamp=dict(type="str", required=False), + latest_snapshot=dict(type="bool", required=False), timezone=dict(type="str", default="Asia/Calcutta", required=False), ) @@ -700,7 +701,7 @@ def get_module_spec(): time_machine=dict( type="dict", options=time_machine, - mutually_exclusive=[("snapshot_uuid", "pitr_timestamp")], + mutually_exclusive=[("snapshot_uuid", "pitr_timestamp", "latest_snapshot")], required=False, ), postgres=dict(type="dict", options=postgres, required=False), diff --git a/plugins/modules/ntnx_ndb_time_machines_info.py b/plugins/modules/ntnx_ndb_time_machines_info.py index f3d9dc861..8fce6fdae 100644 --- a/plugins/modules/ntnx_ndb_time_machines_info.py +++ b/plugins/modules/ntnx_ndb_time_machines_info.py @@ -307,7 +307,7 @@ def get_time_machine(module, result): resp, err = tm.get_time_machine(uuid=uuid, name=name, query=query_params) if err: result["error"] = err - module.fail_json(msg="Failed fetching sla info", **result) + module.fail_json(msg="Failed fetching time machine info", **result) result["response"] = resp From 8579162a3dade19a0f6a67e17c9bc56d2c20bbd8 Mon Sep 17 00:00:00 2001 From: Gevorg Khachatryan Date: Wed, 25 Oct 2023 14:56:56 +0400 Subject: [PATCH 06/41] functionality to update owner of vms (#412) * functionality to update owner of vm * sanity fix * add test --------- Co-authored-by: Gevorg-Khachatryaan Co-authored-by: Alaa Bishtawi --- plugins/doc_fragments/ntnx_vms_base.py | 15 ++++++++ plugins/module_utils/prism/spec/vms.py | 3 ++ plugins/module_utils/prism/vms.py | 17 +++++++++ .../targets/nutanix_vms/tasks/create.yml | 35 +++++++++++++++++++ .../targets/nutanix_vms/tasks/vm_update.yml | 22 ++++++++++++ 5 files changed, 92 insertions(+) diff --git a/plugins/doc_fragments/ntnx_vms_base.py b/plugins/doc_fragments/ntnx_vms_base.py index fed985866..635168013 100644 --- a/plugins/doc_fragments/ntnx_vms_base.py +++ b/plugins/doc_fragments/ntnx_vms_base.py @@ -194,4 +194,19 @@ class ModuleDocFragment(object): - CDROM - DISK - NETWORK + owner: + description: Name or UUID of the owner + required: false + type: dict + suboptions: + name: + description: + - Owner Name + - Mutually exclusive with C(uuid) + type: str + uuid: + description: + - Owner UUID + - Mutually exclusive with C(name) + type: str """ diff --git a/plugins/module_utils/prism/spec/vms.py b/plugins/module_utils/prism/spec/vms.py index 760aeb89b..11f66384f 100644 --- a/plugins/module_utils/prism/spec/vms.py +++ b/plugins/module_utils/prism/spec/vms.py @@ -50,6 +50,9 @@ class DefaultVMSpec: project=dict( type="dict", options=entity_by_spec, mutually_exclusive=mutually_exclusive ), + owner=dict( + type="dict", options=entity_by_spec, mutually_exclusive=mutually_exclusive + ), cluster=dict( type="dict", options=entity_by_spec, mutually_exclusive=mutually_exclusive ), diff --git a/plugins/module_utils/prism/vms.py b/plugins/module_utils/prism/vms.py index a1ca89876..0ecd0ea9e 100644 --- a/plugins/module_utils/prism/vms.py +++ b/plugins/module_utils/prism/vms.py @@ -17,6 +17,7 @@ from .projects import Project from .spec.categories_mapping import CategoriesMapping from .subnets import get_subnet_uuid +from .users import User class VM(Prism): @@ -32,6 +33,7 @@ def __init__(self, module): "name": self._build_spec_name, "desc": self._build_spec_desc, "project": self._build_spec_project, + "owner": self._build_spec_owner, "cluster": self._build_spec_cluster, "vcpus": self._build_spec_vcpus, "cores_per_vcpu": self._build_spec_cores, @@ -220,6 +222,21 @@ def _build_spec_project(self, payload, param): ) return payload, None + def _build_spec_owner(self, payload, param): + if "name" in param: + owner = User(self.module) + name = param["name"] + uuid = owner.get_uuid(name, key="username") + if not uuid: + error = "Owner {0} not found.".format(name) + return None, error + + elif "uuid" in param: + uuid = param["uuid"] + + payload["metadata"].update({"owner_reference": {"uuid": uuid, "kind": "user"}}) + return payload, None + def _build_spec_cluster(self, payload, param): uuid, err = get_cluster_uuid(param, self.module) if err: diff --git a/tests/integration/targets/nutanix_vms/tasks/create.yml b/tests/integration/targets/nutanix_vms/tasks/create.yml index f8f43736a..afe4c5d7c 100644 --- a/tests/integration/targets/nutanix_vms/tasks/create.yml +++ b/tests/integration/targets/nutanix_vms/tasks/create.yml @@ -39,6 +39,41 @@ fail_msg: 'Unable to Create VM with none values ' success_msg: 'VM with none values created successfully ' + - set_fact: + todelete: '{{ todelete + [ result["response"]["metadata"]["uuid"] ] }}' +# ################################################################################## + - name: VM with owner name + ntnx_vms: + state: present + name: none + timezone: GMT + project: + uuid: "{{ project.uuid }}" + cluster: + name: "{{ cluster.name }}" + categories: + AppType: + - Apache_Spark + owner: + name: "{{ vm_owner.name }}" + disks: + - type: DISK + size_gb: 5 + bus: SCSI + register: result + ignore_errors: true + + - name: Creation Status + assert: + that: + - result.response is defined + - result.response.status.state == 'COMPLETE' + - result.response.metadata.owner_reference.name == "{{ vm_owner.name }}" + - result.response.metadata.owner_reference.uuid == "{{ vm_owner.uuid }}" + - result.response.metadata.owner_reference.kind == "user" + fail_msg: 'Unable to Create VM with owner' + success_msg: 'VM with owner created successfully ' + - set_fact: todelete: '{{ todelete + [ result["response"]["metadata"]["uuid"] ] }}' ################################################################################## diff --git a/tests/integration/targets/nutanix_vms/tasks/vm_update.yml b/tests/integration/targets/nutanix_vms/tasks/vm_update.yml index d8ee4048f..8ce3b8bc7 100644 --- a/tests/integration/targets/nutanix_vms/tasks/vm_update.yml +++ b/tests/integration/targets/nutanix_vms/tasks/vm_update.yml @@ -26,6 +26,28 @@ fail_msg: ' Unable to create VM with minimum requiremnts ' success_msg: ' VM with minimum requiremnts created successfully ' #################################################################### +- name: update vm by set owner by uuid + ntnx_vms: + vm_uuid: "{{ result.vm_uuid }}" + owner: + uuid: "{{vm_owner.uuid}}" + register: result + ignore_errors: true + +- name: Update Status + assert: + that: + - result.response is defined + - result.vm_uuid + - result.task_uuid + - result.response.status.state == "COMPLETE" + - result.response.metadata.owner_reference.name == "{{ vm_owner.name }}" + - result.response.metadata.owner_reference.uuid == "{{ vm_owner.uuid }}" + - result.response.metadata.owner_reference.kind == "user" + fail_msg: ' Unable to update vm by setting owner ' + success_msg: ' VM updated successfully by setting owner ' +#################################################################### + - debug: msg: Start update tests for memory vcpus cores_per_vcpu From b32df808d9a1722561262f488b31f785c464c471 Mon Sep 17 00:00:00 2001 From: Gevorg Khachatryan Date: Wed, 25 Oct 2023 15:07:08 +0400 Subject: [PATCH 07/41] example for vms inventory (#410) Co-authored-by: Gevorg-Khachatryaan --- examples/inventory/nutanix.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 examples/inventory/nutanix.yml diff --git a/examples/inventory/nutanix.yml b/examples/inventory/nutanix.yml new file mode 100644 index 000000000..eb8dfcacc --- /dev/null +++ b/examples/inventory/nutanix.yml @@ -0,0 +1,13 @@ +plugin: nutanix.ncp.ntnx_prism_vm_inventory +nutanix_host: +nutanix_username: +nutanix_password: +validate_certs: false +data: {"offset": 0, "length": 1000} +groups: + group_1: "'' in name" + group_2: "''==name" +keyed_groups: + - prefix: "host" + separator: ':' + key: "ansible_host" \ No newline at end of file From 71710278bd108d299d99f049988047656cff2dc3 Mon Sep 17 00:00:00 2001 From: Gevorg Khachatryan Date: Tue, 31 Oct 2023 00:02:59 +0400 Subject: [PATCH 08/41] fix for custom filter and examples (#417) * fix for custom filter and examples * black fix * sanity fix * Add test --------- Co-authored-by: Gevorg-Khachatryaan Co-authored-by: Alaa Bishtawi --- examples/clusters_info.yml | 8 ++++++++ examples/fip_info.yml | 9 +++++++++ examples/hosts_info.yml | 8 ++++++++ examples/subnet_info.yml | 9 +++++++++ examples/vm_info.yml | 9 +++++++++ plugins/module_utils/entity.py | 11 +++++++++++ .../nutanix_subnets_info/tasks/list_subnets.yml | 15 +++++++++++++++ 7 files changed, 69 insertions(+) diff --git a/examples/clusters_info.yml b/examples/clusters_info.yml index 12c0ec7c2..7eab579f3 100644 --- a/examples/clusters_info.yml +++ b/examples/clusters_info.yml @@ -28,3 +28,11 @@ sort_order: "ASCENDING" sort_attribute: "name" register: result + + - name: List clusters using filter and custom_filter + ntnx_clusters_info: + filter: + name: + custom_filter: + external_ip: + register: result diff --git a/examples/fip_info.yml b/examples/fip_info.yml index ac17a5231..804e9ebd4 100644 --- a/examples/fip_info.yml +++ b/examples/fip_info.yml @@ -29,3 +29,12 @@ offset: 0 register: result ignore_errors: True + + + - name: List floating_ips using filter and custom_filter + ntnx_floating_ips_info: + filter: + name: + custom_filter: + private_ip: + register: result diff --git a/examples/hosts_info.yml b/examples/hosts_info.yml index ea7483968..1984cc41c 100644 --- a/examples/hosts_info.yml +++ b/examples/hosts_info.yml @@ -29,3 +29,11 @@ sort_attribute: "name" register: result ignore_errors: True + + - name: List hosts using filter and custom_filter + ntnx_hosts_info: + filter: + name: + custom_filter: + serial_number: + register: result diff --git a/examples/subnet_info.yml b/examples/subnet_info.yml index dd6790857..1d9d93314 100644 --- a/examples/subnet_info.yml +++ b/examples/subnet_info.yml @@ -29,3 +29,12 @@ check_mode: true register: result ignore_errors: True + + - name: List subnets filter and custom_filter + ntnx_subnets_info: + filter: + name: + custom_filter: + adapter_type: + vswitch_name: + register: result diff --git a/examples/vm_info.yml b/examples/vm_info.yml index 53d2928cb..02e362489 100644 --- a/examples/vm_info.yml +++ b/examples/vm_info.yml @@ -37,3 +37,12 @@ sort_attribute: "vm_name" register: result ignore_errors: True + + - name: List vms using filter and custom_filter + ntnx_vms_info: + filter: + vm_name: + custom_filter: + num_sockets: + + register: result diff --git a/plugins/module_utils/entity.py b/plugins/module_utils/entity.py index 2bbc97f54..735d9d3d5 100644 --- a/plugins/module_utils/entity.py +++ b/plugins/module_utils/entity.py @@ -175,6 +175,17 @@ def list( timeout=timeout, ) if resp: + custom_filters = self.module.params.get("custom_filter") + + if custom_filters: + entities_list = self._filter_entities( + resp[self.entity_type], custom_filters + ) + entities_count = len(entities_list) + + resp[self.entity_type] = entities_list + resp["metadata"]["length"] = entities_count + return resp entities_list = [] main_length = data.get("length") diff --git a/tests/integration/targets/nutanix_subnets_info/tasks/list_subnets.yml b/tests/integration/targets/nutanix_subnets_info/tasks/list_subnets.yml index b6b9890cc..cb7478a72 100644 --- a/tests/integration/targets/nutanix_subnets_info/tasks/list_subnets.yml +++ b/tests/integration/targets/nutanix_subnets_info/tasks/list_subnets.yml @@ -42,3 +42,18 @@ fail_msg: " Unable to list subnets " success_msg: " Subnets listed successfully " ######################################################### +- name: List subnet using custom_filter + ntnx_subnets_info: + custom_filter: + vswitch_name: br0 + register: result + ignore_errors: True + +- name: Listing Status + assert: + that: + - result.response is defined + - result.response.entities[0].status.resources.vswitch_name == "br0" + fail_msg: " Unable to List subnet using custom_filter " + success_msg: "List subnet using custom_filter listed successfully " +######################################################### \ No newline at end of file From f5e9dca5ed0ccc298f407a23113d3aeb7f4c00c1 Mon Sep 17 00:00:00 2001 From: Gevorg Khachatryan Date: Tue, 31 Oct 2023 00:05:52 +0400 Subject: [PATCH 09/41] example for vms inventory (#426) * example for vms inventory * ansible cfg * Move cfg to inventory example folder * Minor name changes * Minor fix --------- Co-authored-by: Gevorg-Khachatryaan Co-authored-by: Pradeepsingh Bhati --- examples/inventory/ansible.cfg | 7 +++++++ examples/inventory/nutanix.yaml | 13 +++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 examples/inventory/ansible.cfg create mode 100644 examples/inventory/nutanix.yaml diff --git a/examples/inventory/ansible.cfg b/examples/inventory/ansible.cfg new file mode 100644 index 000000000..7c5781ba3 --- /dev/null +++ b/examples/inventory/ansible.cfg @@ -0,0 +1,7 @@ +[defaults] +inventory = nutanix.yaml + +[inventory] +enable_plugins = nutanix.ncp.ntnx_prism_vm_inventory + + diff --git a/examples/inventory/nutanix.yaml b/examples/inventory/nutanix.yaml new file mode 100644 index 000000000..b38ba655e --- /dev/null +++ b/examples/inventory/nutanix.yaml @@ -0,0 +1,13 @@ +plugin: nutanix.ncp.ntnx_prism_vm_inventory +nutanix_hostname: +nutanix_username: +nutanix_password: +validate_certs: false +data: {"offset": 0, "length": 1000} +groups: + group_1: "'' in name" + group_2: "''==name" +keyed_groups: + - prefix: "host" + separator: ':' + key: "ansible_host" \ No newline at end of file From efb51fdf090a559e6a1249997a7f2d2fd2a0b06f Mon Sep 17 00:00:00 2001 From: Gianluca Salvo Date: Mon, 30 Oct 2023 21:24:21 +0100 Subject: [PATCH 10/41] Add support for PC Categories (#405) Co-authored-by: Gianluca Salvo --- plugins/inventory/ntnx_prism_vm_inventory.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/inventory/ntnx_prism_vm_inventory.py b/plugins/inventory/ntnx_prism_vm_inventory.py index 5273275a3..cf74ed5b2 100644 --- a/plugins/inventory/ntnx_prism_vm_inventory.py +++ b/plugins/inventory/ntnx_prism_vm_inventory.py @@ -178,6 +178,9 @@ def parse(self, inventory, loader, path, cache=True): for key, value in entity["status"]["resources"].items(): self.inventory.set_variable(vm_name, key, value) + + if 'metadata' in entity and 'categories' in entity['metadata']: + self.inventory.set_variable(vm_name, 'ntnx_categories', entity['metadata']['categories']) # Add variables created by the user's Jinja2 expressions to the host self._set_composite_vars( From 8d01d8129f12d17c6c171afc422fae97725bcc3c Mon Sep 17 00:00:00 2001 From: Gevorg Khachatryan Date: Tue, 31 Oct 2023 00:28:38 +0400 Subject: [PATCH 11/41] Bug/issue#400 (#403) * fix issue #400 * fix issue #400 --------- Co-authored-by: Gevorg-Khachatryaan --- plugins/module_utils/prism/vms.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/module_utils/prism/vms.py b/plugins/module_utils/prism/vms.py index 0ecd0ea9e..cb15386ab 100644 --- a/plugins/module_utils/prism/vms.py +++ b/plugins/module_utils/prism/vms.py @@ -442,14 +442,14 @@ def _generate_disk_spec( else: if vdisk.get("size_gb"): - disk_size_bytes = vdisk["size_gb"] * 1024 * 1024 * 1024 + disk_size_bytes = int(vdisk["size_gb"]) * 1024 * 1024 * 1024 if not vdisk.get("uuid") or ( "disk_size_bytes" in disk and disk_size_bytes >= disk.get("disk_size_bytes", 0) ): if disk.get("bus") in ["IDE", "SATA"]: self.require_vm_restart = True - disk["disk_size_bytes"] = vdisk["size_gb"] * 1024 * 1024 * 1024 + disk["disk_size_bytes"] = disk_size_bytes else: if disk.get("device_properties", {}).get("device_type") == "CDROM": self.module.fail_json( From 97c2d8b36e07857643417c7b65fd52743a25957a Mon Sep 17 00:00:00 2001 From: Gevorg Khachatryan Date: Tue, 31 Oct 2023 00:48:47 +0400 Subject: [PATCH 12/41] example for VMs with guest customization file which injects variables from the playbook (#396) Co-authored-by: Gevorg-Khachatryaan --- examples/vm.yml | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/examples/vm.yml b/examples/vm.yml index ebb7da68d..f88ab7064 100644 --- a/examples/vm.yml +++ b/examples/vm.yml @@ -17,6 +17,19 @@ script_path: "" subnet_name: "" image_name: "" + password: "" + fqdn: "" + + - name: Create Cloud-init Script file + copy: + dest: "cloud_init.yml" + content: | + #cloud-config + chpasswd: + list: | + root: "{{ password }}" + expire: False + fqdn: "{{ fqdn }}" - name: create Vm ntnx_vms: @@ -47,7 +60,7 @@ memory_gb: 1 guest_customization: type: "cloud_init" - script_path: "{{ script_path }}" + script_path: "./cloud_init.yml" is_overridable: True register: output From 5069b95a667ae090a6618064d956150d2b9dec16 Mon Sep 17 00:00:00 2001 From: Nathaniel Roberts <107402519+Nathaniel-Roberts@users.noreply.github.com> Date: Tue, 31 Oct 2023 07:51:03 +1100 Subject: [PATCH 13/41] Fix: Syntax Errors in Create App Security Rule Ex (#394) --- plugins/modules/ntnx_security_rules.py | 36 ++++++++++++++------------ 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/plugins/modules/ntnx_security_rules.py b/plugins/modules/ntnx_security_rules.py index a6c92e5de..16124e568 100644 --- a/plugins/modules/ntnx_security_rules.py +++ b/plugins/modules/ntnx_security_rules.py @@ -879,45 +879,47 @@ - name: create app security rule ntnx_security_rules: name: test_app_rule + allow_ipv6_traffic: true + policy_hitlog: true app_rule: + policy_mode: MONITOR target_group: categories: apptype: Apache_Spark default_internal_policy: DENY_ALL - inbound: + inbounds: - categories: AppFamily: - Databases - DevOps - icmp: - - code: 1 - type: 1 + protocol: + icmp: + - code: 1 + type: 1 - categories: AppFamily: - Databases - DevOps - tcp: - - start_port: 22 - end_port: 80 + protocol: + tcp: + - start_port: 22 + end_port: 80 - categories: AppFamily: - Databases - DevOps - udp: - - start_port: 82 - end_port: 8080 + protocol: + udp: + - start_port: 82 + end_port: 8080 + description: test description - ip_subnet: + ip: 192.168.1.0 prefix_length: 24 - ip: 192.168.1.1 - description: test description - protocol: ALL - outbound: + outbounds: - categories: AppFamily: - Databases - policy_mode: MONITOR - allow_ipv6_traffic: true - policy_hitlog:: true register: result - name: update app security rule with outbound list ntnx_security_rules: From 74908fe9ac5cce0d25eb9fa8a39a415107715b7d Mon Sep 17 00:00:00 2001 From: Gevorg Khachatryan Date: Tue, 31 Oct 2023 00:55:08 +0400 Subject: [PATCH 14/41] functionality to handle issue when size of new disk is absent (#393) Co-authored-by: Gevorg-Khachatryaan --- plugins/module_utils/prism/vms.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/plugins/module_utils/prism/vms.py b/plugins/module_utils/prism/vms.py index cb15386ab..a48364499 100644 --- a/plugins/module_utils/prism/vms.py +++ b/plugins/module_utils/prism/vms.py @@ -460,6 +460,11 @@ def _generate_disk_spec( msg="Unsupported operation: Unable to decrease disk size.", disk=disk, ) + elif not vdisk.get("uuid"): + self.module.fail_json( + msg="Unsupported operation: Unable to create disk, 'size_gb' is required.", + disk=disk, + ) if vdisk.get("storage_container"): disk.pop("data_source_reference", None) From 46ca173bea0abff895ca738a7863e8520ae3136d Mon Sep 17 00:00:00 2001 From: Gevorg Khachatryan Date: Tue, 31 Oct 2023 00:56:48 +0400 Subject: [PATCH 15/41] example fix (#392) Co-authored-by: Gevorg-Khachatryaan --- plugins/modules/ntnx_images_info.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/modules/ntnx_images_info.py b/plugins/modules/ntnx_images_info.py index 1f456eb0e..96fbd78f2 100644 --- a/plugins/modules/ntnx_images_info.py +++ b/plugins/modules/ntnx_images_info.py @@ -38,7 +38,7 @@ nutanix_password: "{{ password }}" validate_certs: False filter: - - name: Ubuntu + name: Ubuntu register: result """ RETURN = r""" From 5c943805fd4b811efebbc2d72c7a1cdd8afc2f6b Mon Sep 17 00:00:00 2001 From: Alaa Bishtawi Date: Tue, 31 Oct 2023 09:08:12 +0200 Subject: [PATCH 16/41] sanity fix --- plugins/inventory/ntnx_prism_vm_inventory.py | 8 +++++--- .../modules/ntnx_ndb_database_clone_refresh.py | 15 +++++++++++++-- plugins/modules/ntnx_ndb_database_clones.py | 4 ++++ 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/plugins/inventory/ntnx_prism_vm_inventory.py b/plugins/inventory/ntnx_prism_vm_inventory.py index cf74ed5b2..29cc63551 100644 --- a/plugins/inventory/ntnx_prism_vm_inventory.py +++ b/plugins/inventory/ntnx_prism_vm_inventory.py @@ -178,9 +178,11 @@ def parse(self, inventory, loader, path, cache=True): for key, value in entity["status"]["resources"].items(): self.inventory.set_variable(vm_name, key, value) - - if 'metadata' in entity and 'categories' in entity['metadata']: - self.inventory.set_variable(vm_name, 'ntnx_categories', entity['metadata']['categories']) + + if "metadata" in entity and "categories" in entity["metadata"]: + self.inventory.set_variable( + vm_name, "ntnx_categories", entity["metadata"]["categories"] + ) # Add variables created by the user's Jinja2 expressions to the host self._set_composite_vars( diff --git a/plugins/modules/ntnx_ndb_database_clone_refresh.py b/plugins/modules/ntnx_ndb_database_clone_refresh.py index 8b0934c23..e1e488b08 100644 --- a/plugins/modules/ntnx_ndb_database_clone_refresh.py +++ b/plugins/modules/ntnx_ndb_database_clone_refresh.py @@ -31,6 +31,10 @@ - timestamp for point in time database cone refresh - format is 'yyyy-mm-dd hh:mm:ss' type: str + latest_snapshot: + description: + - write + type: bool extends_documentation_fragment: - nutanix.ncp.ntnx_ndb_base_module - nutanix.ncp.ntnx_operations @@ -301,7 +305,7 @@ def get_module_spec(): snapshot_uuid=dict(type="str", required=False), timezone=dict(type="str", default="Asia/Calcutta", required=False), pitr_timestamp=dict(type="str", required=False), - latest_snapshot=dict(type="bool", required=False) + latest_snapshot=dict(type="bool", required=False), ) return module_args @@ -346,7 +350,14 @@ def run_module(): module = NdbBaseModule( argument_spec=get_module_spec(), supports_check_mode=True, - required_if=[("state", "present", ("snapshot_uuid", "pitr_timestamp", "latest_snapshot"), True)], + required_if=[ + ( + "state", + "present", + ("snapshot_uuid", "pitr_timestamp", "latest_snapshot"), + True, + ) + ], mutually_exclusive=mutually_exclusive_list, ) remove_param_with_none_value(module.params) diff --git a/plugins/modules/ntnx_ndb_database_clones.py b/plugins/modules/ntnx_ndb_database_clones.py index cfaa38451..d8ada7059 100644 --- a/plugins/modules/ntnx_ndb_database_clones.py +++ b/plugins/modules/ntnx_ndb_database_clones.py @@ -169,6 +169,10 @@ description: - timestamp for create clone from point in time type: str + latest_snapshot: + description: + - write + type: bool postgres: description: - postgres database related config From 7a9f51a424ed21a2f2565408688e8eb7fdef4af6 Mon Sep 17 00:00:00 2001 From: Gevorg Khachatryan Date: Tue, 31 Oct 2023 12:27:10 +0400 Subject: [PATCH 17/41] fix for issue#360 (#408) * fix for issue#360 * fix --------- Co-authored-by: Gevorg-Khachatryaan --- plugins/module_utils/prism/vms.py | 13 ++++++++++++- plugins/modules/ntnx_vms_clone.py | 4 +++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/plugins/module_utils/prism/vms.py b/plugins/module_utils/prism/vms.py index a48364499..8e4f2120c 100644 --- a/plugins/module_utils/prism/vms.py +++ b/plugins/module_utils/prism/vms.py @@ -171,6 +171,14 @@ def _get_default_spec(self): } ) + def _get_default_boot_config_spec(self): + return deepcopy( + { + "boot_type": "LEGACY", + "boot_device_order_list": ["CDROM", "DISK", "NETWORK"], + } + ) + def _get_default_network_spec(self): return deepcopy( { @@ -241,7 +249,7 @@ def _build_spec_cluster(self, payload, param): uuid, err = get_cluster_uuid(param, self.module) if err: return None, err - payload["spec"]["cluster_reference"]["uuid"] = uuid + payload["spec"]["cluster_reference"] = {"kind": "cluster", "uuid": uuid} return payload, None def _build_spec_vcpus(self, payload, vcpus): @@ -357,7 +365,10 @@ def _build_spec_disks(self, payload, vdisks): return payload, None def _build_spec_boot_config(self, payload, param): + if not payload["spec"]["resources"].get("boot_config"): + payload["spec"]["resources"]["boot_config"] = self._get_default_boot_config_spec() boot_config = payload["spec"]["resources"]["boot_config"] + if "LEGACY" == param["boot_type"] and "boot_order" in param: boot_config["boot_device_order_list"] = param["boot_order"] diff --git a/plugins/modules/ntnx_vms_clone.py b/plugins/modules/ntnx_vms_clone.py index dd1d0dc6a..5b4d35a5f 100644 --- a/plugins/modules/ntnx_vms_clone.py +++ b/plugins/modules/ntnx_vms_clone.py @@ -285,6 +285,7 @@ def get_module_spec(): def clone_vm(module, result): src_vm_uuid = module.params["src_vm_uuid"] + result["src_vm_uuid"] = src_vm_uuid vm = VM(module) @@ -305,7 +306,8 @@ def clone_vm(module, result): if module.params.get("wait"): wait_for_task_completion(module, result) - resp = vm.read(src_vm_uuid) + vm_uuid = result["response"]["entity_reference_list"][0]["uuid"] + resp = vm.read(vm_uuid) result["response"] = resp From 54d0bef537b3cdaedf75dee5d677e7339a2f53e5 Mon Sep 17 00:00:00 2001 From: alaa-bish Date: Tue, 31 Oct 2023 10:28:31 +0200 Subject: [PATCH 18/41] improve clone examples (#407) * imporve clone examples * Fix Examples --- examples/ndb/create_clone.yml | 121 +++++++++++++++++++++++++++++++++ examples/ndb/refresh_clone.yml | 40 +++++++++++ 2 files changed, 161 insertions(+) create mode 100644 examples/ndb/create_clone.yml create mode 100644 examples/ndb/refresh_clone.yml diff --git a/examples/ndb/create_clone.yml b/examples/ndb/create_clone.yml new file mode 100644 index 000000000..d2533e4f7 --- /dev/null +++ b/examples/ndb/create_clone.yml @@ -0,0 +1,121 @@ +--- +- name: Create clone + hosts: localhost + gather_facts: false + collections: + - nutanix.ncp + module_defaults: + group/nutanix.ncp.ntnx: + nutanix_host: + nutanix_username: + nutanix_password: + validate_certs: false + + tasks: + - set_fact: + clone_db: + name: + db_params_profile: + name: + vm: + name: + password: + cluster: + name: + network_profile: + name: + compute_profile: + name: + public_ssh_key: + time_machine: + name: