Skip to content

Commit

Permalink
[Containerapp] az containerapp env telemetry: add command for CRUD ot…
Browse files Browse the repository at this point in the history
…lp settings (#7356)
  • Loading branch information
michaelkira authored Mar 21, 2024
1 parent b82a9fc commit 6af630c
Show file tree
Hide file tree
Showing 12 changed files with 22,114 additions and 2,614 deletions.
7 changes: 7 additions & 0 deletions src/containerapp/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ Release History
===============
upcoming
++++++
* 'az containerapp env telemetry data-dog show': Support show environment data dog configuration
* 'az containerapp env telemetry app-insights show': Support show environment app insights configuration
* 'az containerapp env telemetry otlp add': Support add environment otlp configuration with --otlp-name, --endpoint, --insecure, --headers, --enable-open-telemetry-traces, --enable-open-telemetry-logs and --enable-open-telemetry-metrics
* 'az containerapp env telemetry otlp update': Support update environment otlp configuration with --otlp-name, --endpoint, --insecure, --headers, --enable-open-telemetry-traces, --enable-open-telemetry-logs and --enable-open-telemetry-metrics
* 'az containerapp env telemetry otlp remove': Support remove environment otlp configuration with --otlp-name
* 'az containerapp env telemetry otlp show': Support show environment otlp configuration with --otlp-name
* 'az containerapp env telemetry otlp list': Support show environment otlp configurations

0.3.49
++++++
Expand Down
75 changes: 75 additions & 0 deletions src/containerapp/azext_containerapp/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -1365,6 +1365,15 @@
--site dataDogSite --key dataDogKey --enable-open-telemetry-traces true --enable-open-telemetry-metrics true
"""

helps['containerapp env telemetry data-dog show'] = """
type: command
short-summary: Show container apps environment telemetry data dog settings.
examples:
- name: Show container apps environment telemetry data dog settings.
text: |
az containerapp env telemetry data-dog show -n MyContainerappEnvironment -g MyResourceGroup
"""

helps['containerapp env telemetry app-insights set'] = """
type: command
short-summary: Create or update container apps environment telemetry app insights settings.
Expand All @@ -1375,6 +1384,15 @@
--connection-string connectionString --enable-open-telemetry-traces true --enable-open-telemetry-logs true
"""

helps['containerapp env telemetry app-insights show'] = """
type: command
short-summary: Show container apps environment telemetry app insights settings.
examples:
- name: Show container apps environment telemetry app insights settings.
text: |
az containerapp env telemetry app-insights show -n MyContainerappEnvironment -g MyResourceGroup
"""

helps['containerapp env telemetry data-dog delete'] = """
type: command
short-summary: Delete container apps environment telemetry data dog settings.
Expand All @@ -1392,3 +1410,60 @@
text: |
az containerapp env telemetry app-insights delete -n MyContainerappEnvironment -g MyResourceGroup
"""

helps['containerapp env telemetry otlp'] = """
type: group
short-summary: Commands to manage otlp settings for the container apps environment.
"""

helps['containerapp env telemetry otlp add'] = """
type: command
short-summary: Add container apps environment telemetry otlp settings.
examples:
- name: Add container apps environment telemetry otlp settings.
text: |
az containerapp env telemetry otlp add -n MyContainerappEnvironment -g MyResourceGroup \\
--otlp-name otlpName --endpoint otlpEndpoint --insecure false --headers api-key=apiKey \\
--enable-open-telemetry-traces true --enable-open-telemetry-logs true --enable-open-telemetry-metrics true
"""

helps['containerapp env telemetry otlp update'] = """
type: command
short-summary: Update container apps environment telemetry otlp settings.
examples:
- name: Update container apps environment telemetry otlp settings.
text: |
az containerapp env telemetry otlp update -n MyContainerappEnvironment -g MyResourceGroup \\
--otlp-name otlpName --endpoint otlpEndpoint --insecure false --headers api-key=apiKey \\
--enable-open-telemetry-traces true --enable-open-telemetry-logs true --enable-open-telemetry-metrics true
"""

helps['containerapp env telemetry otlp remove'] = """
type: command
short-summary: Remove container apps environment telemetry otlp settings.
examples:
- name: Remove container apps environment telemetry otlp settings.
text: |
az containerapp env telemetry otlp remove -n MyContainerappEnvironment -g MyResourceGroup \\
--otlp-name otlpName
"""

helps['containerapp env telemetry otlp show'] = """
type: command
short-summary: Show container apps environment telemetry otlp settings.
examples:
- name: Show container apps environment telemetry otlp settings.
text: |
az containerapp env telemetry otlp show -n MyContainerappEnvironment -g MyResourceGroup \\
--otlp-name otlpName
"""

helps['containerapp env telemetry otlp list'] = """
type: command
short-summary: List container apps environment telemetry otlp settings.
examples:
- name: List container apps environment telemetry otlp settings.
text: |
az containerapp env telemetry otlp list -n MyContainerappEnvironment -g MyResourceGroup
"""

22 changes: 18 additions & 4 deletions src/containerapp/azext_containerapp/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@

from .action import AddCustomizedKeys
from ._validators import (validate_env_name_or_id, validate_build_env_vars,
validate_custom_location_name_or_id, validate_env_name_or_id_for_up)
validate_custom_location_name_or_id, validate_env_name_or_id_for_up,
validate_otlp_headers)
from ._constants import MAXIMUM_CONTAINER_APP_NAME_LENGTH, MAXIMUM_APP_RESILIENCY_NAME_LENGTH, MAXIMUM_COMPONENT_RESILIENCY_NAME_LENGTH


Expand Down Expand Up @@ -65,17 +66,30 @@ def load_arguments(self, _):
help='Boolean indicating whether to parse json string log into dynamic json columns. Only work for destination log-analytics.', is_preview=True)

# Telemetry
with self.argument_context('containerapp env telemetry') as c:
c.argument('name', id_part=None)

with self.argument_context('containerapp env telemetry data-dog set') as c:
c.argument('site', options_list=['--site'], help='Specify the data dog site')
c.argument('key', options_list=['--key'], help='Specify the data dog api key')
c.argument('site', help='Specify the data dog site')
c.argument('key', help='Specify the data dog api key')
c.argument('enable_open_telemetry_traces', options_list=['--enable-open-telemetry-traces', '-t'], arg_type=get_three_state_flag(), help='Boolean indicating whether to enable data dog open telemetry traces')
c.argument('enable_open_telemetry_metrics', options_list=['--enable-open-telemetry-metrics', '-m'], arg_type=get_three_state_flag(), help='Boolean indicating whether to enable data dog open telemetry metrics')

with self.argument_context('containerapp env telemetry app-insights set') as c:
c.argument('connection_string', options_list=['--connection-string'], help='Application Insights connection string used by container apps environment')
c.argument('connection_string', help='Application Insights connection string used by container apps environment')
c.argument('enable_open_telemetry_traces', options_list=['--enable-open-telemetry-traces', '-t'], arg_type=get_three_state_flag(), help='Boolean indicating whether to enable application insights open telemetry traces')
c.argument('enable_open_telemetry_logs', options_list=['--enable-open-telemetry-logs', '-l'], arg_type=get_three_state_flag(), help='Boolean indicating whether to enable application insights open telemetry logs')

with self.argument_context('containerapp env telemetry otlp') as c:
c.argument('otlp_name', help='The name of the otlp entry')
c.argument('endpoint', options_list=['--endpoint', '-e'], help='The endpoint of the otlp entry')
c.argument('insecure', arg_type=get_three_state_flag(), help='Boolean indicating whether the otlp is insecure or not')
c.argument('enable_open_telemetry_traces', options_list=['--enable-open-telemetry-traces', '-t'], arg_type=get_three_state_flag(), help='Boolean indicating whether to enable open telemetry traces')
c.argument('enable_open_telemetry_logs', options_list=['--enable-open-telemetry-logs', '-l'], arg_type=get_three_state_flag(), help='Boolean indicating whether to enable open telemetry logs')
c.argument('enable_open_telemetry_metrics', options_list=['--enable-open-telemetry-metrics', '-m'], arg_type=get_three_state_flag(), help='Boolean indicating whether to enable open telemetry metrics')
c.argument('headers', nargs='+', help="A list of headers for the otlp. Space-separated values in 'key=value' format.",
validator=validate_otlp_headers)

# Storage
with self.argument_context('containerapp env storage') as c:
c.argument('storage_type', arg_type=get_enum_type(['AzureFile', 'NfsAzureFile']), help="Type of the storage. Assumed to be AzureFile if not specified.", is_preview=True)
Expand Down
126 changes: 125 additions & 1 deletion src/containerapp/azext_containerapp/_transformers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------
from ._utils import safe_get
from azure.cli.command_modules.containerapp._utils import safe_set, safe_get
from .containerapp_env_telemetry_decorator import DATA_DOG_DEST, APP_INSIGHTS_DEST
from knack.log import get_logger
from azure.cli.core.azclierror import ResourceNotFoundError

logger = get_logger(__name__)


def transform_sensitive_values(response_json):
Expand Down Expand Up @@ -39,3 +44,122 @@ def transform_usages_output(result):
table_result.append(value)

return table_result


def transform_telemetry_data_dog_values(response_json):
containerapp_env_def = response_json

r = safe_get(containerapp_env_def, "properties", "openTelemetryConfiguration", "destinationsConfiguration", "dataDogConfiguration")

if r is not None:
if "key" in safe_get(containerapp_env_def, "properties", "openTelemetryConfiguration", "destinationsConfiguration", "dataDogConfiguration"):
safe_set(r, "key", value=None)

safe_set(r, "site", value=safe_get(containerapp_env_def, "properties", "openTelemetryConfiguration", "destinationsConfiguration", "dataDogConfiguration", "site"))

enable_open_telemetry_traces = False
existing_traces = safe_get(containerapp_env_def, "properties", "openTelemetryConfiguration", "tracesConfiguration", "destinations")
if existing_traces and DATA_DOG_DEST in existing_traces:
enable_open_telemetry_traces = True

safe_set(r, "enableOpenTelemetryTraces", value=enable_open_telemetry_traces)

enable_open_telemetry_metrics = False
existing_metrics = safe_get(containerapp_env_def, "properties", "openTelemetryConfiguration", "metricsConfiguration", "destinations")
if existing_metrics and DATA_DOG_DEST in existing_metrics:
enable_open_telemetry_metrics = True

safe_set(r, "enableOpenTelemetryMetrics", value=enable_open_telemetry_metrics)

return r


def transform_telemetry_app_insights_values(response_json):
containerapp_env_def = response_json

r = safe_get(containerapp_env_def, "properties", "appInsightsConfiguration")

if r is not None:
if "connectionString" in safe_get(containerapp_env_def, "properties", "appInsightsConfiguration"):
safe_set(r, "connectionString", value=None)

enable_open_telemetry_traces = False
existing_traces = safe_get(containerapp_env_def, "properties", "openTelemetryConfiguration", "tracesConfiguration", "destinations")
if existing_traces and APP_INSIGHTS_DEST in existing_traces:
enable_open_telemetry_traces = True

safe_set(r, "enableOpenTelemetryTraces", value=enable_open_telemetry_traces)

enable_open_telemetry_logs = False
existing_logs = safe_get(containerapp_env_def, "properties", "openTelemetryConfiguration", "logsConfiguration", "destinations")
if existing_logs and APP_INSIGHTS_DEST in existing_logs:
enable_open_telemetry_logs = True

safe_set(r, "enableOpenTelemetryLogs", value=enable_open_telemetry_logs)

return r


def transform_telemetry_otlp_values(response_json):
containerapp_env_def = response_json

existing_otlps = safe_get(containerapp_env_def, "properties", "openTelemetryConfiguration", "destinationsConfiguration", "otlpConfigurations")
existing_traces = safe_get(containerapp_env_def, "properties", "openTelemetryConfiguration", "tracesConfiguration", "destinations")
existing_logs = safe_get(containerapp_env_def, "properties", "openTelemetryConfiguration", "logsConfiguration", "destinations")
existing_metrics = safe_get(containerapp_env_def, "properties", "openTelemetryConfiguration", "metricsConfiguration", "destinations")

if existing_otlps is not None:
for otlp in existing_otlps:
if "headers" in otlp:
dict = otlp["headers"]
if dict:
for header in dict:
if "value" in header:
header["value"] = None
enable_open_telemetry_traces = False

otlp_name = safe_get(otlp, "name")

enable_open_telemetry_traces = False
if existing_traces and otlp_name in existing_traces:
enable_open_telemetry_traces = True

safe_set(otlp, "enableOpenTelemetryTraces", value=enable_open_telemetry_traces)

enable_open_telemetry_logs = False
if existing_logs and otlp_name in existing_logs:
enable_open_telemetry_logs = True

safe_set(otlp, "enableOpenTelemetryLogs", value=enable_open_telemetry_logs)

enable_open_telemetry_metrics = False
if existing_metrics and otlp_name in existing_metrics:
enable_open_telemetry_metrics = True

safe_set(otlp, "enableOpenTelemetryMetrics", value=enable_open_telemetry_metrics)

return existing_otlps


def transform_telemetry_otlp_values_by_name_wrapper(args):
def transform_telemetry_otlp_values_by_name(response_json):
if '--otlp-name' in args:
otlp_name = args[args.index("--otlp-name") + 1]
if not otlp_name:
raise ResourceNotFoundError(f"Otlp entry does not exist, please retry with different name")
existing_otlps = safe_get(response_json, "properties", "openTelemetryConfiguration", "destinationsConfiguration", "otlpConfigurations")
otlp = [p for p in existing_otlps if p["name"].lower() == otlp_name.lower()]
if otlp:
existing_otlps = otlp
else:
raise ResourceNotFoundError(f"Otlp entry with name --otlp-name {otlp_name} does not exist, please retry with different name")
safe_set(response_json, "properties", "openTelemetryConfiguration", "destinationsConfiguration", "otlpConfigurations", value=existing_otlps)
existing_otlps = transform_telemetry_otlp_values(response_json)
if existing_otlps:
return existing_otlps[0]

raise ResourceNotFoundError(f"Otlp entry with name --otlp-name {otlp_name} does not exist, please retry with different name")

return transform_telemetry_otlp_values_by_name


19 changes: 19 additions & 0 deletions src/containerapp/azext_containerapp/_validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,3 +169,22 @@ def validate_build_env_vars(cmd, namespace):
"Duplicate build environment variable {env} found, environment variable names must be unique.".format(
env=key_val[0]))
env_pairs[key_val[0]] = key_val[1]

def validate_otlp_headers(cmd, namespace):
headers = namespace.headers

if not headers:
return

header_pairs = {}

for pair in headers:
key_val = pair.split('=', 1)
if len(key_val) != 2:
raise ValidationError("Otlp headers must be in the format \"<key>=<value>\".")
if key_val[0] in header_pairs:
raise ValidationError(
"Duplicate headers {header} found, header names must be unique.".format(
header=key_val[0]))
header_pairs[key_val[0]] = key_val[1]

Loading

0 comments on commit 6af630c

Please sign in to comment.