From e18d5ea8b33e9f9fc4b4946c9aa4972f44647129 Mon Sep 17 00:00:00 2001
From: Jake Hill <jake@naphta.uk>
Date: Mon, 25 Feb 2019 08:37:07 +0000
Subject: [PATCH] VMware: Add support in VMWare modules for BIOS and instance
 UUID's (#44399)

* Add support for changing UUID type referenced
* Update all appropriate VMware modules to include UUID type
* Add integration test for filtering on instance UUID
---
 lib/ansible/module_utils/vmware.py            | 12 +++++--
 .../modules/cloud/vmware/vmware_guest.py      |  7 ++++
 .../cloud/vmware/vmware_guest_boot_facts.py   | 15 ++++++--
 .../cloud/vmware/vmware_guest_boot_manager.py | 15 ++++++--
 .../vmware/vmware_guest_custom_attributes.py  |  7 ++++
 .../cloud/vmware/vmware_guest_disk_facts.py   |  7 ++++
 .../cloud/vmware/vmware_guest_facts.py        |  8 +++++
 .../vmware/vmware_guest_file_operation.py     | 10 ++++--
 .../modules/cloud/vmware/vmware_guest_find.py | 15 ++++++--
 .../modules/cloud/vmware/vmware_guest_move.py |  7 ++++
 .../cloud/vmware/vmware_guest_powerstate.py   |  7 ++++
 .../cloud/vmware/vmware_guest_snapshot.py     | 11 ++++--
 .../vmware/vmware_guest_snapshot_facts.py     | 11 ++++--
 .../cloud/vmware/vmware_guest_tools_wait.py   |  7 ++++
 .../modules/cloud/vmware/vmware_vm_shell.py   | 11 ++++--
 .../modules/cloud/vmware/vmware_vmotion.py    | 16 +++++++--
 .../targets/vmware_guest_facts/tasks/main.yml | 34 +++++++++++++++++++
 17 files changed, 179 insertions(+), 21 deletions(-)

diff --git a/lib/ansible/module_utils/vmware.py b/lib/ansible/module_utils/vmware.py
index 68e46b9d288..cae43438109 100644
--- a/lib/ansible/module_utils/vmware.py
+++ b/lib/ansible/module_utils/vmware.py
@@ -181,7 +181,8 @@ def find_network_by_name(content, network_name):
     return find_object_by_name(content, network_name, [vim.Network])
 
 
-def find_vm_by_id(content, vm_id, vm_id_type="vm_name", datacenter=None, cluster=None, folder=None, match_first=False):
+def find_vm_by_id(content, vm_id, vm_id_type="vm_name", datacenter=None,
+                  cluster=None, folder=None, match_first=False):
     """ UUID is unique to a VM, every other id returns the first match. """
     si = content.searchIndex
     vm = None
@@ -191,6 +192,8 @@ def find_vm_by_id(content, vm_id, vm_id_type="vm_name", datacenter=None, cluster
     elif vm_id_type == 'uuid':
         # Search By BIOS UUID rather than instance UUID
         vm = si.FindByUuid(datacenter=datacenter, instanceUuid=False, uuid=vm_id, vmSearch=True)
+    elif vm_id_type == 'instance_uuid':
+        vm = si.FindByUuid(datacenter=datacenter, instanceUuid=True, uuid=vm_id, vmSearch=True)
     elif vm_id_type == 'ip':
         vm = si.FindByIp(datacenter=datacenter, ip=vm_id, vmSearch=True)
     elif vm_id_type == 'vm_name':
@@ -870,9 +873,12 @@ class PyVmomi(object):
         vm_obj = None
         user_desired_path = None
 
-        if self.params['uuid']:
+        if self.params['uuid'] and not self.params['use_instance_uuid']:
             vm_obj = find_vm_by_id(self.content, vm_id=self.params['uuid'], vm_id_type="uuid")
-
+        elif self.params['uuid'] and self.params['use_instance_uuid']:
+            vm_obj = find_vm_by_id(self.content,
+                                   vm_id=self.params['uuid'],
+                                   vm_id_type="instance_uuid")
         elif self.params['name']:
             objects = self.get_managed_objects_properties(vim_type=vim.VirtualMachine, properties=['name'])
             vms = []
diff --git a/lib/ansible/modules/cloud/vmware/vmware_guest.py b/lib/ansible/modules/cloud/vmware/vmware_guest.py
index 8ee221b4597..344cc78e0df 100644
--- a/lib/ansible/modules/cloud/vmware/vmware_guest.py
+++ b/lib/ansible/modules/cloud/vmware/vmware_guest.py
@@ -82,6 +82,12 @@ options:
     - This is required if C(name) is not supplied.
     - If virtual machine does not exists, then this parameter is ignored.
     - Please note that a supplied UUID will be ignored on virtual machine creation, as VMware creates the UUID internally.
+  use_instance_uuid:
+    description:
+    - Whether to use the VMWare instance UUID rather than the BIOS UUID.
+    default: no
+    type: bool
+    version_added: '2.8'
   template:
     description:
     - Template or existing virtual machine used to create new virtual machine.
@@ -2523,6 +2529,7 @@ def main():
         name=dict(type='str'),
         name_match=dict(type='str', choices=['first', 'last'], default='first'),
         uuid=dict(type='str'),
+        use_instance_uuid=dict(type='bool', default=False),
         folder=dict(type='str'),
         guest_id=dict(type='str'),
         disk=dict(type='list', default=[]),
diff --git a/lib/ansible/modules/cloud/vmware/vmware_guest_boot_facts.py b/lib/ansible/modules/cloud/vmware/vmware_guest_boot_facts.py
index b14b6c24062..d99f49f793e 100644
--- a/lib/ansible/modules/cloud/vmware/vmware_guest_boot_facts.py
+++ b/lib/ansible/modules/cloud/vmware/vmware_guest_boot_facts.py
@@ -36,8 +36,14 @@ options:
      - This is required if C(uuid) parameter is not supplied.
    uuid:
      description:
-     - UUID of the instance to manage if known, this is VMware's BIOS UUID.
+     - UUID of the instance to manage if known, this is VMware's BIOS UUID by default.
      - This is required if C(name) parameter is not supplied.
+   use_instance_uuid:
+     description:
+     - Whether to use the VMWare instance UUID rather than the BIOS UUID.
+     default: no
+     type: bool
+     version_added: '2.8'
    name_match:
      description:
      - If multiple virtual machines matching the name, use the first or last found.
@@ -93,13 +99,17 @@ class VmBootFactsManager(PyVmomi):
         super(VmBootFactsManager, self).__init__(module)
         self.name = self.params['name']
         self.uuid = self.params['uuid']
+        self.use_instance_uuid = self.params['use_instance_uuid']
         self.vm = None
 
     def _get_vm(self):
         vms = []
 
         if self.uuid:
-            vm_obj = find_vm_by_id(self.content, vm_id=self.uuid, vm_id_type="uuid")
+            if self.use_instance_uuid:
+                vm_obj = find_vm_by_id(self.content, vm_id=self.uuid, vm_id_type="use_instance_uuid")
+            else:
+                vm_obj = find_vm_by_id(self.content, vm_id=self.uuid, vm_id_type="uuid")
             if vm_obj is None:
                 self.module.fail_json(msg="Failed to find the virtual machine with UUID : %s" % self.uuid)
             vms = [vm_obj]
@@ -155,6 +165,7 @@ def main():
     argument_spec.update(
         name=dict(type='str'),
         uuid=dict(type='str'),
+        use_instance_uuid=dict(type='bool', default=False),
         name_match=dict(
             choices=['first', 'last'],
             default='first'
diff --git a/lib/ansible/modules/cloud/vmware/vmware_guest_boot_manager.py b/lib/ansible/modules/cloud/vmware/vmware_guest_boot_manager.py
index a138adac2ff..5717e2515fd 100644
--- a/lib/ansible/modules/cloud/vmware/vmware_guest_boot_manager.py
+++ b/lib/ansible/modules/cloud/vmware/vmware_guest_boot_manager.py
@@ -36,8 +36,14 @@ options:
      - This is required if C(uuid) parameter is not supplied.
    uuid:
      description:
-     - UUID of the instance to manage if known, this is VMware's BIOS UUID.
+     - UUID of the instance to manage if known, this is VMware's BIOS UUID by default.
      - This is required if C(name) parameter is not supplied.
+   use_instance_uuid:
+     description:
+     - Whether to use the VMWare instance UUID rather than the BIOS UUID.
+     default: no
+     type: bool
+     version_added: '2.8'
    boot_order:
      description:
      - List of the boot devices.
@@ -152,13 +158,17 @@ class VmBootManager(PyVmomi):
         super(VmBootManager, self).__init__(module)
         self.name = self.params['name']
         self.uuid = self.params['uuid']
+        self.use_instance_uuid = self.params['use_instance_uuid']
         self.vm = None
 
     def _get_vm(self):
         vms = []
 
         if self.uuid:
-            vm_obj = find_vm_by_id(self.content, vm_id=self.uuid, vm_id_type="uuid")
+            if self.use_instance_uuid:
+                vm_obj = find_vm_by_id(self.content, vm_id=self.uuid, vm_id_type="instance_uuid")
+            else:
+                vm_obj = find_vm_by_id(self.content, vm_id=self.uuid, vm_id_type="uuid")
             if vm_obj is None:
                 self.module.fail_json(msg="Failed to find the virtual machine with UUID : %s" % self.uuid)
             vms = [vm_obj]
@@ -314,6 +324,7 @@ def main():
     argument_spec.update(
         name=dict(type='str'),
         uuid=dict(type='str'),
+        use_instance_uuid=dict(type='bool', default=False),
         boot_order=dict(
             type='list',
             default=[],
diff --git a/lib/ansible/modules/cloud/vmware/vmware_guest_custom_attributes.py b/lib/ansible/modules/cloud/vmware/vmware_guest_custom_attributes.py
index 356a453ecb4..1ae4e31605b 100644
--- a/lib/ansible/modules/cloud/vmware/vmware_guest_custom_attributes.py
+++ b/lib/ansible/modules/cloud/vmware/vmware_guest_custom_attributes.py
@@ -48,6 +48,12 @@ options:
      description:
      - UUID of the virtual machine to manage if known. This is VMware's unique identifier.
      - This is required parameter, if C(name) is not supplied.
+   use_instance_uuid:
+     description:
+     - Whether to use the VMWare instance UUID rather than the BIOS UUID.
+     default: no
+     type: bool
+     version_added: '2.8'
    folder:
      description:
      - Absolute path to find an existing guest.
@@ -180,6 +186,7 @@ def main():
         name=dict(required=True, type='str'),
         folder=dict(type='str'),
         uuid=dict(type='str'),
+        use_instance_uuid=dict(type='bool', default=False),
         state=dict(type='str', default='present',
                    choices=['absent', 'present']),
         attributes=dict(
diff --git a/lib/ansible/modules/cloud/vmware/vmware_guest_disk_facts.py b/lib/ansible/modules/cloud/vmware/vmware_guest_disk_facts.py
index f77aa2590c6..c740042916e 100644
--- a/lib/ansible/modules/cloud/vmware/vmware_guest_disk_facts.py
+++ b/lib/ansible/modules/cloud/vmware/vmware_guest_disk_facts.py
@@ -39,6 +39,12 @@ options:
      description:
      - UUID of the instance to gather facts if known, this is VMware's unique identifier.
      - This is required parameter, if parameter C(name) is not supplied.
+   use_instance_uuid:
+     description:
+     - Whether to use the VMWare instance UUID rather than the BIOS UUID.
+     default: no
+     type: bool
+     version_added: '2.8'
    folder:
      description:
      - Destination folder, absolute or relative path to find an existing guest.
@@ -166,6 +172,7 @@ def main():
     argument_spec.update(
         name=dict(type='str'),
         uuid=dict(type='str'),
+        use_instance_uuid=dict(type='bool', default=False),
         folder=dict(type='str'),
         datacenter=dict(type='str', required=True),
     )
diff --git a/lib/ansible/modules/cloud/vmware/vmware_guest_facts.py b/lib/ansible/modules/cloud/vmware/vmware_guest_facts.py
index 13c1c726aaf..ea0facbba1d 100644
--- a/lib/ansible/modules/cloud/vmware/vmware_guest_facts.py
+++ b/lib/ansible/modules/cloud/vmware/vmware_guest_facts.py
@@ -43,6 +43,12 @@ options:
      description:
      - UUID of the instance to manage if known, this is VMware's unique identifier.
      - This is required if name is not supplied.
+   use_instance_uuid:
+     description:
+     - Whether to use the VMWare instance UUID rather than the BIOS UUID.
+     default: no
+     type: bool
+     version_added: '2.8'
    folder:
      description:
      - Destination folder, absolute or relative path to find an existing guest.
@@ -155,6 +161,7 @@ from ansible.module_utils._text import to_text
 from ansible.module_utils.vmware import PyVmomi, vmware_argument_spec
 from ansible.module_utils.vmware_rest_client import VmwareRestClient
 try:
+    from com.vmware.vapi.std_client import DynamicID
     from com.vmware.cis.tagging_client import Tag, TagAssociation
     HAS_VCLOUD = True
 except ImportError:
@@ -179,6 +186,7 @@ def main():
         name=dict(type='str'),
         name_match=dict(type='str', choices=['first', 'last'], default='first'),
         uuid=dict(type='str'),
+        use_instance_uuid=dict(type='bool', default=False),
         folder=dict(type='str'),
         datacenter=dict(type='str', required=True),
         tags=dict(type='bool', default=False)
diff --git a/lib/ansible/modules/cloud/vmware/vmware_guest_file_operation.py b/lib/ansible/modules/cloud/vmware/vmware_guest_file_operation.py
index 13658d5a701..c3dfcb850f0 100644
--- a/lib/ansible/modules/cloud/vmware/vmware_guest_file_operation.py
+++ b/lib/ansible/modules/cloud/vmware/vmware_guest_file_operation.py
@@ -65,6 +65,7 @@ options:
         default: vm_name
         choices:
             - 'uuid'
+            - 'instance_uuid'
             - 'dns_name'
             - 'inventory_path'
             - 'vm_name'
@@ -194,8 +195,11 @@ class VmwareGuestFileManager(PyVmomi):
         if module.params['vm_id_type'] == 'inventory_path':
             vm = find_vm_by_id(self.content, vm_id=module.params['vm_id'], vm_id_type="inventory_path", folder=folder)
         else:
-            vm = find_vm_by_id(self.content, vm_id=module.params['vm_id'], vm_id_type=module.params['vm_id_type'],
-                               datacenter=datacenter, cluster=cluster)
+            vm = find_vm_by_id(self.content,
+                               vm_id=module.params['vm_id'],
+                               vm_id_type=module.params['vm_id_type'],
+                               datacenter=datacenter,
+                               cluster=cluster)
 
         if not vm:
             module.fail_json(msg='Unable to find virtual machine.')
@@ -391,7 +395,7 @@ def main():
         vm_id_type=dict(
             default='vm_name',
             type='str',
-            choices=['inventory_path', 'uuid', 'dns_name', 'vm_name']),
+            choices=['inventory_path', 'uuid', 'instance_uuid', 'dns_name', 'vm_name']),
         vm_username=dict(type='str', required=True),
         vm_password=dict(type='str', no_log=True, required=True),
         directory=dict(
diff --git a/lib/ansible/modules/cloud/vmware/vmware_guest_find.py b/lib/ansible/modules/cloud/vmware/vmware_guest_find.py
index 64c912bc395..9a33bcbe651 100644
--- a/lib/ansible/modules/cloud/vmware/vmware_guest_find.py
+++ b/lib/ansible/modules/cloud/vmware/vmware_guest_find.py
@@ -34,8 +34,14 @@ options:
      - This is required if C(uuid) parameter is not supplied.
    uuid:
      description:
-     - UUID of the instance to manage if known, this is VMware's BIOS UUID.
+     - UUID of the instance to manage if known, this is VMware's BIOS UUID by default.
      - This is required if C(name) parameter is not supplied.
+   use_instance_uuid:
+     description:
+     - Whether to use the VMWare instance UUID rather than the BIOS UUID.
+     default: no
+     type: bool
+     version_added: '2.8'
    datacenter:
      description:
      - Destination datacenter for the find operation.
@@ -90,13 +96,17 @@ class PyVmomiHelper(PyVmomi):
         super(PyVmomiHelper, self).__init__(module)
         self.name = self.params['name']
         self.uuid = self.params['uuid']
+        self.use_instance_uuid = self.params['use_instance_uuid']
 
     def getvm_folder_paths(self):
         results = []
         vms = []
 
         if self.uuid:
-            vm_obj = find_vm_by_id(self.content, vm_id=self.uuid, vm_id_type="uuid")
+            if self.use_instance_uuid:
+                vm_obj = find_vm_by_id(self.content, vm_id=self.uuid, vm_id_type="instance_uuid")
+            else:
+                vm_obj = find_vm_by_id(self.content, vm_id=self.uuid, vm_id_type="uuid")
             if vm_obj is None:
                 self.module.fail_json(msg="Failed to find the virtual machine with UUID : %s" % self.uuid)
             vms = [vm_obj]
@@ -119,6 +129,7 @@ def main():
     argument_spec.update(
         name=dict(type='str'),
         uuid=dict(type='str'),
+        use_instance_uuid=dict(type='bool', default=False),
         datacenter=dict(removed_in_version=2.9, type='str')
     )
 
diff --git a/lib/ansible/modules/cloud/vmware/vmware_guest_move.py b/lib/ansible/modules/cloud/vmware/vmware_guest_move.py
index ae960f1fbea..ccc0445a77e 100644
--- a/lib/ansible/modules/cloud/vmware/vmware_guest_move.py
+++ b/lib/ansible/modules/cloud/vmware/vmware_guest_move.py
@@ -37,6 +37,12 @@ options:
         description:
             - UUID of the virtual machine to manage if known, this is VMware's unique identifier.
             - This is required if C(name) is not supplied.
+   use_instance_uuid:
+        description:
+            - Whether to use the VMWare instance UUID rather than the BIOS UUID.
+        default: no
+        type: bool
+        version_added: '2.8'
    name_match:
         description:
             - If multiple virtual machines matching the name, use the first or last found.
@@ -169,6 +175,7 @@ def main():
         name_match=dict(
             type='str', choices=['first', 'last'], default='first'),
         uuid=dict(type='str'),
+        use_instance_uuid=dict(type='bool', default=False),
         dest_folder=dict(type='str', required=True),
         datacenter=dict(type='str', required=True),
     )
diff --git a/lib/ansible/modules/cloud/vmware/vmware_guest_powerstate.py b/lib/ansible/modules/cloud/vmware/vmware_guest_powerstate.py
index 522931657dd..340cb776a02 100644
--- a/lib/ansible/modules/cloud/vmware/vmware_guest_powerstate.py
+++ b/lib/ansible/modules/cloud/vmware/vmware_guest_powerstate.py
@@ -42,6 +42,12 @@ options:
     description:
     - UUID of the instance to manage if known, this is VMware's unique identifier.
     - This is required if name is not supplied.
+  use_instance_uuid:
+    description:
+    - Whether to use the VMWare instance UUID rather than the BIOS UUID.
+    default: no
+    type: bool
+    version_added: '2.8'
   folder:
     description:
     - Destination folder, absolute or relative path to find an existing guest or create the new guest.
@@ -139,6 +145,7 @@ def main():
         name=dict(type='str'),
         name_match=dict(type='str', choices=['first', 'last'], default='first'),
         uuid=dict(type='str'),
+        use_instance_uuid=dict(type='bool', default=False),
         folder=dict(type='str', default='/vm'),
         force=dict(type='bool', default=False),
         scheduled_at=dict(type='str'),
diff --git a/lib/ansible/modules/cloud/vmware/vmware_guest_snapshot.py b/lib/ansible/modules/cloud/vmware/vmware_guest_snapshot.py
index 55222b9aa53..1e554770c89 100644
--- a/lib/ansible/modules/cloud/vmware/vmware_guest_snapshot.py
+++ b/lib/ansible/modules/cloud/vmware/vmware_guest_snapshot.py
@@ -52,8 +52,14 @@ options:
      choices: ['first', 'last']
    uuid:
      description:
-     - UUID of the instance to manage if known, this is VMware's unique identifier.
-     - This is required parameter, if C(name) is not supplied.
+     - UUID of the instance to manage if known, this is VMware's BIOS UUID by default.
+     - This is required if C(name) parameter is not supplied.
+   use_instance_uuid:
+     description:
+     - Whether to use the VMWare instance UUID rather than the BIOS UUID.
+     default: no
+     type: bool
+     version_added: '2.8'
    folder:
      description:
      - Destination folder, absolute or relative path to find an existing guest.
@@ -367,6 +373,7 @@ def main():
         name=dict(type='str'),
         name_match=dict(type='str', choices=['first', 'last'], default='first'),
         uuid=dict(type='str'),
+        use_instance_uuid=dict(type='bool', default=False),
         folder=dict(type='str'),
         datacenter=dict(required=True, type='str'),
         snapshot_name=dict(type='str'),
diff --git a/lib/ansible/modules/cloud/vmware/vmware_guest_snapshot_facts.py b/lib/ansible/modules/cloud/vmware/vmware_guest_snapshot_facts.py
index f2bc92d47f3..55d4f2e5397 100644
--- a/lib/ansible/modules/cloud/vmware/vmware_guest_snapshot_facts.py
+++ b/lib/ansible/modules/cloud/vmware/vmware_guest_snapshot_facts.py
@@ -35,9 +35,15 @@ options:
      - This is required if C(uuid) is not supplied.
    uuid:
      description:
-     - UUID of the instance to manage if known, this value is VMware's unique identifier.
-     - This is required if C(name) is not supplied.
+     - UUID of the instance to manage if known, this is VMware's BIOS UUID by default.
+     - This is required if C(name) parameter is not supplied.
      - The C(folder) is ignored, if C(uuid) is provided.
+   use_instance_uuid:
+     description:
+     - Whether to use the VMWare instance UUID rather than the BIOS UUID.
+     default: no
+     type: bool
+     version_added: '2.8'
    folder:
      description:
      - Destination folder, absolute or relative path to find an existing guest.
@@ -125,6 +131,7 @@ def main():
     argument_spec.update(
         name=dict(type='str'),
         uuid=dict(type='str'),
+        use_instance_uuid=dict(type='bool', default=False),
         folder=dict(type='str'),
         datacenter=dict(required=True, type='str'),
     )
diff --git a/lib/ansible/modules/cloud/vmware/vmware_guest_tools_wait.py b/lib/ansible/modules/cloud/vmware/vmware_guest_tools_wait.py
index 4d2f88640e5..1c9dc56b14c 100644
--- a/lib/ansible/modules/cloud/vmware/vmware_guest_tools_wait.py
+++ b/lib/ansible/modules/cloud/vmware/vmware_guest_tools_wait.py
@@ -56,6 +56,12 @@ options:
      description:
      - UUID of the VM  for which to wait until the tools become available, if known. This is VMware's unique identifier.
      - This is required, if C(name) is not supplied.
+   use_instance_uuid:
+     description:
+     - Whether to use the VMWare instance UUID rather than the BIOS UUID.
+     default: no
+     type: bool
+     version_added: '2.8'
 extends_documentation_fragment: vmware.documentation
 '''
 
@@ -146,6 +152,7 @@ def main():
         name_match=dict(type='str', default='first', choices=['first', 'last']),
         folder=dict(type='str'),
         uuid=dict(type='str'),
+        use_instance_uuid=dict(type='bool', default=False),
     )
     module = AnsibleModule(
         argument_spec=argument_spec,
diff --git a/lib/ansible/modules/cloud/vmware/vmware_vm_shell.py b/lib/ansible/modules/cloud/vmware/vmware_vm_shell.py
index 9f3a46a6861..0bc30149d00 100644
--- a/lib/ansible/modules/cloud/vmware/vmware_vm_shell.py
+++ b/lib/ansible/modules/cloud/vmware/vmware_vm_shell.py
@@ -62,7 +62,7 @@ options:
       description:
       - The VMware identification method by which the virtual machine will be identified.
       default: vm_name
-      choices: ['uuid', 'dns_name', 'inventory_path', 'vm_name']
+      choices: ['uuid', 'instance_uuid', 'dns_name', 'inventory_path', 'vm_name']
     vm_username:
       description:
       - The user to login-in to the virtual machine.
@@ -230,7 +230,8 @@ class VMwareShellManager(PyVmomi):
             vm = find_vm_by_id(self.content,
                                vm_id=module.params['vm_id'],
                                vm_id_type=module.params['vm_id_type'],
-                               datacenter=datacenter, cluster=cluster)
+                               datacenter=datacenter,
+                               cluster=cluster)
 
         if not vm:
             module.fail_json(msg='Unable to find virtual machine.')
@@ -327,7 +328,11 @@ def main():
             folder=dict(type='str'),
             vm_id=dict(type='str', required=True),
             vm_id_type=dict(default='vm_name', type='str',
-                            choices=['inventory_path', 'uuid', 'dns_name', 'vm_name']),
+                            choices=['inventory_path',
+                                     'uuid',
+                                     'instance_uuid',
+                                     'dns_name',
+                                     'vm_name']),
             vm_username=dict(type='str', required=True),
             vm_password=dict(type='str', no_log=True, required=True),
             vm_shell=dict(type='str', required=True),
diff --git a/lib/ansible/modules/cloud/vmware/vmware_vmotion.py b/lib/ansible/modules/cloud/vmware/vmware_vmotion.py
index fede1ac9883..433dd4a2767 100644
--- a/lib/ansible/modules/cloud/vmware/vmware_vmotion.py
+++ b/lib/ansible/modules/cloud/vmware/vmware_vmotion.py
@@ -47,6 +47,12 @@ options:
       - This is a required parameter, if C(vm_name) is not set.
       aliases: ['uuid']
       version_added: 2.7
+    use_instance_uuid:
+      description:
+      - Whether to use the VMWare instance UUID rather than the BIOS UUID.
+      default: no
+      type: bool
+      version_added: '2.8'
     destination_host:
       description:
       - Name of the destination host the virtual machine should be running on.
@@ -118,6 +124,7 @@ class VmotionManager(PyVmomi):
         super(VmotionManager, self).__init__(module)
         self.vm = None
         self.vm_uuid = self.params.get('vm_uuid', None)
+        self.use_instance_uuid = self.params.get('use_instance_uuid', False)
         self.vm_name = self.params.get('vm_name', None)
         result = dict()
 
@@ -254,10 +261,14 @@ class VmotionManager(PyVmomi):
 
         """
         vms = []
-        if self.vm_uuid:
+        if self.vm_uuid and not self.use_instance_uuid:
             vm_obj = find_vm_by_id(self.content, vm_id=self.params['vm_uuid'], vm_id_type="uuid")
             vms = [vm_obj]
-
+        elif self.vm_uuid and self.use_instance_uuid:
+            vm_obj = find_vm_by_id(self.content,
+                                   vm_id=self.params['vm_uuid'],
+                                   vm_id_type="instance_uuid")
+            vms = [vm_obj]
         elif self.vm_name:
             objects = self.get_managed_objects_properties(vim_type=vim.VirtualMachine, properties=['name'])
             for temp_vm_object in objects:
@@ -280,6 +291,7 @@ def main():
         dict(
             vm_name=dict(aliases=['vm']),
             vm_uuid=dict(aliases=['uuid']),
+            use_instance_uuid=dict(type='bool', default=False),
             destination_host=dict(aliases=['destination']),
             destination_datastore=dict(aliases=['datastore'])
         )
diff --git a/test/integration/targets/vmware_guest_facts/tasks/main.yml b/test/integration/targets/vmware_guest_facts/tasks/main.yml
index 879631be6e0..ade4d6283c7 100644
--- a/test/integration/targets/vmware_guest_facts/tasks/main.yml
+++ b/test/integration/targets/vmware_guest_facts/tasks/main.yml
@@ -79,9 +79,12 @@
       - "guest_facts_0001['instance']['guest_consolidation_needed'] is defined"
       - "'portgroup_portkey' in guest_facts_0001['instance']['hw_eth0']"
       - "'portgroup_key' in guest_facts_0001['instance']['hw_eth0']"
+      - "guest_facts_0001['instance']['instance_uuid'] is defined"
 
 - set_fact: vm1_uuid="{{ guest_facts_0001['instance']['hw_product_uuid'] }}"
 
+- set_fact: vm1_instance_uuid="{{ guest_facts_0001['instance']['instance_uuid'] }}"
+
 - debug: var=vm1_uuid
 
 # Testcase 0002: Get details about virtual machines using UUID
@@ -175,3 +178,34 @@
 #      - "guest_facts_0004['instance']['snapshots'][1]['name'] == 'snap2'"
 #      - "guest_facts_0004['instance']['current_snapshot']['name'] == 'snap2'"
 #      - "guest_facts_0002['instance']['hw_folder'] == vm1 | dirname"
+
+# Testcase 0005: Get details about virtual machines using UUID
+- name: get list of facts about virtual machines using instance UUID
+  vmware_guest_facts:
+    validate_certs: False
+    hostname: "{{ vcsim }}"
+    username: "{{ vcsim_instance['json']['username'] }}"
+    password: "{{ vcsim_instance['json']['password'] }}"
+    datacenter: "{{ dc1 | basename }}"
+    uuid: "{{ vm1_instance_uuid }}"
+    use_instance_uuid: True
+  register: guest_facts_0005
+
+- debug: msg="{{ guest_facts_0005 }}"
+
+- assert:
+    that:
+      - "guest_facts_0005['instance']['hw_name'] == vm1 | basename"
+      - "guest_facts_0005['instance']['hw_product_uuid'] is defined"
+      - "guest_facts_0005['instance']['hw_product_uuid'] == vm1_uuid"
+      - "guest_facts_0005['instance']['hw_cores_per_socket'] is defined"
+      - "guest_facts_0005['instance']['hw_datastores'] is defined"
+      - "guest_facts_0005['instance']['hw_esxi_host'] == h1 | basename"
+      - "guest_facts_0005['instance']['hw_files'] is defined"
+      - "guest_facts_0005['instance']['hw_guest_ha_state'] is defined"
+      - "guest_facts_0005['instance']['hw_is_template'] is defined"
+      - "guest_facts_0005['instance']['hw_folder'] is defined"
+      - "guest_facts_0005['instance']['guest_question'] is defined"
+      - "guest_facts_0005['instance']['guest_consolidation_needed'] is defined"
+      - "guest_facts_0005['instance']['instance_uuid'] is defined"
+      - "guest_facts_0005['instance']['instance_uuid'] == vm1_instance_uuid"