Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
d9a3562
[aks-preview] Add --enable-backup to az aks create and az aks update
May 25, 2026
d1bb93b
[aks-preview] HISTORY: note --enable-backup under Pending
May 25, 2026
08bc672
[aks-preview] aks_backup: align continuation indent + silence too-man…
May 25, 2026
0b138f9
Merge branch 'main' into feat/aks-enable-backup
anshulahuja98 May 25, 2026
e2739c7
[aks-preview] _params: note backup-strategy enum mirrors dataprotection
May 25, 2026
237444b
[aks-preview] Address CI lint feedback
May 25, 2026
2ce8293
[aks-preview] Extract backup-strategy enum into a shared constant
May 26, 2026
938d597
[aks-preview] aks_backup: prompt to install dataprotection extension …
Jun 1, 2026
b70c8ae
[aks-preview] Add live tests for aks create/update --enable-backup
Jun 1, 2026
59b7722
Merge branch 'main' into feat/aks-enable-backup
anshulahuja98 Jun 1, 2026
cdf039a
[aks-preview] Fix error type and release notes for --enable-backup
Jun 1, 2026
1d6194a
[aks-preview][dataprotection] Auto-install dependent CLI extensions o…
Jun 1, 2026
61d86c3
[aks-preview] Fix HISTORY.rst: --backup-configuration-file -> --backu…
Jun 1, 2026
de88d3e
[aks-preview] Release enable-backup preview support
Jun 2, 2026
7bfd2c0
Merge remote-tracking branch 'upstream/main' into feat/aks-enable-backup
Jun 2, 2026
9e69b8a
[aks-preview] Fix flake8 indentation in backup parameter
Jun 2, 2026
5260826
[dataprotection] Remove redundant prompt import in AKS helper
Jun 2, 2026
0b4a133
Refactor docstring in aks_backup.py to simplify description of AKS ba…
Jun 3, 2026
3e7cf63
Merge remote-tracking branch 'upstream/main' into feat/aks-enable-backup
Jun 3, 2026
b0c335b
[aks-preview] Move pending notes into 21.0.0b4 release
Jun 3, 2026
2e020dd
[aks-preview] Remove dataprotection helper changes
Jun 3, 2026
bed0ec0
Merge branch 'main' into feat/aks-enable-backup
anshulahuja98 Jun 9, 2026
c047a50
Fix AKS backup storage account create payload
Jun 9, 2026
f31e690
Revert "Fix AKS backup storage account create payload"
Jun 9, 2026
d792590
Merge branch 'main' into feat/aks-enable-backup
anshulahuja98 Jun 22, 2026
8e5e895
lint fix
Jun 22, 2026
7462d6e
[aks-preview] Add 21.0.0b7 release notes
Jun 23, 2026
8f984eb
Merge branch 'main' into feat/aks-enable-backup
anshulahuja98 Jun 23, 2026
18294f0
Merge branch 'main' into feat/aks-enable-backup
FumingZhang Jun 23, 2026
1a7c734
Merge branch 'main' into feat/aks-enable-backup
FumingZhang Jun 24, 2026
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
8 changes: 6 additions & 2 deletions src/aks-preview/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,15 @@ To release a new version, please select a new version number (usually plus 1 to

Pending
+++++++

21.0.0b7
++++++++
* `az aks create`: Add `--node-disruption-policy` (preview) to set the node disruption policy at cluster creation time. Requires AFEC registration `Microsoft.ContainerService/NodeDisruptionProfile`. This is a cluster-level property that applies to all node pools in the cluster.
* `az aks maintenancewindow`: Add CRUD commands (`create`, `show`, `list`, `update`, `delete`, `wait`) for the new MaintenanceWindow peer ARM resource. Available with API version `2026-04-02-preview`. Requires the `Microsoft.ContainerService/AKSSharedMaintenanceWindowPreview` feature to be registered on the subscription (auto-approval).
* `az aks bastion`: Fix failure when the bastion host is in a different subscription than the cluster by using the subscription from the bastion resource ID for the internal `az network bastion tunnel` command.
* Set `principalType` when creating role assignments to avoid `PrincipalNotFound` failures caused by Microsoft Entra ID replication delay for freshly created identities.
* `az aks create` and `az aks update`: Add `--enable-backup` (preview) to configure Azure Backup for the AKS cluster in a single command. Supports `--backup-strategy` presets (Week, Month, DisasterRecovery, Custom) and an optional `--backup-configuration` for bring-your-own vault/policy/storage. Requires the `dataprotection` CLI extension.
* `az aks maintenancewindow`: Add CRUD commands (`create`, `show`, `list`, `update`, `delete`, `wait`) for the new MaintenanceWindow peer ARM resource. Available with API version `2026-04-02-preview`. Requires the `Microsoft.ContainerService/AKSSharedMaintenanceWindowPreview` feature to be registered on the subscription (auto-approval).
* `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.
* Set `principalType` when creating role assignments to avoid `PrincipalNotFound` failures caused by Microsoft Entra ID replication delay for freshly created identities.

21.0.0b6
++++++++
Expand Down
6 changes: 6 additions & 0 deletions src/aks-preview/azext_aks_preview/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -843,6 +843,8 @@
text: az aks create -g MyResourceGroup -n MyManagedCluster --control-plane-scaling-size H4
- name: Create an automatic cluster with hosted system components enabled.
text: az aks create -g MyResourceGroup -n MyManagedCluster --sku automatic --enable-hosted-system
- name: Create a kubernetes cluster with Azure Backup enabled (default Week strategy). Requires the 'dataprotection' extension. Implicitly waits for cluster creation.
text: az aks create -g MyResourceGroup -n MyManagedCluster --generate-ssh-keys --enable-backup --yes

"""

Expand Down Expand Up @@ -1613,6 +1615,10 @@
text: az aks update -g MyResourceGroup -n MyManagedCluster --safeguards-level Warning --safeguards-excluded-ns ns1,ns2
- name: Enable Azure Monitor logs for a kubernetes cluster
text: az aks update -g MyResourceGroup -n MyManagedCluster --enable-azure-monitor-logs
- name: Enable Azure Backup for a kubernetes cluster (default Week strategy). Requires the 'dataprotection' extension.
text: az aks update -g MyResourceGroup -n MyManagedCluster --enable-backup --yes
- name: Enable Azure Backup with a custom strategy using an existing vault and policy
text: az aks update -g MyResourceGroup -n MyManagedCluster --enable-backup --backup-strategy Custom --backup-configuration @config.json --yes
- name: Disable Azure Monitor logs for a kubernetes cluster
text: az aks update -g MyResourceGroup -n MyManagedCluster --disable-azure-monitor-logs
- name: Update a kubernetes cluster to clear any namespaces excluded from safeguards. Assumes azure policy addon is already enabled
Expand Down
59 changes: 59 additions & 0 deletions src/aks-preview/azext_aks_preview/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,10 @@
CONST_UPGRADE_STRATEGY_BLUE_GREEN,
]

# AKS backup strategy presets exposed by --backup-strategy.
# NOTE: must mirror CONST_AKS_BACKUP_STRATEGIES in azext_dataprotection.manual._consts.
aks_backup_strategies = ["Week", "Month", "DisasterRecovery", "Custom"]

node_disruption_policies = [
CONST_NODE_DISRUPTION_POLICY_ALLOW,
CONST_NODE_DISRUPTION_POLICY_BLOCK,
Expand Down Expand Up @@ -1318,6 +1322,34 @@ def load_arguments(self, _):
is_preview=True,
help="Enable continuous control plane and addon monitor for the cluster.",
)
# Backup (delegates to the dataprotection extension)
c.argument(
"enable_backup",
action="store_true",
is_preview=True,
help="Enable Azure Backup for this AKS cluster. Orchestrates the same flow as "
"'az dataprotection enable-backup trigger' (requires the 'dataprotection' extension). "
"Implicitly waits for cluster creation to complete (ignores --no-wait).",
Comment thread
anshulahuja98 marked this conversation as resolved.
)
c.argument(
"backup_strategy",
arg_type=get_enum_type(aks_backup_strategies),
is_preview=True,
help="Backup strategy preset. Week (default, 7-day operational retention), Month "
"(30-day operational retention), DisasterRecovery (7-day operational + 90-day vault "
"retention), Custom (bring your own vault and policy via --backup-configuration). "
"Only valid with --enable-backup.",
)
c.argument(
"backup_configuration_file",
options_list=["--backup-configuration"],
type=validate_file_or_dict,
is_preview=True,
help="Backup configuration as inline JSON string or @file.json. "
"Supports storageAccountResourceId, blobContainerName, backupResourceGroupId, "
"backupVaultId, backupPolicyId, tags. backupVaultId and backupPolicyId are required "
"for Custom strategy. Only valid with --enable-backup.",
)
# prepared image specification
c.argument(
'prepared_image_specification_id',
Expand Down Expand Up @@ -1989,6 +2021,33 @@ def load_arguments(self, _):
is_preview=True,
help="Disable continuous control plane and addon monitor for the cluster.",
)
# Backup (delegates to the dataprotection extension)
c.argument(
"enable_backup",
action="store_true",
is_preview=True,
help="Enable Azure Backup for this AKS cluster. Orchestrates the same flow as "
"'az dataprotection enable-backup trigger' (requires the 'dataprotection' extension).",
)
c.argument(
"backup_strategy",
arg_type=get_enum_type(aks_backup_strategies),
is_preview=True,
help="Backup strategy preset. Week (default, 7-day operational retention), Month "
"(30-day operational retention), DisasterRecovery (7-day operational + 90-day vault "
"retention), Custom (bring your own vault and policy via --backup-configuration). "
"Only valid with --enable-backup.",
)
c.argument(
"backup_configuration_file",
options_list=["--backup-configuration"],
type=validate_file_or_dict,
is_preview=True,
help="Backup configuration as inline JSON string or @file.json. "
"Supports storageAccountResourceId, blobContainerName, backupResourceGroupId, "
"backupVaultId, backupPolicyId, tags. backupVaultId and backupPolicyId are required "
"for Custom strategy. Only valid with --enable-backup.",
)
c.argument(
"control_plane_scaling_size",
options_list=["--control-plane-scaling-size", "--cp-scaling-size"],
Expand Down
84 changes: 84 additions & 0 deletions src/aks-preview/azext_aks_preview/aks_backup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

"""Helpers that delegate AKS backup enablement to the dataprotection extension."""

from knack.log import get_logger
from knack.prompting import prompt_y_n, NoTTYException

from azure.cli.core.azclierror import RequiredArgumentMissingError

DATAPROTECTION_EXTENSION_NAME = "dataprotection"

logger = get_logger(__name__)


def _ensure_dataprotection_extension(cmd, yes):
"""Make ``azext_dataprotection.manual.aks.aks_helper`` importable.

If the ``dataprotection`` extension is not installed, prompt the user to
install it (or install silently when ``yes`` is True). Raises
``RequiredArgumentMissingError`` if the user declines or the install fails.
"""
from azure.cli.core.extension.operations import add_extension_to_path

try:
add_extension_to_path(DATAPROTECTION_EXTENSION_NAME)
from azext_dataprotection.manual.aks.aks_helper import ( # pylint: disable=unused-import,import-error
dataprotection_enable_backup_helper,
)
return
except Exception: # pylint: disable=broad-except
pass

install_msg = (
f"The '{DATAPROTECTION_EXTENSION_NAME}' extension is required for "
"--enable-backup but is not installed. Install it now?"
)
proceed = yes
if not proceed:
try:
proceed = prompt_y_n(install_msg, default="y")
except NoTTYException:
proceed = False
if not proceed:
raise RequiredArgumentMissingError(
f"The '{DATAPROTECTION_EXTENSION_NAME}' extension is required for "
"--enable-backup with 'az aks create' / 'az aks update'.\n"
f"Run `az extension add --name {DATAPROTECTION_EXTENSION_NAME}` "
"and retry, or rerun with --yes to auto-install."
)
Comment thread
anshulahuja98 marked this conversation as resolved.

logger.warning("Installing extension '%s'...", DATAPROTECTION_EXTENSION_NAME)
from azure.cli.core.extension.operations import add_extension
add_extension(cmd=cmd, extension_name=DATAPROTECTION_EXTENSION_NAME)
add_extension_to_path(DATAPROTECTION_EXTENSION_NAME)


def enable_aks_backup(cmd, resource_group_name, cluster_name, # pylint: disable=too-many-positional-arguments
backup_strategy, backup_configuration_file, yes):
"""Enable Azure Backup for an AKS cluster by delegating to the
``dataprotection`` extension.
"""
from azure.cli.core.commands.client_factory import get_subscription_id

_ensure_dataprotection_extension(cmd, yes)

from azext_dataprotection.manual.aks.aks_helper import ( # pylint: disable=import-error
dataprotection_enable_backup_helper,
)

subscription_id = get_subscription_id(cmd.cli_ctx)
datasource_id = (
f"/subscriptions/{subscription_id}/resourceGroups/{resource_group_name}"
f"/providers/Microsoft.ContainerService/managedClusters/{cluster_name}"
)
dataprotection_enable_backup_helper(
cmd,
datasource_id,
backup_strategy or "Week",
backup_configuration_file or {},
yes=yes,
)
8 changes: 8 additions & 0 deletions src/aks-preview/azext_aks_preview/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -1440,6 +1440,10 @@ def aks_create(
control_plane_scaling_size=None,
# health monitor
enable_continuous_control_plane_and_addon_monitor=False,
# backup (delegates to the dataprotection extension)
enable_backup=False,
backup_strategy=None,
backup_configuration_file=None,
# prepared image specification
prepared_image_specification_id=None,
):
Expand Down Expand Up @@ -1702,6 +1706,10 @@ def aks_update(
# health monitor
enable_continuous_control_plane_and_addon_monitor=False,
disable_continuous_control_plane_and_addon_monitor=False,
# backup (delegates to the dataprotection extension)
enable_backup=False,
backup_strategy=None,
backup_configuration_file=None,
# node disruption policy
node_disruption_policy=None,
# control plane scaling
Expand Down
34 changes: 32 additions & 2 deletions src/aks-preview/azext_aks_preview/managed_cluster_decorator.py
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,9 @@ def external_functions(self) -> SimpleNamespace:
external_functions["ensure_container_insights_for_monitoring"] = (
ensure_container_insights_for_monitoring_preview
)
# AKS backup (delegates to the dataprotection extension)
from azext_aks_preview.aks_backup import enable_aks_backup
external_functions["enable_aks_backup"] = enable_aks_backup
self.__external_functions = SimpleNamespace(**external_functions)
return self.__external_functions

Expand Down Expand Up @@ -5516,6 +5519,7 @@ def check_is_postprocessing_required(self, mc: ManagedCluster) -> bool:
"enable_azure_container_storage",
default_value=False
)
enable_backup = self.context.raw_param.get("enable_backup", False)

# pylint: disable=too-many-boolean-expressions
if (
Expand All @@ -5525,7 +5529,8 @@ def check_is_postprocessing_required(self, mc: ManagedCluster) -> bool:
azuremonitormetrics_addon_enabled or
(enable_managed_identity and attach_acr) or
need_grant_vnet_permission_to_cluster_identity or
enable_azure_container_storage
enable_azure_container_storage or
enable_backup
):
return True
return False
Expand Down Expand Up @@ -5787,6 +5792,17 @@ def postprocessing_after_mc_created(self, cluster: ManagedCluster) -> None:
assignee_principal_type="User",
)

# Enable Azure Backup for the AKS cluster (delegates to dataprotection extension)
if self.context.raw_param.get("enable_backup", False):
self.context.external_functions.enable_aks_backup(
self.cmd,
self.context.get_resource_group_name(),
self.context.get_name(),
self.context.raw_param.get("backup_strategy"),
self.context.raw_param.get("backup_configuration_file"),
self.context.raw_param.get("yes", False),
)

def put_mc(self, mc: ManagedCluster) -> ManagedCluster:
etag, match_condition = _get_etag_match_condition(
self.context.get_if_match(), self.context.get_if_none_match()
Expand Down Expand Up @@ -8512,10 +8528,13 @@ def check_is_postprocessing_required(self, mc: ManagedCluster) -> bool:
monitoring_addon_postprocessing_required = self.context.get_intermediate(
"monitoring_addon_postprocessing_required", default_value=False
)
enable_backup = self.context.raw_param.get("enable_backup", False)
# Note: monitoring_addon_disable_postprocessing_required is no longer used - cleanup is done upfront
# pylint: disable=too-many-boolean-expressions
if (enable_azure_container_storage or disable_azure_container_storage) or \
(keyvault_id and enable_azure_keyvault_secrets_provider_addon) or \
(monitoring_addon_postprocessing_required):
(monitoring_addon_postprocessing_required) or \
enable_backup:
return True
return postprocessing_required

Expand Down Expand Up @@ -8748,6 +8767,17 @@ def postprocessing_after_mc_created(self, cluster: ManagedCluster) -> None:
else:
raise CLIError('Keyvault secrets provider addon must be enabled to attach keyvault.\n')

# Enable Azure Backup for the AKS cluster (delegates to dataprotection extension)
if self.context.raw_param.get("enable_backup", False):
self.context.external_functions.enable_aks_backup(
self.cmd,
self.context.get_resource_group_name(),
self.context.get_name(),
self.context.raw_param.get("backup_strategy"),
self.context.raw_param.get("backup_configuration_file"),
self.context.raw_param.get("yes", False),
)

def put_mc(self, mc: ManagedCluster) -> ManagedCluster:
etag, match_condition = _get_etag_match_condition(
self.context.get_if_match(), self.context.get_if_none_match()
Expand Down
Loading
Loading