VMware: Gather extended datastore facts (#46546)

* Add datacenter_name alias
* Add check mode support
* Add extended datastore information
This commit is contained in:
Christian Kotte 2018-10-11 12:22:30 +02:00 committed by Abhijeet Kasurde
parent db69f46cf9
commit 0bc2e6795d
2 changed files with 151 additions and 34 deletions

View file

@ -40,12 +40,27 @@ options:
- Datacenter to search for datastores. - Datacenter to search for datastores.
- This parameter is required, if C(cluster) is not supplied. - This parameter is required, if C(cluster) is not supplied.
required: False required: False
aliases: ['datacenter_name']
cluster: cluster:
description: description:
- Cluster to search for datastores. - Cluster to search for datastores.
- If set, facts of datastores belonging this clusters will be returned. - If set, facts of datastores belonging this clusters will be returned.
- This parameter is required, if C(datacenter) is not supplied. - This parameter is required, if C(datacenter) is not supplied.
required: False required: False
gather_nfs_mount_info:
description:
- Gather mount information of NFS datastores.
- Disabled per default because this slows down the execution if you have a lot of datastores.
type: bool
default: false
version_added: 2.8
gather_vmfs_mount_info:
description:
- Gather mount information of VMFS datastores.
- Disabled per default because this slows down the execution if you have a lot of datastores.
type: bool
default: false
version_added: 2.8
extends_documentation_fragment: vmware.documentation extends_documentation_fragment: vmware.documentation
''' '''
@ -55,7 +70,7 @@ EXAMPLES = '''
hostname: '{{ vcenter_hostname }}' hostname: '{{ vcenter_hostname }}'
username: '{{ vcenter_username }}' username: '{{ vcenter_username }}'
password: '{{ vcenter_password }}' password: '{{ vcenter_password }}'
datacenter: '{{ datacenter_name }}' datacenter_name: '{{ datacenter_name }}'
validate_certs: no validate_certs: no
delegate_to: localhost delegate_to: localhost
register: facts register: facts
@ -65,7 +80,7 @@ EXAMPLES = '''
hostname: '{{ vcenter_hostname }}' hostname: '{{ vcenter_hostname }}'
username: '{{ vcenter_username }}' username: '{{ vcenter_username }}'
password: '{{ vcenter_password }}' password: '{{ vcenter_password }}'
datacenter: '{{ datacenter_name }}' datacenter_name: '{{ datacenter_name }}'
name: datastore1 name: datastore1
delegate_to: localhost delegate_to: localhost
register: facts register: facts
@ -88,7 +103,25 @@ datastores:
"provisioned": 12289211488, "provisioned": 12289211488,
"type": "VMFS", "type": "VMFS",
"uncommitted": 9246243936, "uncommitted": 9246243936,
"url": "ds:///vmfs/volumes/5a69b18a-c03cd88c-36ae-5254001249ce/" "url": "ds:///vmfs/volumes/5a69b18a-c03cd88c-36ae-5254001249ce/",
"vmfs_blockSize": 1024,
"vmfs_uuid": "5a69b18a-c03cd88c-36ae-5254001249ce",
"vmfs_version": "6.81"
},
{
"accessible": true,
"capacity": 5497558138880,
"datastore_cluster": "datacluster0",
"freeSpace": 4279000641536,
"maintenanceMode": "normal",
"multipleHostAccess": true,
"name": "datastore3",
"nfs_path": "/vol/datastore3",
"nfs_server": "nfs_server1",
"provisioned": 1708109410304,
"type": "NFS",
"uncommitted": 489551912960,
"url": "ds:///vmfs/volumes/420b3e73-67070776/"
}, },
] ]
""" """
@ -103,6 +136,70 @@ from ansible.module_utils.vmware import (PyVmomi, vmware_argument_spec, get_all_
find_cluster_by_name, get_parent_datacenter) find_cluster_by_name, get_parent_datacenter)
class VMwareHostDatastore(PyVmomi):
""" This class populates the datastore list """
def __init__(self, module):
super(VMwareHostDatastore, self).__init__(module)
self.gather_nfs_mount_info = self.module.params['gather_nfs_mount_info']
self.gather_vmfs_mount_info = self.module.params['gather_vmfs_mount_info']
def check_datastore_host(self, esxi_host, datastore):
""" Get all datastores of specified ESXi host """
esxi = self.find_hostsystem_by_name(esxi_host)
if esxi is None:
self.module.fail_json(msg="Failed to find ESXi hostname %s " % esxi_host)
storage_system = esxi.configManager.storageSystem
host_file_sys_vol_mount_info = storage_system.fileSystemVolumeInfo.mountInfo
for host_mount_info in host_file_sys_vol_mount_info:
if host_mount_info.volume.name == datastore:
return host_mount_info
return None
def build_datastore_list(self, datastore_list):
""" Build list with datastores """
datastores = list()
for datastore in datastore_list:
summary = datastore.summary
datastore_summary = dict()
datastore_summary['accessible'] = summary.accessible
datastore_summary['capacity'] = summary.capacity
datastore_summary['name'] = summary.name
datastore_summary['freeSpace'] = summary.freeSpace
datastore_summary['maintenanceMode'] = summary.maintenanceMode
datastore_summary['multipleHostAccess'] = summary.multipleHostAccess
datastore_summary['type'] = summary.type
if self.gather_nfs_mount_info or self.gather_vmfs_mount_info:
if self.gather_nfs_mount_info and summary.type.startswith("NFS"):
# get mount info from the first ESXi host attached to this NFS datastore
host_mount_info = self.check_datastore_host(summary.datastore.host[0].key.name, summary.name)
datastore_summary['nfs_server'] = host_mount_info.volume.remoteHost
datastore_summary['nfs_path'] = host_mount_info.volume.remotePath
if self.gather_vmfs_mount_info and summary.type == "VMFS":
# get mount info from the first ESXi host attached to this VMFS datastore
host_mount_info = self.check_datastore_host(summary.datastore.host[0].key.name, summary.name)
datastore_summary['vmfs_blockSize'] = host_mount_info.volume.blockSize
datastore_summary['vmfs_version'] = host_mount_info.volume.version
datastore_summary['vmfs_uuid'] = host_mount_info.volume.uuid
# vcsim does not return uncommitted
if not summary.uncommitted:
summary.uncommitted = 0
datastore_summary['uncommitted'] = summary.uncommitted
datastore_summary['url'] = summary.url
# Calculated values
datastore_summary['provisioned'] = summary.capacity - summary.freeSpace + summary.uncommitted
datastore_summary['datastore_cluster'] = 'N/A'
if isinstance(datastore.parent, vim.StoragePod):
datastore_summary['datastore_cluster'] = datastore.parent.name
if self.module.params['name']:
if datastore_summary['name'] == self.module.params['name']:
datastores.extend([datastore_summary])
else:
datastores.extend([datastore_summary])
return datastores
class PyVmomiCache(object): class PyVmomiCache(object):
""" This class caches references to objects which are requested multiples times but not modified """ """ This class caches references to objects which are requested multiples times but not modified """
def __init__(self, content, dc_name=None): def __init__(self, content, dc_name=None):
@ -129,15 +226,18 @@ class PyVmomiCache(object):
class PyVmomiHelper(PyVmomi): class PyVmomiHelper(PyVmomi):
""" This class gets datastores """
def __init__(self, module): def __init__(self, module):
super(PyVmomiHelper, self).__init__(module) super(PyVmomiHelper, self).__init__(module)
self.cache = PyVmomiCache(self.content, dc_name=self.params['datacenter']) self.cache = PyVmomiCache(self.content, dc_name=self.params['datacenter'])
def lookup_datastore(self): def lookup_datastore(self):
""" Get datastore(s) per ESXi host or vCenter server """
datastores = self.cache.get_all_objs(self.content, [vim.Datastore], confine_to_datacenter=True) datastores = self.cache.get_all_objs(self.content, [vim.Datastore], confine_to_datacenter=True)
return datastores return datastores
def lookup_datastore_by_cluster(self): def lookup_datastore_by_cluster(self):
""" Get datastore(s) per cluster """
cluster = find_cluster_by_name(self.content, self.params['cluster']) cluster = find_cluster_by_name(self.content, self.params['cluster'])
if not cluster: if not cluster:
self.module.fail_json(msg='Failed to find cluster "%(cluster)s"' % self.params) self.module.fail_json(msg='Failed to find cluster "%(cluster)s"' % self.params)
@ -146,16 +246,20 @@ class PyVmomiHelper(PyVmomi):
def main(): def main():
""" Main """
argument_spec = vmware_argument_spec() argument_spec = vmware_argument_spec()
argument_spec.update( argument_spec.update(
name=dict(type='str'), name=dict(type='str'),
datacenter=dict(type='str'), datacenter=dict(type='str', aliases=['datacenter_name']),
cluster=dict(type='str') cluster=dict(type='str'),
gather_nfs_mount_info=dict(type='bool', default=False),
gather_vmfs_mount_info=dict(type='bool', default=False)
) )
module = AnsibleModule(argument_spec=argument_spec, module = AnsibleModule(argument_spec=argument_spec,
required_one_of=[ required_one_of=[
['cluster', 'datacenter'], ['cluster', 'datacenter'],
], ],
supports_check_mode=True
) )
result = dict(changed=False) result = dict(changed=False)
@ -166,33 +270,8 @@ def main():
else: else:
dxs = pyv.lookup_datastore() dxs = pyv.lookup_datastore()
datastores = list() vmware_host_datastore = VMwareHostDatastore(module)
for ds in dxs: datastores = vmware_host_datastore.build_datastore_list(dxs)
summary = ds.summary
dds = dict()
dds['accessible'] = summary.accessible
dds['capacity'] = summary.capacity
dds['name'] = summary.name
dds['freeSpace'] = summary.freeSpace
dds['maintenanceMode'] = summary.maintenanceMode
dds['multipleHostAccess'] = summary.multipleHostAccess
dds['type'] = summary.type
# vcsim does not return uncommitted
if not summary.uncommitted:
summary.uncommitted = 0
dds['uncommitted'] = summary.uncommitted
dds['url'] = summary.url
# Calculated values
dds['provisioned'] = summary.capacity - summary.freeSpace + summary.uncommitted
dds['datastore_cluster'] = 'N/A'
if isinstance(ds.parent, vim.StoragePod):
dds['datastore_cluster'] = ds.parent.name
if module.params['name']:
if dds['name'] == module.params['name']:
datastores.extend([dds])
else:
datastores.extend([dds])
result['datastores'] = datastores result['datastores'] = datastores

View file

@ -38,7 +38,7 @@
- set_fact: - set_fact:
cl1: "{{ clusters['json'][0] }}" cl1: "{{ clusters['json'][0] }}"
- name: get a list of Datacenters from vcsim - name: get a list of Datacenters from vcsim
uri: uri:
url: http://{{ vcsim }}:5000/govc_find?filter=DC url: http://{{ vcsim }}:5000/govc_find?filter=DC
@ -54,7 +54,7 @@
- set_fact: - set_fact:
ds1: "{{ datastores['json'][0] }}" ds1: "{{ datastores['json'][0] }}"
# Testcase 0001: Get a full list of datastores in a datacenter # Testcase 0001: Get a full list of datastores in a datacenter
- name: get list of facts about datastores - name: get list of facts about datastores
vmware_datastore_facts: vmware_datastore_facts:
@ -109,3 +109,41 @@
that: that:
- "datastore_facts_0003['datastores'][0]['name'] == ds1 | basename" - "datastore_facts_0003['datastores'][0]['name'] == ds1 | basename"
- "datastore_facts_0003['datastores'][0]['capacity'] is defined" - "datastore_facts_0003['datastores'][0]['capacity'] is defined"
- name: get list of extended facts about one datastore
vmware_datastore_facts:
validate_certs: False
hostname: "{{ vcsim }}"
username: "{{ vcsim_instance['json']['username'] }}"
password: "{{ vcsim_instance['json']['password'] }}"
datacenter: "{{ dc1 | basename }}"
name: "{{ ds1 | basename }}"
gather_nfs_mount_info: True
gather_vmfs_mount_info: True
register: datastore_facts_0004
- debug:
msg: "{{ datastore_facts_0004 }}"
- assert:
that:
- "datastore_facts_0004['datastores'][0]['name'] == ds1 | basename"
- "datastore_facts_0004['datastores'][0]['capacity'] is defined"
- name: get list of facts about one datastore in check mode
vmware_datastore_facts:
validate_certs: False
hostname: "{{ vcsim }}"
username: "{{ vcsim_instance['json']['username'] }}"
password: "{{ vcsim_instance['json']['password'] }}"
datacenter: "{{ dc1 | basename }}"
name: "{{ ds1 | basename }}"
register: datastore_facts_0005
- debug:
msg: "{{ datastore_facts_0005 }}"
- assert:
that:
- "datastore_facts_0005['datastores'][0]['name'] == ds1 | basename"
- "datastore_facts_0005['datastores'][0]['capacity'] is defined"