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
4 changes: 4 additions & 0 deletions src/azure-cli/azure/cli/command_modules/acs/_consts.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,10 @@
CONST_APP_ROUTING_INTERNAL_NGINX = "Internal"
CONST_APP_ROUTING_NONE_NGINX = "None"

# managed gateway api installation
CONST_MANAGED_GATEWAY_INSTALLATION_DISABLED = "Disabled"
CONST_MANAGED_GATEWAY_INSTALLATION_STANDARD = "Standard"

# all supported addons
ADDONS = {
"http_application_routing": CONST_HTTP_APPLICATION_ROUTING_ADDON_NAME,
Expand Down
15 changes: 15 additions & 0 deletions src/azure-cli/azure/cli/command_modules/acs/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -616,6 +616,9 @@
- name: --enable-ai-toolchain-operator
type: bool
short-summary: Enable AI toolchain operator to the cluster.
- name: --enable-gateway-api
type: bool
short-summary: Enable managed installation of Gateway API CRDs from the standard release channel.
- name: --bootstrap-container-registry-resource-id
type: string
short-summary: Configure container registry resource ID. Must use "Cache" as bootstrap artifact source.
Expand Down Expand Up @@ -725,6 +728,8 @@
text: az aks create -g MyResourceGroup -n MyManagedCluster --node-provisioning-mode Auto --node-provisioning-default-pools None
- name: Create a Kubernetes cluster with KataVmIsolation enabled.
text: az aks create -g MyResourceGroup -n MyManagedCluster --os-sku AzureLinux --vm-size Standard_D4s_v3 --workload-runtime KataVmIsolation --node-count 1
- name: Create a kubernetes cluster with a managed installation of Gateway API CRDs from the standard release channel.
text: az aks create -g MyResourceGroup -n MyManagedCluster --enable-gateway-api
"""

helps["aks update"] = """
Expand Down Expand Up @@ -1142,6 +1147,12 @@
- name: --disable-ai-toolchain-operator
type: bool
short-summary: Disable AI toolchain operator.
- name: --enable-gateway-api
type: bool
short-summary: Enable managed installation of Gateway API CRDs from the standard release channel.
- name: --disable-gateway-api
type: bool
short-summary: Disable managed installation of Gateway API CRDs.
- name: --bootstrap-container-registry-resource-id
type: string
short-summary: Configure container registry resource ID. Must use "Cache" as bootstrap artifact source.
Expand Down Expand Up @@ -1230,6 +1241,10 @@
text: az aks update -g MyResourceGroup -n MyManagedCluster --node-provisioning-mode Auto --node-provisioning-default-pools None
- name: Upgrade load balancer sku to standard
text: az aks update --load-balancer-sku standard -g MyResourceGroup -n MyManagedCluster
- name: Update a kubernetes cluster to enable a managed installation of Gateway API CRDs from the standard release channel.
text: az aks update -g MyResourceGroup -n MyManagedCluster --enable-gateway-api
- name: Update a kubernetes cluster to disable the managed installation of Gateway API CRDs.
text: az aks update -g MyResourceGroup -n MyManagedCluster --disable-gateway-api
"""

helps["aks delete"] = """
Expand Down
17 changes: 17 additions & 0 deletions src/azure-cli/azure/cli/command_modules/acs/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,12 @@ def load_arguments(self, _):
'by that action.'
)
)
c.argument(
"enable_gateway_api",
action="store_true",
help="Enable managed installation of Gateway API CRDs from the standard release channel. "
"Requires a Gateway API implementation to be installed on the cluster (e.g., Azure Service Mesh)."
)

with self.argument_context('aks update') as c:
# managed cluster paramerters
Expand Down Expand Up @@ -873,6 +879,17 @@ def load_arguments(self, _):
'by that action.'
)
)
c.argument(
"enable_gateway_api",
action="store_true",
help="Enable managed installation of Gateway API CRDs from the standard release channel. "
"Requires a Gateway API implementation to be installed on the cluster (e.g., Azure Service Mesh)."
)
c.argument(
"disable_gateway_api",
action="store_true",
help="Disable managed installation of Gateway API CRDs."
)
with self.argument_context('aks delete') as c:
c.argument("if_match")
c.argument("if_none_match")
Expand Down
5 changes: 5 additions & 0 deletions src/azure-cli/azure/cli/command_modules/acs/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -1035,6 +1035,8 @@ def aks_create(
# node provisioning
node_provisioning_mode=None,
node_provisioning_default_pools=None,
# gateway api
enable_gateway_api=False,
):
# DO NOT MOVE: get all the original parameters and save them as a dictionary
raw_parameters = locals()
Expand Down Expand Up @@ -1228,6 +1230,9 @@ def aks_update(
# node provisioning
node_provisioning_mode=None,
node_provisioning_default_pools=None,
# gateway api
enable_gateway_api=False,
disable_gateway_api=False,
):
# DO NOT MOVE: get all the original parameters and save them as a dictionary
raw_parameters = locals()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@
CONST_AVAILABILITY_SET,
CONST_VIRTUAL_MACHINES,
CONST_ACNS_DATAPATH_ACCELERATION_MODE_BPFVETH,
CONST_ACNS_DATAPATH_ACCELERATION_MODE_NONE
CONST_ACNS_DATAPATH_ACCELERATION_MODE_NONE,
CONST_MANAGED_GATEWAY_INSTALLATION_DISABLED,
CONST_MANAGED_GATEWAY_INSTALLATION_STANDARD,
)
from azure.cli.command_modules.acs.azurecontainerstorage._consts import (
CONST_ACSTOR_EXT_INSTALLATION_NAME,
Expand Down Expand Up @@ -5973,6 +5975,20 @@ def get_node_provisioning_default_pools(self) -> Union[str, None]:
"""
return self.raw_param.get("node_provisioning_default_pools")

def get_enable_gateway_api(self) -> bool:
"""Obtain the value of enable_gateway_api.

:return: bool
"""
return self.raw_param.get("enable_gateway_api", False)

def get_disable_gateway_api(self) -> bool:
"""Obtain the value of disable_gateway_api.

:return: bool
"""
return self.raw_param.get("disable_gateway_api", False)


class AKSManagedClusterCreateDecorator(BaseAKSManagedClusterDecorator):
def __init__(
Expand Down Expand Up @@ -7362,6 +7378,19 @@ def set_up_ingress_web_app_routing(self, mc: ManagedCluster) -> ManagedCluster:

return mc

def set_up_ingress_profile_gateway_api(self, mc: ManagedCluster) -> ManagedCluster:
self._ensure_mc(mc)
if self.context.get_enable_gateway_api():
if mc.ingress_profile is None:
mc.ingress_profile = self.models.ManagedClusterIngressProfile()
if mc.ingress_profile.gateway_api is None:
mc.ingress_profile.gateway_api = (
self.models.ManagedClusterIngressProfileGatewayConfiguration(
installation=CONST_MANAGED_GATEWAY_INSTALLATION_STANDARD
)
)
return mc
Comment on lines +7381 to +7392
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

--enable-gateway-api is documented as requiring an ingress provider (e.g., Azure Service Mesh/Istio), but this create-path setup unconditionally sets ingress_profile.gateway_api when the flag is present and does not validate the prerequisite. This means users may get a late RP-side failure or end up with an invalid configuration depending on RP behavior. Consider adding an explicit validation here (or in the context getter) that checks the relevant provider flags (e.g., enable_azure_service_mesh / other managed providers) and raises a clear CLI error before sending the PUT.

Copilot uses AI. Check for mistakes.

def set_up_ai_toolchain_operator(self, mc: ManagedCluster) -> ManagedCluster:
self._ensure_mc(mc)

Expand Down Expand Up @@ -7514,6 +7543,8 @@ def construct_mc_profile_default(self, bypass_restore_defaults: bool = False) ->
mc = self.set_up_workload_auto_scaler_profile(mc)
# set up app routing profile
mc = self.set_up_ingress_web_app_routing(mc)
# set up gateway api
mc = self.set_up_ingress_profile_gateway_api(mc)
# set up custom ca trust certificates
mc = self.set_up_custom_ca_trust_certificates(mc)
# set up run command
Expand Down Expand Up @@ -9011,6 +9042,31 @@ def _update_app_routing_nginx(self, mc: ManagedCluster, nginx) -> None:
else:
raise CLIError('App Routing must be enabled to modify the default nginx ingress controller.\n')

def update_ingress_profile_gateway_api(self, mc: ManagedCluster) -> ManagedCluster:
"""Update gateway api installation in the ingress profile for the ManagedCluster object.

:return: the ManagedCluster object
"""
self._ensure_mc(mc)
enable_gateway_api = self.context.get_enable_gateway_api()
disable_gateway_api = self.context.get_disable_gateway_api()
if enable_gateway_api and disable_gateway_api:
raise MutuallyExclusiveArgumentError(
"Cannot specify --enable-gateway-api and --disable-gateway-api at the same time."
)
if enable_gateway_api or disable_gateway_api:
if mc.ingress_profile is None:
mc.ingress_profile = self.models.ManagedClusterIngressProfile() # pylint: disable=no-member
if mc.ingress_profile.gateway_api is None:
mc.ingress_profile.gateway_api = (
self.models.ManagedClusterIngressProfileGatewayConfiguration() # pylint: disable=no-member
)
if enable_gateway_api:
mc.ingress_profile.gateway_api.installation = CONST_MANAGED_GATEWAY_INSTALLATION_STANDARD
elif disable_gateway_api:
mc.ingress_profile.gateway_api.installation = CONST_MANAGED_GATEWAY_INSTALLATION_DISABLED
return mc
Comment on lines +9045 to +9068
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This update-path method sets/clears gateway_api.installation but does not validate the documented prerequisite that a managed Gateway API ingress provider is enabled on the cluster. Please add a precondition check (e.g., when enabling, verify service_mesh_profile.mode != Disabled or other supported providers are enabled) and raise a clear RequiredArgumentMissingError/InvalidArgumentValueError, instead of relying on an RP-side failure.

Copilot uses AI. Check for mistakes.

def update_node_resource_group_profile(self, mc: ManagedCluster) -> ManagedCluster:
"""Update node resource group profile for the ManagedCluster object.
:return: the ManagedCluster object
Expand Down Expand Up @@ -9928,6 +9984,8 @@ def update_mc_profile_default(self) -> ManagedCluster:
mc = self.update_node_resource_group_profile(mc)
# update AI toolchain operator
mc = self.update_ai_toolchain_operator(mc)
# update gateway api
mc = self.update_ingress_profile_gateway_api(mc)
# update bootstrap profile
mc = self.update_bootstrap_profile(mc)
# update static egress gateway
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15051,3 +15051,150 @@ def test_aks_nodepool_add_with_localdns_required_mode(self, resource_group, reso
"aks delete --resource-group={resource_group} --name={name} --yes --no-wait",
checks=[self.is_empty()],
)

@AllowLargeResponse()
@AKSCustomResourceGroupPreparer(
random_name_length=17, name_prefix="clitest", location="centraluseuap"
)
def test_aks_create_with_gateway_api_and_azureservicemesh(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Queued live test to validate the change.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please commit recording files to pass built-in CI checks.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The live test failed with error

E azure.cli.core.azclierror.BadRequestError: (PreviewFeatureNotRegistered) Preview feature Microsoft.ContainerService/ManagedGatewayAPIPreview not registered.
E Code: PreviewFeatureNotRegistered
E Message: Preview feature Microsoft.ContainerService/ManagedGatewayAPIPreview not registered.

https://dev.azure.com/msazure/CloudNativeCompute/CloudNativeCompute%20Team/_build/results?buildId=161520143&view=logs&j=b162b355-d59d-5864-ce0f-0a70f12dd28b&t=dc59ccd1-231f-538b-777f-33a592c7ca57&l=4020

  1. Remove the feature flag validation for features published to the stable API.
  2. For now, you can test it with a subscription where the feature is registered to confirm it works as intended.

Please also resolve merge conflict.
@meecethereese

self, resource_group, resource_group_location
):
# reset the count so in replay mode the random names will start with 0
self.test_resources_count = 0

aks_name = self.create_random_name("cliakstest", 16)
_, create_version = self._get_versions(resource_group_location)
asm_revision = self._get_asm_supported_revision(resource_group_location)
self.kwargs.update(
{
Comment thread
meecethereese marked this conversation as resolved.
"resource_group": resource_group,
"name": aks_name,
"ssh_key_value": self.generate_ssh_keys(),
"k8s_version": create_version,
"asm_revision": asm_revision,
}
)

# Test successful creation with Gateway API and Azure Service Mesh addon
create_cmd = (
"aks create --resource-group={resource_group} --name={name} "
"--enable-app-routing "
"--enable-azure-service-mesh "
Comment thread
meecethereese marked this conversation as resolved.
"--enable-gateway-api "
"--ssh-key-value={ssh_key_value} -o json "
)
self.cmd(
create_cmd,
checks=[
self.check("provisioningState", "Succeeded"),
self.check("serviceMeshProfile.mode", "Istio"),
self.check("ingressProfile.gatewayApi.installation", "Standard"),
],
)

# Test disabling Gateway API
update_cmd = (
"aks update --resource-group={resource_group} --name={name} "
"--disable-gateway-api "
)
self.cmd(
update_cmd,
checks=[
self.check("provisioningState", "Succeeded"),
self.check("ingressProfile.gatewayApi.installation", "Disabled"),
],
)

# Test re-enabling Gateway API
update_cmd = (
"aks update --resource-group={resource_group} --name={name} "
"--enable-gateway-api "
)
self.cmd(
update_cmd,
checks=[
self.check("provisioningState", "Succeeded"),
self.check("ingressProfile.gatewayApi.installation", "Standard"),
],
)
Comment on lines +15078 to +15119
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

test_aks_create_with_gateway_api_and_azureservicemesh creates a cluster but never deletes it. This will leak live-test resources (and can cause subsequent test failures/cost). Please add cleanup at the end (ideally aks delete ... --yes --no-wait like other tests in this file).

Suggested change
# Test successful creation with Gateway API and Azure Service Mesh addon
create_cmd = (
"aks create --resource-group={resource_group} --name={name} "
"--enable-azure-service-mesh "
"--enable-gateway-api "
"--ssh-key-value={ssh_key_value} -o json "
)
self.cmd(
create_cmd,
checks=[
self.check("provisioningState", "Succeeded"),
self.check("serviceMeshProfile.mode", "Istio"),
self.check("ingressProfile.gatewayApi.installation", "Standard"),
],
)
# Test disabling Gateway API
update_cmd = (
"aks update --resource-group={resource_group} --name={name} "
"--disable-gateway-api "
)
self.cmd(
update_cmd,
checks=[
self.check("provisioningState", "Succeeded"),
self.check("ingressProfile.gatewayApi.installation", "Disabled"),
],
)
# Test re-enabling Gateway API
update_cmd = (
"aks update --resource-group={resource_group} --name={name} "
"--enable-gateway-api "
)
self.cmd(
update_cmd,
checks=[
self.check("provisioningState", "Succeeded"),
self.check("ingressProfile.gatewayApi.installation", "Standard"),
],
)
try:
# Test successful creation with Gateway API and Azure Service Mesh addon
create_cmd = (
"aks create --resource-group={resource_group} --name={name} "
"--enable-azure-service-mesh "
"--enable-gateway-api "
"--ssh-key-value={ssh_key_value} -o json "
)
self.cmd(
create_cmd,
checks=[
self.check("provisioningState", "Succeeded"),
self.check("serviceMeshProfile.mode", "Istio"),
self.check("ingressProfile.gatewayApi.installation", "Standard"),
],
)
# Test disabling Gateway API
update_cmd = (
"aks update --resource-group={resource_group} --name={name} "
"--disable-gateway-api "
)
self.cmd(
update_cmd,
checks=[
self.check("provisioningState", "Succeeded"),
self.check("ingressProfile.gatewayApi.installation", "Disabled"),
],
)
# Test re-enabling Gateway API
update_cmd = (
"aks update --resource-group={resource_group} --name={name} "
"--enable-gateway-api "
)
self.cmd(
update_cmd,
checks=[
self.check("provisioningState", "Succeeded"),
self.check("ingressProfile.gatewayApi.installation", "Standard"),
],
)
finally:
self.cmd(
"aks delete --resource-group={resource_group} --name={name} --yes --no-wait"
)

Copilot uses AI. Check for mistakes.

# Cleanup
self.cmd(
"aks delete --resource-group={resource_group} --name={name} --yes --no-wait",
checks=[self.is_empty()],
)


@AllowLargeResponse()
@AKSCustomResourceGroupPreparer(
random_name_length=17, name_prefix="clitest", location="centraluseuap"
)
def test_aks_managed_gateway_without_gateway_implementation(
self, resource_group, resource_group_location
):
"""
Verify that managed Gateway API can be enabled without a Gateway API implementation
(e.g., Azure Service Mesh) on the cluster.

This test:
- Creates a cluster with --enable-gateway-api but no gateway implementation enabled.
- Disables and re-enables Gateway API on the existing cluster.
"""

# reset the count so in replay mode the random names will start with 0
self.test_resources_count = 0

aks_name = self.create_random_name("cliakstest", 16)
self.kwargs.update(
{
"resource_group": resource_group,
"name": aks_name,
"ssh_key_value": self.generate_ssh_keys(),
"location": resource_group_location,
}
)

# Create a cluster with Gateway API enabled and no gateway implementation
create_cmd = (
"aks create --resource-group={resource_group} --name={name} "
"--enable-app-routing "
"--enable-gateway-api "
"--ssh-key-value={ssh_key_value} -o json "
)
self.cmd(
create_cmd,
checks=[
self.check("provisioningState", "Succeeded"),
self.check("ingressProfile.gatewayApi.installation", "Standard"),
],
)

# Disable Gateway API
disable_cmd = (
"aks update --resource-group={resource_group} --name={name} "
"--disable-gateway-api "
)
self.cmd(
disable_cmd,
checks=[
self.check("provisioningState", "Succeeded"),
self.check("ingressProfile.gatewayApi.installation", "Disabled"),
],
)

# Re-enable Gateway API
enable_cmd = (
"aks update --resource-group={resource_group} --name={name} "
"--enable-gateway-api "
)
self.cmd(
enable_cmd,
checks=[
self.check("provisioningState", "Succeeded"),
self.check("ingressProfile.gatewayApi.installation", "Standard"),
],
)

# Cleanup
delete_cmd = "aks delete --resource-group={resource_group} --name={name} --yes --no-wait"
self.cmd(delete_cmd, checks=[self.is_empty()])
Loading
Loading