From 9c77509cbc61629a0acf767e91f80ccd43913d70 Mon Sep 17 00:00:00 2001
From: Zim Kalinowski <zikalino@microsoft.com>
Date: Thu, 21 Mar 2019 15:53:44 +0800
Subject: [PATCH] azure virtual machine facts -- querying all machines in
 subscription fix (#54075)

---
 .../azure/azure_rm_virtualmachine_facts.py    | 39 ++++++++++++-------
 .../tasks/virtualmachine.yml                  | 18 ++++++---
 2 files changed, 39 insertions(+), 18 deletions(-)

diff --git a/lib/ansible/modules/cloud/azure/azure_rm_virtualmachine_facts.py b/lib/ansible/modules/cloud/azure/azure_rm_virtualmachine_facts.py
index 3003580d034..56237db57df 100644
--- a/lib/ansible/modules/cloud/azure/azure_rm_virtualmachine_facts.py
+++ b/lib/ansible/modules/cloud/azure/azure_rm_virtualmachine_facts.py
@@ -201,6 +201,7 @@ vms:
 
 try:
     from msrestazure.azure_exceptions import CloudError
+    from msrestazure.tools import parse_resource_id
 except Exception:
     # This is handled in azure_rm_common
     pass
@@ -248,8 +249,10 @@ class AzureRMVirtualMachineFacts(AzureRMModuleBase):
             self.fail("Parameter error: resource group required when filtering by name.")
         if self.name:
             self.results['vms'] = self.get_item()
+        elif self.resource_group:
+            self.results['vms'] = self.list_items_by_resourcegroup()
         else:
-            self.results['vms'] = self.list_items()
+            self.results['vms'] = self.list_all_items()
 
         return self.results
 
@@ -258,17 +261,14 @@ class AzureRMVirtualMachineFacts(AzureRMModuleBase):
         item = None
         result = []
 
-        try:
-            item = self.compute_client.virtual_machines.get(self.resource_group, self.name)
-        except CloudError as err:
-            self.module.warn("Error getting virtual machine {0} - {1}".format(self.name, str(err)))
+        item = self.get_vm(self.resource_group, self.name)
 
-        if item and self.has_tags(item.tags, self.tags):
-            result = [self.serialize_vm(item)]
+        if item and self.has_tags(item.get('tags'), self.tags):
+            result = [item]
 
         return result
 
-    def list_items(self):
+    def list_items_by_resourcegroup(self):
         self.log('List all items')
         try:
             items = self.compute_client.virtual_machines.list(self.resource_group)
@@ -278,18 +278,31 @@ class AzureRMVirtualMachineFacts(AzureRMModuleBase):
         results = []
         for item in items:
             if self.has_tags(item.tags, self.tags):
-                results.append(self.serialize_vm(self.get_vm(item.name)))
+                results.append(self.get_vm(self.resource_group, item.name))
         return results
 
-    def get_vm(self, name):
+    def list_all_items(self):
+        self.log('List all items')
+        try:
+            items = self.compute_client.virtual_machines.list_all()
+        except CloudError as exc:
+            self.fail("Failed to list all items - {0}".format(str(exc)))
+
+        results = []
+        for item in items:
+            if self.has_tags(item.tags, self.tags):
+                results.append(self.get_vm(parse_resource_id(item.id).get('resource_group'), item.name))
+        return results
+
+    def get_vm(self, resource_group, name):
         '''
         Get the VM with expanded instanceView
 
         :return: VirtualMachine object
         '''
         try:
-            vm = self.compute_client.virtual_machines.get(self.resource_group, name, expand='instanceview')
-            return vm
+            vm = self.compute_client.virtual_machines.get(resource_group, name, expand='instanceview')
+            return self.serialize_vm(vm)
         except Exception as exc:
             self.fail("Error getting virtual machine {0} - {1}".format(self.name, str(exc)))
 
@@ -302,7 +315,7 @@ class AzureRMVirtualMachineFacts(AzureRMModuleBase):
         '''
 
         result = self.serialize_obj(vm, AZURE_OBJECT_CLASS, enum_modules=AZURE_ENUM_MODULES)
-        resource_group = re.sub('\\/.*', '', re.sub('.*resourceGroups\\/', '', result['id']))
+        resource_group = parse_resource_id(result['id']).get('resource_group')
         instance = None
         power_state = None
 
diff --git a/test/integration/targets/azure_rm_virtualmachine/tasks/virtualmachine.yml b/test/integration/targets/azure_rm_virtualmachine/tasks/virtualmachine.yml
index 21cf7e86683..56d361ba5fe 100644
--- a/test/integration/targets/azure_rm_virtualmachine/tasks/virtualmachine.yml
+++ b/test/integration/targets/azure_rm_virtualmachine/tasks/virtualmachine.yml
@@ -332,7 +332,8 @@
         publisher: Canonical
         sku: 16.04-LTS
         version: latest
-
+      tags:
+        abc: def
 - assert:
       that:
         - azure_vm.properties.availabilitySet.id
@@ -344,10 +345,6 @@
     name: "{{ vm_name2 }}"
   register: results
 
-- name: Just dump output
-  debug:
-    var: results
-
 - name: Assert that facts module returned the second vm
   assert:
     that: 
@@ -358,6 +355,17 @@
       - results.vms[0].resource_group == "{{ resource_group }}"
       - results.vms[0].power_state != None
 
+- name: Retrieve facts by tags
+  azure_rm_virtualmachine_facts:
+    tags:
+      - abc:def
+  register: results
+
+- name: Assert that facts module returned the second vm
+  assert:
+    that: 
+      - results.vms | length >= 1
+
 - name: Should be idempotent with a dual NICs
   azure_rm_virtualmachine:
       resource_group: "{{ resource_group }}"