From 1a8332d2cde376af8688d39e7da70f99dd5f747b Mon Sep 17 00:00:00 2001 From: Abhijeet Kasurde Date: Mon, 25 Feb 2019 15:02:56 +0530 Subject: [PATCH] VMware: new module: vmware_guest_customization_facts (#38588) This module gathers facts about customization specification created for virtual machine. Signed-off-by: Abhijeet Kasurde --- .../vmware_guest_customization_facts.py | 192 ++++++++++++++++++ .../vmware_guest_customization_facts/aliases | 2 + .../tasks/main.yml | 44 ++++ 3 files changed, 238 insertions(+) create mode 100644 lib/ansible/modules/cloud/vmware/vmware_guest_customization_facts.py create mode 100644 test/integration/targets/vmware_guest_customization_facts/aliases create mode 100644 test/integration/targets/vmware_guest_customization_facts/tasks/main.yml diff --git a/lib/ansible/modules/cloud/vmware/vmware_guest_customization_facts.py b/lib/ansible/modules/cloud/vmware/vmware_guest_customization_facts.py new file mode 100644 index 0000000000..cb4319d32f --- /dev/null +++ b/lib/ansible/modules/cloud/vmware/vmware_guest_customization_facts.py @@ -0,0 +1,192 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright: (c) 2018, Ansible Project +# Copyright: (c) 2018, Abhijeet Kasurde +# 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_guest_customization_facts +short_description: Gather facts about VM customization specifications +description: + - This module can be used to gather facts about customization specifications. + - All parameters and VMware object names are case sensitive. +version_added: 2.8 +author: + - Abhijeet Kasurde (@Akasurde) +notes: + - Tested on vSphere 6.0 and 6.5 +requirements: + - "python >= 2.6" + - PyVmomi +options: + spec_name: + description: + - Name of customization specification to find. + required: False +extends_documentation_fragment: vmware.documentation +''' + +EXAMPLES = ''' +- name: Gather facts about all customization specification + vmware_guest_customization_facts: + hostname: "{{ vcenter_hostname }}" + username: "{{ vcenter_username }}" + password: "{{ vcenter_password }}" + validate_certs: no + delegate_to: localhost + register: all_custom_spec_facts + +- name: Gather facts about customization specification with the given name + vmware_guest_customization_facts: + hostname: "{{ vcenter_hostname }}" + username: "{{ vcenter_username }}" + password: "{{ vcenter_password }}" + validate_certs: no + spec_name: custom_linux_spec + delegate_to: localhost + register: custom_spec_facts +''' + +RETURN = """ +custom_spec_facts: + description: metadata about the customization specification + returned: always + type: dict + sample: { + "assignip-eee0d684-44b7-457c-8c55-2585590b0d99": { + "change_version": "1523438001", + "description": "sample description", + "dns_server_list": [], + "dns_suffix_list": [], + "domain": "None", + "hostname": "sample1", + "hw_clock_utc": null, + "last_updated_time": "2018-04-11T09:13:21+00:00", + "name": "sample", + "nic_setting_map": [ + { + "dns_domain": null, + "gateway": [], + "ip_address": "192.168.10.10", + "net_bios": null, + "nic_dns_server_list": [], + "primary_wins": null, + "secondry_wins": null, + "subnet_mask": "255.255.255.0" + } + ], + "time_zone": null, + "type": "Linux" + }, + } +""" + +try: + 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 PyVmomi, vmware_argument_spec + + +class VmwareCustomSpecManger(PyVmomi): + def __init__(self, module): + super(VmwareCustomSpecManger, self).__init__(module) + self.cc_mgr = self.content.customizationSpecManager + if self.cc_mgr is None: + self.module.fail_json(msg="Failed to get customization spec manager.") + + def gather_custom_spec_facts(self): + """ + Gather facts about customization specifications + """ + + spec_name = self.params.get('spec_name', None) + specs_list = [] + if spec_name: + if self.cc_mgr.DoesCustomizationSpecExist(name=spec_name): + specs_list.append(spec_name) + else: + self.module.fail_json(msg="Unable to find customization specification named '%s'" % spec_name) + else: + available_specs = self.cc_mgr.info + for spec_info in available_specs: + specs_list.append(spec_info.name) + + spec_facts = dict() + for spec in specs_list: + current_spec = self.cc_mgr.GetCustomizationSpec(name=spec) + adapter_mapping_list = [] + for nic in current_spec.spec.nicSettingMap: + temp_data = dict( + mac_address=nic.macAddress, + ip_address=nic.adapter.ip.ipAddress, + subnet_mask=nic.adapter.subnetMask, + gateway=[gw for gw in nic.adapter.gateway], + nic_dns_server_list=[ndsl for ndsl in nic.adapter.dnsServerList], + dns_domain=nic.adapter.dnsDomain, + primary_wins=nic.adapter.primaryWINS, + secondry_wins=nic.adapter.secondaryWINS, + net_bios=nic.adapter.netBIOS, + ) + adapter_mapping_list.append(temp_data) + + current_hostname = None + if isinstance(current_spec.spec.identity.hostName, vim.vm.customization.PrefixNameGenerator): + current_hostname = current_spec.spec.identity.hostName.base + elif isinstance(current_spec.spec.identity.hostName, vim.vm.customization.FixedName): + current_hostname = current_spec.spec.identity.hostName.name + + spec_facts[spec] = dict( + # Spec + name=current_spec.info.name, + description=current_spec.info.description, + type=current_spec.info.type, + last_updated_time=current_spec.info.lastUpdateTime, + change_version=current_spec.info.changeVersion, + # Identity + hostname=current_hostname, + domain=current_spec.spec.identity.domain, + time_zone=current_spec.spec.identity.timeZone, + hw_clock_utc=current_spec.spec.identity.hwClockUTC, + # global IP Settings + dns_suffix_list=[i for i in current_spec.spec.globalIPSettings.dnsSuffixList], + dns_server_list=[i for i in current_spec.spec.globalIPSettings.dnsServerList], + # NIC setting map + nic_setting_map=adapter_mapping_list, + ) + return spec_facts + + +def main(): + argument_spec = vmware_argument_spec() + argument_spec.update( + spec_name=dict(type='str'), + ) + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True + ) + + pyv = VmwareCustomSpecManger(module) + try: + module.exit_json(custom_spec_facts=pyv.gather_custom_spec_facts()) + except Exception as exc: + module.fail_json(msg="Failed to gather facts with exception : %s" % to_text(exc)) + + +if __name__ == '__main__': + main() diff --git a/test/integration/targets/vmware_guest_customization_facts/aliases b/test/integration/targets/vmware_guest_customization_facts/aliases new file mode 100644 index 0000000000..845e8a6dad --- /dev/null +++ b/test/integration/targets/vmware_guest_customization_facts/aliases @@ -0,0 +1,2 @@ +cloud/vcenter +unsupported diff --git a/test/integration/targets/vmware_guest_customization_facts/tasks/main.yml b/test/integration/targets/vmware_guest_customization_facts/tasks/main.yml new file mode 100644 index 0000000000..0efd237ef0 --- /dev/null +++ b/test/integration/targets/vmware_guest_customization_facts/tasks/main.yml @@ -0,0 +1,44 @@ +# Test code for the vmware_guest_customization_facts module. +# Copyright: (c) 2018, Abhijeet Kasurde +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +# TODO: vcsim does not support customizationspecmanager related functionalities + +- 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 with no folders + uri: + url: http://{{ vcsim }}:5000/spawn?datacenter=1&cluster=1&folder=1 + register: vcsim_instance + +- name: Wait for Flask controller to come up online + wait_for: + host: "{{ vcsim }}" + port: 443 + state: started + +- debug: var=vcsim_instance +- debug: var=vmlist + +- name: Gather facts about given customization spec + vmware_guest_customization_facts: + validate_certs: False + hostname: "{{ vcsim }}" + username: "{{ vcsim_instance['json']['username'] }}" + password: "{{ vcsim_instance['json']['password'] }}" + spec_name: sample_spec + register: vm_custom_spec_facts + +- debug: var=vm_custom_spec_facts + +- assert: + that: + - "not vm_custom_spec_facts.changed"