Add a vmware_datastore_facts module (#30815)

Fix a bunch of things mentioned in the review.

Delete commented code from module.  Add fix for vcsim not returning
uncommitted.
Add integration test.

Add changes suggested
This commit is contained in:
Tim Rightnour 2017-12-10 08:55:55 -07:00 committed by ansibot
parent 326b208b19
commit 51475cd623
4 changed files with 335 additions and 0 deletions

View file

@ -144,6 +144,21 @@ def find_datacenter_by_name(content, datacenter_name):
return None
def get_parent_datacenter(obj):
""" Walk the parent tree to find the objects datacenter """
if isinstance(obj, vim.Datacenter):
return obj
datacenter = None
while True:
if not hasattr(obj, 'parent'):
break
obj = obj.parent
if isinstance(obj, vim.Datacenter):
datacenter = obj
break
return datacenter
def find_datastore_by_name(content, datastore_name):
datastores = get_all_objs(content, [vim.Datastore])

View file

@ -0,0 +1,188 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2017 Tim Rightnour <thegarbledone@gmail.com>
# 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
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: vmware_datastore_facts
short_description: Gather facts about datastores
description:
- Gather facts about datastores in VMWare
version_added: 2.5
author:
- Tim Rightnour (@garbled1)
notes:
- Tested on vSphere 5.5
requirements:
- "python >= 2.6"
- PyVmomi
options:
name:
description:
- Name of a datastore to match
datacenter:
description:
- Datacenter to search for datastores
- This is required if cluster is not supplied
cluster:
description:
- Cluster to search for datastores
- This is required if datacenter is not supplied
required: False
extends_documentation_fragment: vmware.documentation
'''
EXAMPLES = '''
- name: Gather facts from standalone ESXi server having datacenter as 'ha-datacenter'
vmware_datastore_facts:
hostname: 192.168.1.209
username: administrator@vsphere.local
password: vmware
datacenter: ha-datacenter
validate_certs: no
delegate_to: localhost
register: facts
'''
RETURN = """
instance:
description: metadata about the available datastores
returned: always
type: dict
sample: None
"""
try:
import pyVmomi
from pyVmomi import vim
except ImportError:
pass
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_text
from ansible.module_utils.vmware import (connect_to_api, vmware_argument_spec,
get_all_objs, HAS_PYVMOMI, find_obj,
find_cluster_by_name, get_parent_datacenter)
class PyVmomiCache(object):
""" This class caches references to objects which are requested multiples times but not modified """
def __init__(self, content, dc_name=None):
self.content = content
self.dc_name = dc_name
self.clusters = {}
self.parent_datacenters = {}
def get_all_objs(self, content, types, confine_to_datacenter=True):
""" Wrapper around get_all_objs to set datacenter context """
objects = get_all_objs(content, types)
if confine_to_datacenter:
if hasattr(objects, 'items'):
# resource pools come back as a dictionary
for k, v in objects.items():
parent_dc = get_parent_datacenter(k)
if parent_dc.name != self.dc_name:
objects.pop(k, None)
else:
# everything else should be a list
objects = [x for x in objects if get_parent_datacenter(x).name == self.dc_name]
return objects
class PyVmomiHelper(object):
def __init__(self, module):
if not HAS_PYVMOMI:
module.fail_json(msg='pyvmomi module required')
self.module = module
self.params = module.params
self.content = connect_to_api(self.module)
self.cache = PyVmomiCache(self.content, dc_name=self.params['datacenter'])
def lookup_datastore(self):
datastores = self.cache.get_all_objs(self.content, [vim.Datastore], confine_to_datacenter=True)
return datastores
def lookup_datastore_by_cluster(self):
cluster = find_cluster_by_name(self.content, self.params['cluster'])
if not cluster:
self.module.fail_json(msg='Failed to find cluster "%(cluster)s"' % self.params)
c_dc = cluster.datastore
return c_dc
def main():
argument_spec = vmware_argument_spec()
argument_spec.update(
name=dict(type='str'),
datacenter=dict(type='str'),
cluster=dict(type='str')
)
module = AnsibleModule(argument_spec=argument_spec,
required_one_of=[
['cluster', 'datacenter'],
],
)
result = dict(changed=False)
pyv = PyVmomiHelper(module)
if module.params['cluster']:
dxs = pyv.lookup_datastore_by_cluster()
else:
dxs = pyv.lookup_datastore()
datastores = list()
for ds in 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
if module.params['name']:
if dds['name'] == module.params['name']:
datastores.extend([dds])
else:
datastores.extend([dds])
result['datastores'] = datastores
# found a datastore
if datastores:
try:
module.exit_json(**result)
except Exception as exc:
module.fail_json(msg="Fact gather failed with exception %s" % to_text(exc))
else:
msg = "Unable to gather datastore facts"
if module.params['name']:
msg += " for %(name)s" % module.params
msg += " in datacenter %(datacenter)s" % module.params
module.fail_json(msg=msg)
if __name__ == '__main__':
main()

View file

@ -0,0 +1,3 @@
posix/ci/cloud/group1/vcenter
cloud/vcenter
destructive

View file

@ -0,0 +1,129 @@
# Test code for the vmware_datastore_facts module.
# (c) 2017, Tim Rightnour <thegarbledone@gmail.com>
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
#
- name: make sure pyvmomi is installed
pip:
name: pyvmomi
state: latest
- name: store the vcenter container ip
set_fact:
vcsim: "{{ lookup('env', 'vcenter_host') }}"
- debug:
var: vcsim
- name: Wait for Flask controller to come up online
wait_for:
host: "{{ vcsim }}"
port: 5000
state: started
- name: kill vcsim
uri:
url: "{{ 'http://' + vcsim + ':5000/killall' }}"
- name: start vcsim
uri:
url: "{{ 'http://' + vcsim + ':5000/spawn?ds=2&datacenter=1&cluster=1&folder=0' }}"
register: vcsim_instance
- name: Wait for vcsim server to come up online
wait_for:
host: "{{ vcsim }}"
port: 443
state: started
- name: get a list of Clusters from vcsim
uri:
url: "{{ 'http://' + vcsim + ':5000/govc_find?filter=CCR' }}"
register: clusters
- set_fact:
cl1: "{{ clusters['json'][0] }}"
- name: get a list of Datacenters from vcsim
uri:
url: "{{ 'http://' + vcsim + ':5000/govc_find?filter=DC' }}"
register: datacenters
- set_fact:
dc1: "{{ datacenters['json'][0] }}"
- name: get a list of Datastores from vcsim
uri:
url: "{{ 'http://' + vcsim + ':5000/govc_find?filter=D' }}"
register: datastores
- set_fact:
ds1: "{{ datastores['json'][0] }}"
# Testcase 0001: Get a full list of datastores in a datacenter
- name: get list of facts about datastores
vmware_datastore_facts:
validate_certs: False
hostname: "{{ vcsim }}"
username: "{{ vcsim_instance['json']['username'] }}"
password: "{{ vcsim_instance['json']['password'] }}"
datacenter: "{{ dc1 | basename }}"
register: datastore_facts_0001
- debug:
msg: "{{ datastore_facts_0001 }}"
- assert:
that:
- "datastore_facts_0001['datastores'][0]['capacity'] is defined"
- "datastore_facts_0001['datastores'][1]['capacity'] is defined"
# Testcase 0002: Get a full list of datastores in a cluster
- name: get list of facts about datastores - no dc
vmware_datastore_facts:
validate_certs: False
hostname: "{{ vcsim }}"
username: "{{ vcsim_instance['json']['username'] }}"
password: "{{ vcsim_instance['json']['password'] }}"
cluster: "{{ cl1 | basename }}"
register: datastore_facts_0002
- debug:
msg: "{{ datastore_facts_0002 }}"
- assert:
that:
- "datastore_facts_0002['datastores'][0]['capacity'] is defined"
- "datastore_facts_0002['datastores'][1]['capacity'] is defined"
# Testcase 0003: Find a specific datastore
- name: get list of 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 }}"
register: datastore_facts_0003
- debug:
msg: "{{ datastore_facts_0003 }}"
- assert:
that:
- "datastore_facts_0003['datastores'][0]['name'] == ds1 | basename"
- "datastore_facts_0003['datastores'][0]['capacity'] is defined"