Skip to content

Commit

Permalink
vmware_content_deploy_template: Make parameter optional (ansible-coll…
Browse files Browse the repository at this point in the history
…ections#476)

vmware_content_deploy_template: Make parameter optional

Reviewed-by: https://github.com/apps/ansible-zuul
  • Loading branch information
Akasurde authored Feb 1, 2021
1 parent f57e815 commit a606edd
Show file tree
Hide file tree
Showing 8 changed files with 156 additions and 120 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ Name | Description
[community.vmware.vmware_drs_group](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_drs_group_module.rst)|Creates vm/host group in a given cluster.
[community.vmware.vmware_drs_group_facts](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_drs_group_facts_module.rst)|Gathers facts about DRS VM/Host groups on the given cluster
[community.vmware.vmware_drs_group_info](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_drs_group_info_module.rst)|Gathers info about DRS VM/Host groups on the given cluster
[community.vmware.vmware_drs_group_manager](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_drs_group_manager_module.rst)|Manage VMs/Hosts group in the DRS group.
[community.vmware.vmware_drs_group_manager](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_drs_group_manager_module.rst)|Manage VMs and Hosts in DRS group.
[community.vmware.vmware_drs_rule_facts](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_drs_rule_facts_module.rst)|Gathers facts about DRS rule on the given cluster
[community.vmware.vmware_drs_rule_info](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_drs_rule_info_module.rst)|Gathers info about DRS rule on the given cluster
[community.vmware.vmware_dvs_host](https://github.com/ansible-collections/community.vmware/blob/main/docs/community.vmware.vmware_dvs_host_module.rst)|Add or remove a host from distributed virtual switch
Expand Down
3 changes: 3 additions & 0 deletions changelogs/fragments/397_vmware_content.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
minor_changes:
- vmware_content_deploy_template - make resource pool, host, cluster, datastore optional parameter and add check (https://github.com/ansible-collections/community.vmware/issues/397).
- vmware_content_deploy_template - add datastore cluster parameter (https://github.com/ansible-collections/community.vmware/issues/397).
32 changes: 28 additions & 4 deletions docs/community.vmware.vmware_content_deploy_template_module.rst
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ Parameters
</td>
<td>
<div>Name of the cluster in datacenter in which to place deployed VM.</div>
<div>Required if <em>resource_pool</em> is not specified.</div>
</td>
</tr>
<tr>
Expand Down Expand Up @@ -98,13 +99,32 @@ Parameters
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
<div style="font-size: small">
<span style="color: purple">string</span>
/ <span style="color: red">required</span>
</div>
</td>
<td>
</td>
<td>
<div>Name of the datastore to store deployed VM and disk.</div>
<div>Required if <em>datastore_cluster</em> is not provided.</div>
</td>
</tr>
<tr>
<td colspan="1">
<div class="ansibleOptionAnchor" id="parameter-"></div>
<b>datastore_cluster</b>
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
<div style="font-size: small">
<span style="color: purple">string</span>
</div>
<div style="font-style: italic; font-size: small; color: darkgreen">added in 1.7.0</div>
</td>
<td>
</td>
<td>
<div>Name of the datastore cluster to store deployed VM and disk.</div>
<div>Please make sure Storage DRS is active for recommended datastore from the given datastore cluster.</div>
<div>If Storage DRS is not enabled, datastore with largest free storage space is selected.</div>
<div>Required if <em>datastore</em> is not provided.</div>
</td>
</tr>
<tr>
Expand All @@ -130,13 +150,14 @@ Parameters
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
<div style="font-size: small">
<span style="color: purple">string</span>
/ <span style="color: red">required</span>
</div>
</td>
<td>
</td>
<td>
<div>Name of the ESX Host in datacenter in which to place deployed VM.</div>
<div>The host has to be a member of the cluster that contains the resource pool.</div>
<div>Required with <em>resource_pool</em> to find resource pool details. This will be used as additional information when there are resource pools with same name.</div>
</td>
</tr>
<tr>
Expand Down Expand Up @@ -237,7 +258,10 @@ Parameters
<td>
</td>
<td>
<div>Name of the resourcepool in datacenter in which to place deployed VM.</div>
<div>Name of the resource pool in datacenter in which to place deployed VM.</div>
<div>Required if <em>cluster</em> is not specified.</div>
<div>For default or non-unique resource pool names, specify <em>host</em> and <em>cluster</em>.</div>
<div><code>Resources</code> is the default name of resource pool.</div>
</td>
</tr>
<tr>
Expand Down Expand Up @@ -333,7 +357,7 @@ Notes
Examples
--------

.. code-block:: yaml
.. code-block:: yaml+jinja

- name: Deploy Virtual Machine from template in content library
community.vmware.vmware_content_deploy_template:
Expand Down
4 changes: 2 additions & 2 deletions docs/community.vmware.vmware_drs_group_manager_module.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
community.vmware.vmware_drs_group_manager
*****************************************

**Manage VMs/Hosts group in the DRS group.**
**Manage VMs and Hosts in DRS group.**


Version added: 1.7.0
Expand All @@ -17,7 +17,7 @@ Version added: 1.7.0

Synopsis
--------
- The module can be used to add / remove VMs/Hosts groups in a given cluster.
- The module can be used to add VMs / Hosts to or remove them from a DRS group.



Expand Down
47 changes: 45 additions & 2 deletions plugins/module_utils/vmware.py
Original file line number Diff line number Diff line change
Expand Up @@ -1413,19 +1413,20 @@ def find_folder_by_name(self, folder_name):
return find_folder_by_name(self.content, folder_name=folder_name)

# Datastore cluster
def find_datastore_cluster_by_name(self, datastore_cluster_name, datacenter=None):
def find_datastore_cluster_by_name(self, datastore_cluster_name, datacenter=None, folder=None):
"""
Get datastore cluster managed object by name
Args:
datastore_cluster_name: Name of datastore cluster
datacenter: Managed object of the datacenter
folder: Managed object of the folder which holds datastore
Returns: Datastore cluster managed object if found else None
"""
if datacenter and hasattr(datacenter, 'datastoreFolder'):
folder = datacenter.datastoreFolder
else:
if not folder:
folder = self.content.rootFolder

data_store_clusters = get_all_objs(self.content, [vim.StoragePod], folder=folder)
Expand All @@ -1434,6 +1435,48 @@ def find_datastore_cluster_by_name(self, datastore_cluster_name, datacenter=None
return dsc
return None

def get_recommended_datastore(self, datastore_cluster_obj=None):
"""
Return Storage DRS recommended datastore from datastore cluster
Args:
datastore_cluster_obj: datastore cluster managed object
Returns: Name of recommended datastore from the given datastore cluster
"""
if datastore_cluster_obj is None:
return None
# Check if Datastore Cluster provided by user is SDRS ready
sdrs_status = datastore_cluster_obj.podStorageDrsEntry.storageDrsConfig.podConfig.enabled
if sdrs_status:
# We can get storage recommendation only if SDRS is enabled on given datastorage cluster
pod_sel_spec = vim.storageDrs.PodSelectionSpec()
pod_sel_spec.storagePod = datastore_cluster_obj
storage_spec = vim.storageDrs.StoragePlacementSpec()
storage_spec.podSelectionSpec = pod_sel_spec
storage_spec.type = 'create'

try:
rec = self.content.storageResourceManager.RecommendDatastores(storageSpec=storage_spec)
rec_action = rec.recommendations[0].action[0]
return rec_action.destination.name
except Exception:
# There is some error so we fall back to general workflow
pass
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 not self.is_datastore_valid(datastore_obj=ds):
continue

datastore = ds
datastore_freespace = ds.summary.freeSpace
if datastore:
return datastore.name
return None

# Resource pool
def find_resource_pool_by_name(self, resource_pool_name, folder=None):
"""
Expand Down
106 changes: 77 additions & 29 deletions plugins/modules/vmware_content_deploy_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,18 @@
datastore:
description:
- Name of the datastore to store deployed VM and disk.
- Required if I(datastore_cluster) is not provided.
type: str
required: True
required: False
datastore_cluster:
description:
- Name of the datastore cluster to store deployed VM and disk.
- Please make sure Storage DRS is active for recommended datastore from the given datastore cluster.
- If Storage DRS is not enabled, datastore with largest free storage space is selected.
- Required if I(datastore) is not provided.
type: str
required: False
version_added: '1.7.0'
folder:
description:
- Name of the folder in datacenter in which to place deployed VM.
Expand All @@ -63,16 +73,23 @@
host:
description:
- Name of the ESX Host in datacenter in which to place deployed VM.
- The host has to be a member of the cluster that contains the resource pool.
- Required with I(resource_pool) to find resource pool details. This will be used as additional
information when there are resource pools with same name.
type: str
required: True
required: False
resource_pool:
description:
- Name of the resourcepool in datacenter in which to place deployed VM.
- Name of the resource pool in datacenter in which to place deployed VM.
- Required if I(cluster) is not specified.
- For default or non-unique resource pool names, specify I(host) and I(cluster).
- C(Resources) is the default name of resource pool.
type: str
required: False
cluster:
description:
- Name of the cluster in datacenter in which to place deployed VM.
- Required if I(resource_pool) is not specified.
type: str
required: False
state:
Expand Down Expand Up @@ -151,12 +168,24 @@ class VmwareContentDeployTemplate(VmwareRestClient):
def __init__(self, module):
"""Constructor."""
super(VmwareContentDeployTemplate, self).__init__(module)
self.pyv = PyVmomi(module=module)
vm = self.pyv.get_vm()
if vm:
self.module.exit_json(
changed=False,
vm_deploy_info=dict(
msg="Virtual Machine '%s' already exists." % self.module.params['name'],
vm_id=vm._moId,
)
)
self.template_service = self.api_client.vcenter.vm_template.LibraryItems
self.template_name = self.params.get('template')
self.content_library_name = self.params.get('content_library')
self.vm_name = self.params.get('name')
self.datacenter = self.params.get('datacenter')
self.datastore = self.params.get('datastore')
self.datastore_cluster = self.params.get('datastore_cluster')
self.datastore_id = None
self.folder = self.params.get('folder')
self.resourcepool = self.params.get('resource_pool')
self.cluster = self.params.get('cluster')
Expand All @@ -167,10 +196,23 @@ def deploy_vm_from_template(self, power_on=False):
self.datacenter_id = self.get_datacenter_by_name(datacenter_name=self.datacenter)
if not self.datacenter_id:
self.module.fail_json(msg="Failed to find the datacenter %s" % self.datacenter)
# Find the datastore by the given datastore name
self.datastore_id = self.get_datastore_by_name(self.datacenter, self.datastore)

if self.datastore:
# Find the datastore by the given datastore name
self.datastore_id = self.get_datastore_by_name(self.datacenter, self.datastore)
if self.datastore_cluster:
# Find the datastore by the given datastore cluster name
datastore_cluster = self.pyv.find_datastore_cluster_by_name(self.datastore_cluster, folder=self.datastore_id.datastoreFolder)
if not datastore_cluster:
self.module.fail_json(msg="Failed to find the datastore cluster %s" % self.datastore_cluster)
self.datastore_id = self.pyv.get_recommended_datastore(datastore_cluster)

if not self.datastore_id:
self.module.fail_json(msg="Failed to find the datastore %s" % self.datastore)
if self.datastore:
self.module.fail_json(msg="Failed to find the datastore %s" % self.datastore)
if self.datastore_cluster:
self.module.fail_json(msg="Failed to find the datastore using datastore cluster %s" % self.datastore_cluster)

# Find the LibraryItem (Template) by the given LibraryItem name
if self.content_library_name:
self.library_item_id = self.get_library_item_from_content_library_name(
Expand All @@ -186,27 +228,36 @@ def deploy_vm_from_template(self, power_on=False):
if not self.folder_id:
self.module.fail_json(msg="Failed to find the folder %s" % self.folder)
# Find the Host by given HostName
self.host_id = self.get_host_by_name(self.datacenter, self.host)
if not self.host_id:
self.module.fail_json(msg="Failed to find the Host %s" % self.host)
self.host_id = None
if self.host:
self.host_id = self.get_host_by_name(self.datacenter, self.host)
if not self.host_id:
self.module.fail_json(msg="Failed to find the Host %s" % self.host)

# Find the resourcepool by the given resourcepool name
self.cluster_id = None
self.resourcepool_id = None

if self.resourcepool:
self.resourcepool_id = self.get_resource_pool_by_name(self.datacenter, self.resourcepool)
self.resourcepool_id = self.get_resource_pool_by_name(self.datacenter, self.resourcepool, self.cluster, self.host)
if not self.resourcepool_id:
self.module.fail_json(msg="Failed to find the resource_pool %s" % self.resourcepool)

# Find the Cluster by the given Cluster name
self.cluster_id = None
if self.cluster:
self.cluster_id = self.get_cluster_by_name(self.datacenter, self.cluster)
if not self.cluster_id:
self.module.fail_json(msg="Failed to find the Cluster %s" % self.cluster)
cluster_obj = self.api_client.vcenter.Cluster.get(self.cluster_id)
self.resourcepool_id = cluster_obj.resource_pool

# Create VM placement specs
self.placement_spec = LibraryItems.DeployPlacementSpec(folder=self.folder_id,
host=self.host_id
)
if self.resourcepool_id or self.cluster_id:
self.placement_spec = LibraryItems.DeployPlacementSpec(folder=self.folder_id)
if self.host_id:
self.placement_spec.host = self.host_id
if self.resourcepool_id:
self.placement_spec.resource_pool = self.resourcepool_id
if self.cluster_id:
self.placement_spec.cluster = self.cluster_id
self.vm_home_storage_spec = LibraryItems.DeploySpecVmHomeStorage(datastore=to_native(self.datastore_id))
self.disk_storage_spec = LibraryItems.DeploySpecDiskStorage(datastore=to_native(self.datastore_id))
Expand Down Expand Up @@ -246,25 +297,22 @@ def main():
'content_library_src'], required=False),
name=dict(type='str', required=True, aliases=['vm_name']),
datacenter=dict(type='str', required=True),
datastore=dict(type='str', required=True),
datastore=dict(type='str', required=False),
datastore_cluster=dict(type='str', required=False),
folder=dict(type='str', required=True),
host=dict(type='str', required=True),
host=dict(type='str', required=False),
resource_pool=dict(type='str', required=False),
cluster=dict(type='str', required=False),
)
module = AnsibleModule(argument_spec=argument_spec,
supports_check_mode=True)
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True,
required_one_of=[
['datastore', 'datastore_cluster'],
],
)
result = {'failed': False, 'changed': False}
pyv = PyVmomi(module=module)
vm = pyv.get_vm()
if vm:
module.exit_json(
changed=False,
vm_deploy_info=dict(
msg="Virtual Machine '%s' already Exists." % module.params['name'],
vm_id=vm._moId,
)
)

vmware_contentlib_create = VmwareContentDeployTemplate(module)
if module.params['state'] in ['present']:
if module.check_mode:
Expand Down
Loading

0 comments on commit a606edd

Please sign in to comment.