Skip to content

Commit d53fbd0

Browse files
committed
Fix aks update --outbound-type validation for UDR and userAssignedNATGateway
Fixes Azure/azure-cli#33204 The CLI incorrectly required --vnet-subnet-id when updating outbound type to userDefinedRouting or userAssignedNATGateway. This parameter is not registered for 'aks update', creating an impossible state for users. Changes: - In UPDATE mode, when vnet_subnet_id is empty, raise a clear InvalidArgumentValueError explaining that updating to UDR/ userAssignedNATGateway is only supported for BYO VNet clusters - In CREATE mode, preserve existing RequiredArgumentMissingError - For BYO VNet clusters, the subnet is already known from the agentpool, so validation passes and the update works correctly - Added 4 unit tests covering CREATE and UPDATE scenarios
1 parent 62e05d9 commit d53fbd0

3 files changed

Lines changed: 106 additions & 4 deletions

File tree

src/aks-preview/HISTORY.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ To release a new version, please select a new version number (usually plus 1 to
1111

1212
Pending
1313
+++++++
14+
* `az aks update`: Fix misleading error when updating outbound type to `userDefinedRouting` or `userAssignedNATGateway`. For managed VNet clusters (unsupported), a clear error message is now shown instead of asking for `--vnet-subnet-id`. For BYO VNet clusters, the update works correctly without requiring the user to re-specify the subnet.
1415

1516
20.0.0b2
1617
+++++++

src/aks-preview/azext_aks_preview/managed_cluster_decorator.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -594,10 +594,19 @@ def _get_outbound_type(
594594
CONST_OUTBOUND_TYPE_USER_ASSIGNED_NAT_GATEWAY,
595595
]:
596596
if self.get_vnet_subnet_id() in ["", None]:
597-
raise RequiredArgumentMissingError(
598-
"--vnet-subnet-id must be specified for userDefinedRouting and it must "
599-
"be pre-configured with a route table with egress rules"
600-
)
597+
if self.decorator_mode == DecoratorMode.CREATE:
598+
raise RequiredArgumentMissingError(
599+
"--vnet-subnet-id must be specified for userDefinedRouting and it must "
600+
"be pre-configured with a route table with egress rules"
601+
)
602+
else:
603+
raise InvalidArgumentValueError(
604+
f"Updating outbound type to {outbound_type} is only supported for "
605+
"clusters using a custom (BYO) virtual network. Managed VNet clusters "
606+
f"cannot be updated to {outbound_type}. Please refer to "
607+
"https://learn.microsoft.com/en-us/azure/aks/egress-outboundtype"
608+
"#updating-outboundtype-after-cluster-creation for supported migration paths."
609+
)
601610

602611
if (
603612
self.decorator_mode == DecoratorMode.CREATE and

src/aks-preview/azext_aks_preview/tests/latest/test_managed_cluster_decorator.py

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@
9999
from azure.cli.command_modules.acs._consts import (
100100
CONST_OUTBOUND_TYPE_LOAD_BALANCER,
101101
CONST_OUTBOUND_TYPE_MANAGED_NAT_GATEWAY,
102+
CONST_OUTBOUND_TYPE_USER_DEFINED_ROUTING,
103+
CONST_OUTBOUND_TYPE_USER_ASSIGNED_NAT_GATEWAY,
102104
DecoratorEarlyExitException,
103105
DecoratorMode,
104106
)
@@ -4705,6 +4707,96 @@ def test_get_outbound_type(self):
47054707
CONST_OUTBOUND_TYPE_MANAGED_NAT_GATEWAY_V2,
47064708
)
47074709

4710+
def test_get_outbound_type_update_udr_byo_vnet(self):
4711+
"""Test that updating to UDR succeeds when the cluster has a BYO VNet (vnet_subnet_id is set on agentpool)."""
4712+
ctx = AKSPreviewManagedClusterContext(
4713+
self.cmd,
4714+
AKSManagedClusterParamDict({"outbound_type": "userDefinedRouting"}),
4715+
self.models,
4716+
decorator_mode=DecoratorMode.UPDATE,
4717+
)
4718+
self.create_attach_agentpool_context(ctx)
4719+
# Simulate a BYO VNet cluster: agentpool has vnet_subnet_id set
4720+
agentpool = self.models.ManagedClusterAgentPoolProfile(
4721+
name="nodepool1",
4722+
vnet_subnet_id="/subscriptions/test/resourceGroups/rg/providers/Microsoft.Network/virtualNetworks/vnet/subnets/subnet",
4723+
)
4724+
mc = self.models.ManagedCluster(
4725+
location="test_location",
4726+
agent_pool_profiles=[agentpool],
4727+
network_profile=self.models.ContainerServiceNetworkProfile(
4728+
load_balancer_sku="standard",
4729+
),
4730+
)
4731+
ctx.attach_mc(mc)
4732+
ctx.agentpool_context.attach_agentpool(agentpool)
4733+
# Should succeed — BYO VNet cluster can update to UDR
4734+
outbound_type = ctx._get_outbound_type(enable_validation=True)
4735+
self.assertEqual(outbound_type, CONST_OUTBOUND_TYPE_USER_DEFINED_ROUTING)
4736+
4737+
def test_get_outbound_type_update_udr_managed_vnet(self):
4738+
"""Test that updating to UDR fails with clear error when the cluster uses managed VNet (no vnet_subnet_id)."""
4739+
ctx = AKSPreviewManagedClusterContext(
4740+
self.cmd,
4741+
AKSManagedClusterParamDict({"outbound_type": "userDefinedRouting"}),
4742+
self.models,
4743+
decorator_mode=DecoratorMode.UPDATE,
4744+
)
4745+
self.create_attach_agentpool_context(ctx)
4746+
# Simulate a managed VNet cluster: agentpool has no vnet_subnet_id
4747+
agentpool = self.models.ManagedClusterAgentPoolProfile(
4748+
name="nodepool1",
4749+
)
4750+
mc = self.models.ManagedCluster(
4751+
location="test_location",
4752+
agent_pool_profiles=[agentpool],
4753+
network_profile=self.models.ContainerServiceNetworkProfile(
4754+
load_balancer_sku="standard",
4755+
),
4756+
)
4757+
ctx.attach_mc(mc)
4758+
ctx.agentpool_context.attach_agentpool(agentpool)
4759+
# Should fail with InvalidArgumentValueError for managed VNet clusters
4760+
with self.assertRaises(InvalidArgumentValueError):
4761+
ctx._get_outbound_type(enable_validation=True)
4762+
4763+
def test_get_outbound_type_update_user_assigned_nat_gw_managed_vnet(self):
4764+
"""Test that updating to userAssignedNATGateway fails with clear error when using managed VNet."""
4765+
ctx = AKSPreviewManagedClusterContext(
4766+
self.cmd,
4767+
AKSManagedClusterParamDict({"outbound_type": "userAssignedNATGateway"}),
4768+
self.models,
4769+
decorator_mode=DecoratorMode.UPDATE,
4770+
)
4771+
self.create_attach_agentpool_context(ctx)
4772+
agentpool = self.models.ManagedClusterAgentPoolProfile(
4773+
name="nodepool1",
4774+
)
4775+
mc = self.models.ManagedCluster(
4776+
location="test_location",
4777+
agent_pool_profiles=[agentpool],
4778+
network_profile=self.models.ContainerServiceNetworkProfile(
4779+
load_balancer_sku="standard",
4780+
),
4781+
)
4782+
ctx.attach_mc(mc)
4783+
ctx.agentpool_context.attach_agentpool(agentpool)
4784+
with self.assertRaises(InvalidArgumentValueError):
4785+
ctx._get_outbound_type(enable_validation=True)
4786+
4787+
def test_get_outbound_type_create_udr_no_subnet(self):
4788+
"""Test that creating with UDR but no vnet_subnet_id raises RequiredArgumentMissingError."""
4789+
ctx = AKSPreviewManagedClusterContext(
4790+
self.cmd,
4791+
AKSManagedClusterParamDict({"outbound_type": "userDefinedRouting"}),
4792+
self.models,
4793+
decorator_mode=DecoratorMode.CREATE,
4794+
)
4795+
self.create_attach_agentpool_context(ctx)
4796+
# Should fail with RequiredArgumentMissingError during create
4797+
with self.assertRaises(RequiredArgumentMissingError):
4798+
ctx._get_outbound_type(enable_validation=True)
4799+
47084800
def test_get_enable_gateway_api(self):
47094801
# default value
47104802
ctx_1 = AKSPreviewManagedClusterContext(

0 commit comments

Comments
 (0)