Skip to content

Commit adb7895

Browse files
authored
[Containerapp] az containerapp create: Support other cloud for acr (#33160)
1 parent 397614a commit adb7895

6 files changed

Lines changed: 53 additions & 26 deletions

File tree

src/azure-cli/azure/cli/command_modules/containerapp/_constants.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
LONG_POLLING_INTERVAL_SECS = 10
1515

1616
ACR_IMAGE_SUFFIX = ".azurecr.io"
17+
ACR_IMAGE_SUFFIXES = (".azurecr.io", ".azurecr.cn", ".azurecr.us")
1718

1819
CONTAINER_APPS_SDK_MODELS = "azure.cli.command_modules.containerapp._sdk_models"
1920

src/azure-cli/azure/cli/command_modules/containerapp/_up_utils.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,9 @@
5151
format_location,
5252
is_docker_running,
5353
get_pack_exec_path,
54-
get_latest_buildpack_run_tag
54+
get_latest_buildpack_run_tag,
55+
is_acr_url,
56+
get_acr_name,
5557

5658
)
5759

@@ -414,7 +416,7 @@ def create_acr_if_needed(self):
414416
def create_acr(self):
415417
registry_rg = self.resource_group
416418
url = self.registry_server
417-
registry_name = url[: url.rindex(ACR_IMAGE_SUFFIX)]
419+
registry_name = get_acr_name(url) or url.split('.')[0]
418420
location = "eastus"
419421
if self.env.location and self.env.location.lower() != "northcentralusstage":
420422
location = self.env.location
@@ -548,7 +550,7 @@ def build_container_from_source_with_acr_task(self, image_name, source):
548550
import os
549551

550552
task_name = "cli_build_containerapp"
551-
registry_name = (self.registry_server[: self.registry_server.rindex(ACR_IMAGE_SUFFIX)]).lower()
553+
registry_name = (get_acr_name(self.registry_server) or self.registry_server.split('.')[0]).lower()
552554
if not self.target_port:
553555
self.target_port = DEFAULT_PORT
554556
task_content = ACR_TASK_TEMPLATE.replace("{{image_name}}", image_name).replace("{{target_port}}",
@@ -919,7 +921,7 @@ def _get_registry_from_app(app, source):
919921
containerapp_def = app.get()
920922
existing_registries = safe_get(containerapp_def, "properties", "configuration", "registries", default=[])
921923
if source:
922-
existing_registries = [r for r in existing_registries if ACR_IMAGE_SUFFIX in r["server"]]
924+
existing_registries = [r for r in existing_registries if is_acr_url(r["server"])]
923925
if containerapp_def:
924926
if len(existing_registries) == 1:
925927
app.registry_server = existing_registries[0]["server"]
@@ -931,7 +933,7 @@ def _get_registry_from_app(app, source):
931933

932934

933935
def _get_acr_rg(app):
934-
registry_name = app.registry_server[: app.registry_server.rindex(ACR_IMAGE_SUFFIX)]
936+
registry_name = get_acr_name(app.registry_server) or app.registry_server.split('.')[0]
935937
client = get_mgmt_service_client(
936938
app.cmd.cli_ctx, ContainerRegistryManagementClient
937939
).registries
@@ -967,7 +969,7 @@ def _get_registry_details(cmd, app: "ContainerApp", source):
967969
registry_rg = None
968970
registry_name = None
969971
if app.registry_server:
970-
if "azurecr.io" not in app.registry_server and source:
972+
if not is_acr_url(app.registry_server) and source:
971973
raise ValidationError(
972974
"Cannot supply non-Azure registry when using --source."
973975
)

src/azure-cli/azure/cli/command_modules/containerapp/_utils.py

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,9 @@
4444
from ._clients import ContainerAppClient, ManagedEnvironmentClient, WorkloadProfileClient, ContainerAppsJobClient
4545
from ._client_factory import handle_raw_exception, providers_client_factory, cf_resource_groups, log_analytics_client_factory, log_analytics_shared_key_client_factory
4646
from ._constants import (MAXIMUM_CONTAINER_APP_NAME_LENGTH, SHORT_POLLING_INTERVAL_SECS, LONG_POLLING_INTERVAL_SECS,
47-
LOG_ANALYTICS_RP, CONTAINER_APPS_RP, CHECK_CERTIFICATE_NAME_AVAILABILITY_TYPE, ACR_IMAGE_SUFFIX,
48-
LOGS_STRING, PENDING_STATUS, SUCCEEDED_STATUS, UPDATING_STATUS, DEV_SERVICE_LIST)
47+
LOG_ANALYTICS_RP, CONTAINER_APPS_RP, CHECK_CERTIFICATE_NAME_AVAILABILITY_TYPE,
48+
LOGS_STRING, PENDING_STATUS, SUCCEEDED_STATUS, UPDATING_STATUS, DEV_SERVICE_LIST,
49+
ACR_IMAGE_SUFFIXES)
4950
from ._models import (ContainerAppCustomDomainEnvelope as ContainerAppCustomDomainEnvelopeModel,
5051
ManagedCertificateEnvelop as ManagedCertificateEnvelopModel)
5152
from ._models import OryxMarinerRunImgTagProperty
@@ -59,6 +60,25 @@ class AppType(Enum):
5960
logger = get_logger(__name__)
6061

6162

63+
def is_acr_url(registry_server):
64+
"""Check if a registry server URL belongs to Azure Container Registry (supports sovereign clouds)."""
65+
if not registry_server:
66+
return False
67+
registry_server_lower = registry_server.lower()
68+
return any(registry_server_lower.endswith(suffix) for suffix in ACR_IMAGE_SUFFIXES)
69+
70+
71+
def get_acr_name(registry_server):
72+
"""Extract the ACR registry name from a registry server URL (supports sovereign clouds)."""
73+
if not registry_server:
74+
return None
75+
registry_server_lower = registry_server.lower()
76+
for suffix in ACR_IMAGE_SUFFIXES:
77+
if registry_server_lower.endswith(suffix):
78+
return registry_server[: registry_server_lower.rindex(suffix)]
79+
return None
80+
81+
6282
def register_provider_if_needed(cmd, rp_name):
6383
if not _is_resource_provider_registered(cmd, rp_name):
6484
_register_resource_provider(cmd, rp_name)
@@ -1170,7 +1190,7 @@ def _get_app_from_revision(revision):
11701190

11711191
def _infer_acr_credentials(cmd, registry_server, disable_warnings=False):
11721192
# If registry is Azure Container Registry, we can try inferring credentials
1173-
if ACR_IMAGE_SUFFIX not in registry_server:
1193+
if not is_acr_url(registry_server):
11741194
raise RequiredArgumentMissingError('Registry username and password are required if not using Azure Container Registry.')
11751195
not disable_warnings and logger.warning('No credential was provided to access Azure Container Registry. Trying to look up credentials...')
11761196
parsed = urlparse(registry_server)
@@ -1656,7 +1676,10 @@ def create_acrpull_role_assignment(cmd, registry_server, registry_identity=None,
16561676

16571677
client = get_mgmt_service_client(cmd.cli_ctx, ContainerRegistryManagementClient).registries
16581678
try:
1659-
acr_id = acr_show(cmd, client, registry_server[: registry_server.rindex(ACR_IMAGE_SUFFIX)]).id
1679+
acr_name = get_acr_name(registry_server)
1680+
if not acr_name:
1681+
raise RequiredArgumentMissingError(f'Could not parse ACR name from registry server: {registry_server}')
1682+
acr_id = acr_show(cmd, client, acr_name).id
16601683
except ResourceNotFound as e:
16611684
message = (f"Role assignment failed with error message: \"{' '.join(e.args)}\". \n"
16621685
f"To add the role assignment manually, please run 'az role assignment create --assignee {sp_id} --scope <container-registry-resource-id> --role acrpull'. \n"

src/azure-cli/azure/cli/command_modules/containerapp/_validators.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212

1313
from ._clients import ContainerAppClient, ManagedEnvironmentClient
1414
from ._ssh_utils import ping_container_app
15-
from ._utils import safe_get, is_registry_msi_system
16-
from ._constants import ACR_IMAGE_SUFFIX, LOG_TYPE_SYSTEM, MANAGED_ENVIRONMENT_RESOURCE_TYPE
15+
from ._utils import safe_get, is_registry_msi_system, is_acr_url
16+
from ._constants import LOG_TYPE_SYSTEM, MANAGED_ENVIRONMENT_RESOURCE_TYPE
1717

1818
logger = get_logger(__name__)
1919

@@ -26,8 +26,8 @@ def validate_create(registry_identity, registry_pass, registry_user, registry_se
2626
raise MutuallyExclusiveArgumentError("--no-wait is not supported with system registry identity")
2727
if registry_identity and not is_valid_resource_id(registry_identity) and not is_registry_msi_system(registry_identity):
2828
raise InvalidArgumentValueError("--registry-identity must be an identity resource ID or 'system'")
29-
if registry_identity and ACR_IMAGE_SUFFIX not in (registry_server or ""):
30-
raise InvalidArgumentValueError("--registry-identity: expected an ACR registry (*.azurecr.io) for --registry-server")
29+
if registry_identity and not is_acr_url(registry_server or ""):
30+
raise InvalidArgumentValueError("--registry-identity: expected an ACR registry (*.azurecr.io / *.azurecr.cn / *.azurecr.us) for --registry-server")
3131

3232

3333
def _is_number(s):
@@ -106,21 +106,21 @@ def validate_registry_server(namespace):
106106
if "create" in namespace.command.lower():
107107
if namespace.registry_server:
108108
if not namespace.registry_user or not namespace.registry_pass:
109-
if ACR_IMAGE_SUFFIX not in namespace.registry_server:
109+
if not is_acr_url(namespace.registry_server):
110110
raise ValidationError("Usage error: --registry-server, --registry-password and --registry-username are required together if not using Azure Container Registry")
111111

112112

113113
def validate_registry_user(namespace):
114114
if "create" in namespace.command.lower():
115115
if namespace.registry_user:
116-
if not namespace.registry_server or (not namespace.registry_pass and ACR_IMAGE_SUFFIX not in namespace.registry_server):
116+
if not namespace.registry_server or (not namespace.registry_pass and not is_acr_url(namespace.registry_server)):
117117
raise ValidationError("Usage error: --registry-server, --registry-password and --registry-username are required together if not using Azure Container Registry")
118118

119119

120120
def validate_registry_pass(namespace):
121121
if "create" in namespace.command.lower():
122122
if namespace.registry_pass:
123-
if not namespace.registry_server or (not namespace.registry_user and ACR_IMAGE_SUFFIX not in namespace.registry_server):
123+
if not namespace.registry_server or (not namespace.registry_user and not is_acr_url(namespace.registry_server)):
124124
raise ValidationError("Usage error: --registry-server, --registry-password and --registry-username are required together if not using Azure Container Registry")
125125

126126

src/azure-cli/azure/cli/command_modules/containerapp/containerapp_job_registry_decorator.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121

2222
from knack.log import get_logger
2323

24-
from ._constants import ACR_IMAGE_SUFFIX
2524
from .base_resource import BaseResource
2625
from ._client_factory import handle_raw_exception, handle_non_404_status_code_exception
2726

@@ -33,7 +32,8 @@
3332
safe_set,
3433
safe_get,
3534
_remove_registry_secret,
36-
_get_acr_cred)
35+
_get_acr_cred,
36+
is_acr_url)
3737

3838
logger = get_logger(__name__)
3939

@@ -163,7 +163,7 @@ def construct_payload(self):
163163

164164
if (not self.get_argument_username() or not self.get_argument_password()) and not self.get_argument_identity():
165165
# If registry is Azure Container Registry, we can try inferring credentials
166-
if ACR_IMAGE_SUFFIX not in self.get_argument_server():
166+
if not is_acr_url(self.get_argument_server()):
167167
raise RequiredArgumentMissingError(
168168
'Registry username and password are required if you are not using Azure Container Registry.')
169169
not self.get_argument_disable_warnings() and logger.warning(

src/azure-cli/azure/cli/command_modules/containerapp/custom.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -82,13 +82,14 @@
8282
ensure_workload_profile_supported, _generate_secret_volume_name,
8383
trigger_workflow, AppType,
8484
format_location, certificate_location_matches, generate_randomized_managed_cert_name,
85-
check_managed_cert_name_availability, prepare_managed_certificate_envelop)
85+
check_managed_cert_name_availability, prepare_managed_certificate_envelop,
86+
is_acr_url)
8687
from ._validators import validate_revision_suffix
8788
from ._ssh_utils import (SSH_DEFAULT_ENCODING, WebSocketConnection, read_ssh, get_stdin_writer, SSH_CTRL_C_MSG,
8889
SSH_BACKUP_ENCODING)
8990
from ._constants import (MICROSOFT_SECRET_SETTING_NAME, FACEBOOK_SECRET_SETTING_NAME, GITHUB_SECRET_SETTING_NAME,
9091
GOOGLE_SECRET_SETTING_NAME, TWITTER_SECRET_SETTING_NAME, APPLE_SECRET_SETTING_NAME, CONTAINER_APPS_RP,
91-
NAME_INVALID, NAME_ALREADY_EXISTS, ACR_IMAGE_SUFFIX, HELLO_WORLD_IMAGE, LOG_TYPE_SYSTEM, LOG_TYPE_CONSOLE,
92+
NAME_INVALID, NAME_ALREADY_EXISTS, HELLO_WORLD_IMAGE, LOG_TYPE_SYSTEM, LOG_TYPE_CONSOLE,
9293
MANAGED_CERTIFICATE_RT, PRIVATE_CERTIFICATE_RT, PENDING_STATUS, SUCCEEDED_STATUS, CONTAINER_APPS_SDK_MODELS,
9394
BLOB_STORAGE_TOKEN_STORE_SECRET_SETTING_NAME, DEFAULT_PORT)
9495

@@ -665,7 +666,7 @@ def update_containerapp_logic(cmd,
665666

666667
if registry_server:
667668
if not registry_pass or not registry_user:
668-
if ACR_IMAGE_SUFFIX not in registry_server:
669+
if not is_acr_url(registry_server):
669670
raise RequiredArgumentMissingError('Registry url is required if using Azure Container Registry, otherwise Registry username and password are required if using Dockerhub')
670671
logger.warning('No credential was provided to access Azure Container Registry. Trying to look up...')
671672
parsed = urlparse(registry_server)
@@ -1401,7 +1402,7 @@ def update_containerappsjob_logic(cmd,
14011402

14021403
if registry_server:
14031404
if not registry_pass or not registry_user:
1404-
if ACR_IMAGE_SUFFIX not in registry_server:
1405+
if not is_acr_url(registry_server):
14051406
raise RequiredArgumentMissingError('Registry url is required if using Azure Container Registry, otherwise Registry username and password are required if using Dockerhub')
14061407
logger.warning('No credential was provided to access Azure Container Registry. Trying to look up...')
14071408
parsed = urlparse(registry_server)
@@ -2010,7 +2011,7 @@ def create_or_update_github_action(cmd,
20102011
# Registry
20112012
if registry_username is None or registry_password is None:
20122013
# If registry is Azure Container Registry, we can try inferring credentials
2013-
if not registry_url or ACR_IMAGE_SUFFIX not in registry_url:
2014+
if not registry_url or not is_acr_url(registry_url):
20142015
raise RequiredArgumentMissingError('Registry url is required if using Azure Container Registry, otherwise Registry username and password are required if using Dockerhub')
20152016
logger.warning('No credential was provided to access Azure Container Registry. Trying to look up...')
20162017
parsed = urlparse(registry_url)
@@ -2953,7 +2954,7 @@ def set_registry(cmd, name, resource_group_name, server, username=None, password
29532954

29542955
if (not username or not password) and not identity:
29552956
# If registry is Azure Container Registry, we can try inferring credentials
2956-
if ACR_IMAGE_SUFFIX not in server:
2957+
if not is_acr_url(server):
29572958
raise RequiredArgumentMissingError('Registry username and password are required if you are not using Azure Container Registry.')
29582959
not disable_warnings and logger.warning('No credential was provided to access Azure Container Registry. Trying to look up...')
29592960
parsed = urlparse(server)

0 commit comments

Comments
 (0)