Skip to content
Open
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
1 change: 1 addition & 0 deletions src/aks-preview/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ To release a new version, please select a new version number (usually plus 1 to

Pending
+++++++
* `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.

20.0.0b2
+++++++
Expand Down
16 changes: 12 additions & 4 deletions src/aks-preview/azext_aks_preview/managed_cluster_decorator.py
Original file line number Diff line number Diff line change
Expand Up @@ -510,7 +510,7 @@ def _get_disable_local_accounts(self, enable_validation: bool = False) -> bool:
)
return disable_local_accounts

def _get_outbound_type(
def _get_outbound_type( # pylint: disable=too-many-branches
self,
enable_validation: bool = False,
read_only: bool = False,
Expand Down Expand Up @@ -594,9 +594,17 @@ def _get_outbound_type(
CONST_OUTBOUND_TYPE_USER_ASSIGNED_NAT_GATEWAY,
]:
if self.get_vnet_subnet_id() in ["", None]:
raise RequiredArgumentMissingError(
"--vnet-subnet-id must be specified for userDefinedRouting and it must "
"be pre-configured with a route table with egress rules"
if self.decorator_mode == DecoratorMode.CREATE:
raise RequiredArgumentMissingError(
"--vnet-subnet-id must be specified for userDefinedRouting and it must "
"be pre-configured with a route table with egress rules"
Comment thread
FumingZhang marked this conversation as resolved.
)
raise InvalidArgumentValueError(
f"Updating outbound type to {outbound_type} is only supported for "
"clusters using a custom (BYO) virtual network. Managed VNet clusters "
f"cannot be updated to {outbound_type}. Please refer to "
"https://learn.microsoft.com/en-us/azure/aks/egress-outboundtype"
"#updating-outboundtype-after-cluster-creation for supported migration paths."
)

if (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@
from azure.cli.command_modules.acs._consts import (
CONST_OUTBOUND_TYPE_LOAD_BALANCER,
CONST_OUTBOUND_TYPE_MANAGED_NAT_GATEWAY,
CONST_OUTBOUND_TYPE_USER_DEFINED_ROUTING,
CONST_OUTBOUND_TYPE_USER_ASSIGNED_NAT_GATEWAY,
DecoratorEarlyExitException,
DecoratorMode,
Comment thread
FumingZhang marked this conversation as resolved.
)
Expand Down Expand Up @@ -4705,6 +4707,96 @@ def test_get_outbound_type(self):
CONST_OUTBOUND_TYPE_MANAGED_NAT_GATEWAY_V2,
)

def test_get_outbound_type_update_udr_byo_vnet(self):
"""Test that updating to UDR succeeds when the cluster has a BYO VNet (vnet_subnet_id is set on agentpool)."""
ctx = AKSPreviewManagedClusterContext(
self.cmd,
AKSManagedClusterParamDict({"outbound_type": "userDefinedRouting"}),
self.models,
decorator_mode=DecoratorMode.UPDATE,
)
self.create_attach_agentpool_context(ctx)
# Simulate a BYO VNet cluster: agentpool has vnet_subnet_id set
agentpool = self.models.ManagedClusterAgentPoolProfile(
name="nodepool1",
vnet_subnet_id="/subscriptions/test/resourceGroups/rg/providers/Microsoft.Network/virtualNetworks/vnet/subnets/subnet",
)
mc = self.models.ManagedCluster(
location="test_location",
agent_pool_profiles=[agentpool],
network_profile=self.models.ContainerServiceNetworkProfile(
load_balancer_sku="standard",
),
)
ctx.attach_mc(mc)
ctx.agentpool_context.attach_agentpool(agentpool)
# Should succeed — BYO VNet cluster can update to UDR
outbound_type = ctx._get_outbound_type(enable_validation=True)
self.assertEqual(outbound_type, CONST_OUTBOUND_TYPE_USER_DEFINED_ROUTING)

def test_get_outbound_type_update_udr_managed_vnet(self):
"""Test that updating to UDR fails with clear error when the cluster uses managed VNet (no vnet_subnet_id)."""
ctx = AKSPreviewManagedClusterContext(
self.cmd,
AKSManagedClusterParamDict({"outbound_type": "userDefinedRouting"}),
self.models,
decorator_mode=DecoratorMode.UPDATE,
)
self.create_attach_agentpool_context(ctx)
# Simulate a managed VNet cluster: agentpool has no vnet_subnet_id
agentpool = self.models.ManagedClusterAgentPoolProfile(
name="nodepool1",
)
mc = self.models.ManagedCluster(
location="test_location",
agent_pool_profiles=[agentpool],
network_profile=self.models.ContainerServiceNetworkProfile(
load_balancer_sku="standard",
),
)
ctx.attach_mc(mc)
ctx.agentpool_context.attach_agentpool(agentpool)
# Should fail with InvalidArgumentValueError for managed VNet clusters
with self.assertRaises(InvalidArgumentValueError):
ctx._get_outbound_type(enable_validation=True)
Comment thread
FumingZhang marked this conversation as resolved.

def test_get_outbound_type_update_user_assigned_nat_gw_managed_vnet(self):
"""Test that updating to userAssignedNATGateway fails with clear error when using managed VNet."""
ctx = AKSPreviewManagedClusterContext(
self.cmd,
AKSManagedClusterParamDict({"outbound_type": "userAssignedNATGateway"}),
self.models,
decorator_mode=DecoratorMode.UPDATE,
)
self.create_attach_agentpool_context(ctx)
agentpool = self.models.ManagedClusterAgentPoolProfile(
name="nodepool1",
)
mc = self.models.ManagedCluster(
location="test_location",
agent_pool_profiles=[agentpool],
network_profile=self.models.ContainerServiceNetworkProfile(
load_balancer_sku="standard",
),
)
ctx.attach_mc(mc)
ctx.agentpool_context.attach_agentpool(agentpool)
with self.assertRaises(InvalidArgumentValueError):
ctx._get_outbound_type(enable_validation=True)

def test_get_outbound_type_create_udr_no_subnet(self):
"""Test that creating with UDR but no vnet_subnet_id raises RequiredArgumentMissingError."""
ctx = AKSPreviewManagedClusterContext(
self.cmd,
AKSManagedClusterParamDict({"outbound_type": "userDefinedRouting"}),
self.models,
decorator_mode=DecoratorMode.CREATE,
)
self.create_attach_agentpool_context(ctx)
# Should fail with RequiredArgumentMissingError during create
with self.assertRaises(RequiredArgumentMissingError):
ctx._get_outbound_type(enable_validation=True)

Comment thread
FumingZhang marked this conversation as resolved.
def test_get_enable_gateway_api(self):
# default value
ctx_1 = AKSPreviewManagedClusterContext(
Expand Down
Loading