Repository: ansible/ansible

Issue:
vmware_guest uses another VM when explicitly asked to create a new one
<!---
Please verify first that your issue/request is not already reported in GitHub
-->

##### ISSUE TYPE
<!--- Pick one below and delete the rest: -->
 - Bug Report

##### COMPONENT NAME
<!--- Name of the module/plugin/task/feature -->
vmware_guest

##### ANSIBLE VERSION
<!--- Paste verbatim output from “ansible --version” between quotes below -->
v2.2 (with latest vmware_guest from devel)

##### SUMMARY
<!--- Explain the problem briefly -->
Something very fishy is going on.

I use vmware_guest to template a new system (unique hostname) that does not exist. But instead the module returns successful (with no change) and returns the facts of another hostname consistently.

Even when I run the same playbook to create 3 new VMs, it returns for each three the same VM facts of this specific running VM.

Any idea why this could be happening ?

We do a very simple
```yaml
- vmware_guest:
    hostname: '{{ vcenter_ipaddress }}'
    username: '{{ vcenter_username }}'
    password: '{{ vcenter_password }}'
    datacenter: '{{ vcenter_datacenter }}'
    cluster: '{{ vcenter_cluster }}'
    folder: '{{ vcenter_folder }}'
    template: 'windows-2012r2-template01'
    name: '{{ inventory_hostname_short }}'
    state: present
    wait_for_ip_address: yes
    validate_certs: no
    customize: yes
    domain: '{{ domain }}'
    dns_servers: '{{ dns_ip }}'
    ips: '{{ ansible_host }}'
    networks:
      '{{ vm_cidr }}':
        network: 'VM Network'
        gateway: '{{ gw_ip }}'
    register: vmware_facts
    connection: local
```

So nothing fancy at all. vSphere is v5.5


Discussion:
The name of the VM it is using has no relation to the VM we want to create. So there cannot be a mix-up because the name already exists. Let that be clear.
@dagwieers This isn't exactly a fix, but could help narrow down the problem.. 

Try removing the "Folder" parameter. I was having a similar issue this morning and removing the folder parameter allowed me to create a new VM. 

Same issue here. Removing the "Folder" parameter was a straightforward workaround ;)
I had to explicitly state /vm/Folder to make it do what was needed. Still the module takes a very long time before it actually starts to clone using the template. So I am reviewing the module to see how we can improve it. It seems to be using various strategies to find the VM (which does not exist)...

Also, the created VM was not created in the Folder I specified (which I assumed it would, why else provide a folder-location for a new VM, right ?). I think this module as it is now needs to be refactored before we release it to the public.
cc @jctanner
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->
@nerzhul @jctanner I have witnessed this issue with PR #19228 merged today.

This is *dangerous* as in my case I was testing if the module was idempotent (and the 3 VMs I targeted did exist), however the module modified another existing VM (3 times) with a very different name (but consistently the same one). And what's worse, I don't know what exactly was modified to that *other* VM that is in production, as the module did report a change (and the vSphere Client also states "Reconfigured virtual machine" three times).
The module is also slow as hell for doing something on a system that already exists (even when it somehow used a different one). It takes minutes while it isn't even templating anything.
@dagwieers what is your vsphere version ? what are instance names ?

For the slowness it's due to python append mode, i divided time by 3 but there are other required bottlenecks at this moment
@nerzhul I cannot disclose the instance-names, but they look like:

 - abcde-xyz##-sql-01
 - abcde-xyz##-dc-01
 - abcde-xyz##-scvmm-01

When I target the three abcde-xyz33-* systems, the module returns for each of the three systems: abcde-xyz17-scvmm-01. It seems as if it always returns this host. I wonder if the search functionality returns the complete list when no match is found, and whether the first match is not causing whatever system is first to be picked.

Personally, I would only do an exact VM name match, and clearly state that the module will not work when system names are not unique. I already rewrote the matching part before, but when merging my changes with your improvements I dropped a lot of that code :-/
And to be clear, the VM I am targeting *does* exist. And they live on the same datacenter and folder as the others VMs. So there should have been no other hit than the one by name.
Okay, thanks for the comment, i will do more tests using your pattern to identify what is the problem and how is this possible to target the wrong machine 
@stobias123 can you confirm you have the same problem using vmware_guest from module before merge or after merge ? It will permit me to be more precise on the code part to focus
I think i see the problem, it was added with this PR, maybe. Can you try a little test for me ?

Look at these lines:
https://github.com/ansible/ansible/commit/2c17f9becda010188e57f1751bfcbdf64a600ff8#diff-ed147163551d1eaa084b21f6bab29f96R635

Comment L635 & L641 & try again. These lines are required by VM creation without template, and if you are using a template & providing folder name you match this code which, i think, causes the problem
Err: don't comment L635 but only L641
@nerzhul The problem existed before your changes, so I doubt you introduced this.

But looking at the code, it seems to be correct. It only matches the path, not the VM name.
@dagwieers okay, if it existed before L641 is not the root cause. It could be very great if you can find which API call returns the wrong machine
BTW The only reason for me to explicitly add the folder, is that I want the *new* VM to be templated there. However folder was not used for that (at least not in the previous version of the module).

I don't see why the folder would be used to detect the VM, other than as a speed improvement. (But that would be bad taste IMO).

Resolving patch:
diff --git a/lib/ansible/modules/cloud/vmware/vmware_guest.py b/lib/ansible/modules/cloud/vmware/vmware_guest.py
--- a/lib/ansible/modules/cloud/vmware/vmware_guest.py
+++ b/lib/ansible/modules/cloud/vmware/vmware_guest.py
@@ -638,8 +638,10 @@ def getvm(self, name=None, uuid=None, folder=None, name_match=None, cache=False)
                     if not isinstance(vobj.parent, vim.Folder):
                         continue
                     if self.compile_folder_path_for_object(vobj) == searchpath:
-                        self.current_vm_obj = vobj
-                        return vobj
+                        # Match by name
+                        if vobj.config.name == name:
+                            self.current_vm_obj = vobj
+                            return vobj
 
             if name_match:
                 if name_match == 'first':


Test patch: