Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
dfb6797
support ase get ops
kumarutkarsh3b2166 Apr 7, 2025
3a64da9
is sap check
kumarutkarsh3b2166 Apr 7, 2025
d2de35f
support ase get ops
kumarutkarsh3b2166 Apr 7, 2025
f284859
long line fix
kumarutkarsh3b2166 Apr 7, 2025
dd58d71
flake8 failures resolved
kumarutkarsh3b2166 Apr 7, 2025
6375e75
unit tests
kumarutkarsh3b2166 Apr 14, 2025
aace0e6
fix
kumarutkarsh3b2166 Apr 14, 2025
90eb7cf
support ase get ops
kumarutkarsh3b2166 Apr 7, 2025
a45c208
is sap check
kumarutkarsh3b2166 Apr 7, 2025
3a50f5a
support ase get ops
kumarutkarsh3b2166 Apr 7, 2025
9da3e2c
long line fix
kumarutkarsh3b2166 Apr 7, 2025
8c087df
flake8 failures resolved
kumarutkarsh3b2166 Apr 7, 2025
22d02e1
unit tests
kumarutkarsh3b2166 Apr 14, 2025
73e848e
fix
kumarutkarsh3b2166 Apr 14, 2025
8e9e68b
tests for backup restore added
kumarutkarsh3b2166 Apr 29, 2025
9d71a27
bkp res policy command tests added
kumarutkarsh3b2166 May 2, 2025
afb3740
resolve conflicts
kumarutkarsh3b2166 May 5, 2025
946fdc7
seperate tests for conf prot and stop prot
kumarutkarsh3b2166 May 6, 2025
efeec61
comments updated
kumarutkarsh3b2166 May 6, 2025
7347ae3
unregister test correction
kumarutkarsh3b2166 May 6, 2025
38f19ab
registration test added
kumarutkarsh3b2166 May 7, 2025
f28c761
resolve comments
kumarutkarsh3b2166 May 7, 2025
7a3f57e
refactor
kumarutkarsh3b2166 May 7, 2025
2a4559b
remove cert
kumarutkarsh3b2166 May 7, 2025
71f2f1a
flake8 fixes
kumarutkarsh3b2166 May 8, 2025
ee5cb51
remove yaml
kumarutkarsh3b2166 May 8, 2025
a517983
remove too many returns
kumarutkarsh3b2166 May 8, 2025
02a8639
flake8 fix
kumarutkarsh3b2166 May 8, 2025
8e9f91b
fix test failures
kumarutkarsh3b2166 May 9, 2025
1af2723
latest test runs yaml
kumarutkarsh3b2166 May 12, 2025
4e5c2bf
Merge branch 'dev' of https://github.com/Azure/azure-cli into users/k…
kumarutkarsh3b2166 May 12, 2025
312119f
Merge branch 'dev' of https://github.com/Azure/azure-cli into users/k…
kumarutkarsh3b2166 May 12, 2025
c8d0913
remove commented code
kumarutkarsh3b2166 May 13, 2025
b93d244
revert unnecessary changes
kumarutkarsh3b2166 May 13, 2025
8bb6d1d
failed tests fix
kumarutkarsh3b2166 May 14, 2025
941c69c
Most SQL tests pass now
May 16, 2025
0a835e7
CRR test
May 16, 2025
38e854b
All SQL tests operational
May 16, 2025
791356e
SQL record only due to size and time
May 16, 2025
bc60b16
Skipping monitor tests that use VMPreparers from backup module.
May 19, 2025
32702e5
Fix monitor recordings
May 19, 2025
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
6 changes: 3 additions & 3 deletions src/azure-cli/azure/cli/command_modules/backup/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@
# ARGUMENT DEFINITIONS

allowed_container_types = ['AzureIaasVM']
allowed_workload_types = ['VM', 'AzureFileShare', 'SAPHANA', 'MSSQL', 'SAPHanaDatabase', 'SQLDataBase']
allowed_azure_workload_types = ['MSSQL', 'SAPHANA', 'SAPASE', 'SAPHanaDatabase', 'SQLDataBase']
allowed_workload_types = ['VM', 'AzureFileShare', 'SAPHANA', 'SAPASE', 'MSSQL', 'SAPHanaDatabase', 'SQLDataBase', 'SAPAseDatabase']
allowed_azure_workload_types = ['MSSQL', 'SAPHANA', 'SAPASE', 'SAPAseDatabase', 'SAPHanaDatabase', 'SQLDataBase']
allowed_backup_management_types = ['AzureIaasVM', 'AzureStorage', 'AzureWorkload']
allowed_extended_backup_management_types = allowed_backup_management_types + ['MAB']
allowed_protectable_item_type = ['SQLAG', 'SQLInstance', 'SQLDatabase', 'HANAInstance', 'SAPHanaDatabase', 'SAPHanaSystem']
allowed_protectable_item_type = ['SQLAG', 'SQLInstance', 'SQLDatabase', 'HANAInstance', 'SAPAseDatabase', 'SAPHanaDatabase', 'SAPHanaSystem']
allowed_target_tier_type_chk_archivable = ['VaultArchive']
allowed_tier_type = ['VaultStandard', 'Snapshot', 'VaultArchive', 'VaultStandardRehydrated', 'SnapshotAndVaultStandard', 'SnapshotAndVaultArchive']
allowed_rehyd_priority_type = ['Standard', 'High']
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,10 @@ def validate_wl_restore(item, item_type, restore_mode, recovery_mode):
# operation. Correct value should be - {}.
# """.format(item.properties.workload_type))

if item_type is None or item_type.lower() not in ['sql', 'saphana']:
if item_type is None or item_type.lower() not in ['sql', 'saphana', 'sapase']:
raise InvalidArgumentValueError("""
The item_type specified in recovery config file is incorrect. Please correct it and retry the
operation. Allowed values are: 'SQL', 'SAPHana'.
operation. Allowed values are: 'SQL', 'SAPHana', 'SAPAse'.
""")

if item_type.lower() not in item.properties.workload_type.lower():
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@
'SAPHANA': 'SAPHanaDatabase',
'SQLDataBase': 'SQLDataBase',
'SAPHanaDatabase': 'SAPHanaDatabase',
'SAPAseDatabase': 'SAPAseDatabase',
'VM': 'VM',
'AzureFileShare': 'AzureFileShare'}

workload_bmt_map = {'SQLDataBase': 'AzureWorkload',
'SAPHanaDatabase': 'AzureWorkload',
'SAPAseDatabase': 'AzureWorkload',
'VM': 'AzureIaasVM',
'AzureFileShare': 'AzureStorage'}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,10 @@ def is_hana(resource_type):
return resource_type.lower() == 'saphanadatabase'


def is_sapase(resource_type):
return resource_type.lower() == 'sapasedatabase'


def is_wl_container(name):
return 'vmappcontainer' in name.lower()

Expand Down
57 changes: 37 additions & 20 deletions src/azure-cli/azure/cli/command_modules/backup/custom_wl.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@
AzureWorkloadBackupRequest, ProtectedItemResource, AzureRecoveryServiceVaultProtectionIntent, TargetRestoreInfo, \
RestoreRequestResource, BackupRequestResource, ProtectionIntentResource, SQLDataDirectoryMapping, \
ProtectionContainerResource, AzureWorkloadSAPHanaRestoreRequest, AzureWorkloadSQLRestoreRequest, \
AzureWorkloadSAPHanaPointInTimeRestoreRequest, AzureWorkloadSQLPointInTimeRestoreRequest, \
AzureVmWorkloadSAPHanaDatabaseProtectedItem, AzureVmWorkloadSQLDatabaseProtectedItem, MoveRPAcrossTiersRequest, \
AzureWorkloadSAPAseRestoreRequest, AzureWorkloadSAPHanaPointInTimeRestoreRequest, \
AzureWorkloadSQLPointInTimeRestoreRequest, AzureWorkloadSAPAsePointInTimeRestoreRequest, \
AzureVmWorkloadSAPHanaDatabaseProtectedItem, AzureVmWorkloadSQLDatabaseProtectedItem, \
RecoveryPointRehydrationInfo, AzureWorkloadSAPHanaRestoreWithRehydrateRequest, \
AzureWorkloadSQLRestoreWithRehydrateRequest, ProtectionState
AzureWorkloadSQLRestoreWithRehydrateRequest, ProtectionState, AzureVmWorkloadSAPAseDatabaseProtectedItem, \
MoveRPAcrossTiersRequest \

from azure.mgmt.recoveryservicesbackup.passivestamp.models import CrossRegionRestoreRequest

Expand Down Expand Up @@ -49,7 +51,8 @@
'SAPHANA': 'SAPHanaDatabase',
'SQLDataBase': 'SQLDataBase',
'SAPHanaDatabase': 'SAPHanaDatabase',
'SAPASE': 'SAPAseDatabase'}
'SAPASE': 'SAPAseDatabase',
'SAPAseDatabase': 'SAPAseDatabase'}

# Mapping of module name
module_map = {'sqldatabase': 'sql_database',
Expand All @@ -67,7 +70,9 @@
'HANAInstance': 'SAPHanaSystem',
'SAPHanaSystem': 'SAPHanaSystem',
'SQLInstance': 'SQLInstance',
'SQLAG': 'SQLAvailabilityGroupContainer'}
'SQLAG': 'SQLAvailabilityGroupContainer',
'SAPASE': 'SAPAseDatabase',
'SAPAseDatabase': 'SAPAseDatabase'}


def show_wl_policy(client, resource_group_name, vault_name, name):
Expand Down Expand Up @@ -203,8 +208,10 @@ def update_policy_for_item(cmd, client, resource_group_name, vault_name, item, p
item_uri = cust_help.get_protected_item_uri_from_id(item.id)

backup_item_type = item_uri.split(';')[0]
if not cust_help.is_sql(backup_item_type) and not cust_help.is_hana(backup_item_type):
raise InvalidArgumentValueError("Item must be either of type SQLDataBase or SAPHanaDatabase.")
if (not cust_help.is_sql(backup_item_type) and not
cust_help.is_hana(backup_item_type) and not
cust_help.is_sapase(backup_item_type)):
raise InvalidArgumentValueError("Item must be of type SQLDataBase, SAPHanaDatabase, or SAPAseDatabase")

item_properties = _get_protected_item_instance(backup_item_type)
item_properties.policy_id = policy.id
Expand Down Expand Up @@ -434,10 +441,12 @@ def enable_protection_for_azure_wl(cmd, client, resource_group_name, vault_name,
# Get protectable item.
protectable_item_object = protectable_item
protectable_item_type = protectable_item_object.properties.protectable_item_type
if protectable_item_type.lower() not in ["sqldatabase", "sqlinstance", "saphanadatabase", "saphanasystem"]:
if protectable_item_type.lower() not in ["sqldatabase", "sqlinstance", "saphanadatabase", "saphanasystem",
"sapasedatabase"]:
raise CLIError(
"""
Protectable Item must be either of type SQLDataBase, HANADatabase, HANAInstance or SQLInstance.
Protectable Item must be either of type SQLDataBase, HANADatabase, HANAInstance, SAPAseDatabase or
SQLInstance.
""")

item_name = protectable_item_object.name
Expand Down Expand Up @@ -794,7 +803,7 @@ def show_recovery_config(cmd, client, resource_group_name, vault_name, restore_m
item_type = item.properties.workload_type
item_name = item.name

if not cust_help.is_sql(item_type) and not cust_help.is_hana(item_type):
if not cust_help.is_sql(item_type) and not cust_help.is_hana(item_type) and not cust_help.is_sapase(item_type):
raise CLIError(
"""
Item must be either of type SQLDataBase or SAPHanaDatabase.
Expand Down Expand Up @@ -860,7 +869,7 @@ def show_recovery_config(cmd, client, resource_group_name, vault_name, restore_m
'item_uri': item_name,
'recovery_point_id': recovery_point.name,
'log_point_in_time': log_point_in_time,
'item_type': 'SQL' if 'sql' in item_type.lower() else 'SAPHana',
'item_type': 'SQL' if 'sql' in item_type.lower() else 'SAPASE' if 'sapase' in item_type.lower() else 'SAPHana',
'workload_type': item_type,
'source_resource_id': item.properties.source_resource_id,
'database_name': db_name,
Expand Down Expand Up @@ -931,16 +940,22 @@ def _get_log_time_range(cmd, resource_group_name, vault_name, item, use_secondar


def _get_restore_request_instance(item_type, log_point_in_time, rehydration_priority):
if rehydration_priority is None:
if item_type.lower() == "saphana":
if log_point_in_time is not None:
return AzureWorkloadSAPHanaPointInTimeRestoreRequest()
return AzureWorkloadSAPHanaRestoreRequest()
workload_restore_request_map = {
"saphana": AzureWorkloadSAPHanaRestoreRequest,
"sql": AzureWorkloadSQLRestoreRequest,
"sapase": AzureWorkloadSAPAseRestoreRequest
}

workload_pit_restore_request_map = {
"saphana": AzureWorkloadSAPHanaPointInTimeRestoreRequest,
"sql": AzureWorkloadSQLPointInTimeRestoreRequest,
"sapase": AzureWorkloadSAPAsePointInTimeRestoreRequest
}

if item_type.lower() == "sql":
if log_point_in_time is not None:
return AzureWorkloadSQLPointInTimeRestoreRequest()
return AzureWorkloadSQLRestoreRequest()
if rehydration_priority is None:
if log_point_in_time is not None:
return workload_pit_restore_request_map[item_type.lower()]()
return workload_restore_request_map[item_type.lower()]()

if item_type.lower() == "saphana":
if log_point_in_time is not None:
Expand All @@ -956,6 +971,8 @@ def _get_restore_request_instance(item_type, log_point_in_time, rehydration_prio
def _get_protected_item_instance(item_type):
if item_type.lower() == "saphanadatabase":
return AzureVmWorkloadSAPHanaDatabaseProtectedItem()
if item_type.lower() == "sapasedatabase":
return AzureVmWorkloadSAPAseDatabaseProtectedItem()
return AzureVmWorkloadSQLDatabaseProtectedItem()


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,38 @@
logger = get_logger(__name__)


# Temporary Resource Group Preparer for testing while we update the RecoveryServices SDK to deal with new Soft Delete rules
class RGPreparer(AbstractPreparer, SingleValueReplacer):
def __init__(self, name_prefix='clitest.rg',
parameter_name='resource_group',
parameter_name_for_location='resource_group_location', location='westus',
dev_setting_name='AZURE_CLI_TEST_DEV_RESOURCE_GROUP_NAME',
dev_setting_location='AZURE_CLI_TEST_DEV_RESOURCE_GROUP_LOCATION',
random_name_length=75, key='rg', subscription=None, additional_tags=None):
if ' ' in name_prefix:
raise CliTestError('Error: Space character in resource group name prefix \'%s\'' % name_prefix)
super().__init__(name_prefix, random_name_length)
from azure.cli.core.mock import DummyCli
self.cli_ctx = DummyCli()
self.location = location
self.subscription = subscription
self.parameter_name = parameter_name
self.parameter_name_for_location = parameter_name_for_location
self.key = key
self.additional_tags = additional_tags

self.dev_setting_name = os.environ.get(dev_setting_name, None)
self.dev_setting_location = os.environ.get(dev_setting_location, location)

def create_resource(self, name, **kwargs):
cmd = 'az group create --location {} --name {}'.format(self.location, name)
execute(self.cli_ctx, cmd)
return {self.parameter_name: name, self.parameter_name_for_location: self.location}

def remove_resource(self, name, **kwargs):
pass


class VaultPreparer(AbstractPreparer, SingleValueReplacer): # pylint: disable=too-many-instance-attributes
def __init__(self, name_prefix='clitest-vault', parameter_name='vault_name',
resource_group_location_parameter_name='resource_group_location',
Expand Down Expand Up @@ -87,14 +119,13 @@ def _cleanup(self, vault_name, resource_group):
try:
execute(self.cli_ctx, 'az backup vault delete -n {} -g {} --yes'.format(vault_name, resource_group))
except HttpResponseError as ex:
if "Operation returned an invalid status 'Bad Request'" not in str(ex):
raise ex
logger.warning('Unable to delete the vault. Please delete it manually.')


class VMPreparer(AbstractPreparer, SingleValueReplacer):
def __init__(self, name_prefix='clitest-vm', parameter_name='vm_name',
resource_group_location_parameter_name='resource_group_location',
resource_group_parameter_name='resource_group', dev_setting_name='AZURE_CLI_TEST_DEV_BACKUP_VM_NAME', image = "Win2012R2Datacenter"):
resource_group_parameter_name='resource_group', dev_setting_name='AZURE_CLI_TEST_DEV_BACKUP_VM_NAME', image = "Win2022Datacenter"):
super().__init__(name_prefix, 15)
from azure.cli.core.mock import DummyCli
self.cli_ctx = DummyCli()
Expand All @@ -111,18 +142,23 @@ def create_resource(self, name, **kwargs):
self.resource_group = self._get_resource_group(**kwargs)
self.location = self._get_resource_group_location(**kwargs)
param_format = '-n {} -g {} --image {} --admin-username {} --admin-password {} '
param_format += '--tags {} --nsg-rule None --security-type {}'
param_format += '--tags {} --nsg-rule None'
# param_format += '--tags {} --size {} --nsg-rule None'
param_tags = 'MabUsed=Yes Owner=sisi Purpose=CLITest DeleteBy=12-2099 AutoShutdown=No'
param_string = param_format.format(name, self.resource_group, self.image, name,
'%j^VYw9Q3Z@Cu$*h', param_tags, "Standard") #, 'Standard_D2a_v4')
'%j^VYw9Q3Z@Cu$*h', param_tags) #, 'Standard_D2a_v4')
cmd = 'az vm create {}'.format(param_string)
execute(self.cli_ctx, cmd)
return {self.parameter_name: name}
return {self.parameter_name: self.dev_setting_value}

def remove_resource(self, name, **kwargs):
# Resource group deletion will take care of this.
cmd = 'az vm delete -g {} -n {} --yes'.format(self.resource_group, name)
try:
execute(self.cli_ctx, cmd)
except:
logger.warning("Unable to delete the Virtual Machine. Please delete it manually.")
pass

def _get_resource_group(self, **kwargs):
Expand Down Expand Up @@ -644,7 +680,7 @@ def _delete_lock(self, lock):
command_string = 'az lock delete --ids {}'.format(lock_id)
execute(self.cli_ctx, command_string)
except Exception:
raise CliTestError('Unable to delete the lock with ID {}, please delete it manually'.format(lock_id))
logger.warning('Unable to delete the lock with ID {}, please delete it manually'.format(lock_id))

def _cleanup(self, resource_group, storage_account, vault, afs):
# Need to remove any resource locks on the Storage Account, and also manually delete the item
Expand Down
Loading