From 5c144acd3815b3cfcd6ec529042899ef08f65190 Mon Sep 17 00:00:00 2001 From: Silas Strawn Date: Mon, 16 May 2022 10:27:27 -0700 Subject: [PATCH] add AZ support --- src/containerapp/azext_containerapp/_params.py | 4 +++- src/containerapp/azext_containerapp/_utils.py | 11 +++++++++++ src/containerapp/azext_containerapp/custom.py | 18 +++++++++++++++++- 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/containerapp/azext_containerapp/_params.py b/src/containerapp/azext_containerapp/_params.py index ffc21858791..c4779541fb8 100644 --- a/src/containerapp/azext_containerapp/_params.py +++ b/src/containerapp/azext_containerapp/_params.py @@ -130,12 +130,14 @@ def load_arguments(self, _): c.argument('instrumentation_key', options_list=['--dapr-instrumentation-key'], help='Application Insights instrumentation key used by Dapr to export Service to Service communication telemetry') with self.argument_context('containerapp env', arg_group='Virtual Network') as c: - c.argument('infrastructure_subnet_resource_id', options_list=['--infrastructure-subnet-resource-id'], help='Resource ID of a subnet for infrastructure components and user app containers.') + c.argument('infrastructure_subnet_resource_id', options_list=['--infrastructure-subnet-resource-id', '-s'], help='Resource ID of a subnet for infrastructure components and user app containers.') c.argument('app_subnet_resource_id', options_list=['--app-subnet-resource-id'], help='Resource ID of a subnet that Container App containers are injected into. This subnet must be in the same VNET as the subnet defined in infrastructureSubnetResourceId.') c.argument('docker_bridge_cidr', options_list=['--docker-bridge-cidr'], help='CIDR notation IP range assigned to the Docker bridge. It must not overlap with any Subnet IP ranges or the IP range defined in Platform Reserved CIDR, if defined') c.argument('platform_reserved_cidr', options_list=['--platform-reserved-cidr'], help='IP range in CIDR notation that can be reserved for environment infrastructure IP addresses. It must not overlap with any other Subnet IP ranges') c.argument('platform_reserved_dns_ip', options_list=['--platform-reserved-dns-ip'], help='An IP address from the IP range defined by Platform Reserved CIDR that will be reserved for the internal DNS server.') c.argument('internal_only', arg_type=get_three_state_flag(), options_list=['--internal-only'], help='Boolean indicating the environment only has an internal load balancer. These environments do not have a public static IP resource, therefore must provide infrastructureSubnetResourceId if enabling this property') + with self.argument_context('containerapp env create') as c: + c.argument('zone_redundant', options_list=["--zone-redundant", "-z"], help="Enable zone redundancy on the environment. Cannot be used without --infrastructure-subnet-resource-id. If used with --location, the subnet's location must match") with self.argument_context('containerapp env update') as c: c.argument('name', name_type, help='Name of the Container Apps environment.') diff --git a/src/containerapp/azext_containerapp/_utils.py b/src/containerapp/azext_containerapp/_utils.py index 93c6c79328d..441a630da41 100644 --- a/src/containerapp/azext_containerapp/_utils.py +++ b/src/containerapp/azext_containerapp/_utils.py @@ -14,6 +14,9 @@ from azure.cli.core.azclierror import (ValidationError, RequiredArgumentMissingError, CLIInternalError, ResourceNotFoundError, ArgumentUsageError) from azure.cli.core.commands.client_factory import get_subscription_id +from azure.cli.command_modules.appservice.utils import _normalize_location +from azure.cli.command_modules.network._client_factory import network_client_factory + from knack.log import get_logger from msrestazure.tools import parse_resource_id, is_valid_resource_id, resource_id @@ -31,6 +34,14 @@ def validate_container_app_name(name): f"Please shorten {name}") +def get_vnet_location(cmd, subnet_resource_id): + parsed_rid = parse_resource_id(subnet_resource_id) + vnet_client = network_client_factory(cmd.cli_ctx) + location = vnet_client.virtual_networks.get(resource_group_name=parsed_rid.get("resource_group"), + virtual_network_name=parsed_rid.get("name")).location + return _normalize_location(cmd, location) + + # original implementation at azure.cli.command_modules.role.custom.create_service_principal_for_rbac # reimplemented to remove incorrect warning statements def create_service_principal_for_rbac( # pylint:disable=too-many-statements,too-many-locals, too-many-branches, unused-argument, inconsistent-return-statements diff --git a/src/containerapp/azext_containerapp/custom.py b/src/containerapp/azext_containerapp/custom.py index f4fe046f9a3..5f824f4573e 100644 --- a/src/containerapp/azext_containerapp/custom.py +++ b/src/containerapp/azext_containerapp/custom.py @@ -19,6 +19,7 @@ InvalidArgumentValueError) from azure.cli.core.commands.client_factory import get_subscription_id from azure.cli.core.util import open_page_in_browser +from azure.cli.command_modules.appservice.utils import _normalize_location from knack.log import get_logger from msrestazure.tools import parse_resource_id, is_valid_resource_id @@ -55,7 +56,7 @@ _get_app_from_revision, raise_missing_token_suggestion, _infer_acr_credentials, _remove_registry_secret, _remove_secret, _ensure_identity_resource_id, _remove_dapr_readonly_attributes, _remove_env_vars, _validate_traffic_sum, _update_revision_env_secretrefs, _get_acr_cred, safe_get, await_github_action, repo_url_to_name, - validate_container_app_name, _update_weights) + validate_container_app_name, _update_weights, get_vnet_location) from ._ssh_utils import (SSH_DEFAULT_ENCODING, WebSocketConnection, read_ssh, get_stdin_writer, SSH_CTRL_C_MSG, SSH_BACKUP_ENCODING) @@ -754,7 +755,21 @@ def create_managed_environment(cmd, internal_only=False, tags=None, disable_warnings=False, + zone_redundant=False, no_wait=False): + if zone_redundant: + if not infrastructure_subnet_resource_id: + raise RequiredArgumentMissingError("Cannot use --zone-redundant/-z without " + "--infrastructure-subnet-resource-id/-s") + if not is_valid_resource_id(infrastructure_subnet_resource_id): + raise ValidationError("--infrastructure-subnet-resource-id must be a valid resource id") + vnet_location = get_vnet_location(cmd, infrastructure_subnet_resource_id) + if location: + if _normalize_location(cmd, location) != vnet_location: + raise ValidationError(f"Location '{location}' does not match the subnet's location: '{vnet_location}'. " + "Please change either --location/-l or --infrastructure-subnet-resource-id/-s") + else: + location = vnet_location location = location or _get_location_from_resource_group(cmd.cli_ctx, resource_group_name) @@ -777,6 +792,7 @@ def create_managed_environment(cmd, managed_env_def["properties"]["internalLoadBalancerEnabled"] = False managed_env_def["properties"]["appLogsConfiguration"] = app_logs_config_def managed_env_def["tags"] = tags + managed_env_def["properties"]["zoneRedundant"] = zone_redundant if instrumentation_key is not None: managed_env_def["properties"]["daprAIInstrumentationKey"] = instrumentation_key