Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
4 changes: 4 additions & 0 deletions src/log-analytics/HISTORY.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
1.0.0b2
++++++++++++++++++
* Add AzureChinaCloud and AzureUSGovernment host templates for log-analytics data-plane client.

1.0.0b1
++++++++++++++++++
* Migrate to AAZ codegen.
Expand Down
6 changes: 4 additions & 2 deletions src/log-analytics/azext_loganalytics/aaz/latest/_clients.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@
class AAZMicrosoftOperationalinsightsDataPlaneClient(AAZBaseClient):
_CLOUD_HOST_TEMPLATES = {
CloudNameEnum.AzureCloud: "https://api.loganalytics.io",
CloudNameEnum.AzureChinaCloud: "https://api.loganalytics.azure.cn",
CloudNameEnum.AzureUSGovernment: "https://api.loganalytics.us",
}
Comment on lines 16 to 20
Comment on lines 16 to 20
_CLOUD_HOST_METADATA_INDEX = "logAnalyticslogAnalyticsResourceId"
_CLOUD_HOST_METADATA_INDEX = "logAnalyticsResourceId"

_AAD_CREDENTIAL_SCOPES = [
"https://api.loganalytics.io/.default",
Expand All @@ -27,7 +29,7 @@ def _build_base_url(cls, ctx, **kwargs):
endpoint = cls.get_cloud_endpoint(ctx, cls._CLOUD_HOST_METADATA_INDEX)
if not endpoint:
endpoint = cls._CLOUD_HOST_TEMPLATES.get(ctx.cli_ctx.cloud.name, None)
return endpoint
return endpoint.rstrip('/') if endpoint else endpoint

@classmethod
def _build_configuration(cls, ctx, credential, **kwargs):
Expand Down
Original file line number Diff line number Diff line change
@@ -1,119 +1,4 @@
interactions:
- request:
body: '{"location": "eastus", "properties": {"publicNetworkAccessForIngestion":
"Enabled", "publicNetworkAccessForQuery": "Enabled", "retentionInDays": 30,
"sku": {"capacityReservationLevel": 100, "name": "CapacityReservation"}, "workspaceCapping":
{"dailyQuotaGb": 1.0}}}'
headers:
Accept:
- application/json
Accept-Encoding:
- gzip, deflate
CommandName:
- monitor log-analytics workspace create
Connection:
- keep-alive
Content-Length:
- '265'
Content-Type:
- application/json
ParameterSetName:
- -g -n --location --quota --level --sku
User-Agent:
- AZURECLI/2.64.0 azsdk-python-core/1.28.0 Python/3.12.6 (Windows-11-10.0.22631-SP0)
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=2023-09-01
response:
body:
string: '{"properties":{"customerId":"062c153f-f7b2-4a8b-b57d-05b9f5cadfdc","provisioningState":"Creating","sku":{"name":"CapacityReservation","capacityReservationLevel":100,"lastSkuUpdate":"2024-09-14T04:50:29.9279239Z"},"retentionInDays":30,"features":{"legacy":0,"searchVersion":1,"enableLogAccessUsingOnlyResourcePermissions":true},"workspaceCapping":{"dailyQuotaGb":1.0,"quotaNextResetTime":"2024-09-14T20:00:00Z","dataIngestionStatus":"RespectQuota"},"publicNetworkAccessForIngestion":"Enabled","publicNetworkAccessForQuery":"Enabled","createdDate":"2024-09-14T04:50:29.9279239Z","modifiedDate":"2024-09-14T04:50:29.9279239Z"},"location":"eastus","id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_log_analytics000001/providers/Microsoft.OperationalInsights/workspaces/clitest000002","name":"clitest000002","type":"Microsoft.OperationalInsights/workspaces","etag":"\"18004b51-0000-0100-0000-66e516150000\""}'
headers:
access-control-allow-origin:
- '*'
api-supported-versions:
- 2015-03-20, 2020-08-01, 2020-10-01, 2021-06-01, 2022-10-01, 2023-09-01
cache-control:
- no-cache
content-length:
- '935'
content-type:
- application/json; charset=utf-8
date:
- Sat, 14 Sep 2024 04:50:29 GMT
expires:
- '-1'
location:
- https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_log_analytics000001/providers/Microsoft.OperationalInsights/workspaces/clitest000002?api-version=2023-09-01
pragma:
- no-cache
request-context:
- appId=cid-v1:e6336c63-aab2-45f0-996a-e5dbab2a1508
strict-transport-security:
- max-age=31536000; includeSubDomains
x-cache:
- CONFIG_NOCACHE
x-content-type-options:
- nosniff
x-ms-ratelimit-remaining-subscription-global-writes:
- '5999'
x-ms-ratelimit-remaining-subscription-writes:
- '399'
x-msedge-ref:
- 'Ref A: 969F1114F8B045CE99F05F0392FCBD71 Ref B: MAA201060513039 Ref C: 2024-09-14T04:50:26Z'
status:
code: 201
message: Created
- request:
body: null
headers:
Accept:
- '*/*'
Accept-Encoding:
- gzip, deflate
CommandName:
- monitor log-analytics workspace create
Connection:
- keep-alive
ParameterSetName:
- -g -n --location --quota --level --sku
User-Agent:
- AZURECLI/2.64.0 azsdk-python-core/1.28.0 Python/3.12.6 (Windows-11-10.0.22631-SP0)
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=2023-09-01
response:
body:
string: '{"properties":{"customerId":"062c153f-f7b2-4a8b-b57d-05b9f5cadfdc","provisioningState":"Succeeded","sku":{"name":"CapacityReservation","capacityReservationLevel":100,"lastSkuUpdate":"2024-09-14T04:50:29.9279239Z"},"retentionInDays":30,"features":{"legacy":0,"searchVersion":1,"enableLogAccessUsingOnlyResourcePermissions":true},"workspaceCapping":{"dailyQuotaGb":1.0,"quotaNextResetTime":"2024-09-14T20:00:00Z","dataIngestionStatus":"RespectQuota"},"publicNetworkAccessForIngestion":"Enabled","publicNetworkAccessForQuery":"Enabled","createdDate":"2024-09-14T04:50:29.9279239Z","modifiedDate":"2024-09-14T04:50:30.9494306Z"},"location":"eastus","id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_log_analytics000001/providers/Microsoft.OperationalInsights/workspaces/clitest000002","name":"clitest000002","type":"Microsoft.OperationalInsights/workspaces","etag":"\"18004c51-0000-0100-0000-66e516160000\""}'
headers:
access-control-allow-origin:
- '*'
api-supported-versions:
- 2015-03-20, 2020-08-01, 2020-10-01, 2021-06-01, 2022-10-01, 2023-09-01
cache-control:
- no-cache
content-length:
- '936'
content-type:
- application/json; charset=utf-8
date:
- Sat, 14 Sep 2024 04:50:30 GMT
expires:
- '-1'
pragma:
- no-cache
request-context:
- appId=cid-v1:e6336c63-aab2-45f0-996a-e5dbab2a1508
strict-transport-security:
- max-age=31536000; includeSubDomains
x-cache:
- CONFIG_NOCACHE
x-content-type-options:
- nosniff
x-ms-ratelimit-remaining-subscription-global-reads:
- '7499'
x-msedge-ref:
- 'Ref A: 7BFCFDBF1A6F44838E333CA298740C12 Ref B: MAA201060513039 Ref C: 2024-09-14T04:50:30Z'
status:
code: 200
message: OK
- request:
body: '{"query": "Heartbeat | getschema"}'
headers:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,21 @@
# --------------------------------------------------------------------------------------------

# pylint: disable=line-too-long
from azure.cli.testsdk import (ScenarioTest, ResourceGroupPreparer)
import unittest
from unittest.mock import MagicMock, patch

from azure.cli.testsdk import ScenarioTest


class LogAnalyticsDataClientTests(ScenarioTest):
"""Test class for Log Analytics data client."""

@ResourceGroupPreparer(name_prefix='cli_test_log_analytics')
def test_query(self, resource_group):
def test_query(self):
"""Tests data plane query capabilities for Log Analytics."""
self.kwargs.update({
'workspace_name': self.create_random_name('clitest', 20),
'location': "eastus",
'workspace_customerId': '062c153f-f7b2-4a8b-b57d-05b9f5cadfdc',
})

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']

self.cmd(
'az monitor log-analytics query -w {workspace_customerId} '
'--analytics-query "Heartbeat | getschema"',
Expand All @@ -32,3 +28,72 @@ def test_query(self, resource_group):
'DataType': 'System.String', 'TableName': 'getschema'})
]
)


class LogAnalyticsClientEndpointMappingTests(unittest.TestCase):
"""Unit tests for cloud endpoint mapping in the Log Analytics data-plane client."""

def _make_ctx(self, cloud_name, log_analytics_resource_id=None, raise_endpoint_not_set=False):
"""Build a minimal mock context with the given cloud name and endpoint."""
from unittest.mock import PropertyMock
from azure.cli.core.cloud import CloudEndpointNotSetException

endpoints = MagicMock()
if raise_endpoint_not_set:
type(endpoints).log_analytics_resource_id = PropertyMock(
side_effect=CloudEndpointNotSetException("log_analytics_resource_id not set")
)
else:
endpoints.log_analytics_resource_id = log_analytics_resource_id

cloud = MagicMock()
cloud.name = cloud_name
cloud.endpoints = endpoints

cli_ctx = MagicMock()
cli_ctx.cloud = cloud

ctx = MagicMock()
ctx.cli_ctx = cli_ctx
return ctx

def _get_base_url(self, ctx):
from azext_loganalytics.aaz.latest._clients import AAZMicrosoftOperationalinsightsDataPlaneClient
with patch.object(
AAZMicrosoftOperationalinsightsDataPlaneClient,
'_retrieve_value_in_arm_cloud_metadata',
return_value=None
):
return AAZMicrosoftOperationalinsightsDataPlaneClient._build_base_url(ctx)

def test_azure_public_cloud_endpoint(self):
"""AzureCloud should resolve to the public Log Analytics endpoint."""
ctx = self._make_ctx('AzureCloud', 'https://api.loganalytics.io')
self.assertEqual(self._get_base_url(ctx), 'https://api.loganalytics.io')

def test_azure_public_cloud_endpoint_trailing_slash(self):
"""AzureCloud endpoint with trailing slash should be stripped."""
ctx = self._make_ctx('AzureCloud', 'https://api.loganalytics.io/')
self.assertEqual(self._get_base_url(ctx), 'https://api.loganalytics.io')

def test_azure_china_cloud_endpoint(self):
"""AzureChinaCloud should resolve to the China sovereign endpoint."""
ctx = self._make_ctx('AzureChinaCloud', 'https://api.loganalytics.azure.cn')
self.assertEqual(self._get_base_url(ctx), 'https://api.loganalytics.azure.cn')

def test_azure_us_government_cloud_endpoint(self):
"""AzureUSGovernment should resolve to the US Government endpoint."""
ctx = self._make_ctx('AzureUSGovernment', 'https://api.loganalytics.us')
self.assertEqual(self._get_base_url(ctx), 'https://api.loganalytics.us')

def test_fallback_to_host_templates_when_endpoint_not_set(self):
"""When cloud endpoint is not configured, fall back to _CLOUD_HOST_TEMPLATES."""
expected_by_cloud = {
'AzureCloud': 'https://api.loganalytics.io',
'AzureChinaCloud': 'https://api.loganalytics.azure.cn',
'AzureUSGovernment': 'https://api.loganalytics.us',
}
for cloud_name, expected_url in expected_by_cloud.items():
with self.subTest(cloud_name=cloud_name):
ctx = self._make_ctx(cloud_name, raise_endpoint_not_set=True)
self.assertEqual(self._get_base_url(ctx), expected_url)
2 changes: 1 addition & 1 deletion src/log-analytics/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from codecs import open
from setuptools import setup, find_packages

VERSION = "1.0.0b1"
VERSION = "1.0.0b2"

CLASSIFIERS = [
'Development Status :: 4 - Beta',
Expand Down
Loading