Skip to content

Commit ea2fe45

Browse files
authored
[Container app] az containerapp env create: Add parameter --infrastructure-resource-group to support specifying name for resource group that will contain infrastructure resources (#32457)
1 parent 96e2a7c commit ea2fe45

File tree

7 files changed

+6550
-1
lines changed

7 files changed

+6550
-1
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ def load_arguments(self, _):
165165

166166
with self.argument_context('containerapp env', arg_group='Virtual Network') as c:
167167
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.')
168+
c.argument('infrastructure_resource_group', options_list=['--infrastructure-resource-group', '-i'], help='Name for resource group that will contain infrastructure resources. If not provided, a resource group name will be generated.')
168169
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', deprecate_info=Deprecated(self.cli_ctx, target='--docker-bridge-cidr', hide=True, message_func=lambda x: "Option '--docker-bridge-cidr' has been deprecated and will be removed in the Ignite 2024"))
169170
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')
170171
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.')

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,9 @@ def __init__(self, cmd: AzCliCommand, client: Any, raw_parameters: Dict, models:
133133
def get_argument_enable_workload_profiles(self):
134134
return self.get_param("enable_workload_profiles")
135135

136+
def get_argument_infrastructure_resource_group(self):
137+
return self.get_param("infrastructure_resource_group")
138+
136139
def validate_arguments(self):
137140
location = self.get_argument_location()
138141
if self.get_argument_zone_redundant():
@@ -158,6 +161,15 @@ def validate_arguments(self):
158161
if self.get_argument_p2p_encryption_enabled() is False and self.get_argument_mtls_enabled() is True:
159162
raise ValidationError("Cannot use '--enable-mtls' with '--enable-peer-to-peer-encryption False'")
160163

164+
# Infrastructure Resource Group
165+
if self.get_argument_infrastructure_resource_group() is not None:
166+
if not self.get_argument_infrastructure_subnet_resource_id():
167+
raise RequiredArgumentMissingError("Cannot use --infrastructure-resource-group/-i without "
168+
"--infrastructure-subnet-resource-id/-s")
169+
if not self.get_argument_enable_workload_profiles():
170+
raise RequiredArgumentMissingError("Cannot use --infrastructure-resource-group/-i without "
171+
"--enable-workload-profiles/-w")
172+
161173
def create(self):
162174
try:
163175
return self.client.create(cmd=self.cmd, resource_group_name=self.get_argument_resource_group_name(),
@@ -206,6 +218,12 @@ def construct_payload(self):
206218

207219
self.set_up_peer_to_peer_encryption()
208220

221+
self.set_up_infrastructure_resource_group()
222+
223+
def set_up_infrastructure_resource_group(self):
224+
if self.get_argument_enable_workload_profiles() and self.get_argument_infrastructure_subnet_resource_id() is not None:
225+
self.managed_env_def["properties"]["InfrastructureResourceGroup"] = self.get_argument_infrastructure_resource_group()
226+
209227
def set_up_workload_profiles(self):
210228
if self.get_argument_enable_workload_profiles():
211229
# If the environment exists, infer the environment type

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -853,6 +853,7 @@ def create_managed_environment(cmd,
853853
instrumentation_key=None,
854854
dapr_connection_string=None,
855855
infrastructure_subnet_resource_id=None,
856+
infrastructure_resource_group=None,
856857
docker_bridge_cidr=None,
857858
platform_reserved_cidr=None,
858859
platform_reserved_dns_ip=None,

src/azure-cli/azure/cli/command_modules/containerapp/tests/latest/common.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
TEST_DIR = os.path.abspath(os.path.join(os.path.abspath(__file__), '..'))
1010
TEST_LOCATION = os.getenv("CLITestLocation") if os.getenv("CLITestLocation") else "eastus"
11-
11+
STAGE_LOCATION = "northcentralusstage"
1212

1313
def write_test_file(filename, content):
1414
test_file = open(filename, "w", encoding='utf-8')
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# --------------------------------------------------------------------------------------------
2+
# Copyright (c) Microsoft Corporation. All rights reserved.
3+
# Licensed under the MIT License. See License.txt in the project root for license information.
4+
# --------------------------------------------------------------------------------------------
5+
import time
6+
7+
from azure.cli.command_modules.containerapp._utils import format_location
8+
9+
from azure.cli.testsdk import CliTestError
10+
from azure.cli.testsdk.reverse_dependency import get_dummy_cli
11+
from azure.cli.testsdk.scenario_tests import SingleValueReplacer
12+
from azure.cli.testsdk.preparers import NoTrafficRecordingPreparer, ResourceGroupPreparer
13+
from .common import STAGE_LOCATION
14+
15+
class SubnetPreparer(NoTrafficRecordingPreparer, SingleValueReplacer):
16+
def __init__(self, name_prefix='vnet', location="centralus", location_replace_stage="centralus", resource_group_parameter_name='resource_group', vnet_name=None, vnet_address_prefixes='14.0.0.0/23', subnet_address_prefixes='14.0.0.0/23',
17+
delegations=None, subnet_name="default", service_endpoints=None, skip_delete=False):
18+
super(SubnetPreparer, self).__init__(name_prefix, 15)
19+
self.cli_ctx = get_dummy_cli()
20+
self.location = location
21+
self.resource_group_parameter_name = resource_group_parameter_name
22+
self.vnet_name = vnet_name
23+
if vnet_name is None:
24+
self.vnet_name = self.create_random_name()
25+
self.vnet_address_prefixes = vnet_address_prefixes
26+
self.subnet_address_prefixes = subnet_address_prefixes
27+
self.delegations = delegations
28+
self.subnet_name = subnet_name
29+
self.service_endpoints = service_endpoints
30+
self.skip_delete = skip_delete
31+
self.location_replace_stage = location_replace_stage
32+
33+
def create_resource(self, name, **kwargs):
34+
resource_group = self._get_resource_group(**kwargs)
35+
subnet_id = "FAKESUBNETID"
36+
location = self.location
37+
if format_location(location) == format_location(STAGE_LOCATION):
38+
location = self.location_replace_stage
39+
40+
try:
41+
self.live_only_execute(self.cli_ctx, f"az network vnet create --address-prefixes {self.vnet_address_prefixes} -g {resource_group} -n {self.vnet_name} --subnet-name {self.subnet_name} --location {location}")
42+
subnet_command = f"az network vnet subnet update --address-prefixes {self.subnet_address_prefixes} " \
43+
f"-n {self.subnet_name} " \
44+
f"-g {resource_group} " \
45+
f"--vnet-name {self.vnet_name} "
46+
if self.service_endpoints is not None:
47+
subnet_command += f'--service-endpoints {self.service_endpoints} '
48+
49+
if self.delegations is not None:
50+
subnet_command += f'--delegations {self.delegations} '
51+
52+
subnet_id = self.live_only_execute(self.cli_ctx, subnet_command).get_output_in_json()["id"]
53+
except AttributeError: # live only execute returns None if playing from record
54+
pass
55+
return {'subnet_id': subnet_id,
56+
'vnet_name': self.vnet_name,
57+
'subnet_name': self.subnet_name}
58+
59+
def _get_resource_group(self, **kwargs):
60+
try:
61+
return kwargs.get(self.resource_group_parameter_name)
62+
except KeyError:
63+
template = 'Resource group is required. Please add ' \
64+
'decorator @{} in front of this preparer.'
65+
raise CliTestError(template.format(ResourceGroupPreparer.__name__,
66+
self.resource_group_parameter_name))

0 commit comments

Comments
 (0)