Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 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 src/containerapp/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ Release History
===============
upcoming
++++++
* 'az containerapp function invocations': modifications to app-insights query
* 'az containerapp function keys': updating min-replica check

1.3.0b1
++++++
Expand Down
23 changes: 23 additions & 0 deletions src/containerapp/azext_containerapp/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -835,6 +835,17 @@ def create_acrpull_role_assignment_if_needed(cmd, registry_server, registry_iden
time.sleep(5)


def get_min_replicas_from_revision(cmd, resource_group_name, container_app_name, revision_name):
revision_def = ContainerAppClient.show_revision(
cmd=cmd,
resource_group_name=resource_group_name,
container_app_name=container_app_name,
name=revision_name
)
min_replicas = safe_get(revision_def, "properties", "template", "scale", "minReplicas", default=None)
return min_replicas


def get_random_replica(cmd, resource_group_name, container_app_name, revision_name):
logger.debug(f"Getting random replica for container app: name='{container_app_name}', resource_group='{resource_group_name}', revision='{revision_name}'")

Expand All @@ -851,6 +862,18 @@ def get_random_replica(cmd, resource_group_name, container_app_name, revision_na

if not replicas:
logger.debug(f"No replicas found for revision '{revision_name}' - unable to proceed")
logger.debug(f"checking min replica count for revision='{revision_name}'")

min_replicas = get_min_replicas_from_revision(
cmd,
resource_group_name,
container_app_name,
revision_name
)
if min_replicas is None or min_replicas == 0:
logger.debug(f"The revision '{revision_name}' has minReplicas set to 0.")
raise CLIError(f"The revision '{revision_name}' has minReplicas set to 0. Ensure that there is at least one replica. To update minimum replica: Run 'az containerapp update --name {container_app_name} --resource-group {resource_group_name} --min-replica 1'")

raise CLIError(f"No replicas found for revision '{revision_name}' of container app '{container_app_name}'.")

# Filter replicas by running state
Expand Down
6 changes: 3 additions & 3 deletions src/containerapp/azext_containerapp/_validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ def validate_revision_and_get_name(cmd, resource_group_name, container_app_name,
if not provided_revision_name:
logger.debug("No revision name provided for multiple revision mode container app")
raise ValidationError("Revision name is required when active revision mode is not 'single'.")
return provided_revision_name
return provided_revision_name, active_revision_mode
if not provided_revision_name:
logger.debug("No revision name provided - attempting to determine latest revision")
revision_name = safe_get(containerapp_def, "properties", "latestRevisionName")
Expand All @@ -331,9 +331,9 @@ def validate_revision_and_get_name(cmd, resource_group_name, container_app_name,
if not revision_name or revision_name is None:
logger.debug("Could not determine any revision name from container app properties")
raise ValidationError("Could not determine the latest revision name. Please provide --revision.")
return revision_name
return revision_name, active_revision_mode
logger.debug("Using provided revision name: '%s'", provided_revision_name)
return provided_revision_name
return provided_revision_name, active_revision_mode


def validate_functionapp_kind(cmd, resource_group_name, container_app_name):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def validate_common_arguments(self):
)

# Validate revision and get the appropriate revision name
revision_name = validate_revision_and_get_name(
revision_name, _ = validate_revision_and_get_name(
cmd=self.cmd,
resource_group_name=resource_group_name,
container_app_name=name,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ def validate_common_arguments(self):
)

# Validate revision and get the appropriate revision name
revision_name = validate_revision_and_get_name(
revision_name, _ = validate_revision_and_get_name(
cmd=self.cmd,
resource_group_name=resource_group_name,
container_app_name=name,
Expand Down Expand Up @@ -170,6 +170,10 @@ class ContainerAppFunctionInvocationsDecorator(ContainerAppFunctionsDecorator):

APP_INSIGHTS_API_VERSION = "2018-04-20"

def __init__(self, cmd, client, raw_parameters, models):
super().__init__(cmd, client, raw_parameters, models)
self.active_revision_mode = None

def validate_arguments(self):
"""Validate arguments required for function invocation operations"""
validate_basic_arguments(
Expand All @@ -185,14 +189,17 @@ def validate_arguments(self):
)

revision_name = self.get_argument_revision_name()
revision_name = validate_revision_and_get_name(
revision_name, active_revision_mode = validate_revision_and_get_name(
cmd=self.cmd,
resource_group_name=self.get_argument_resource_group_name(),
container_app_name=self.get_argument_container_app_name(),
provided_revision_name=revision_name
)

# Update the revision name with the validated value
self.set_argument_revision_name(revision_name)
# Store active revision mode for use in query building
self.active_revision_mode = active_revision_mode
self.validate_function_name_requirement()

def _get_app_insights_id(self, resource_group_name, container_app_name, revision_name):
Expand Down Expand Up @@ -267,12 +274,14 @@ def get_summary(self):
# Fetch the app insights resource app id
app_id = self._get_app_insights_id(resource_group_name, container_app_name, revision_name)

# Use application insights query to get function invocations summary
# Set revision_name to empty string for single mode, keep it for multiple mode
revision_name = "" if self.active_revision_mode.lower() == "single" else revision_name

invocation_summary_query = (
f"requests | extend functionNameFromCustomDimension = tostring(customDimensions['faas.name']) "
f"| where timestamp >= ago({timespan}) "
f"| where cloud_RoleName =~ '{container_app_name}' "
f"| where cloud_RoleInstance contains '{revision_name}' "
f"| where isempty(\"{revision_name}\") or cloud_RoleInstance contains '{revision_name}' "
f"| where operation_Name =~ '{function_name}' or functionNameFromCustomDimension =~ '{function_name}' "
f"| summarize SuccessCount = coalesce(countif(success == true), 0), ErrorCount = coalesce(countif(success == false), 0)"
)
Expand All @@ -299,14 +308,16 @@ def get_traces(self):
# Fetch the app insights resource app id
app_id = self._get_app_insights_id(resource_group_name, container_app_name, revision_name)

# Use application insights query to get function invocations traces
# Set revision_name to empty string for single mode, keep it for multiple mode
revision_name = "" if self.active_revision_mode.lower() == "single" else revision_name

invocation_traces_query = (
f"requests | extend functionNameFromCustomDimension = tostring(customDimensions['faas.name']) "
f"| project timestamp, id, operation_Name, success, resultCode, duration, operation_Id, functionNameFromCustomDimension, "
f"cloud_RoleName, cloud_RoleInstance, invocationId=coalesce(tostring(customDimensions['InvocationId']), tostring(customDimensions['faas.invocation_id'])) "
f"| where timestamp > ago({timespan}) "
f"| where cloud_RoleName =~ '{container_app_name}' "
f"| where cloud_RoleInstance contains '{revision_name}' "
f"| where isempty(\"{revision_name}\") or cloud_RoleInstance contains '{revision_name}' "
f"| where operation_Name =~ '{function_name}' or functionNameFromCustomDimension =~ '{function_name}' "
f"| order by timestamp desc | take {limit} "
f"| project timestamp, success, resultCode, durationInMilliSeconds=duration, invocationId, operationId=operation_Id, operationName=operation_Name, functionNameFromCustomDimension "
Expand Down
Loading