Skip to content
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

[containerapp] Hide containerapps and jobs env vars on create and update #6867

Merged
merged 11 commits into from
Oct 25, 2023
2 changes: 2 additions & 0 deletions src/containerapp/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ upcoming
* 'az containerapp compose create': fixed an issue where the environment's resource group was not resolved from --environment when the input value was a resource id.
* 'az containerapp replica count', returns the replica count of a container app
* [Breaking Change] 'az containerapp job create': add default values for container app job properties --replica-completion-count, --replica-retry-limit, --replica-timeout, --parallelism, --min-executions, --max-executions, --polling-interval
* 'az containerapp create/update': hide environment variables, scale rules metadata
* 'az containerapp job create/update': hide environment variables, scale rules metadata, eventTriggerConfig for job
* [Breaking Change] 'az containerapp env create': update the default value of --enable-workload-profiles to `True`
* 'az containerapp compose create': fix containerapp invalid memory resource

Expand Down
21 changes: 21 additions & 0 deletions src/containerapp/azext_containerapp/_transformers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
# 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


def transform_containerapp_output(app):
Expand All @@ -17,6 +18,26 @@ def transform_containerapp_output(app):
return result


def transform_sensitive_values(response_json):
for container in safe_get(response_json, "properties", "template", "containers", default=[]):
if "env" in container:
for env in container["env"]:
if env.get("value"):
del env["value"]

if safe_get(response_json, "properties", "template") and "scale" in response_json["properties"]["template"]:
for rule in safe_get(response_json, "properties", "template", "scale", "rules", default=[]):
for (key, val) in rule.items():
if key != "name":
val["metadata"] = dict((k, "") for k, v in val["metadata"].items())
p-bouchon marked this conversation as resolved.
Show resolved Hide resolved

if safe_get(response_json, "properties", "configuration", "eventTriggerConfig") and "scale" in response_json["properties"]["configuration"]["eventTriggerConfig"]:
for rule in safe_get(response_json, "properties", "configuration", "eventTriggerConfig", "scale", "rules", default=[]):
rule["metadata"] = dict((k, "") for k, v in rule["metadata"].items())

return response_json


def transform_containerapp_list_output(apps):
return [transform_containerapp_output(a) for a in apps]

Expand Down
12 changes: 7 additions & 5 deletions src/containerapp/azext_containerapp/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,17 @@
transform_job_execution_list_output,
transform_job_execution_show_output,
transform_revision_list_output,
transform_revision_output, transform_usages_output)
transform_revision_output,
transform_usages_output,
transform_sensitive_values)


def load_command_table(self, _):
with self.command_group('containerapp') as g:
g.custom_show_command('show', 'show_containerapp', table_transformer=transform_containerapp_output)
g.custom_command('list', 'list_containerapp', table_transformer=transform_containerapp_list_output)
g.custom_command('create', 'create_containerapp', supports_no_wait=True, exception_handler=ex_handler_factory(), table_transformer=transform_containerapp_output)
g.custom_command('update', 'update_containerapp', supports_no_wait=True, exception_handler=ex_handler_factory(), table_transformer=transform_containerapp_output)
g.custom_command('create', 'create_containerapp', supports_no_wait=True, exception_handler=ex_handler_factory(), table_transformer=transform_containerapp_output, transform=transform_sensitive_values)
g.custom_command('update', 'update_containerapp', supports_no_wait=True, exception_handler=ex_handler_factory(), table_transformer=transform_containerapp_output, transform=transform_sensitive_values)
g.custom_command('delete', 'delete_containerapp', supports_no_wait=True, confirmation=True, exception_handler=ex_handler_factory())
g.custom_command('exec', 'containerapp_ssh', validator=validate_ssh)
g.custom_command('up', 'containerapp_up', supports_no_wait=False, exception_handler=ex_handler_factory())
Expand Down Expand Up @@ -50,9 +52,9 @@ def load_command_table(self, _):
with self.command_group('containerapp job') as g:
g.custom_show_command('show', 'show_containerappsjob')
g.custom_command('list', 'list_containerappsjob')
g.custom_command('create', 'create_containerappsjob', supports_no_wait=True, exception_handler=ex_handler_factory())
g.custom_command('create', 'create_containerappsjob', supports_no_wait=True, exception_handler=ex_handler_factory(), transform=transform_sensitive_values)
g.custom_command('delete', 'delete_containerappsjob', supports_no_wait=True, confirmation=True, exception_handler=ex_handler_factory())
g.custom_command('update', 'update_containerappsjob', supports_no_wait=True, exception_handler=ex_handler_factory())
g.custom_command('update', 'update_containerappsjob', supports_no_wait=True, exception_handler=ex_handler_factory(), transform=transform_sensitive_values)
g.custom_command('start', 'start_containerappsjob', supports_no_wait=True, exception_handler=ex_handler_factory())
g.custom_command('stop', 'stop_containerappsjob', supports_no_wait=True, exception_handler=ex_handler_factory())

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1072,17 +1072,18 @@ def test_containerapp_scale_create(self, resource_group):

env = prepare_containerapp_env_for_app_e2e_tests(self)

self.cmd(f'containerapp create -g {resource_group} -n {app} --image nginx --ingress external --target-port 80 --environment {env} --scale-rule-name http-scale-rule --scale-rule-http-concurrency 50 --scale-rule-auth trigger=secretref --scale-rule-metadata key=value')
self.cmd(f'containerapp create -g {resource_group} -n {app} --image nginx --ingress external --target-port 80 --environment {env} --scale-rule-name http-scale-rule --scale-rule-http-concurrency 50 --scale-rule-auth trigger=secretref --scale-rule-metadata key=value', checks=[JMESPathCheck("properties.template.scale.rules[0].http.metadata.key", "")])

self.cmd(f'containerapp show -g {resource_group} -n {app}', checks=[
JMESPathCheck("properties.template.scale.rules[0].name", "http-scale-rule"),
JMESPathCheck("properties.template.scale.rules[0].http.metadata.concurrentRequests", "50"),
JMESPathCheck("properties.template.scale.rules[0].http.metadata.key", "value"),
JMESPathCheck("properties.template.scale.rules[0].http.auth[0].triggerParameter", "trigger"),
JMESPathCheck("properties.template.scale.rules[0].http.auth[0].secretRef", "secretref"),
JMESPathCheck("properties.template.scale.rules[0].http.metadata.key", "value"),
])

self.cmd(f'containerapp create -g {resource_group} -n {app}2 --image nginx --environment {env} --scale-rule-name my-datadog-rule --scale-rule-type datadog --scale-rule-metadata "queryValue=7" "age=120" "metricUnavailableValue=0" --scale-rule-auth "apiKey=api-key" "appKey=app-key"')
self.cmd(f'containerapp create -g {resource_group} -n {app}2 --image nginx --environment {env} --scale-rule-name my-datadog-rule --scale-rule-type datadog --scale-rule-metadata "queryValue=7" "age=120" "metricUnavailableValue=0" --scale-rule-auth "apiKey=api-key" "appKey=app-key"', checks=[JMESPathCheck("properties.template.scale.rules[0].custom.metadata.queryValue", "")])

self.cmd(f'containerapp show -g {resource_group} -n {app}2', checks=[
JMESPathCheck("properties.template.scale.rules[0].name", "my-datadog-rule"),
Expand All @@ -1094,6 +1095,7 @@ def test_containerapp_scale_create(self, resource_group):
JMESPathCheck("properties.template.scale.rules[0].custom.auth[0].secretRef", "api-key"),
JMESPathCheck("properties.template.scale.rules[0].custom.auth[1].triggerParameter", "appKey"),
JMESPathCheck("properties.template.scale.rules[0].custom.auth[1].secretRef", "app-key"),
JMESPathCheck("properties.template.scale.rules[0].custom.metadata.queryValue", "7"),

])

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,8 @@ def test_container_acr(self, resource_group):
JMESPathCheck('properties.template.scale.minReplicas', '0'),
JMESPathCheck('properties.template.scale.maxReplicas', '1'),
JMESPathCheck('length(properties.template.containers[0].env)', 1),
JMESPathCheck('properties.template.containers[0].env[0].name', "testenv"),
JMESPathCheck('properties.template.containers[0].env[0].value', None),
])

# Add secrets to Container App with ACR
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def test_containerapp_eventjob_crudoperations_e2e(self, resource_group):

## test for CRUD operations on Container App Job resource with trigger type as event
# create a Container App Job resource with trigger type as event
self.cmd("az containerapp job create --name {} --resource-group {} --environment {} --trigger-type 'Event' --replica-timeout 60 --replica-retry-limit 1 --replica-completion-count 1 --parallelism 1 --min-executions 0 --max-executions 10 --polling-interval 60 --scale-rule-name 'queue' --scale-rule-type 'azure-queue' --scale-rule-metadata 'accountName=containerappextension' 'queueName=testeventdrivenjobs' 'queueLength=1' 'connectionFromEnv=AZURE_STORAGE_CONNECTION_STRING' --scale-rule-auth 'connection=connection-string-secret' --image 'mcr.microsoft.com/k8se/quickstart-jobs:latest' --cpu '0.5' --memory '1Gi' --secrets 'connection-string-secret=testConnString' --env-vars 'AZURE_STORAGE_QUEUE_NAME=testeventdrivenjobs' 'AZURE_STORAGE_CONNECTION_STRING=secretref:connection-string-secret'".format(job, resource_group, env_id))
self.cmd("az containerapp job create --name {} --resource-group {} --environment {} --trigger-type 'Event' --replica-timeout 60 --replica-retry-limit 1 --replica-completion-count 1 --parallelism 1 --min-executions 0 --max-executions 10 --polling-interval 60 --scale-rule-name 'queue' --scale-rule-type 'azure-queue' --scale-rule-metadata 'accountName=containerappextension' 'queueName=testeventdrivenjobs' 'queueLength=1' 'connectionFromEnv=AZURE_STORAGE_CONNECTION_STRING' --scale-rule-auth 'connection=connection-string-secret' --image 'mcr.microsoft.com/k8se/quickstart-jobs:latest' --cpu '0.5' --memory '1Gi' --secrets 'connection-string-secret=testConnString' --env-vars 'AZURE_STORAGE_QUEUE_NAME=testeventdrivenjobs' 'AZURE_STORAGE_CONNECTION_STRING=secretref:connection-string-secret'".format(job, resource_group, env_id), checks=[JMESPathCheck('properties.configuration.eventTriggerConfig.scale.rules[0].metadata.queueLength', "")])

# verify the container app job resource
self.cmd("az containerapp job show --resource-group {} --name {}".format(resource_group, job), checks=[
Expand All @@ -46,6 +46,7 @@ def test_containerapp_eventjob_crudoperations_e2e(self, resource_group):
JMESPathCheck('properties.configuration.replicaRetryLimit', 1),
JMESPathCheck('properties.configuration.triggerType', "event", case_sensitive=False),
JMESPathCheck('properties.configuration.eventTriggerConfig.scale.maxExecutions', 10),
JMESPathCheck('properties.configuration.eventTriggerConfig.scale.rules[0].metadata.queueLength', "1"),
])

# get list of Container App Jobs
Expand Down