From 281bd37827568293a132cb51128a2024ab13dcd0 Mon Sep 17 00:00:00 2001 From: Sandra Ho Date: Tue, 25 Mar 2025 09:28:32 -0700 Subject: [PATCH 1/5] app insights, added into telemetryoperations as part of the projects class. might need to move to AIProjectClient class instead. --- .../azure/ai/projects/operations/_patch.py | 55 ++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch.py b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch.py index 0db1e7c1a4b8..819abf1c6e04 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch.py @@ -29,7 +29,16 @@ ) from azure.core.exceptions import ResourceNotFoundError +from azure.identity import DefaultAzureCredential from azure.core.tracing.decorator import distributed_trace +from azure.mgmt.applicationinsights import ApplicationInsightsManagementClient +from azure.mgmt.applicationinsights.v2018_05_01_preview.models import ApplicationInsightsComponent +from azure.identity import DefaultAzureCredential +from azure.mgmt.applicationinsights import ApplicationInsightsManagementClient +from azure.mgmt.applicationinsights.models import ApplicationInsightsComponent +from azure.mgmt.authorization import AuthorizationManagementClient +from azure.mgmt.authorization.models import RoleAssignmentCreateParameters +import uuid from .. import models as _models from .._vendor import FileType @@ -797,7 +806,13 @@ def get_connection_string(self) -> str: ) if not get_workspace_response.properties.application_insights: - raise ResourceNotFoundError("Application Insights resource was not enabled for this Project.") + # raise ResourceNotFoundError("Application Insights resource was not enabled for this Project.") + # pur in + self._outer_instance.telemetry.create_application_insights_if_not_exists( + resource_group_name=get_workspace_response.properties.resourceGroupName, + resource_name="your_resource_name", + location="your_location" + ) # Make a GET call to the Application Insights resource URL to get the connection string app_insights_respose: GetAppInsightsResponse = self._get_app_insights( @@ -808,6 +823,44 @@ def get_connection_string(self) -> str: return self._connection_string + def create_application_insights_if_not_exists(self, resource_group_name: str, resource_name: str, location: str) -> str: + """Create an Application Insights resource and assign RBAC roles. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param resource_name: The name of the Application Insights resource. + :type resource_name: str + :param location: The location of the resource. + :type location: str + :return: The connection string of the Application Insights resource. + :rtype: str + """ + credential = DefaultAzureCredential() + client = ApplicationInsightsManagementClient(credential, self._outer_instance.subscription_id) + app_insights_component = ApplicationInsightsComponent( + location=location, + application_type="web", + kind="web" + ) + + component = client.components.get(resource_group_name, resource_name) + self.connection_string = component.connection_string + + # Assign RBAC roles + authorization_client = AuthorizationManagementClient(credential, self._outer_instance.subscription_id) + role_definition_id = f"/subscriptions/{self._outer_instance.subscription_id}/providers/Microsoft.Authorization/roleDefinitions/{role_definition_here}" + principal_id = "your-principal-id" # Replace with the actual principal ID + + role_assignment_params = RoleAssignmentCreateParameters( + role_definition_id=role_definition_id, + principal_id=principal_id + ) + scope = f"/subscriptions/{self._outer_instance.subscription_id}/resourceGroups/{resource_group_name}/providers/microsoft.insights/components/{resource_name}" + role_assignment_name = #tbd here + authorization_client.role_assignments.create(scope, role_assignment_name, role_assignment_params) + + return self.connection_string + # TODO: what about `set AZURE_TRACING_GEN_AI_CONTENT_RECORDING_ENABLED=true`? # TODO: This could be a class method. But we don't have a class property AIProjectClient.telemetry def enable(self, *, destination: Union[TextIO, str, None] = None, **kwargs) -> None: From d3af774a5b03fed213f66bc54be03022545793f2 Mon Sep 17 00:00:00 2001 From: Sandra Ho Date: Tue, 25 Mar 2025 09:33:52 -0700 Subject: [PATCH 2/5] app insights changes to add permissions and create if not exists. have to check how service will link into sdk --- .../azure-ai-projects/azure/ai/projects/operations/_patch.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch.py b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch.py index 819abf1c6e04..808090334d97 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch.py @@ -807,7 +807,9 @@ def get_connection_string(self) -> str: if not get_workspace_response.properties.application_insights: # raise ResourceNotFoundError("Application Insights resource was not enabled for this Project.") - # pur in + # instead or raising resource not found, create resource. may need to refactor depending on if + # we want this to be client choice to create the app insights in case resource doesnt exist + # or just do this automatically self._outer_instance.telemetry.create_application_insights_if_not_exists( resource_group_name=get_workspace_response.properties.resourceGroupName, resource_name="your_resource_name", From 7d7a1de7483dfd646f375ac847d24b196d9a69be Mon Sep 17 00:00:00 2001 From: Sandra Ho Date: Tue, 1 Apr 2025 16:25:58 -0700 Subject: [PATCH 3/5] changes for python sdk --- .../ai/projects/aio/operations/_operations.py | 40 +++++++++++++ .../ai/projects/aio/operations/_patch.py | 59 ++++++++++++++++++- .../azure/ai/projects/operations/_patch.py | 37 ------------ 3 files changed, 98 insertions(+), 38 deletions(-) diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_operations.py b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_operations.py index a5a59c511450..3f01083cf4bb 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_operations.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_operations.py @@ -5401,6 +5401,46 @@ def __init__(self, *args, **kwargs) -> None: self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") + @distributed_trace_async + async def create_application_insights_if_not_exists(self, resource_group_name: str, resource_name: str, location: str) -> str: + """Create an Application Insights resource and assign RBAC roles. + + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param resource_name: The name of the Application Insights resource. + :type resource_name: str + :param location: The location of the resource. + :type location: str + :return: The connection string of the Application Insights resource. + :rtype: str + """ + credential = DefaultAzureCredential() + client = ApplicationInsightsManagementClient(credential, self._outer_instance.subscription_id) + app_insights_component = ApplicationInsightsComponent( + location=location, + application_type="web", + kind="web" + ) + + component = client.components.get(resource_group_name, resource_name) + self.connection_string = component.connection_string + + # Assign RBAC roles + role_definition = '3913510d-42f4-4e42-8a64-420c390055eb' # monitoring metrics publisher" + authorization_client = AuthorizationManagementClient(credential, self._outer_instance.subscription_id) + role_definition_id = f"/subscriptions/{self._outer_instance.subscription_id}/providers/Microsoft.Authorization/roleDefinitions/{role_definition}" + principal_id = "" # this should be RAISvc principal ID. + + role_assignment_params = RoleAssignmentCreateParameters( + role_definition_id=role_definition_id, + principal_id=principal_id + ) + scope = f"/subscriptions/{self._outer_instance.subscription_id}/resourceGroups/{resource_group_name}/providers/microsoft.insights/components/{resource_name}" + role_assignment_name = "monitoring-metrics-publisher" + authorization_client.role_assignments.create(scope, role_assignment_name, role_assignment_params) + + return self.connection_string + @distributed_trace_async async def _get_app_insights( self, app_insights_resource_url: str, **kwargs: Any diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch.py b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch.py index ca9fe7d7ad6a..27d707b3e77c 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch.py @@ -33,6 +33,16 @@ from azure.core.credentials import TokenCredential from azure.core.exceptions import ResourceNotFoundError from azure.core.tracing.decorator_async import distributed_trace_async +from azure.identity import DefaultAzureCredential +from azure.core.tracing.decorator import distributed_trace +from azure.mgmt.applicationinsights import ApplicationInsightsManagementClient +from azure.mgmt.applicationinsights.v2018_05_01_preview.models import ApplicationInsightsComponent +from azure.identity import DefaultAzureCredential +from azure.mgmt.applicationinsights import ApplicationInsightsManagementClient +from azure.mgmt.applicationinsights.models import ApplicationInsightsComponent +from azure.mgmt.authorization import AuthorizationManagementClient +from azure.mgmt.authorization.models import RoleAssignmentCreateParameters +import uuid from ... import models as _models from ..._vendor import FileType @@ -600,6 +610,44 @@ def __init__(self, *args, **kwargs): self._outer_instance = kwargs.pop("outer_instance") super().__init__(*args, **kwargs) + async def create_application_insights_if_not_exists(self, resource_group_name: str, resource_name: str, location: str) -> str: + from azure.identity import DefaultAzureCredential + from azure.mgmt.applicationinsights import ApplicationInsightsManagementClient + from azure.mgmt.applicationinsights.models import ApplicationInsightsComponent + from azure.mgmt.authorization import AuthorizationManagementClient + from azure.mgmt.authorization.models import RoleAssignmentCreateParameters + import uuid + + token_credential = DefaultAzureCredential() + client = ApplicationInsightsManagementClient(token_credential, self._config.subscription_id) + + try: + component = client.components.get(resource_group_name, resource_name) + except Exception: + app_insights_component = ApplicationInsightsComponent( + location=location, + application_type="web", + kind="web" + ) + component = client.components.create_or_update(resource_group_name, resource_name, app_insights_component) + + # Assign RBAC roles + role_definition = '3913510d-42f4-4e42-8a64-420c390055eb' # monitoring metrics publisher + authorization_client = AuthorizationManagementClient(token_credential, self._config.subscription_id) + role_definition_id = f"/subscriptions/{self._config.subscription_id}/providers/Microsoft.Authorization/roleDefinitions/{role_definition}" + principal_id = "" # this should be RAISvc principal ID. + + role_assignment_params = RoleAssignmentCreateParameters( + role_definition_id=role_definition_id, + principal_id=principal_id + ) + + scope = f"/subscriptions/{self._config.subscription_id}/resourceGroups/{resource_group_name}/providers/microsoft.insights/components/{resource_name}" + role_assignment_name = str(uuid.uuid4()) + authorization_client.role_assignments.create(scope, role_assignment_name, role_assignment_params) + + return component.connection_string + async def get_connection_string(self) -> str: """Get the Application Insights connection string associated with the Project's Application Insights resource. @@ -616,7 +664,16 @@ async def get_connection_string(self) -> str: ) if not get_workspace_response.properties.application_insights: - raise ResourceNotFoundError("Application Insights resource was not enabled for this Project.") + # create an AppInsights for the customer using the resource group and project name + create_app_insights_response = await self.create_application_insights_if_not_exists( + resource_group_name=self._outer_instance.resource_group_name, + resource_name=self._outer_instance.project_name, + location=get_workspace_response.location, + ) + if not create_app_insights_response: + raise ResourceNotFoundError("Application Insights resource was not able to be created for this Project.") + + #raise ResourceNotFoundError("Application Insights resource was not enabled for this Project.") # Make a GET call to the Application Insights resource URL to get the connection string app_insights_respose: GetAppInsightsResponse = await self._get_app_insights( diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch.py b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch.py index 808090334d97..a6d29ffe68b1 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/operations/_patch.py @@ -825,43 +825,6 @@ def get_connection_string(self) -> str: return self._connection_string - def create_application_insights_if_not_exists(self, resource_group_name: str, resource_name: str, location: str) -> str: - """Create an Application Insights resource and assign RBAC roles. - - :param resource_group_name: The name of the resource group. - :type resource_group_name: str - :param resource_name: The name of the Application Insights resource. - :type resource_name: str - :param location: The location of the resource. - :type location: str - :return: The connection string of the Application Insights resource. - :rtype: str - """ - credential = DefaultAzureCredential() - client = ApplicationInsightsManagementClient(credential, self._outer_instance.subscription_id) - app_insights_component = ApplicationInsightsComponent( - location=location, - application_type="web", - kind="web" - ) - - component = client.components.get(resource_group_name, resource_name) - self.connection_string = component.connection_string - - # Assign RBAC roles - authorization_client = AuthorizationManagementClient(credential, self._outer_instance.subscription_id) - role_definition_id = f"/subscriptions/{self._outer_instance.subscription_id}/providers/Microsoft.Authorization/roleDefinitions/{role_definition_here}" - principal_id = "your-principal-id" # Replace with the actual principal ID - - role_assignment_params = RoleAssignmentCreateParameters( - role_definition_id=role_definition_id, - principal_id=principal_id - ) - scope = f"/subscriptions/{self._outer_instance.subscription_id}/resourceGroups/{resource_group_name}/providers/microsoft.insights/components/{resource_name}" - role_assignment_name = #tbd here - authorization_client.role_assignments.create(scope, role_assignment_name, role_assignment_params) - - return self.connection_string # TODO: what about `set AZURE_TRACING_GEN_AI_CONTENT_RECORDING_ENABLED=true`? # TODO: This could be a class method. But we don't have a class property AIProjectClient.telemetry From 48e37b826c324158afc0b22e698a8f68b3f3f9ba Mon Sep 17 00:00:00 2001 From: Sandra Ho Date: Wed, 2 Apr 2025 15:36:58 -0700 Subject: [PATCH 4/5] move creation into optional, user will provide a bool on whether they want to opt in for app insights --- .../azure/ai/projects/aio/_patch.py | 54 +++++++++++++++++++ .../ai/projects/aio/operations/_operations.py | 40 -------------- .../ai/projects/aio/operations/_patch.py | 49 +---------------- 3 files changed, 55 insertions(+), 88 deletions(-) diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/_patch.py b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/_patch.py index 6e36aa81fed5..c1f5af75db2f 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/_patch.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/_patch.py @@ -25,6 +25,16 @@ EvaluationsOperations, TelemetryOperations, ) +from azure.identity import DefaultAzureCredential +from azure.core.tracing.decorator import distributed_trace +from azure.mgmt.applicationinsights import ApplicationInsightsManagementClient +from azure.mgmt.applicationinsights.v2018_05_01_preview.models import ApplicationInsightsComponent +from azure.identity import DefaultAzureCredential +from azure.mgmt.applicationinsights import ApplicationInsightsManagementClient +from azure.mgmt.applicationinsights.models import ApplicationInsightsComponent +from azure.mgmt.authorization import AuthorizationManagementClient +from azure.mgmt.authorization.models import RoleAssignmentCreateParameters +import uuid from .operations._patch import _SyncCredentialWrapper, InferenceOperations if TYPE_CHECKING: @@ -66,6 +76,9 @@ def __init__( # pylint: disable=super-init-not-called,too-many-statements kwargs3 = kwargs.copy() self._user_agent: Optional[str] = kwargs.get("user_agent", None) + self._create_app_insights: Optional[bool] = kwargs.get("create_app_insights", None) + if self._create_app_insights: + self.create_app_insights(subscription_id, resource_group_name, project_name, credential) # For getting AppInsights connection string from the AppInsights resource. # The AppInsights resource URL is not known at this point. We need to get it from the @@ -259,6 +272,47 @@ def from_connection_string(cls, conn_str: str, credential: "AsyncTokenCredential credential, **kwargs, ) + + @classmethod + def create_app_insights(cls, subscription_id, resource_group_name, project_name, credential) -> None: + """Create an Application Insights resource and assign RBAC roles. + :param resource_group_name: The name of the resource group. + :type resource_group_name: str + :param resource_name: The name of the Application Insights resource. + :type resource_name: str + :param location: The location of the resource. + :type location: str + :return: The connection string of the Application Insights resource. + :rtype: str + """ + credential = DefaultAzureCredential() + client = ApplicationInsightsManagementClient(credential, subscription_id) + app_insights_component = ApplicationInsightsComponent( + location=cls.location + application_type="web", + kind="web" + ) + + component = client.components.get(resource_group_name, project_name) + connection_string = component.connection_string + + # Assign RBAC roles + role_definition = '3913510d-42f4-4e42-8a64-420c390055eb' # monitoring metrics publisher" + authorization_client = AuthorizationManagementClient(credential, subscription_id) + role_definition_id = f"/subscriptions/{subscription_id}/providers/Microsoft.Authorization/roleDefinitions/{role_definition}" + principal_id = "" # this should be RAISvc principal ID. + + role_assignment_params = RoleAssignmentCreateParameters( + role_definition_id=role_definition_id, + principal_id=principal_id + ) + scope = f"/subscriptions/{subscription_id}/resourceGroups/{resource_group_name}/providers/microsoft.insights/components/{resource_name}" + role_assignment_name = "monitoring-metrics-publisher" + authorization_client.role_assignments.create(scope, role_assignment_name, role_assignment_params) + # create an AIProject from the connection string of the app insights we just created + + cls.from_connection_string(connection_string, credential) + def upload_file(self, file_path: Union[Path, str, PathLike]) -> Tuple[str, str]: """Upload a file to the Azure AI Foundry project. diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_operations.py b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_operations.py index 3f01083cf4bb..a5a59c511450 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_operations.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_operations.py @@ -5401,46 +5401,6 @@ def __init__(self, *args, **kwargs) -> None: self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") - @distributed_trace_async - async def create_application_insights_if_not_exists(self, resource_group_name: str, resource_name: str, location: str) -> str: - """Create an Application Insights resource and assign RBAC roles. - - :param resource_group_name: The name of the resource group. - :type resource_group_name: str - :param resource_name: The name of the Application Insights resource. - :type resource_name: str - :param location: The location of the resource. - :type location: str - :return: The connection string of the Application Insights resource. - :rtype: str - """ - credential = DefaultAzureCredential() - client = ApplicationInsightsManagementClient(credential, self._outer_instance.subscription_id) - app_insights_component = ApplicationInsightsComponent( - location=location, - application_type="web", - kind="web" - ) - - component = client.components.get(resource_group_name, resource_name) - self.connection_string = component.connection_string - - # Assign RBAC roles - role_definition = '3913510d-42f4-4e42-8a64-420c390055eb' # monitoring metrics publisher" - authorization_client = AuthorizationManagementClient(credential, self._outer_instance.subscription_id) - role_definition_id = f"/subscriptions/{self._outer_instance.subscription_id}/providers/Microsoft.Authorization/roleDefinitions/{role_definition}" - principal_id = "" # this should be RAISvc principal ID. - - role_assignment_params = RoleAssignmentCreateParameters( - role_definition_id=role_definition_id, - principal_id=principal_id - ) - scope = f"/subscriptions/{self._outer_instance.subscription_id}/resourceGroups/{resource_group_name}/providers/microsoft.insights/components/{resource_name}" - role_assignment_name = "monitoring-metrics-publisher" - authorization_client.role_assignments.create(scope, role_assignment_name, role_assignment_params) - - return self.connection_string - @distributed_trace_async async def _get_app_insights( self, app_insights_resource_url: str, **kwargs: Any diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch.py b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch.py index 27d707b3e77c..3214d496157d 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/operations/_patch.py @@ -610,44 +610,6 @@ def __init__(self, *args, **kwargs): self._outer_instance = kwargs.pop("outer_instance") super().__init__(*args, **kwargs) - async def create_application_insights_if_not_exists(self, resource_group_name: str, resource_name: str, location: str) -> str: - from azure.identity import DefaultAzureCredential - from azure.mgmt.applicationinsights import ApplicationInsightsManagementClient - from azure.mgmt.applicationinsights.models import ApplicationInsightsComponent - from azure.mgmt.authorization import AuthorizationManagementClient - from azure.mgmt.authorization.models import RoleAssignmentCreateParameters - import uuid - - token_credential = DefaultAzureCredential() - client = ApplicationInsightsManagementClient(token_credential, self._config.subscription_id) - - try: - component = client.components.get(resource_group_name, resource_name) - except Exception: - app_insights_component = ApplicationInsightsComponent( - location=location, - application_type="web", - kind="web" - ) - component = client.components.create_or_update(resource_group_name, resource_name, app_insights_component) - - # Assign RBAC roles - role_definition = '3913510d-42f4-4e42-8a64-420c390055eb' # monitoring metrics publisher - authorization_client = AuthorizationManagementClient(token_credential, self._config.subscription_id) - role_definition_id = f"/subscriptions/{self._config.subscription_id}/providers/Microsoft.Authorization/roleDefinitions/{role_definition}" - principal_id = "" # this should be RAISvc principal ID. - - role_assignment_params = RoleAssignmentCreateParameters( - role_definition_id=role_definition_id, - principal_id=principal_id - ) - - scope = f"/subscriptions/{self._config.subscription_id}/resourceGroups/{resource_group_name}/providers/microsoft.insights/components/{resource_name}" - role_assignment_name = str(uuid.uuid4()) - authorization_client.role_assignments.create(scope, role_assignment_name, role_assignment_params) - - return component.connection_string - async def get_connection_string(self) -> str: """Get the Application Insights connection string associated with the Project's Application Insights resource. @@ -664,16 +626,7 @@ async def get_connection_string(self) -> str: ) if not get_workspace_response.properties.application_insights: - # create an AppInsights for the customer using the resource group and project name - create_app_insights_response = await self.create_application_insights_if_not_exists( - resource_group_name=self._outer_instance.resource_group_name, - resource_name=self._outer_instance.project_name, - location=get_workspace_response.location, - ) - if not create_app_insights_response: - raise ResourceNotFoundError("Application Insights resource was not able to be created for this Project.") - - #raise ResourceNotFoundError("Application Insights resource was not enabled for this Project.") + raise ResourceNotFoundError("Application Insights resource was not enabled for this Project.") # Make a GET call to the Application Insights resource URL to get the connection string app_insights_respose: GetAppInsightsResponse = await self._get_app_insights( From edcacedf334c96dd61d406543c3149098ae82afc Mon Sep 17 00:00:00 2001 From: Sandra Ho Date: Wed, 2 Apr 2025 16:15:05 -0700 Subject: [PATCH 5/5] api version type mismatch --- .../azure/ai/projects/aio/_patch.py | 41 +++++++++++-------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/_patch.py b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/_patch.py index c1f5af75db2f..5c8fbcc18ab2 100644 --- a/sdk/ai/azure-ai-projects/azure/ai/projects/aio/_patch.py +++ b/sdk/ai/azure-ai-projects/azure/ai/projects/aio/_patch.py @@ -26,14 +26,13 @@ TelemetryOperations, ) from azure.identity import DefaultAzureCredential -from azure.core.tracing.decorator import distributed_trace -from azure.mgmt.applicationinsights import ApplicationInsightsManagementClient -from azure.mgmt.applicationinsights.v2018_05_01_preview.models import ApplicationInsightsComponent from azure.identity import DefaultAzureCredential from azure.mgmt.applicationinsights import ApplicationInsightsManagementClient -from azure.mgmt.applicationinsights.models import ApplicationInsightsComponent +from azure.mgmt.applicationinsights.v2020_02_02_preview.models import ApplicationInsightsComponent from azure.mgmt.authorization import AuthorizationManagementClient from azure.mgmt.authorization.models import RoleAssignmentCreateParameters +from azure.mgmt.applicationinsights.v2020_02_02_preview.operations._components_operations import ComponentsOperations + import uuid from .operations._patch import _SyncCredentialWrapper, InferenceOperations @@ -274,7 +273,7 @@ def from_connection_string(cls, conn_str: str, credential: "AsyncTokenCredential ) @classmethod - def create_app_insights(cls, subscription_id, resource_group_name, project_name, credential) -> None: + def create_app_insights(cls, subscription_id, resource_group_name, resource_name, location, principal_id, credential=None) -> Self: """Create an Application Insights resource and assign RBAC roles. :param resource_group_name: The name of the resource group. :type resource_group_name: str @@ -285,34 +284,42 @@ def create_app_insights(cls, subscription_id, resource_group_name, project_name, :return: The connection string of the Application Insights resource. :rtype: str """ - credential = DefaultAzureCredential() + # Use provided credential or create a new one + credential = credential or DefaultAzureCredential() + + # Create Application Insights resource client = ApplicationInsightsManagementClient(credential, subscription_id) app_insights_component = ApplicationInsightsComponent( - location=cls.location + location=location, application_type="web", kind="web" ) + client.components.create_or_update(resource_group_name, resource_name, app_insights_component) - component = client.components.get(resource_group_name, project_name) + # Retrieve the connection string + component = client.components.get(resource_group_name, resource_name) connection_string = component.connection_string # Assign RBAC roles - role_definition = '3913510d-42f4-4e42-8a64-420c390055eb' # monitoring metrics publisher" + role_definition = '3913510d-42f4-4e42-8a64-420c390055eb' # Monitoring Metrics Publisher authorization_client = AuthorizationManagementClient(credential, subscription_id) role_definition_id = f"/subscriptions/{subscription_id}/providers/Microsoft.Authorization/roleDefinitions/{role_definition}" - principal_id = "" # this should be RAISvc principal ID. + scope = f"/subscriptions/{subscription_id}/resourceGroups/{resource_group_name}/providers/microsoft.insights/components/{resource_name}" + role_assignment_name = str(uuid.uuid4()) # Generate a unique role assignment name role_assignment_params = RoleAssignmentCreateParameters( role_definition_id=role_definition_id, principal_id=principal_id ) - scope = f"/subscriptions/{subscription_id}/resourceGroups/{resource_group_name}/providers/microsoft.insights/components/{resource_name}" - role_assignment_name = "monitoring-metrics-publisher" - authorization_client.role_assignments.create(scope, role_assignment_name, role_assignment_params) - # create an AIProject from the connection string of the app insights we just created - - cls.from_connection_string(connection_string, credential) - + authorization_client.role_assignments.create( + scope=scope, + role_assignment_name=role_assignment_name, + parameters=role_assignment_params + ) + if not connection_string: + raise ValueError("Connection string cannot be None") + credential = DefaultAzureCredential() + return cls.from_connection_string(connection_string, credential) def upload_file(self, file_path: Union[Path, str, PathLike]) -> Tuple[str, str]: """Upload a file to the Azure AI Foundry project.