From fab815fc3b19e83c02efd0d8824ff19248fb048e Mon Sep 17 00:00:00 2001 From: Abhijeet Kasurde Date: Tue, 12 Feb 2019 16:31:42 +0530 Subject: [PATCH] VMware: Handle duplicate VM names in vmware_vm_facts (#45412) This fix changes facts returned from vmware_vm_facts to list of dict from dict of dict. Signed-off-by: Abhijeet Kasurde --- .../rst/porting_guides/porting_guide_2.8.rst | 4 ++ .../modules/cloud/vmware/vmware_vm_facts.py | 58 ++++++++++++------- .../targets/vmware_vm_facts/tasks/main.yml | 55 ++++++++++++------ 3 files changed, 77 insertions(+), 40 deletions(-) diff --git a/docs/docsite/rst/porting_guides/porting_guide_2.8.rst b/docs/docsite/rst/porting_guides/porting_guide_2.8.rst index 972093f1cdc..3494b6595f0 100644 --- a/docs/docsite/rst/porting_guides/porting_guide_2.8.rst +++ b/docs/docsite/rst/porting_guides/porting_guide_2.8.rst @@ -164,6 +164,10 @@ Noteworthy module changes * The ``docker_swarm_service`` module no longer sets a default for the ``user`` option. Before, the default was ``root``. +* ``vmware_vm_facts`` used to return dict of dict with virtual machine's facts. Ansible 2.8 and onwards will return list of dict with virtual machine's facts. + Please see module ``vmware_vm_facts`` documentation for example. + + Plugins ======= diff --git a/lib/ansible/modules/cloud/vmware/vmware_vm_facts.py b/lib/ansible/modules/cloud/vmware/vmware_vm_facts.py index 797c0fafba5..d8523f4e2cb 100644 --- a/lib/ansible/modules/cloud/vmware/vmware_vm_facts.py +++ b/lib/ansible/modules/cloud/vmware/vmware_vm_facts.py @@ -27,6 +27,7 @@ author: - Abhijeet Kasurde (@Akasurde) notes: - Tested on vSphere 5.5 and vSphere 6.5 +- From 2.8 and onwards, facts are returned as list of dict instead of dict. requirements: - python >= 2.6 - PyVmomi @@ -78,16 +79,32 @@ EXAMPLES = r''' - debug: var: vm_facts.virtual_machines + +- name: Get UUID from given VM Name + vmware_vm_facts: + hostname: '{{ vcenter_hostname }}' + username: '{{ vcenter_username }}' + password: '{{ vcenter_password }}' + vm_type: vm + delegate_to: localhost + register: vm_facts + +- debug: + msg: "{{ item.uuid }}" + with_items: + - "{{ vm_facts.virtual_machines | json_query(query) }}" + vars: + query: "[?guest_name=='DC0_H0_VM0']" ''' RETURN = r''' virtual_machines: - description: dictionary of virtual machines and their facts + description: list of dictionary of virtual machines and their facts returned: success - type: dict - sample: + type: list + sample: [ { - "ubuntu_t": { + "guest_name": "ubuntu_t", "cluster": null, "esxi_hostname": "10.76.33.226", "guest_fullname": "Ubuntu Linux (64-bit)", @@ -98,8 +115,8 @@ virtual_machines: "power_state": "poweredOff", "uuid": "4207072c-edd8-3bd5-64dc-903fd3a0db04", "vm_network": {} - } } + ] ''' try: @@ -118,10 +135,10 @@ class VmwareVmFacts(PyVmomi): # https://github.com/vmware/pyvmomi-community-samples/blob/master/samples/getallvms.py def get_all_virtual_machines(self): """ - Function to get all virtual machines and related configurations information + Get all virtual machines and related configurations information """ virtual_machines = get_all_objs(self.content, [vim.VirtualMachine]) - _virtual_machines = {} + _virtual_machines = [] for vm in virtual_machines: _ip_address = "" @@ -161,26 +178,25 @@ class VmwareVmFacts(PyVmomi): cluster_name = summary.runtime.host.parent.name virtual_machine = { - summary.config.name: { - "guest_fullname": summary.config.guestFullName, - "power_state": summary.runtime.powerState, - "ip_address": _ip_address, # Kept for backward compatibility - "mac_address": _mac_address, # Kept for backward compatibility - "uuid": summary.config.uuid, - "vm_network": net_dict, - "esxi_hostname": esxi_hostname, - "cluster": cluster_name, - } + "guest_name": summary.config.name, + "guest_fullname": summary.config.guestFullName, + "power_state": summary.runtime.powerState, + "ip_address": _ip_address, # Kept for backward compatibility + "mac_address": _mac_address, # Kept for backward compatibility + "uuid": summary.config.uuid, + "vm_network": net_dict, + "esxi_hostname": esxi_hostname, + "cluster": cluster_name, } vm_type = self.module.params.get('vm_type') is_template = _get_vm_prop(vm, ('config', 'template')) if vm_type == 'vm' and not is_template: - _virtual_machines.update(virtual_machine) + _virtual_machines.append(virtual_machine) elif vm_type == 'template' and is_template: - _virtual_machines.update(virtual_machine) + _virtual_machines.append(virtual_machine) elif vm_type == 'all': - _virtual_machines.update(virtual_machine) + _virtual_machines.append(virtual_machine) return _virtual_machines @@ -190,7 +206,7 @@ def main(): vm_type=dict(type='str', choices=['vm', 'all', 'template'], default='all'), ) module = AnsibleModule(argument_spec=argument_spec, - supports_check_mode=False) + supports_check_mode=True) vmware_vm_facts = VmwareVmFacts(module) _virtual_machines = vmware_vm_facts.get_all_virtual_machines() diff --git a/test/integration/targets/vmware_vm_facts/tasks/main.yml b/test/integration/targets/vmware_vm_facts/tasks/main.yml index 9052dfbf542..6d29cb9ca4e 100644 --- a/test/integration/targets/vmware_vm_facts/tasks/main.yml +++ b/test/integration/targets/vmware_vm_facts/tasks/main.yml @@ -16,6 +16,7 @@ - name: kill vcsim uri: url: http://{{ vcsim }}:5000/killall + - name: start vcsim uri: url: http://{{ vcsim }}:5000/spawn?cluster=2 @@ -29,8 +30,7 @@ - debug: var=vcsim_instance -# Testcase 0001: Get detail of vms from given esxi -- name: get facts about available vms +- name: Get facts about available vms vmware_vm_facts: validate_certs: false hostname: "{{ vcsim }}" @@ -38,25 +38,42 @@ password: "{{ vcsim_instance['json']['password'] }}" register: vm_facts_0001 -- debug: - msg: "{{ vm_facts_0001['virtual_machines'].keys() }}" +- name: Verify if VM facts exist + assert: + that: + - "item.esxi_hostname is defined" + - "item.guest_fullname is defined" + - "item.ip_address is defined" + - "item.mac_address is defined" + - "item.power_state is defined" + - "item.uuid is defined" + - "item.vm_network is defined" + with_items: + - "{{ vm_facts_0001.virtual_machines | json_query(query) }}" + vars: + query: "[?guest_name=='DC0_H0_VM0']" + -- name: get all VMs - uri: - url: http://{{ vcsim }}:5000/govc_find?filter=VM - register: host_info_result +- name: Get facts about available vms in check mode + vmware_vm_facts: + validate_certs: false + hostname: "{{ vcsim }}" + username: "{{ vcsim_instance['json']['username'] }}" + password: "{{ vcsim_instance['json']['password'] }}" + register: vm_facts_0001 + check_mode: yes -- name: verify if VM exists +- name: Verify if VM facts exist in check mode assert: that: - - "{{ item | basename in vm_facts_0001['virtual_machines'].keys()}}" - - "vm_facts_0001['virtual_machines'][item | basename]['cluster'] is defined" - - "vm_facts_0001['virtual_machines'][item | basename]['esxi_hostname'] is defined" - - "vm_facts_0001['virtual_machines'][item | basename]['guest_fullname'] is defined" - - "vm_facts_0001['virtual_machines'][item | basename]['ip_address'] is defined" - - "vm_facts_0001['virtual_machines'][item | basename]['mac_address'] is defined" - - "vm_facts_0001['virtual_machines'][item | basename]['power_state'] is defined" - - "vm_facts_0001['virtual_machines'][item | basename]['uuid'] is defined" - - "vm_facts_0001['virtual_machines'][item | basename]['vm_network'] is defined" + - "item.esxi_hostname is defined" + - "item.guest_fullname is defined" + - "item.ip_address is defined" + - "item.mac_address is defined" + - "item.power_state is defined" + - "item.uuid is defined" + - "item.vm_network is defined" with_items: - - "{{ host_info_result['json'] }}" + - "{{ vm_facts_0001.virtual_machines | json_query(query) }}" + vars: + query: "[?guest_name=='DC0_H0_VM0']"