From de66abe52182bc124ffbd0ef0559375d471c79fe Mon Sep 17 00:00:00 2001 From: Abhijeet Kasurde Date: Tue, 16 Jul 2019 13:14:21 +0530 Subject: [PATCH] VMware: Add support for storagePod (#58627) * User now can be specify datastore cluster for deploying OVF * Added find_resource_pool_by_cluster API Fixes: #57849 Signed-off-by: Abhijeet Kasurde --- lib/ansible/module_utils/vmware.py | 46 ++++++++++++++ .../modules/cloud/vmware/vmware_deploy_ovf.py | 62 +++++++++++++------ test/sanity/validate-modules/ignore.txt | 1 - 3 files changed, 89 insertions(+), 20 deletions(-) diff --git a/lib/ansible/module_utils/vmware.py b/lib/ansible/module_utils/vmware.py index 0134cb1162e..a889591a7d2 100644 --- a/lib/ansible/module_utils/vmware.py +++ b/lib/ansible/module_utils/vmware.py @@ -1252,6 +1252,52 @@ class PyVmomi(object): return dsc return None + # Resource pool + def find_resource_pool_by_name(self, resource_pool_name, folder=None): + """ + Get resource pool managed object by name + Args: + resource_pool_name: Name of resource pool + + Returns: Resource pool managed object if found else None + + """ + if not folder: + folder = self.content.rootFolder + + resource_pools = get_all_objs(self.content, [vim.ResourcePool], folder=folder) + for rp in resource_pools: + if rp.name == resource_pool_name: + return rp + return None + + def find_resource_pool_by_cluster(self, resource_pool_name='Resources', cluster=None): + """ + Get resource pool managed object by cluster object + Args: + resource_pool_name: Name of resource pool + cluster: Managed object of cluster + + Returns: Resource pool managed object if found else None + + """ + desired_rp = None + if not cluster: + return desired_rp + + if resource_pool_name != 'Resources': + # Resource pool name is different than default 'Resources' + resource_pools = cluster.resourcePool.resourcePool + if resource_pools: + for rp in resource_pools: + if rp.name == resource_pool_name: + desired_rp = rp + break + else: + desired_rp = cluster.resourcePool + + return desired_rp + # VMDK stuff def vmdk_disk_path_split(self, vmdk_path): """ diff --git a/lib/ansible/modules/cloud/vmware/vmware_deploy_ovf.py b/lib/ansible/modules/cloud/vmware/vmware_deploy_ovf.py index fd948e7e141..4be54cc0e9c 100644 --- a/lib/ansible/modules/cloud/vmware/vmware_deploy_ovf.py +++ b/lib/ansible/modules/cloud/vmware/vmware_deploy_ovf.py @@ -31,16 +31,21 @@ options: default: ha-datacenter description: - Datacenter to deploy to. + type: str cluster: description: - Cluster to deploy to. + type: str datastore: default: datastore1 description: - Datastore to deploy to. + - "You can also specify datastore storage cluster. version_added: 2.9" + type: str deployment_option: description: - The key of the chosen deployment option. + type: str disk_provisioning: choices: - flat @@ -56,6 +61,7 @@ options: default: thin description: - Disk provisioning type. + type: str fail_on_spec_warnings: description: - Cause the module to treat OVF Import Spec warnings as errors. @@ -75,6 +81,7 @@ options: - ' folder: /folder1/datacenter1/vm' - ' folder: folder1/datacenter1/vm' - ' folder: /folder1/datacenter1/vm/folder2' + type: str inject_ovf_env: description: - Force the given properties to be inserted into an OVF Environment and injected through VMware Tools. @@ -84,11 +91,13 @@ options: description: - Name of the VM to work with. - Virtual machine names in vCenter are not necessarily unique, which may be problematic. + type: str networks: default: VM Network: VM Network description: - 'C(key: value) mapping of OVF network name, to the vCenter network name.' + type: dict ovf: description: - 'Path to OVF or OVA file to deploy.' @@ -102,10 +111,12 @@ options: properties: description: - The assignment of values to the properties found in the OVF as key value pairs. + type: dict resource_pool: default: Resources description: - - 'Resource Pool to deploy to.' + - Resource Pool to deploy to. + type: str wait: default: true description: @@ -172,8 +183,7 @@ from ansible.module_utils._text import to_native from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.six import string_types from ansible.module_utils.urls import generic_urlparse, open_url, urlparse, urlunparse -from ansible.module_utils.vmware import (HAS_PYVMOMI, connect_to_api, find_datacenter_by_name, find_datastore_by_name, - find_network_by_name, find_resource_pool_by_name, find_vm_by_name, find_cluster_by_name, +from ansible.module_utils.vmware import (find_network_by_name, find_vm_by_name, PyVmomi, gather_vm_facts, vmware_argument_spec, wait_for_task, wait_for_vm_ip) try: from ansible.module_utils.vmware import vim @@ -290,9 +300,9 @@ class VMDKUploader(Thread): self.e = sys.exc_info() -class VMwareDeployOvf: +class VMwareDeployOvf(PyVmomi): def __init__(self, module): - self.si = connect_to_api(module) + super(VMwareDeployOvf, self).__init__(module) self.module = module self.params = module.params @@ -309,24 +319,41 @@ class VMwareDeployOvf: self.entity = None def get_objects(self): - self.datastore = find_datastore_by_name(self.si, self.params['datastore']) - if not self.datastore: - self.module.fail_json(msg='%(datastore)s could not be located' % self.params) - - self.datacenter = find_datacenter_by_name(self.si, self.params['datacenter']) + self.datacenter = self.find_datacenter_by_name(self.params['datacenter']) if not self.datacenter: self.module.fail_json(msg='%(datacenter)s could not be located' % self.params) + self.datastore = None + datastore_cluster_obj = self.find_datastore_cluster_by_name(self.params['datastore']) + if datastore_cluster_obj: + datastore = None + datastore_freespace = 0 + for ds in datastore_cluster_obj.childEntity: + if isinstance(ds, vim.Datastore) and ds.summary.freeSpace > datastore_freespace: + # If datastore field is provided, filter destination datastores + if ds.summary.maintenanceMode != 'normal' or not ds.summary.accessible: + continue + datastore = ds + datastore_freespace = ds.summary.freeSpace + if datastore: + self.datastore = datastore + else: + self.datastore = self.find_datastore_by_name(self.params['datastore']) + + if not self.datastore: + self.module.fail_json(msg='%(datastore)s could not be located' % self.params) + if self.params['cluster']: - cluster = find_cluster_by_name(self.si, self.params['cluster']) + resource_pools = [] + cluster = self.find_cluster_by_name(self.params['cluster'], datacenter_name=self.datacenter) if cluster is None: self.module.fail_json(msg="Unable to find cluster '%(cluster)s'" % self.params) - else: - self.resource_pool = cluster.resourcePool + self.resource_pool = self.find_resource_pool_by_cluster(self.params['resource_pool'], cluster=cluster) else: - self.resource_pool = find_resource_pool_by_name(self.si, self.params['resource_pool']) - if not self.resource_pool: - self.module.fail_json(msg='%(resource_pool)s could not be located' % self.params) + self.resource_pool = self.find_resource_pool_by_name(self.params['resource_pool']) + + if not self.resource_pool: + self.module.fail_json(msg='%(resource_pool)s could not be located' % self.params) for key, value in self.params['networks'].items(): network = find_network_by_name(self.si, value) @@ -665,9 +692,6 @@ def main(): supports_check_mode=True, ) - if not HAS_PYVMOMI: - module.fail_json(msg='pyvmomi python library not found') - deploy_ovf = VMwareDeployOvf(module) deploy_ovf.upload() deploy_ovf.complete() diff --git a/test/sanity/validate-modules/ignore.txt b/test/sanity/validate-modules/ignore.txt index 8cfffadba4d..54a535d9a8c 100644 --- a/test/sanity/validate-modules/ignore.txt +++ b/test/sanity/validate-modules/ignore.txt @@ -1248,7 +1248,6 @@ lib/ansible/modules/cloud/vmware/vmware_datastore_cluster.py E337 lib/ansible/modules/cloud/vmware/vmware_datastore_facts.py E337 lib/ansible/modules/cloud/vmware/vmware_datastore_maintenancemode.py E337 lib/ansible/modules/cloud/vmware/vmware_deploy_ovf.py E337 -lib/ansible/modules/cloud/vmware/vmware_deploy_ovf.py E338 lib/ansible/modules/cloud/vmware/vmware_dns_config.py E337 lib/ansible/modules/cloud/vmware/vmware_drs_group_facts.py E337 lib/ansible/modules/cloud/vmware/vmware_drs_group.py E337