Repository: Azure/azure-cli-extensions

Issue:
Is it possible to query Log Analytics via the az cli with a saved query?

I can’t tell from the documentation, is it possible to run a saved Log Analytics Query from this CLI command?  

If not, a useful enhancement would be to enable the use a saved query in addition to the ability to execute queries in-line.  The queries get long and cumbersome to maintain outside of Log Analytics.

If it is, however, possible to run a saved query, would you mind updating the documentation here?  Thanks.


---
#### Document Details

⚠ *Do not edit this section. It is required for docs.microsoft.com ➟ GitHub issue linking.*

* ID: f0fd6a58-ac1a-fa45-8d96-579b4af36499
* Version Independent ID: 4098ca97-1b85-eb29-18e9-e6f0495fd030
* Content: [az monitor log-analytics](https://docs.microsoft.com/en-us/cli/azure/ext/log-analytics/monitor/log-analytics?view=azure-cli-latest)
* Content Source: [latest/docs-ref-autogen/ext/log-analytics/monitor/log-analytics.yml](https://github.com/MicrosoftDocs/azure-docs-cli/blob/master/latest/docs-ref-autogen/ext/log-analytics/monitor/log-analytics.yml)
* GitHub Login: @rloutlaw
* Microsoft Alias: **routlaw**


Discussion:
add to S179
Hi @GitMje, do you mean to read the saved query from a file?
@kairu-ms I was hoping to use a saved query like one from the `saved queries` or `solutions queries`.  This would be similar to how azure devops can run team queries via the API.  Rather than having to hard code a query into the az cli command/scripts.  

Please see image below:
<img width="838" alt="001974-" src="https://user-images.githubusercontent.com/8420128/103233150-53d68380-490a-11eb-81a9-99c8547590df.png">


Resolving patch:
diff --git a/src/log-analytics/azext_loganalytics/_help.py b/src/log-analytics/azext_loganalytics/_help.py
--- a/src/log-analytics/azext_loganalytics/_help.py
+++ b/src/log-analytics/azext_loganalytics/_help.py
@@ -18,5 +18,9 @@
     examples:
       - name: Execute a simple query over past 3.5 days.
         text: |
-          az monitor log-analytics query -w b8317023-66e4-4edc-8a5b-7c002b22f92f --analytics-query "AzureActivity | summarize count() by bin(timestamp, 1h)" -t P3DT12H
+          az monitor log-analytics query -w workspace-customId --analytics-query "AzureActivity | summarize count() by bin(timestamp, 1h)" -t P3DT12H
+      - name: Execute a saved query in workspace
+        text: |
+          QUERY=$(az monitor log-analytics workspace saved-search show -g resource-group --workspace-name workspace-name -n query-name --query query --output tsv)
+          az monitor log-analytics query -w workspace-customId --analytics-query "$QUERY"
 """
diff --git a/src/log-analytics/setup.py b/src/log-analytics/setup.py
--- a/src/log-analytics/setup.py
+++ b/src/log-analytics/setup.py
@@ -8,7 +8,7 @@
 from codecs import open
 from setuptools import setup, find_packages
 
-VERSION = "0.2.1"
+VERSION = "0.2.2"
 
 CLASSIFIERS = [
     'Development Status :: 4 - Beta',


Test patch:
diff --git a/src/log-analytics/azext_loganalytics/tests/latest/recordings/test_query.yaml b/src/log-analytics/azext_loganalytics/tests/latest/recordings/test_query.yaml
--- a/src/log-analytics/azext_loganalytics/tests/latest/recordings/test_query.yaml
+++ b/src/log-analytics/azext_loganalytics/tests/latest/recordings/test_query.yaml
@@ -1,63 +1,180 @@
 interactions:
 - request:
-    body: '{"query": "Heartbeat | getschema"}'
+    body: '{"location": "eastus", "properties": {"sku": {"name": "CapacityReservation",
+      "capacityReservationLevel": 100}, "retentionInDays": 30, "workspaceCapping":
+      {"dailyQuotaGb": 1.0}}}'
     headers:
-      Accept: [application/json]
-      Accept-Encoding: ['gzip, deflate']
-      Connection: [keep-alive]
-      Content-Length: ['34']
-      Content-Type: [application/json; charset=utf-8]
-      User-Agent: [python/3.6.6 (Windows-10-10.0.17134-SP0) requests/2.19.1 msrest/0.5.4
-          azure-loganalytics/0.1.0]
-    method: POST
-    uri: https://api.loganalytics.io/v1/workspaces/cab864ad-d0c1-496b-bc5e-4418315621bf/query
+      Accept:
+      - application/json
+      Accept-Encoding:
+      - gzip, deflate
+      CommandName:
+      - monitor log-analytics workspace create
+      Connection:
+      - keep-alive
+      Content-Length:
+      - '177'
+      Content-Type:
+      - application/json; charset=utf-8
+      ParameterSetName:
+      - -g -n --location --quota --level --sku
+      User-Agent:
+      - python/3.8.5 (Windows-10-10.0.19041-SP0) msrest/0.6.18 msrest_azure/0.6.3
+        azure-mgmt-loganalytics/0.7.0 Azure-SDK-For-Python AZURECLI/2.17.0
+      accept-language:
+      - en-US
+    method: PUT
+    uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/cli_test_log_analytics000001/providers/Microsoft.OperationalInsights/workspaces/clitest000002?api-version=2020-03-01-preview
+  response:
+    body:
+      string: "{\r\n  \"properties\": {\r\n    \"source\": \"Azure\",\r\n    \"customerId\":
+        \"fad18499-958d-48d0-ae36-0bece90e1f50\",\r\n    \"provisioningState\": \"Creating\",\r\n
+        \   \"sku\": {\r\n      \"name\": \"capacityreservation\",\r\n      \"capacityReservationLevel\":
+        100,\r\n      \"maxCapacityReservationLevel\": 3000,\r\n      \"lastSkuUpdate\":
+        \"Wed, 30 Dec 2020 10:22:17 GMT\"\r\n    },\r\n    \"retentionInDays\": 30,\r\n
+        \   \"features\": {\r\n      \"legacy\": 0,\r\n      \"searchVersion\": 1,\r\n
+        \     \"enableLogAccessUsingOnlyResourcePermissions\": true\r\n    },\r\n
+        \   \"workspaceCapping\": {\r\n      \"dailyQuotaGb\": -1.0,\r\n      \"quotaNextResetTime\":
+        \"Thu, 31 Dec 2020 09:00:00 GMT\",\r\n      \"dataIngestionStatus\": \"RespectQuota\"\r\n
+        \   },\r\n    \"publicNetworkAccessForIngestion\": \"Enabled\",\r\n    \"publicNetworkAccessForQuery\":
+        \"Enabled\",\r\n    \"createdDate\": \"Wed, 30 Dec 2020 10:22:17 GMT\",\r\n
+        \   \"modifiedDate\": \"Wed, 30 Dec 2020 10:22:17 GMT\"\r\n  },\r\n  \"id\":
+        \"/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/cli_test_log_analytics000001/providers/microsoft.operationalinsights/workspaces/clitest000002\",\r\n
+        \ \"name\": \"clitest000002\",\r\n  \"type\": \"Microsoft.OperationalInsights/workspaces\",\r\n
+        \ \"location\": \"eastus\"\r\n}"
+    headers:
+      cache-control:
+      - no-cache
+      content-length:
+      - '1227'
+      content-type:
+      - application/json
+      date:
+      - Wed, 30 Dec 2020 10:22:19 GMT
+      pragma:
+      - no-cache
+      server:
+      - Microsoft-IIS/10.0
+      - Microsoft-IIS/10.0
+      strict-transport-security:
+      - max-age=31536000; includeSubDomains
+      x-content-type-options:
+      - nosniff
+      x-ms-ratelimit-remaining-subscription-writes:
+      - '1199'
+      x-powered-by:
+      - ASP.NET
+      - ASP.NET
+    status:
+      code: 201
+      message: Created
+- request:
+    body: null
+    headers:
+      Accept:
+      - application/json
+      Accept-Encoding:
+      - gzip, deflate
+      CommandName:
+      - monitor log-analytics workspace create
+      Connection:
+      - keep-alive
+      ParameterSetName:
+      - -g -n --location --quota --level --sku
+      User-Agent:
+      - python/3.8.5 (Windows-10-10.0.19041-SP0) msrest/0.6.18 msrest_azure/0.6.3
+        azure-mgmt-loganalytics/0.7.0 Azure-SDK-For-Python AZURECLI/2.17.0
+    method: GET
+    uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/cli_test_log_analytics000001/providers/Microsoft.OperationalInsights/workspaces/clitest000002?api-version=2020-03-01-preview
   response:
-    body: {string: '{"tables":[{"name":"getschema","columns":[{"name":"ColumnName","type":"string"},{"name":"ColumnOrdinal","type":"int"},{"name":"DataType","type":"string"},{"name":"ColumnType","type":"string"}],"rows":[["TenantId",0,"System.String","string"],["SourceSystem",1,"System.String","string"],["TimeGenerated",2,"System.DateTime","datetime"],["MG",3,"System.String","string"],["ManagementGroupName",4,"System.String","string"],["SourceComputerId",5,"System.String","string"],["ComputerIP",6,"System.String","string"],["Computer",7,"System.String","string"],["Category",8,"System.String","string"],["OSType",9,"System.String","string"],["OSName",10,"System.String","string"],["OSMajorVersion",11,"System.String","string"],["OSMinorVersion",12,"System.String","string"],["Version",13,"System.String","string"],["SCAgentChannel",14,"System.String","string"],["IsGatewayInstalled",15,"System.SByte","bool"],["RemoteIPLongitude",16,"System.Double","real"],["RemoteIPLatitude",17,"System.Double","real"],["RemoteIPCountry",18,"System.String","string"],["SubscriptionId",19,"System.String","string"],["ResourceGroup",20,"System.String","string"],["ResourceProvider",21,"System.String","string"],["Resource",22,"System.String","string"],["ResourceId",23,"System.String","string"],["ResourceType",24,"System.String","string"],["ComputerEnvironment",25,"System.String","string"],["Solutions",26,"System.String","string"],["VMUUID",27,"System.String","string"],["Type",28,"System.String","string"]]}]}'}
+    body:
+      string: "{\r\n  \"properties\": {\r\n    \"source\": \"Azure\",\r\n    \"customerId\":
+        \"fad18499-958d-48d0-ae36-0bece90e1f50\",\r\n    \"provisioningState\": \"Succeeded\",\r\n
+        \   \"sku\": {\r\n      \"name\": \"capacityreservation\",\r\n      \"capacityReservationLevel\":
+        100,\r\n      \"maxCapacityReservationLevel\": 3000,\r\n      \"lastSkuUpdate\":
+        \"Wed, 30 Dec 2020 10:22:17 GMT\"\r\n    },\r\n    \"retentionInDays\": 30,\r\n
+        \   \"features\": {\r\n      \"legacy\": 0,\r\n      \"searchVersion\": 1,\r\n
+        \     \"enableLogAccessUsingOnlyResourcePermissions\": true\r\n    },\r\n
+        \   \"workspaceCapping\": {\r\n      \"dailyQuotaGb\": 1.0,\r\n      \"quotaNextResetTime\":
+        \"Thu, 31 Dec 2020 09:00:00 GMT\",\r\n      \"dataIngestionStatus\": \"RespectQuota\"\r\n
+        \   },\r\n    \"publicNetworkAccessForIngestion\": \"Enabled\",\r\n    \"publicNetworkAccessForQuery\":
+        \"Enabled\",\r\n    \"createdDate\": \"Wed, 30 Dec 2020 10:22:17 GMT\",\r\n
+        \   \"modifiedDate\": \"Wed, 30 Dec 2020 10:22:18 GMT\"\r\n  },\r\n  \"id\":
+        \"/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/cli_test_log_analytics000001/providers/microsoft.operationalinsights/workspaces/clitest000002\",\r\n
+        \ \"name\": \"clitest000002\",\r\n  \"type\": \"Microsoft.OperationalInsights/workspaces\",\r\n
+        \ \"location\": \"eastus\"\r\n}"
     headers:
-      access-control-allow-origin: ['*']
-      access-control-expose-headers: ['Retry-After,Age,WWW-Authenticate,x-resource-identities,x-ms-status-location']
-      connection: [keep-alive]
-      content-length: ['1482']
-      content-location: ['https://eastus.api.loganalytics.io/v1/workspaces/cab864ad-d0c1-496b-bc5e-4418315621bf/query']
-      content-type: [application/json; charset=utf-8]
-      date: ['Fri, 27 Jul 2018 23:07:57 GMT']
-      server: [nginx]
-      strict-transport-security: [max-age=31536000000; includeSubDomains, max-age=31536000;
-          includeSubDomains]
-      transfer-encoding: [chunked]
-      vary: [Accept-Encoding]
-      via: [1.1 draft-oms-blue.aa4dbcee-9107-11e8-9ab8-70b3d5800008]
-      x-content-type-options: [nosniff]
-    status: {code: 200, message: OK}
+      cache-control:
+      - no-cache
+      content-length:
+      - '1227'
+      content-type:
+      - application/json
+      date:
+      - Wed, 30 Dec 2020 10:22:50 GMT
+      pragma:
+      - no-cache
+      server:
+      - Microsoft-IIS/10.0
+      - Microsoft-IIS/10.0
+      strict-transport-security:
+      - max-age=31536000; includeSubDomains
+      transfer-encoding:
+      - chunked
+      vary:
+      - Accept-Encoding
+      x-content-type-options:
+      - nosniff
+      x-powered-by:
+      - ASP.NET
+      - ASP.NET
+    status:
+      code: 200
+      message: OK
 - request:
     body: '{"query": "Heartbeat | getschema"}'
     headers:
-      Accept: [application/json]
-      Accept-Encoding: ['gzip, deflate']
-      Connection: [keep-alive]
-      Content-Length: ['34']
-      Content-Type: [application/json; charset=utf-8]
-      User-Agent: [python/3.6.6 (Windows-10-10.0.17134-SP0) requests/2.19.1 msrest/0.5.4
-          azure-loganalytics/0.1.0]
+      Accept:
+      - application/json
+      Accept-Encoding:
+      - gzip, deflate
+      Connection:
+      - keep-alive
+      Content-Length:
+      - '34'
+      Content-Type:
+      - application/json; charset=utf-8
+      User-Agent:
+      - python/3.8.5 (Windows-10-10.0.19041-SP0) msrest/0.6.18 azure-loganalytics/0.1.0
     method: POST
-    uri: https://api.loganalytics.io/v1/workspaces/cab864ad-d0c1-496b-bc5e-4418315621bf/query
+    uri: https://api.loganalytics.io/v1/workspaces/fad18499-958d-48d0-ae36-0bece90e1f50/query
   response:
-    body: {string: '{"tables":[{"name":"getschema","columns":[{"name":"ColumnName","type":"string"},{"name":"ColumnOrdinal","type":"int"},{"name":"DataType","type":"string"},{"name":"ColumnType","type":"string"}],"rows":[["TenantId",0,"System.String","string"],["SourceSystem",1,"System.String","string"],["TimeGenerated",2,"System.DateTime","datetime"],["MG",3,"System.String","string"],["ManagementGroupName",4,"System.String","string"],["SourceComputerId",5,"System.String","string"],["ComputerIP",6,"System.String","string"],["Computer",7,"System.String","string"],["Category",8,"System.String","string"],["OSType",9,"System.String","string"],["OSName",10,"System.String","string"],["OSMajorVersion",11,"System.String","string"],["OSMinorVersion",12,"System.String","string"],["Version",13,"System.String","string"],["SCAgentChannel",14,"System.String","string"],["IsGatewayInstalled",15,"System.SByte","bool"],["RemoteIPLongitude",16,"System.Double","real"],["RemoteIPLatitude",17,"System.Double","real"],["RemoteIPCountry",18,"System.String","string"],["SubscriptionId",19,"System.String","string"],["ResourceGroup",20,"System.String","string"],["ResourceProvider",21,"System.String","string"],["Resource",22,"System.String","string"],["ResourceId",23,"System.String","string"],["ResourceType",24,"System.String","string"],["ComputerEnvironment",25,"System.String","string"],["Solutions",26,"System.String","string"],["VMUUID",27,"System.String","string"],["Type",28,"System.String","string"]]}]}'}
+    body:
+      string: '{"tables":[{"name":"getschema","columns":[{"name":"ColumnName","type":"string"},{"name":"ColumnOrdinal","type":"int"},{"name":"DataType","type":"string"},{"name":"ColumnType","type":"string"}],"rows":[["TenantId",0,"System.String","string"],["SourceSystem",1,"System.String","string"],["TimeGenerated",2,"System.DateTime","datetime"],["MG",3,"System.String","string"],["ManagementGroupName",4,"System.String","string"],["SourceComputerId",5,"System.String","string"],["ComputerIP",6,"System.String","string"],["Computer",7,"System.String","string"],["Category",8,"System.String","string"],["OSType",9,"System.String","string"],["OSName",10,"System.String","string"],["OSMajorVersion",11,"System.String","string"],["OSMinorVersion",12,"System.String","string"],["Version",13,"System.String","string"],["SCAgentChannel",14,"System.String","string"],["IsGatewayInstalled",15,"System.SByte","bool"],["RemoteIPLongitude",16,"System.Double","real"],["RemoteIPLatitude",17,"System.Double","real"],["RemoteIPCountry",18,"System.String","string"],["SubscriptionId",19,"System.String","string"],["ResourceGroup",20,"System.String","string"],["ResourceProvider",21,"System.String","string"],["Resource",22,"System.String","string"],["ResourceId",23,"System.String","string"],["ResourceType",24,"System.String","string"],["ComputerEnvironment",25,"System.String","string"],["Solutions",26,"System.String","string"],["VMUUID",27,"System.String","string"],["Type",28,"System.String","string"],["_ResourceId",29,"System.String","string"]]}]}'
     headers:
-      access-control-allow-origin: ['*']
-      access-control-expose-headers: ['Retry-After,Age,WWW-Authenticate,x-resource-identities,x-ms-status-location']
-      age: ['0']
-      connection: [keep-alive]
-      content-length: ['1482']
-      content-location: ['https://eastus.api.loganalytics.io/v1/workspaces/cab864ad-d0c1-496b-bc5e-4418315621bf/query']
-      content-type: [application/json; charset=utf-8]
-      date: ['Fri, 27 Jul 2018 23:07:58 GMT']
-      server: [nginx]
-      strict-transport-security: [max-age=31536000000; includeSubDomains, max-age=31536000;
-          includeSubDomains]
-      transfer-encoding: [chunked]
-      vary: [Accept-Encoding]
-      via: [1.1 draft-oms-blue.cbd591df-9107-11e8-9ab8-70b3d5800008]
-      x-content-type-options: [nosniff]
-    status: {code: 200, message: OK}
+      access-control-allow-origin:
+      - '*'
+      access-control-expose-headers:
+      - Retry-After,Age,WWW-Authenticate,x-resource-identities,x-ms-status-location
+      connection:
+      - keep-alive
+      content-length:
+      - '1526'
+      content-type:
+      - application/json; charset=utf-8
+      date:
+      - Wed, 30 Dec 2020 10:22:53 GMT
+      strict-transport-security:
+      - max-age=15724800; includeSubDomains
+      transfer-encoding:
+      - chunked
+      vary:
+      - Accept-Encoding
+      via:
+      - 1.1 draft-oms-7d684489b6-hfrdr
+      x-content-type-options:
+      - nosniff
+    status:
+      code: 200
+      message: OK
 version: 1
diff --git a/src/log-analytics/azext_loganalytics/tests/latest/test_loganalytics_commands.py b/src/log-analytics/azext_loganalytics/tests/latest/test_loganalytics_commands.py
--- a/src/log-analytics/azext_loganalytics/tests/latest/test_loganalytics_commands.py
+++ b/src/log-analytics/azext_loganalytics/tests/latest/test_loganalytics_commands.py
@@ -4,23 +4,31 @@
 # --------------------------------------------------------------------------------------------
 
 # pylint: disable=line-too-long
-from azure.cli.testsdk import ScenarioTest
+from azure.cli.testsdk import (ScenarioTest, ResourceGroupPreparer)
 
 
 class LogAnalyticsDataClientTests(ScenarioTest):
     """Test class for Log Analytics data client."""
-    def test_query(self):
-        """Tests data plane query capabilities for Log Analytics."""
 
-        query_result = self.cmd('az monitor log-analytics query -w cab864ad-d0c1-496b-bc5e-4418315621bf --analytics-query "Heartbeat | getschema"').get_output_in_json()
+    @ResourceGroupPreparer(name_prefix='cli_test_log_analytics')
+    def test_query(self, resource_group):
+        """Tests data plane query capabilities for Log Analytics."""
+        self.kwargs.update({
+            'workspace_name': self.create_random_name('clitest', 20),
+            'location': "eastus",
+        })
 
-        desired_row = {
-            'ColumnName': 'TenantId',
-            'ColumnOrdinal': '0',
-            'ColumnType': 'string',
-            'DataType': 'System.String',
-            'TableName': 'getschema'
-        }
+        workspace_json = self.cmd(
+            "monitor log-analytics workspace create -g {rg} -n {workspace_name} --location {location} --quota 1 "
+            "--level 100 --sku CapacityReservation").get_output_in_json()
+        self.kwargs['workspace_customerId'] = workspace_json['customerId']
 
-        assert len(query_result) == 29
-        self.assertDictEqual(query_result[0], desired_row)
+        self.cmd(
+            'az monitor log-analytics query -w {workspace_customerId} '
+            '--analytics-query "Heartbeat | getschema"',
+            checks=[
+                self.check("length(@)", 30),
+                self.check("@[0]", {'ColumnName': 'TenantId', 'ColumnOrdinal': '0', 'ColumnType': 'string',
+                                    'DataType': 'System.String', 'TableName': 'getschema'})
+            ]
+        )