Skip to content

Sandraho/add app insights #40327

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

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
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
61 changes: 61 additions & 0 deletions sdk/ai/azure-ai-projects/azure/ai/projects/aio/_patch.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,15 @@
EvaluationsOperations,
TelemetryOperations,
)
from azure.identity import DefaultAzureCredential
from azure.identity import DefaultAzureCredential
Copy link
Contributor

Choose a reason for hiding this comment

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

Double import?

from azure.mgmt.applicationinsights import ApplicationInsightsManagementClient
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

if TYPE_CHECKING:
Expand Down Expand Up @@ -66,6 +75,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
Expand Down Expand Up @@ -259,6 +271,55 @@ def from_connection_string(cls, conn_str: str, credential: "AsyncTokenCredential
credential,
**kwargs,
)

@classmethod
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
: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
"""
# 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=location,
application_type="web",
kind="web"
)
client.components.create_or_update(resource_group_name, resource_name, app_insights_component)

# 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
authorization_client = AuthorizationManagementClient(credential, subscription_id)
role_definition_id = f"/subscriptions/{subscription_id}/providers/Microsoft.Authorization/roleDefinitions/{role_definition}"
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
)
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()
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do you need to redefine the credential value here from the value above?

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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do you need to add all of these dependencies that aren't used in the code?

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
Copy link
Contributor

Choose a reason for hiding this comment

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

Double import of this from above.

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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -797,7 +806,15 @@ def get_connection_string(self) -> str:
)

if not get_workspace_response.properties.application_insights:
Copy link
Member

Choose a reason for hiding this comment

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

The same as the function above

raise ResourceNotFoundError("Application Insights resource was not enabled for this Project.")
# raise ResourceNotFoundError("Application Insights resource was not enabled for this Project.")
# 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",
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(
Expand All @@ -808,6 +825,7 @@ def get_connection_string(self) -> str:

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:
Expand Down
Loading