From 50e9955a2376c7bc37235cbf60b8b6cf82ee4eb5 Mon Sep 17 00:00:00 2001 From: David Hewitt Date: Thu, 16 May 2019 09:48:07 +0100 Subject: [PATCH] VMware: Add new module vmware_folder_info (#54344) * Adds a new vmware module to support getting the folders and their paths within a datacenter * Add integration tests * Bump version added * Refactor integration test * Improve grammar in docs --- .../cloud/vmware/vmware_folder_info.py | 164 ++++++++++++++++++ .../targets/vmware_folder_info/aliases | 3 + .../targets/vmware_folder_info/tasks/main.yml | 51 ++++++ 3 files changed, 218 insertions(+) create mode 100644 lib/ansible/modules/cloud/vmware/vmware_folder_info.py create mode 100644 test/integration/targets/vmware_folder_info/aliases create mode 100644 test/integration/targets/vmware_folder_info/tasks/main.yml diff --git a/lib/ansible/modules/cloud/vmware/vmware_folder_info.py b/lib/ansible/modules/cloud/vmware/vmware_folder_info.py new file mode 100644 index 00000000000..14f2ba3fd3b --- /dev/null +++ b/lib/ansible/modules/cloud/vmware/vmware_folder_info.py @@ -0,0 +1,164 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright: (c) 2019, David Hewitt +# +# 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 = r''' +--- +module: vmware_folder_info +short_description: Provides information about folders in a datacenter +description: +- The module can be used to gather a hierarchical view of the folders that exist within a datacenter +version_added: 2.9 +author: +- David Hewitt (@davidmhewitt) +notes: +- Tested on vSphere 6.5 +requirements: +- python >= 2.6 +- PyVmomi +options: + datacenter: + description: + - Name of the datacenter. + required: true + type: str + aliases: ['datacenter_name'] +extends_documentation_fragment: vmware.documentation +''' + +EXAMPLES = r''' +- name: Provide information about vCenter folders + vmware_folder_info: + hostname: '{{ vcenter_hostname }}' + username: '{{ vcenter_username }}' + password: '{{ vcenter_password }}' + datacenter: datacenter_name + delegate_to: localhost + register: vcenter_folder_info +''' + +RETURN = r''' +folder_info: + description: + - dict about folders + returned: success + type: str + sample: + { + "datastoreFolders": { + "path": "/DC01/datastore", + "subfolders": { + "Local Datastores": { + "path": "/DC01/datastore/Local Datastores", + "subfolders": {} + } + } + }, + "hostFolders": { + "path": "/DC01/host", + "subfolders": {} + }, + "networkFolders": { + "path": "/DC01/network", + "subfolders": {} + }, + "vmFolders": { + "path": "/DC01/vm", + "subfolders": { + "Core Infrastructure Servers": { + "path": "/DC01/vm/Core Infrastructure Servers", + "subfolders": { + "Staging Network Services": { + "path": "/DC01/vm/Core Infrastructure Servers/Staging Network Services", + "subfolders": {} + }, + "VMware": { + "path": "/DC01/vm/Core Infrastructure Servers/VMware", + "subfolders": {} + } + } + } + } + } + } +''' + +try: + from pyVmomi import vim +except ImportError as import_err: + pass + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.vmware import vmware_argument_spec, PyVmomi + + +class VmwareFolderInfoManager(PyVmomi): + def __init__(self, module): + super(VmwareFolderInfoManager, self).__init__(module) + self.dc_name = self.params['datacenter'] + + def gather_folder_info(self): + datacenter = self.find_datacenter_by_name(self.dc_name) + if datacenter is None: + self.module.fail_json(msg="Failed to find the datacenter %s" % self.dc_name) + + folder_trees = {} + folder_trees['vmFolders'] = self.build_folder_tree(datacenter.vmFolder, "/%s/vm" % self.dc_name) + folder_trees['hostFolders'] = self.build_folder_tree(datacenter.hostFolder, "/%s/host" % self.dc_name) + folder_trees['networkFolders'] = self.build_folder_tree(datacenter.networkFolder, "/%s/network" % self.dc_name) + folder_trees['datastoreFolders'] = self.build_folder_tree(datacenter.datastoreFolder, "/%s/datastore" % self.dc_name) + + self.module.exit_json( + changed=False, + folder_info=folder_trees + ) + + def build_folder_tree(self, folder, path): + tree = { + 'path': path, + 'subfolders': {} + } + + children = None + if hasattr(folder, 'childEntity'): + children = folder.childEntity + + if children: + for child in children: + if child == folder: + continue + if isinstance(child, vim.Folder): + ctree = self.build_folder_tree(child, "%s/%s" % (path, child.name)) + tree['subfolders'][child.name] = dict.copy(ctree) + return tree + + +def main(): + argument_spec = vmware_argument_spec() + argument_spec.update( + datacenter=dict(type='str', required=True, aliases=['datacenter_name']) + ) + + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True, + ) + + vmware_folder_info_mgr = VmwareFolderInfoManager(module) + vmware_folder_info_mgr.gather_folder_info() + + +if __name__ == "__main__": + main() diff --git a/test/integration/targets/vmware_folder_info/aliases b/test/integration/targets/vmware_folder_info/aliases new file mode 100644 index 00000000000..eb39c07bac0 --- /dev/null +++ b/test/integration/targets/vmware_folder_info/aliases @@ -0,0 +1,3 @@ +shippable/vcenter/group1 +cloud/vcenter +needs/target/prepare_vmware_tests diff --git a/test/integration/targets/vmware_folder_info/tasks/main.yml b/test/integration/targets/vmware_folder_info/tasks/main.yml new file mode 100644 index 00000000000..8022b6b5abb --- /dev/null +++ b/test/integration/targets/vmware_folder_info/tasks/main.yml @@ -0,0 +1,51 @@ +# Test code for the vmware_folder_info module. +# Copyright: (c) 2019, David Hewitt (@davidmhewitt) +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +- import_role: + name: prepare_vmware_tests + +- name: create example toplevel folder + vcenter_folder: + <<: &vcenter_folder_data + hostname: "{{ vcenter_hostname }}" + username: "{{ vcenter_username }}" + password: "{{ vcenter_password }}" + datacenter: "{{ dc1 | basename }}" + validate_certs: no + folder_name: "toplevel" + +- name: create an example child folder + vcenter_folder: + <<: *vcenter_folder_data + folder_name: "child_folder" + parent_folder: "toplevel" + +# Testcase 0001: Get details about folders +- name: get info about folders + vmware_folder_info: + <<: *vcenter_folder_data + register: folder_info_0001 + +- debug: var=folder_info_0001 + +- assert: + that: + - "{{ item }} is defined" + with_items: + - folder_info_0001['folder_info'] + - folder_info_0001['folder_info']['datastoreFolders'] + - folder_info_0001['folder_info']['hostFolders'] + - folder_info_0001['folder_info']['vmFolders'] + - folder_info_0001['folder_info']['networkFolders'] + - folder_info_0001['folder_info']['vmFolders']['subfolders']['toplevel'] + - folder_info_0001['folder_info']['vmFolders']['subfolders']['toplevel']['subfolders']['child_folder'] + +- assert: + that: + - "folder_info_0001['folder_info']['datastoreFolders']['path'] == \"/{{ dc1 | basename }}/datastore\"" + - "folder_info_0001['folder_info']['hostFolders']['path'] == \"/{{ dc1 | basename }}/host\"" + - "folder_info_0001['folder_info']['vmFolders']['path'] == \"/{{ dc1 | basename }}/vm\"" + - "folder_info_0001['folder_info']['networkFolders']['path'] == \"/{{ dc1 | basename }}/network\"" + - "folder_info_0001['folder_info']['vmFolders']['subfolders']['toplevel']['path'] == \"/{{ dc1 | basename }}/vm/toplevel\"" + - "folder_info_0001['folder_info']['vmFolders']['subfolders']['toplevel']['subfolders']['child_folder']['path'] == \"/{{ dc1 | basename }}/vm/toplevel/child_folder\""