Skip to content

Commit c3e6bbc

Browse files
committed
[Release] Add support for AKS backup configuration modification
1 parent 4f9675f commit c3e6bbc

File tree

6 files changed

+101
-6
lines changed

6 files changed

+101
-6
lines changed

src/dataprotection/HISTORY.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
33
Release History
44
===============
5+
1.7.2
6+
+++++
7+
* `az dataprotection backup-instance update`: New parameters: `--backup-configuration` to update AKS datasource parameters.
8+
* Fix in `helpers.py` to correctly prepare/normalize AKS backup-configuration payloads passed via the CLI.
59

610
1.7.1
711
+++++

src/dataprotection/azext_dataprotection/manual/_params.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,9 @@ def load_arguments(self, _):
134134
c.argument('vaulted_blob_container_list', type=validate_file_or_dict, options_list=['--vaulted-blob-container-list', '--container-blob-list'],
135135
help="Enter the container list to modify a vaulted blob backup. The output for "
136136
"'az dataprotection backup-instance initialize-backupconfig' needs to be provided as input")
137+
c.argument('backup_configuration', type=validate_file_or_dict,
138+
help="Enter the Backup configuration to modify AKS backup datasource parameters. "
139+
"The output for 'az dataprotection backup-instance initialize-backupconfig' needs to be provided as input.")
137140
c.argument('use_system_assigned_identity', options_list=['--system-assigned', '--use-system-identity', '--use-system-assigned-identity'], arg_type=get_three_state_flag(), help="Use system assigned identity")
138141
c.argument('user_assigned_identity_arm_url', options_list=['--user-assigned', '--user-assigned-identity-arm-url', '--uami'], type=str, help="ARM ID of the User Assigned Managed Identity")
139142

src/dataprotection/azext_dataprotection/manual/custom.py

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ def dataprotection_backup_instance_validate_for_update(cmd, resource_group_name,
246246

247247

248248
def dataprotection_backup_instance_update(cmd, resource_group_name, vault_name, backup_instance_name,
249-
vaulted_blob_container_list=None, no_wait=False,
249+
vaulted_blob_container_list=None, backup_configuration=None, no_wait=False,
250250
use_system_assigned_identity=None, user_assigned_identity_arm_url=None):
251251
from azext_dataprotection.aaz.latest.dataprotection.backup_instance import Show as BackupInstanceShow
252252
backup_instance = BackupInstanceShow(cli_ctx=cmd.cli_ctx)(command_args={
@@ -266,10 +266,33 @@ def dataprotection_backup_instance_update(cmd, resource_group_name, vault_name,
266266
identity_details = helper.get_identity_details(use_system_assigned_identity, user_assigned_identity_arm_url)
267267
backup_instance["properties"]["identityDetails"] = identity_details
268268

269-
# Policy changes - updating the vaulted blob container list for vaulted blob backups
270-
if vaulted_blob_container_list is not None:
271-
backup_instance['properties']['policyInfo']['policyParameters']['backupDatasourceParametersList'] = \
272-
[vaulted_blob_container_list,]
269+
# Policy changes
270+
# - Updating the vaulted blob container list for vaulted blob backups
271+
# - Updating the backup datasource parameters for AKS backups
272+
datasource_type = backup_instance["properties"]["dataSourceInfo"]["datasourceType"]
273+
274+
# If user provided any of the datasource parameter update inputs, handle according to datasource type
275+
if vaulted_blob_container_list is not None or backup_configuration is not None:
276+
if datasource_type == "Microsoft.ContainerService/managedClusters":
277+
if vaulted_blob_container_list is not None:
278+
raise InvalidArgumentValueError('Invalid argument --vaulted-blob-container-list for given datasource type.')
279+
elif backup_configuration is not None:
280+
# Allow passing JSON string or already-parsed object
281+
if isinstance(backup_configuration, str):
282+
import json
283+
try:
284+
backup_configuration = json.loads(backup_configuration)
285+
except Exception:
286+
raise InvalidArgumentValueError("Provided --backup-configuration is not valid JSON")
287+
backup_instance['properties']['policyInfo']['policyParameters']['backupDatasourceParametersList'] = [backup_configuration]
288+
elif datasource_type == "Microsoft.Storage/storageAccounts/blobServices":
289+
if backup_configuration is not None:
290+
raise InvalidArgumentValueError('Invalid argument --backup-configuration for given datasource type.')
291+
elif vaulted_blob_container_list is not None:
292+
backup_instance['properties']['policyInfo']['policyParameters']['backupDatasourceParametersList'] = [vaulted_blob_container_list,]
293+
else:
294+
raise InvalidArgumentValueError('Setting backup datasource parameters is not supported for given DataSourceType')
295+
273296

274297
backup_instance = helper.convert_backup_instance_show_to_input(backup_instance)
275298

src/dataprotection/azext_dataprotection/manual/helpers.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -997,6 +997,16 @@ def convert_backup_instance_show_to_input(backup_instance):
997997
del backup_instance['properties']['protectionStatus']
998998
if 'provisioningState' in backup_instance['properties']:
999999
del backup_instance['properties']['provisioningState']
1000+
# Cleaning up resourceProperties if objectType is null to avoid schema validation error
1001+
for datasource_property in ['dataSourceInfo', 'dataSourceSetInfo']:
1002+
if datasource_property in backup_instance['properties']:
1003+
datasource_info = backup_instance['properties'][datasource_property]
1004+
if (isinstance(datasource_info, dict) and
1005+
'resourceProperties' in datasource_info and
1006+
isinstance(datasource_info['resourceProperties'], dict)):
1007+
if datasource_info['resourceProperties'].get('objectType') is None:
1008+
# Set resourceProperties to None when objectType is null to avoid schema validation error
1009+
del backup_instance['properties'][datasource_property]['resourceProperties']
10001010
return backup_instance
10011011

10021012

src/dataprotection/azext_dataprotection/tests/latest/test_dataprotection_backup_instance_operations.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from azure.cli.testsdk import ScenarioTest, live_only
1111
from azure.cli.testsdk.scenario_tests import AllowLargeResponse
1212
import time
13+
import copy
1314

1415

1516
def reset_softdelete_base_state(test):
@@ -279,3 +280,57 @@ def test_dataprotection_backup_instance_softdelete(test):
279280
# Once protection elsewhere is stopped, we can resume protection on the undeleted BI
280281
time.sleep(60)
281282
reset_softdelete_base_state(test)
283+
284+
@AllowLargeResponse()
285+
def test_dataprotection_backup_instance_update_aks_configuration(test):
286+
# Update with AKS backup configuration using simple az CLI commands.
287+
test.kwargs.update({
288+
'location': 'eastus2euap',
289+
'rg': 'clitest-dpp-rg',
290+
'vaultName': 'clitest-bkp-vault-aks-donotdelete',
291+
'policyId': '/subscriptions/38304e13-357e-405e-9e9a-220351dcce8c/resourceGroups/clitest-dpp-rg/providers/Microsoft.DataProtection/backupVaults/clitest-bkp-vault-aks-donotdelete/backupPolicies/akspolicy',
292+
'dataSourceType': 'AzureKubernetesService',
293+
'aksClusterName': 'clitest-cluster1-donotdelete',
294+
'aksClusterId': '/subscriptions/38304e13-357e-405e-9e9a-220351dcce8c/resourceGroups/oss-clitest-rg/providers/Microsoft.ContainerService/managedClusters/clitest-cluster1-donotdelete',
295+
'friendlyName': 'clitest-friendly-aks',
296+
'backupInstanceName': 'clitestsabidonotdelete-clitestsabidonotdelete-887c3538-0bfc-11ee-acd3-002b670b472e'
297+
})
298+
299+
# Fetch original BI backupDatasourceParametersList (if any) to allow resetting later
300+
original_bi = test.cmd('az dataprotection backup-instance show -g "{rg}" --vault-name "{vaultName}" --name "{backupInstanceName}"').get_output_in_json()
301+
original_bi_backup_config_json = original_bi['properties']['policyInfo']['policyParameters'].get('backupDatasourceParametersList')[0]
302+
test.kwargs.update({
303+
'backupConfig': original_bi_backup_config_json
304+
})
305+
306+
# Generate the AKS backup configuration using the dedicated CLI helper
307+
new_backup_config_json = test.cmd('az dataprotection backup-instance initialize-backupconfig --datasource-type AzureKubernetesService').get_output_in_json()
308+
309+
# mutate a visible field to make the change observable
310+
new_backup_config_json['included_namespaces'] = ["nsA", "nsB"]
311+
new_backup_config_json['label_selectors'] = ["app=web"]
312+
new_backup_config_json['excluded_resource_types'] = ["ResourceX"]
313+
new_backup_config_json['include_cluster_scope_resources'] = False
314+
new_backup_config_json['snapshot_volumes'] = False
315+
test.kwargs.update({
316+
'tempBackupConfig': new_backup_config_json
317+
})
318+
319+
# Apply temp configuration
320+
test.cmd('az dataprotection backup-instance update -g "{rg}" --vault-name "{vaultName}" --backup-instance-name "{backupInstanceName}" --backup-configuration "{tempBackupConfig}"', checks=[
321+
test.check('name', "{backupInstanceName}")
322+
])
323+
324+
# Fetch the BI and verify that the backupDatasourceParametersList was updated to reflect the AKS config
325+
test.cmd('az dataprotection backup-instance show -g "{rg}" --vault-name "{vaultName}" --name "{backupInstanceName}"', checks=[
326+
test.check("properties.policyInfo.policyParameters.backupDatasourceParametersList[0].included_namespaces", ['nsA', 'nsB']),
327+
test.check("properties.policyInfo.policyParameters.backupDatasourceParametersList[0].label_selectors", ['app=web']),
328+
test.check("properties.policyInfo.policyParameters.backupDatasourceParametersList[0].excluded_resource_types", ['ResourceX']),
329+
test.check("properties.policyInfo.policyParameters.backupDatasourceParametersList[0].include_cluster_scope_resources", False),
330+
test.check("properties.policyInfo.policyParameters.backupDatasourceParametersList[0].snapshot_volumes", False)
331+
])
332+
333+
# Reset to original configuration
334+
test.cmd('az dataprotection backup-instance update -g "{rg}" --vault-name "{vaultName}" --backup-instance-name "{backupInstanceName}" --backup-configuration "{backupConfig}"', checks=[
335+
test.check('name', "{backupInstanceName}")
336+
])

src/dataprotection/setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from setuptools import setup, find_packages
1111

1212
# HISTORY.rst entry.
13-
VERSION = '1.7.1'
13+
VERSION = '1.7.2'
1414

1515
# The full list of classifiers is available at
1616
# https://pypi.python.org/pypi?%3Aaction=list_classifiers

0 commit comments

Comments
 (0)