Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add preview Log Analytics query extension #250

Merged
merged 23 commits into from
Jul 27, 2018
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,6 @@

/src/express-route-cross-connection/ @tjprescott

/src/loganalytics/ @alexeldeib

/src/mesh/ @linggengmsft
33 changes: 33 additions & 0 deletions src/index.json
Original file line number Diff line number Diff line change
Expand Up @@ -951,6 +951,39 @@
"version": "0.9.1"
}
}
],
"log-analytics": [
{
"filename": "log_analytics-0.1.1-py2.py3-none-any.whl",
"sha256Digest": "98b88daa6eb978354bbcdc177fba48921186193da0b3f2906fb61845024f352b",
"downloadUrl": "https://files.pythonhosted.org/packages/87/ff/6aff19ead74388299b176b907ec2f0abbd39dbfedf46349ab37476b5f57b/log_analytics-0.1.1-py2.py3-none-any.whl",
"metadata": {
"azext.isPreview": true,
"extensions": {
"python.details": {
"contacts": [
{
"email": "aleldeib@microsoft.com",
"name": "Ace Eldeib",
"role": "author"
}
],
"document_names": {
"description": "DESCRIPTION.rst"
},
"project_urls": {
"Home": "https://github.com/Azure/azure-cli-extensions/tree/master/src/log-analytics"
}
}
},
"generator": "bdist_wheel (0.30.0)",
"license": "MIT",
"metadata_version": "2.0",
"name": "log-analytics",
"summary": "Support for Azure Log Analytics query capabilities.",
"version": "0.1.1"
}
}
]
}
}
9 changes: 9 additions & 0 deletions src/loganalytics/HISTORY.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
0.1.1
++++++++++++++++++

* Fix homepage

0.1.0
++++++++++++++++++

* Initial release.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

start with version 0.1.0

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

edit: replied to stale comment

2 changes: 2 additions & 0 deletions src/loganalytics/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Commands for working with Azure Log Analytics
==============================================
36 changes: 36 additions & 0 deletions src/loganalytics/azext_loganalytics/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

from azure.cli.core import AzCommandsLoader

from azext_loganalytics._help import helps # pylint: disable=unused-import


class LogAnalyticsCommandsLoader(AzCommandsLoader):

def __init__(self, cli_ctx=None):
from azure.cli.core.commands import CliCommandType
from azext_loganalytics._client_factory import loganalytics_data_plane_client
loganalytics_custom = CliCommandType(
operations_tmpl='azext_loganalytics.custom#{}',
client_factory=loganalytics_data_plane_client
)

super(LogAnalyticsCommandsLoader, self).__init__(
cli_ctx=cli_ctx,
custom_command_type=loganalytics_custom
)

def load_command_table(self, args):
from azext_loganalytics.commands import load_command_table
load_command_table(self, args)
return self.command_table

def load_arguments(self, command):
from azext_loganalytics._params import load_arguments
load_arguments(self, command)


COMMAND_LOADER_CLS = LogAnalyticsCommandsLoader
14 changes: 14 additions & 0 deletions src/loganalytics/azext_loganalytics/_client_factory.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------


def loganalytics_data_plane_client(cli_ctx, _):
"""Initialize Log Analytics data client for use with CLI."""
from .vendored_sdks.loganalytics import LogAnalyticsDataClient
from azure.cli.core._profile import Profile
profile = Profile(cli_ctx=cli_ctx)
cred, _, _ = profile.get_login_credentials(
resource="https://api.loganalytics.io")
return LogAnalyticsDataClient(cred)
28 changes: 28 additions & 0 deletions src/loganalytics/azext_loganalytics/_help.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

from knack.help_files import helps

# pylint: disable=line-too-long

helps['monitor loganalytics query'] = """
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

log-analytics

type: command
short-summary: Query a Log Analytics workspace.
parameters:
- workspace: --workspace -w
type: string
short-summary: GUID of the Log Analytics workspace.
- kql: --kql -k
type: string
short-summary: Query to execute over the Log Analytics data.
- timespan: --timespan -t
type: string
short-summary: Timespan over which to query data. Defaults to all data.
- workspaces: --workspaces
type: array
short-summary: Additional workspaces to union data for querying. Specify additional workspace IDs separated by commas.
examples:
- name:
"""
14 changes: 14 additions & 0 deletions src/loganalytics/azext_loganalytics/_params.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

# pylint: disable=line-too-long


def load_arguments(self, _):
with self.argument_context('loganalytics') as c:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

monitor log-analytics query

c.argument('workspace', options_list=['--workspace', '-w'], help='GUID of the Log Analytics Workspace', required=True)
c.argument('kql', help='Query to execute over Log Analytics data.', required=True)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you don't need the required=True for workspace or kql; they will be implied from the command signature in execute_query

c.argument('timespan', options_list=['--timespan', '-t'], help='Timespan over which to query. Defaults to querying all available data.')
c.argument('workspaces', nargs='+', help='Optional additional workspaces over which to join data for the query.')
3 changes: 3 additions & 0 deletions src/loganalytics/azext_loganalytics/azext_metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"azext.isPreview": true
}
12 changes: 12 additions & 0 deletions src/loganalytics/azext_loganalytics/commands.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

# pylint: disable=line-too-long


def load_command_table(self, _):

with self.command_group('monitor log-analytics') as g:
g.custom_command('query', 'execute_query')
14 changes: 14 additions & 0 deletions src/loganalytics/azext_loganalytics/custom.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

from knack.log import get_logger

logger = get_logger(__name__)


def execute_query(client, workspace, kql, timespan=None, workspaces=None):
"""Executes a query against the provided Log Analytics workspace."""
from .vendored_sdks.loganalytics.models import QueryBody
return client.query(workspace, QueryBody(query=kql, timespan=timespan, workspaces=workspaces))
4 changes: 4 additions & 0 deletions src/loganalytics/azext_loganalytics/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------
4 changes: 4 additions & 0 deletions src/loganalytics/azext_loganalytics/tests/latest/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
interactions:
- 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.4 (Windows-10-10.0.17134-SP0) requests/2.19.1 msrest/0.5.3
azure-loganalytics/0.1.0]
method: POST
uri: https://api.loganalytics.io/v1/workspaces/cab864ad-d0c1-496b-bc5e-4418315621bf/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"]]}]}'}
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: ['Mon, 16 Jul 2018 18:19:50 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-green.9ae239f1-88dc-11e8-aedf-70b3d5800006]
x-content-type-options: [nosniff]
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.4 (Windows-10-10.0.17134-SP0) requests/2.19.1 msrest/0.5.3
azure-loganalytics/0.1.0]
method: POST
uri: https://api.loganalytics.io/v1/workspaces/cab864ad-d0c1-496b-bc5e-4418315621bf/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"]]}]}'}
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: ['Mon, 16 Jul 2018 18:19:50 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-green.c01b97e7-888d-11e8-aedf-70b3d5800006]
x-content-type-options: [nosniff]
status: {code: 200, message: OK}
version: 1
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

# pylint: disable=line-too-long
from azure.cli.testsdk import ScenarioTest


class LogAnalyticsDataClientTests(ScenarioTest):
"""Test class for Log Analytics data client."""
def test_query(self):
"""Tests data plane query capabilities for Log Analytics."""
self.cmd('az loganalytics query -w cab864ad-d0c1-496b-bc5e-4418315621bf --kql "Heartbeat | getschema"', checks=[
self.check('tables[0].rows[0][0]', 'TenantId')
])
query_result = self.cmd('az loganalytics query -w cab864ad-d0c1-496b-bc5e-4418315621bf --kql "Heartbeat | getschema"').get_output_in_json()
assert len(query_result['tables'][0]['rows']) == 29
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test looks stale. Can you run your test again? that should also pick up some of the other problems i saw.

assert isinstance(query_result['tables'][0]['rows'][0][1], (int, float, complex))
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# coding=utf-8
# --------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for
# license information.
#
# Code generated by Microsoft (R) AutoRest Code Generator.
# Changes may cause incorrect behavior and will be lost if the code is
# regenerated.
# --------------------------------------------------------------------------

from .log_analytics_data_client import LogAnalyticsDataClient
from .version import VERSION

__all__ = ['LogAnalyticsDataClient']

__version__ = VERSION

Loading