Skip to content

Commit 90a1c40

Browse files
joshharrinJosh Harrington
andauthored
Deploy log analytics in same resource group as workspace in basic scenario (Azure#29304)
* deploy log analytics with workspace in same rg * fix casing * disable cspell for single line * fix test * remove space --------- Co-authored-by: Josh Harrington <[email protected]>
1 parent b97b631 commit 90a1c40

File tree

10 files changed

+68
-176
lines changed

10 files changed

+68
-176
lines changed

sdk/ml/azure-ai-ml/azure/ai/ml/_arm_deployments/arm_deployment_executor.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,12 @@ def _check_deployment_status(self) -> None:
168168
resource_name = (
169169
f"{arm_id_obj.asset_name} {arm_id_obj.asset_version if hasattr(arm_id_obj,'asset_version') else ''}"
170170
)
171+
# do swap on asset_type to avoid collision with workspaces asset_type in arm id
172+
arm_id_obj.asset_type = (
173+
arm_id_obj.asset_type
174+
if not arm_id_obj.provider_namespace_with_type == "OperationalInsightsworkspaces"
175+
else "LogAnalytics"
176+
)
171177
deployment_message = deployment_message_mapping[arm_id_obj.asset_type].format(f"{resource_name} ")
172178
if target_resource.resource_name not in self._resources_being_deployed.keys():
173179
self._resources_being_deployed[target_resource.resource_name] = (

sdk/ml/azure-ai-ml/azure/ai/ml/_arm_deployments/arm_helper.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,12 @@
3737
ArmConstants.ONLINE_DEPLOYMENT_TYPE: "Creating or updating deployment: {0}",
3838
AzureMLResourceType.DEPLOYMENT: "Creating or updating deployment: {0}",
3939
ArmConstants.UPDATE_ONLINE_ENDPOINT_TYPE: "Updating traffic",
40-
ArmConstants.KEY_VAULT_PARAMETER_NAME: "Creating KeyVault: ({0})",
41-
ArmConstants.APP_INSIGHTS_PARAMETER_NAME: "Creating AppInsights: ({0})",
40+
ArmConstants.KEY_VAULT_PARAMETER_NAME: "Creating Key Vault: ({0})",
41+
ArmConstants.LOG_ANALYTICS: "Creating Log Analytics Workspace: ({0})",
42+
ArmConstants.APP_INSIGHTS_PARAMETER_NAME: "Creating Application Insights: ({0})",
4243
ArmConstants.CONTAINER_REGISTRY_PARAMETER_NAME: "Creating Container Registry: ({0})",
4344
ArmConstants.STORAGE_ACCOUNT_PARAMETER_NAME: "Creating Storage Account: ({0})",
44-
AzureMLResourceType.WORKSPACE: "Creating workspace: ({0})",
45+
AzureMLResourceType.WORKSPACE: "Creating AzureML Workspace: ({0})",
4546
AzureMLResourceType.CONNECTIONS: "Creating connection: ({0})",
4647
}
4748

sdk/ml/azure-ai-ml/azure/ai/ml/_arm_deployments/arm_templates/workspace_base.json

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,20 @@
128128
"description": "Determines whether or not new ApplicationInsights should be provisioned."
129129
}
130130
},
131+
"logAnalyticsName": {
132+
"type": "string",
133+
"defaultValue": "[concat('la', uniqueString(parameters('resourceGroupName'), parameters('workspaceName')))]",
134+
"metadata": {
135+
"description": "Name of LogAnalytics to be used by ApplicationInsights resource."
136+
}
137+
},
138+
"logAnalyticsArmId": {
139+
"type": "string",
140+
"defaultValue": "",
141+
"metadata": {
142+
"description": "ARM Id of LogAnalytics to be used by ApplicationInsights resource."
143+
}
144+
},
131145
"applicationInsightsName": {
132146
"type": "string",
133147
"defaultValue": "[concat('ai', uniqueString(parameters('resourceGroupName'), parameters('workspaceName')))]",
@@ -597,6 +611,18 @@
597611
"networkRuleSet": "[if(equals(parameters('containerRegistryBehindVNet'), 'true'), variables('networkRuleSetBehindVNet'), json('null'))]"
598612
}
599613
},
614+
{
615+
"condition": "[and(variables('enablePE'), equals(parameters('applicationInsightsOption'), 'new'))]",
616+
"type": "Microsoft.OperationalInsights/workspaces",
617+
"tags": "[parameters('tagValues')]",
618+
"apiVersion": "2020-08-01",
619+
"name": "[parameters('logAnalyticsName')]",
620+
"location": "[if(or(equals(toLower(parameters('applicationInsightsLocation')),'westcentralus'), equals(toLower(parameters('applicationInsightsLocation')),'eastus2euap'), equals(toLower(parameters('applicationInsightsLocation')),'centraluseuap')),'southcentralus', parameters('applicationInsightsLocation'))]",
621+
"kind": "web",
622+
"properties": {
623+
"Application_Type": "web"
624+
}
625+
},
600626
{
601627
"condition": "[and(variables('enablePE'), equals(parameters('applicationInsightsOption'), 'new'))]",
602628
"type": "Microsoft.Insights/components",
@@ -605,8 +631,12 @@
605631
"name": "[parameters('applicationInsightsName')]",
606632
"location": "[if(or(equals(toLower(parameters('applicationInsightsLocation')),'westcentralus'), equals(toLower(parameters('applicationInsightsLocation')),'eastus2euap'), equals(toLower(parameters('applicationInsightsLocation')),'centraluseuap')),'southcentralus', parameters('applicationInsightsLocation'))]",
607633
"kind": "web",
634+
"dependsOn": [
635+
"[resourceId('Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsName'))]"
636+
],
608637
"properties": {
609-
"Application_Type": "web"
638+
"Application_Type": "web",
639+
"WorkspaceResourceId": "[parameters('logAnalyticsArmId')]"
610640
}
611641
},
612642
{

sdk/ml/azure-ai-ml/azure/ai/ml/_arm_deployments/arm_templates/workspace_param.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@
4444
"applicationInsightsName": {
4545
"value": ""
4646
},
47+
"logAnalyticsName": {
48+
"value": ""
49+
},
50+
"logAnalyticsArmId": {
51+
"value": ""
52+
},
4753
"applicationInsightsResourceGroupName": {
4854
"value": ""
4955
},

sdk/ml/azure-ai-ml/azure/ai/ml/_utils/_appinsights_utils.py

Lines changed: 3 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -4,114 +4,13 @@
44

55
import logging
66

7-
from azure.ai.ml._azure_environments import _get_base_url_from_metadata
8-
from azure.ai.ml._vendor.azure_resources._resource_management_client import ResourceManagementClient
9-
from azure.ai.ml.constants._common import ArmConstants
10-
from azure.core.credentials import TokenCredential
11-
from azure.core.exceptions import HttpResponseError
12-
from azure.ai.ml.constants._workspace import AppInsightsDefaults
13-
147
module_logger = logging.getLogger(__name__)
158

169

17-
def default_resource_group_for_app_insights_exists(
18-
credentials: TokenCredential, subscription_id: str, location: str
19-
) -> bool:
20-
client = ResourceManagementClient(
21-
credential=credentials,
22-
subscription_id=subscription_id,
23-
base_url=_get_base_url_from_metadata(),
24-
api_version=ArmConstants.AZURE_MGMT_RESOURCE_API_VERSION,
25-
)
26-
default_rgName = AppInsightsDefaults.DEFAULT_RESOURCE_GROUP_NAME.format(location=location)
27-
try:
28-
client.resource_groups.get(resource_group_name=default_rgName)
29-
return True
30-
except HttpResponseError:
31-
return False
32-
33-
34-
def default_log_analytics_workspace_exists(credentials: TokenCredential, subscription_id: str, location: str) -> bool:
35-
client = ResourceManagementClient(
36-
credential=credentials,
37-
subscription_id=subscription_id,
38-
base_url=_get_base_url_from_metadata(),
39-
api_version=ArmConstants.AZURE_MGMT_RESOURCE_API_VERSION,
40-
)
41-
default_resource_group = AppInsightsDefaults.DEFAULT_RESOURCE_GROUP_NAME.format(location=location)
42-
default_workspace = client.resources.list_by_resource_group(
43-
default_resource_group,
44-
filter=f"substringof('{AppInsightsDefaults.DEFAULT_LOG_ANALYTICS_NAME.format(location=location)}',name)",
45-
)
46-
for item in default_workspace: # pylint: disable=unused-variable
47-
# return true for is_existing
48-
return True
49-
# else return false for is_existing
50-
return False
51-
52-
53-
def get_default_log_analytics_arm_id(subscription_id: str, location: str) -> str:
10+
def get_log_analytics_arm_id(subscription_id: str, resource_group_name: str, log_analytics_name: str) -> str:
5411
return (
5512
f"/subscriptions/{subscription_id}/"
56-
f"resourceGroups/{AppInsightsDefaults.DEFAULT_RESOURCE_GROUP_NAME.format(location=location)}/"
13+
f"resourceGroups/{resource_group_name}/"
5714
"providers/Microsoft.OperationalInsights/workspaces/"
58-
f"{AppInsightsDefaults.DEFAULT_LOG_ANALYTICS_NAME.format(location=location)}"
15+
f"{log_analytics_name}"
5916
)
60-
61-
62-
def get_default_resource_group_deployment(deployment_name: str, location: str, subscription_id: str) -> dict:
63-
return {
64-
"type": "Microsoft.Resources/deployments",
65-
"apiVersion": "2019-10-01",
66-
"name": deployment_name,
67-
"subscriptionId": subscription_id,
68-
"location": location,
69-
"properties": {
70-
"mode": "Incremental",
71-
"template": {
72-
"$schema": (
73-
"https://schema.management.azure.com/schemas/2018-05-01/" + "subscriptionDeploymentTemplate.json#"
74-
),
75-
"contentVersion": "1.0.0.1",
76-
"parameters": {},
77-
"variables": {},
78-
"resources": [
79-
{
80-
"type": "Microsoft.Resources/resourceGroups",
81-
"apiVersion": "2018-05-01",
82-
"location": location,
83-
"name": AppInsightsDefaults.DEFAULT_RESOURCE_GROUP_NAME.format(location=location),
84-
"properties": {},
85-
}
86-
],
87-
},
88-
},
89-
}
90-
91-
92-
def get_default_log_analytics_deployment(deployment_name: str, location: str, subscription_id: str) -> dict:
93-
return {
94-
"type": "Microsoft.Resources/deployments",
95-
"apiVersion": "2019-10-01",
96-
"name": deployment_name,
97-
"resourceGroup": AppInsightsDefaults.DEFAULT_RESOURCE_GROUP_NAME.format(location=location),
98-
"subscriptionId": subscription_id,
99-
"properties": {
100-
"mode": "Incremental",
101-
"template": {
102-
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
103-
"contentVersion": "1.0.0.0",
104-
"parameters": {},
105-
"variables": {},
106-
"resources": [
107-
{
108-
"apiVersion": "2020-08-01",
109-
"name": AppInsightsDefaults.DEFAULT_LOG_ANALYTICS_NAME.format(location=location),
110-
"type": "Microsoft.OperationalInsights/workspaces",
111-
"location": location,
112-
"properties": {},
113-
}
114-
],
115-
},
116-
},
117-
}

sdk/ml/azure-ai-ml/azure/ai/ml/_utils/_arm_id_utils.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ def __init__(self, arm_id=None):
221221
if match:
222222
self.subscription_id = match.group(1)
223223
self.resource_group_name = match.group(2)
224+
self.provider_namespace_with_type = match.group(3) + match.group(4)
224225
self.asset_type = match.group(4)
225226
self.asset_name = match.group(5)
226227
elif rg_match:

sdk/ml/azure-ai-ml/azure/ai/ml/constants/_common.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,7 @@ class ArmConstants:
303303
STORAGE = "StorageAccount"
304304
KEY_VAULT = "KeyVault"
305305
APP_INSIGHTS = "AppInsights"
306+
LOG_ANALYTICS = "LogAnalytics"
306307
WORKSPACE = "Workspace"
307308

308309
AZURE_MGMT_RESOURCE_API_VERSION = "2020-06-01"

sdk/ml/azure-ai-ml/azure/ai/ml/constants/_workspace.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,6 @@
66
from azure.core import CaseInsensitiveEnumMeta
77

88

9-
class AppInsightsDefaults(object):
10-
DEFAULT_LOG_ANALYTICS_NAME = "DefaultWorkspace-{location}"
11-
DEFAULT_RESOURCE_GROUP_NAME = "DefaultResourceGroup-{location}"
12-
13-
149
class ManagedServiceIdentityType(str, Enum, metaclass=CaseInsensitiveEnumMeta):
1510
"""Type of managed service identity (where both SystemAssigned and UserAssigned types are allowed)."""
1611

sdk/ml/azure-ai-ml/azure/ai/ml/operations/_workspace_operations_base.py

Lines changed: 15 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,7 @@
2828
get_resource_and_group_name,
2929
get_resource_group_location,
3030
)
31-
from azure.ai.ml._utils._appinsights_utils import (
32-
default_resource_group_for_app_insights_exists,
33-
default_log_analytics_workspace_exists,
34-
get_default_resource_group_deployment,
35-
get_default_log_analytics_deployment,
36-
get_default_log_analytics_arm_id,
37-
)
31+
from azure.ai.ml._utils._appinsights_utils import get_log_analytics_arm_id
3832
from azure.ai.ml._utils.utils import camel_to_snake, from_iso_duration_format_min_sec
3933
from azure.ai.ml._version import VERSION
4034
from azure.ai.ml.constants import ManagedServiceIdentityType
@@ -360,62 +354,12 @@ def _populate_arm_paramaters(self, workspace: Workspace, **kwargs: Dict) -> Tupl
360354
group_name,
361355
)
362356
else:
363-
# if workspace is located in a region where app insights is not supported, we do this swap
364-
if workspace.location in ["westcentralus", "eastus2euap", "centraluseuap"]:
365-
app_insights_location = "southcentralus"
366-
else:
367-
app_insights_location = workspace.location
368-
# check if default resource group already exists
369-
rg_is_existing = default_resource_group_for_app_insights_exists(
370-
self._credentials, self._subscription_id, app_insights_location
357+
log_analytics = _generate_log_analytics(workspace.name, resources_being_deployed)
358+
_set_val(param["logAnalyticsName"], log_analytics)
359+
_set_val(
360+
param["logAnalyticsArmId"],
361+
get_log_analytics_arm_id(self._subscription_id, self._resource_group_name, log_analytics),
371362
)
372-
# if default resource group does not exist yet, create rg and log analytics
373-
if not rg_is_existing:
374-
# add resource group and log analytics deployments to resources
375-
deployment_string = get_deployment_name("")
376-
app_insights_resource_group_deployment_name = f"DeployResourceGroup{deployment_string}"
377-
app_insights_log_workspace_deployment_name = f"DeployLogWorkspace{deployment_string}"
378-
template["resources"].append(
379-
get_default_resource_group_deployment(
380-
app_insights_resource_group_deployment_name, app_insights_location, self._subscription_id
381-
)
382-
)
383-
log_analytics_deployment = get_default_log_analytics_deployment(
384-
app_insights_log_workspace_deployment_name, app_insights_location, self._subscription_id
385-
)
386-
log_analytics_deployment["dependsOn"] = [app_insights_resource_group_deployment_name]
387-
template["resources"].append(log_analytics_deployment)
388-
for resource in template["resources"]:
389-
if resource["type"] == "Microsoft.Insights/components":
390-
resource["dependsOn"] = [app_insights_log_workspace_deployment_name]
391-
# if default resource group exists, check default log analytics exists
392-
else:
393-
# check if default log analytics workspace already exists
394-
la_is_existing = default_log_analytics_workspace_exists(
395-
self._credentials, self._subscription_id, app_insights_location
396-
)
397-
# if this does not exist yet, add the deployment needed to resources
398-
if not la_is_existing:
399-
deployment_string = get_deployment_name("")
400-
app_insights_log_workspace_deployment_name = f"DeployLogWorkspace{deployment_string}"
401-
template["resources"].append(
402-
get_default_log_analytics_deployment(
403-
app_insights_log_workspace_deployment_name, app_insights_location, self._subscription_id
404-
)
405-
)
406-
for resource in template["resources"]:
407-
if resource["type"] == "Microsoft.Insights/components":
408-
resource["dependsOn"] = [app_insights_log_workspace_deployment_name]
409-
410-
# add WorkspaceResourceId property to app insights in template
411-
for resource in template["resources"]:
412-
if resource["type"] == "Microsoft.Insights/components":
413-
resource["properties"] = {
414-
"Application_Type": "web",
415-
"WorkspaceResourceId": get_default_log_analytics_arm_id(
416-
self._subscription_id, app_insights_location
417-
),
418-
}
419363

420364
app_insights = _generate_app_insights(workspace.name, resources_being_deployed)
421365
_set_val(param["applicationInsightsName"], app_insights)
@@ -543,6 +487,15 @@ def _generate_storage(name: str, resources_being_deployed: dict) -> str:
543487
return storage
544488

545489

490+
def _generate_log_analytics(name: str, resources_being_deployed: dict) -> str:
491+
log_analytics = get_name_for_dependent_resource(name, "logalytics") # cspell:disable-line
492+
resources_being_deployed[log_analytics] = (
493+
ArmConstants.LOG_ANALYTICS,
494+
None,
495+
)
496+
return log_analytics
497+
498+
546499
def _generate_app_insights(name: str, resources_being_deployed: dict) -> str:
547500
# Application name only allows alphanumeric characters, periods, underscores,
548501
# hyphens and parenthesis and cannot end in a period

sdk/ml/azure-ai-ml/tests/workspace/unittests/test_workspace_operations_base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ def test_populate_arm_paramaters(
215215
"azure.ai.ml.operations._workspace_operations_base.get_resource_group_location", return_value="random_name"
216216
)
217217
mocker.patch(
218-
"azure.ai.ml.operations._workspace_operations_base.get_default_log_analytics_arm_id",
218+
"azure.ai.ml.operations._workspace_operations_base.get_log_analytics_arm_id",
219219
return_value=("random_id", True),
220220
)
221221
mock_workspace_operation_base._populate_arm_paramaters(workspace=Workspace(name="name"))

0 commit comments

Comments
 (0)