Skip to content
Merged
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
3 changes: 2 additions & 1 deletion scripts/ci/credscan/CredScanSuppressions.json
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,8 @@
"src\\containerapp\\azext_containerapp\\tests\\latest\\cert.pfx",
"src\\containerapp\\azext_containerapp\\tests\\latest\\test_containerapp_commands.py",
"src\\containerapp\\azext_containerapp\\tests\\latest\\test_containerapp_env_commands.py",
"src\\containerapp\\azext_containerapp\\tests\\latest\\recordings\\test_containerapp_registry_msi.yaml"
"src\\containerapp\\azext_containerapp\\tests\\latest\\recordings\\test_containerapp_registry_msi.yaml",
"src\\containerapp\\azext_containerapp\\tests\\latest\\recordings\\test_containerapp_update_containers.yaml"
],
"_justification": "Dummy resources' keys left during testing Microsoft.App (required for log-analytics to create managedEnvironments)"
},
Expand Down
7 changes: 7 additions & 0 deletions src/containerapp/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@
Release History
===============

0.3.8
++++++
* 'az containerapp update': Fix bug where --yaml would error out due to secret values
* 'az containerapp update': use PATCH API instead of GET and PUT
* 'az containerapp up': Fix bug where using --source with an invalid name parameter causes ACR build to fail
* 'az containerapp logs show'/'az containerapp exec': Fix bug where ssh/logstream they would fail on apps with networking restrictions

0.3.7
++++++
* Fixed bug with 'az containerapp up' where --registry-server was ignored
Expand Down
2 changes: 1 addition & 1 deletion src/containerapp/azext_containerapp/_constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# --------------------------------------------------------------------------------------------

MAXIMUM_SECRET_LENGTH = 20
MAXIMUM_CONTAINER_APP_NAME_LENGTH = 40
MAXIMUM_CONTAINER_APP_NAME_LENGTH = 32

SHORT_POLLING_INTERVAL_SECS = 3
LONG_POLLING_INTERVAL_SECS = 10
Expand Down
4 changes: 2 additions & 2 deletions src/containerapp/azext_containerapp/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

from ._validators import (validate_memory, validate_cpu, validate_managed_env_name_or_id, validate_registry_server,
validate_registry_user, validate_registry_pass, validate_target_port, validate_ingress)
from ._constants import UNAUTHENTICATED_CLIENT_ACTION, FORWARD_PROXY_CONVENTION
from ._constants import UNAUTHENTICATED_CLIENT_ACTION, FORWARD_PROXY_CONVENTION, MAXIMUM_CONTAINER_APP_NAME_LENGTH


def load_arguments(self, _):
Expand All @@ -23,7 +23,7 @@ def load_arguments(self, _):

with self.argument_context('containerapp') as c:
# Base arguments
c.argument('name', name_type, metavar='NAME', id_part='name', help="The name of the Containerapp.")
c.argument('name', name_type, metavar='NAME', id_part='name', help=f"The name of the Containerapp. A name must consist of lower case alphanumeric characters or '-', start with a letter, end with an alphanumeric character, cannot have '--', and must be less than {MAXIMUM_CONTAINER_APP_NAME_LENGTH} characters.")
c.argument('resource_group_name', arg_type=resource_group_name_type)
c.argument('location', arg_type=get_location_type(self.cli_ctx))
c.ignore('disable_warnings')
Expand Down
14 changes: 13 additions & 1 deletion src/containerapp/azext_containerapp/_up_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
register_provider_if_needed
)

from ._constants import MAXIMUM_SECRET_LENGTH, LOG_ANALYTICS_RP, CONTAINER_APPS_RP, ACR_IMAGE_SUFFIX
from ._constants import MAXIMUM_SECRET_LENGTH, LOG_ANALYTICS_RP, CONTAINER_APPS_RP, ACR_IMAGE_SUFFIX, MAXIMUM_CONTAINER_APP_NAME_LENGTH

from .custom import (
create_managed_environment,
Expand Down Expand Up @@ -670,6 +670,18 @@ def _get_registry_details(cmd, app: "ContainerApp", source):
)


def _validate_containerapp_name(name):
is_valid = True
is_valid = is_valid and name.lower() == name
is_valid = is_valid and len(name) <= MAXIMUM_CONTAINER_APP_NAME_LENGTH
is_valid = is_valid and '--' not in name
name = name.replace('-', '')
is_valid = is_valid and name.isalnum()
is_valid = is_valid and name[0].isalpha()
if not is_valid:
raise ValidationError(f"Invalid Container App name {name}. A name must consist of lower case alphanumeric characters or '-', start with a letter, end with an alphanumeric character, cannot have '--', and must be less than {MAXIMUM_CONTAINER_APP_NAME_LENGTH} characters.")

Copy link
Contributor

Choose a reason for hiding this comment

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

seems like the message is copied from portal ;) but "alphabetic character" seems incorrect English to me.

Copy link
Contributor

Choose a reason for hiding this comment

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

This message is copied from the API


# attempt to populate defaults for managed env, RG, ACR, etc
def _set_up_defaults(
cmd,
Expand Down
32 changes: 31 additions & 1 deletion src/containerapp/azext_containerapp/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------
# pylint: disable=line-too-long, consider-using-f-string, no-else-return, duplicate-string-formatting-argument, expression-not-assigned, too-many-locals, logging-fstring-interpolation
# pylint: disable=line-too-long, consider-using-f-string, no-else-return, duplicate-string-formatting-argument, expression-not-assigned, too-many-locals, logging-fstring-interpolation, broad-except

import time
import json
Expand Down Expand Up @@ -788,6 +788,36 @@ def _remove_readonly_attributes(containerapp_def):
del containerapp_def['properties'][unneeded_property]


# Remove null/None properties in a model since the PATCH API will delete those. Not needed once we move to the SDK
def clean_null_values(d):
if isinstance(d, dict):
return {
k: v
for k, v in ((k, clean_null_values(v)) for k, v in d.items())
if v
}
if isinstance(d, list):
return [v for v in map(clean_null_values, d) if v]
return d


def _populate_secret_values(containerapp_def, secret_values):
Copy link
Contributor

Choose a reason for hiding this comment

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

@haroonf , don't need to change this logic for now, since we need to release the fix.
Can you help me understand the behavior in CLI with YAML here , when CLI parses the YAML with secretName & no value, does the payload to the API translate this object in JSON payload just name property & no value i.e{ name: xyz} or. {name: xyz, value: null}. if it is the former is the PATCH API, setting the value to null or is it cleaning these up because CLI explicitly passes null?

Copy link
Contributor

Choose a reason for hiding this comment

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

The deserialization process leaves the json payload to {name: xyz, value: null}. The API returns an error "cannot set secret values to null."

secrets = safe_get(containerapp_def, "properties", "configuration", "secrets", default=None)
if not secrets:
secrets = []
if not secret_values:
secret_values = []
index = 0
while index < len(secrets):
value = secrets[index]
if "value" not in value or not value["value"]:
try:
value["value"] = next(s["value"] for s in secret_values if s["name"] == value["name"])
except StopIteration:
pass
index += 1


def _remove_dapr_readonly_attributes(daprcomponent_def):
unneeded_properties = [
"id",
Expand Down
9 changes: 8 additions & 1 deletion src/containerapp/azext_containerapp/_validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,17 @@
# pylint: disable=line-too-long

from azure.cli.core.azclierror import (ValidationError, ResourceNotFoundError)
from knack.log import get_logger

from ._clients import ContainerAppClient
from ._ssh_utils import ping_container_app
from ._utils import safe_get
from ._constants import ACR_IMAGE_SUFFIX


logger = get_logger(__name__)


def _is_number(s):
try:
float(s)
Expand Down Expand Up @@ -105,7 +109,10 @@ def _set_ssh_defaults(cmd, namespace):
raise ResourceNotFoundError("Could not find a revision")
if not namespace.replica:
# VVV this may not be necessary according to Anthony Chu
ping_container_app(app) # needed to get an alive replica
try:
ping_container_app(app) # needed to get an alive replica
except Exception as e:
logger.warning("Failed to ping container app with error '%s' \nPlease ensure there is an alive replica. ", str(e))
replicas = ContainerAppClient.list_replicas(cmd=cmd,
resource_group_name=namespace.resource_group_name,
container_app_name=namespace.name,
Expand Down
Loading