def dataprotection_backup_policy_retention_set_in_policy( policy, name, lifecycles): retention_policy_index = -1 for index in range(0, len(policy["policyRules"])): if policy["policyRules"][index][ "objectType"] == "AzureRetentionRule" and policy[ "policyRules"][index]["name"] == name: retention_policy_index = index break if retention_policy_index == -1: datasource_type = helper.get_client_datasource_type( policy["datasourceTypes"][0]) manifest = helper.load_manifest(datasource_type) if manifest["policySettings"]["disableAddRetentionRule"]: raise CLIError("Adding New Retention Rule is not supported for " + datasource_type + " datasource type") if name not in manifest["policySettings"]["supportedRetentionTags"]: raise CLIError("Selected Retention Rule " + name + " is not applicable for Datasource Type " + datasource_type) new_retention_rule = { "objectType": "AzureRetentionRule", "isDefault": name == "Default", "name": name, "lifecycles": lifecycles } policy["policyRules"].append(new_retention_rule) return policy policy["policyRules"][retention_policy_index]["lifecycles"] = lifecycles return policy
def dataprotection_backup_policy_get_default_policy_template(datasource_type): manifest = helper.load_manifest(datasource_type) if manifest is not None and manifest[ "policySettings"] is not None and manifest["policySettings"][ "defaultPolicy"] is not None: return manifest["policySettings"]["defaultPolicy"] raise CLIError("Unable to get default policy template.")
def get_backup_job_query(datasource_type, resource_groups, vaults, start_time, end_time, status, operation, datasource_id): query = "RecoveryServicesResources | where type =~ 'microsoft.dataprotection/backupvaults/backupjobs'" query += "| extend vaultName = properties.vaultName" query += "| extend status = properties.status" query += "| extend operation = case( tolower(properties.operationCategory) startswith 'backup' and properties.isUserTriggered == 'true', strcat('OnDemand',properties.operationCategory)" query += ", tolower(properties.operationCategory) startswith 'backup' and properties.isUserTriggered == 'false', strcat('Scheduled', properties.operationCategory)" query += ", type =~ 'microsoft.dataprotection/backupVaults/backupJobs', properties.operationCategory, 'Invalid')" query += "| extend datasourceId = properties.dataSourceId" manifest = helper.load_manifest(datasource_type) query = add_filter_to_query(query, "properties.dataSourceType", manifest["datasourceType"]) query = add_filter_to_query(query, "resourceGroup", resource_groups) query = add_filter_to_query(query, "vaultName", vaults) query = add_filter_to_query(query, "operation", operation) query = add_filter_to_query(query, "status", status) query = add_filter_to_query(query, "datasourceId", datasource_id) if start_time is not None: query += "| where properties.startTime > datetime(" + start_time + "Z)" if end_time is not None: query += "| where properties.endTime > datetime(" + end_time + "Z)" return query
def restore_initialize_for_data_recovery(target_resource_id, datasource_type, source_datastore, restore_location, recovery_point_id=None, point_in_time=None): restore_request = {} restore_mode = None if recovery_point_id is not None and point_in_time is not None: raise CLIError( "Please provide either recovery point id or point in time parameter, not both." ) if recovery_point_id is not None: restore_request[ "object_type"] = "AzureBackupRecoveryPointBasedRestoreRequest" restore_request["recovery_point_id"] = recovery_point_id restore_mode = "RecoveryPointBased" if point_in_time is not None: restore_request[ "object_type"] = "AzureBackupRecoveryTimeBasedRestoreRequest" restore_request["recovery_point_time"] = point_in_time restore_mode = "PointInTimeBased" if recovery_point_id is None and point_in_time is None: raise CLIError( "Please provide either recovery point id or point in time parameter." ) manifest = helper.load_manifest(datasource_type) if manifest is not None and manifest[ "allowedRestoreModes"] is not None and restore_mode not in manifest[ "allowedRestoreModes"]: raise CLIError(restore_mode + " restore mode is not supported for datasource type " + datasource_type + ". Supported restore modes are " + ','.join(manifest["allowedRestoreModes"])) restore_request["source_data_store_type"] = source_datastore restore_request["restore_target_info"] = {} restore_request["restore_target_info"]["object_type"] = "RestoreTargetInfo" restore_request["restore_target_info"][ "restore_location"] = restore_location restore_request["restore_target_info"]["recovery_option"] = "FailIfExists" restore_request["restore_target_info"][ "datasource_info"] = helper.get_datasource_info( datasource_type, target_resource_id, restore_location) if manifest["isProxyResource"]: restore_request["restore_target_info"][ "datasource_set_info"] = helper.get_datasourceset_info( datasource_type, target_resource_id, restore_location) return restore_request
def dataprotection_backup_policy_tag_set_in_policy(name, policy, criteria): datasource_type = helper.get_client_datasource_type( policy["datasourceTypes"][0]) manifest = helper.load_manifest(datasource_type) if name not in manifest["policySettings"]["supportedRetentionTags"]: raise CLIError("Selected Retention Tag " + name + " is not applicable for Datasource Type " + datasource_type) if manifest["policySettings"]["disableCustomRetentionTag"]: for criterion in criteria: if "absoluteCriteria" not in criterion: raise CLIError( "Only Absolute Criteria is supported for this policy") backup_rule_index = -1 for index in range(0, len(policy["policyRules"])): if policy["policyRules"][index]["objectType"] == "AzureBackupRule": backup_rule_index = index break if backup_rule_index != -1: tagindex = -1 for index in range( 0, len(policy["policyRules"][backup_rule_index]["trigger"] ["taggingCriteria"])): if policy["policyRules"][backup_rule_index]["trigger"][ "taggingCriteria"][index]["tagInfo"]["tagName"] == name: tagindex = index break if tagindex != -1: policy["policyRules"][backup_rule_index]["trigger"][ "taggingCriteria"][tagindex]["Criteria"] = criteria return policy tagcriteria = { "criteria": criteria, "isDefault": False, "taggingPriority": helper.get_tagging_priority(name), "tagInfo": { "tagName": name } } policy["policyRules"][backup_rule_index]["trigger"][ "taggingCriteria"].append(tagcriteria) return policy return policy
def dataprotection_backup_instance_initialize(datasource_type, datasource_id, datasource_location, policy_id): datasource_info = helper.get_datasource_info(datasource_type, datasource_id, datasource_location) datasourceset_info = None manifest = helper.load_manifest(datasource_type) if manifest["isProxyResource"]: datasourceset_info = helper.get_datasourceset_info( datasource_type, datasource_id, datasource_location) policy_parameters = None # Azure Disk specific code for adding datastoreparameter list in the json if datasource_type == "AzureDisk": policy_parameters = { "data_store_parameters_list": [{ "object_type": "AzureOperationalStoreParameters", "data_store_type": "OperationalStore", "resource_group_id": "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}" }] } policy_info = { "policy_id": policy_id, "policy_parameters": policy_parameters } guid = uuid.uuid1() backup_instance_name = "" if manifest["isProxyResource"]: backup_instance_name = datasourceset_info[ "resource_name"] + "-" + datasource_info[ "resource_name"] + "-" + str(guid) else: backup_instance_name = datasource_info[ "resource_name"] + "-" + datasource_info[ "resource_name"] + "-" + str(guid) return { "backup_instance_name": backup_instance_name, "properties": { "data_source_info": datasource_info, "data_source_set_info": datasourceset_info, "policy_info": policy_info, "object_type": "BackupInstance" } }
def get_backup_instance_query(datasource_type, resource_groups, vaults, protection_status, datasource_id): query = "RecoveryServicesResources | where type =~ 'microsoft.dataprotection/backupvaults/backupinstances'" query += "| extend vaultName = split(split(id, '/Microsoft.DataProtection/backupVaults/')[1],'/')[0]" query += "| extend protectionState = properties.currentProtectionState" query += "| extend datasourceId = properties.dataSourceInfo.resourceID" manifest = helper.load_manifest(datasource_type) query = add_filter_to_query(query, "properties.dataSourceInfo.datasourceType", manifest["datasourceType"]) query = add_filter_to_query(query, "resourceGroup", resource_groups) query = add_filter_to_query(query, "vaultName", vaults) query = add_filter_to_query(query, "protectionState", protection_status) query = add_filter_to_query(query, "datasourceId", datasource_id) return query
def dataprotection_backup_instance_initialize(datasource_type, datasource_id, datasource_location, policy_id, secret_store_type=None, secret_store_uri=None): datasource_info = helper.get_datasource_info(datasource_type, datasource_id, datasource_location) datasourceset_info = None manifest = helper.load_manifest(datasource_type) if manifest["isProxyResource"]: datasourceset_info = helper.get_datasourceset_info( datasource_type, datasource_id, datasource_location) policy_parameters = None # Azure Disk specific code for adding datastoreparameter list in the json if datasource_type == "AzureDisk": policy_parameters = { "data_store_parameters_list": [{ "object_type": "AzureOperationalStoreParameters", "data_store_type": "OperationalStore", "resource_group_id": "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}" }] } datasource_auth_credentials_info = None if manifest["supportSecretStoreAuthentication"]: if secret_store_uri and secret_store_type: datasource_auth_credentials_info = { "secret_store_resource": { "uri": secret_store_uri, "value": None, "secret_store_type": secret_store_type }, "object_type": "SecretStoreBasedAuthCredentials" } elif secret_store_uri or secret_store_type: raise CLIError( "Either secret store uri or secret store type not provided.") policy_info = { "policy_id": policy_id, "policy_parameters": policy_parameters } guid = uuid.uuid1() backup_instance_name = "" if manifest["isProxyResource"]: backup_instance_name = datasourceset_info[ "resource_name"] + "-" + datasource_info[ "resource_name"] + "-" + str(guid) else: backup_instance_name = datasource_info[ "resource_name"] + "-" + datasource_info[ "resource_name"] + "-" + str(guid) return { "backup_instance_name": backup_instance_name, "properties": { "data_source_info": datasource_info, "data_source_set_info": datasourceset_info, "policy_info": policy_info, "datasource_auth_credentials": datasource_auth_credentials_info, "object_type": "BackupInstance" } }
def restore_initialize_for_item_recovery(client, datasource_type, source_datastore, restore_location, backup_instance_id, recovery_point_id=None, point_in_time=None, container_list=None, from_prefix_pattern=None, to_prefix_pattern=None): restore_request = {} restore_mode = None if recovery_point_id is not None and point_in_time is not None: raise CLIError( "Please provide either recovery point id or point in time parameter, not both." ) if recovery_point_id is not None: restore_request[ "object_type"] = "AzureBackupRecoveryPointBasedRestoreRequest" restore_request["recovery_point_id"] = recovery_point_id restore_mode = "RecoveryPointBased" if point_in_time is not None: restore_request[ "object_type"] = "AzureBackupRecoveryTimeBasedRestoreRequest" restore_request["recovery_point_time"] = point_in_time restore_mode = "PointInTimeBased" if recovery_point_id is None and point_in_time is None: raise CLIError( "Please provide either recovery point id or point in time parameter." ) manifest = helper.load_manifest(datasource_type) if manifest is not None and manifest[ "allowedRestoreModes"] is not None and restore_mode not in manifest[ "allowedRestoreModes"]: raise CLIError(restore_mode + " restore mode is not supported for datasource type " + datasource_type + ". Supported restore modes are " + ','.join(manifest["allowedRestoreModes"])) if manifest is not None and not manifest["itemLevelRecoveyEnabled"]: raise CLIError("Specified DatasourceType " + datasource_type + " doesn't support Item Level Recovery") restore_request["source_data_store_type"] = source_datastore restore_request["restore_target_info"] = {} restore_request["restore_target_info"][ "object_type"] = "ItemLevelRestoreTargetInfo" restore_request["restore_target_info"][ "restore_location"] = restore_location restore_request["restore_target_info"]["recovery_option"] = "FailIfExists" restore_criteria_list = [] if container_list is not None and (from_prefix_pattern is not None or to_prefix_pattern is not None): raise CLIError( "Please specify either container list or prefix pattern.") if container_list is not None: if len(container_list) > 10: raise CLIError( "A maximum of 10 containers can be restored. Please choose up to 10 containers." ) for container in container_list: if container[0] == '$': raise CLIError( "container name can not start with '$'. Please retry with different sets of containers." ) restore_criteria = {} restore_criteria[ "object_type"] = "RangeBasedItemLevelRestoreCriteria" restore_criteria["min_matching_value"] = container restore_criteria["max_matching_value"] = container + "-0" restore_criteria_list.append(restore_criteria) if from_prefix_pattern is not None or to_prefix_pattern is not None: if from_prefix_pattern is None or to_prefix_pattern is None or \ len(from_prefix_pattern) != len(to_prefix_pattern) or len(from_prefix_pattern) > 10: raise CLIError( "from-prefix-pattern and to-prefix-pattern should not be null, both of them should have " "equal length and can have a maximum of 10 patterns.") for index, _ in enumerate(from_prefix_pattern): if from_prefix_pattern[index][0] == '$' or to_prefix_pattern[ index][0] == '$': raise CLIError( "Prefix patterns should not start with '$'. Please provide valid prefix patterns and try again." ) if not 3 <= len(from_prefix_pattern[index]) <= 63 or not 3 <= len( to_prefix_pattern[index]) <= 63: raise CLIError( "Prefix patterns needs to be between 3 to 63 characters.") if from_prefix_pattern[index] >= to_prefix_pattern[index]: raise CLIError( "From prefix pattern must be less than to prefix pattern.") regex_pattern = r"^[a-z0-9](?!.*--)[a-z0-9-]{1,61}[a-z0-9](\/.{1,60})*$" if re.match(regex_pattern, from_prefix_pattern[index]) is None: raise CLIError( "prefix patterns must start or end with a letter or number," "and can contain only lowercase letters, numbers, and the dash (-) character. " "consecutive dashes are not permitted." "Given pattern " + from_prefix_pattern[index] + " violates the above rule.") if re.match(regex_pattern, to_prefix_pattern[index]) is None: raise CLIError( "prefix patterns must start or end with a letter or number," "and can contain only lowercase letters, numbers, and the dash (-) character. " "consecutive dashes are not permitted." "Given pattern " + to_prefix_pattern[index] + " violates the above rule.") for compareindex in range(index + 1, len(from_prefix_pattern)): if (from_prefix_pattern[index] <= from_prefix_pattern[compareindex] and to_prefix_pattern[index] >= from_prefix_pattern[compareindex]) or \ (from_prefix_pattern[index] >= from_prefix_pattern[compareindex] and from_prefix_pattern[index] <= to_prefix_pattern[compareindex]): raise CLIError("overlapping ranges are not allowed.") for index, _ in enumerate(from_prefix_pattern): restore_criteria = {} restore_criteria[ "object_type"] = "RangeBasedItemLevelRestoreCriteria" restore_criteria["min_matching_value"] = from_prefix_pattern[index] restore_criteria["max_matching_value"] = to_prefix_pattern[index] restore_criteria_list.append(restore_criteria) if container_list is None and from_prefix_pattern is None and to_prefix_pattern is None: raise CLIError( "Provide ContainersList or Prefixes for Item Level Recovery") restore_request["restore_target_info"][ "restore_criteria"] = restore_criteria_list vault_resource_group = backup_instance_id.split('/')[4] vault_name = backup_instance_id.split('/')[8] backup_instance_name = backup_instance_id.split('/')[-1] backup_instance = client.get(vault_name=vault_name, resource_group_name=vault_resource_group, backup_instance_name=backup_instance_name) datasource_id = backup_instance.properties.data_source_info.resource_id restore_request["restore_target_info"][ "datasource_info"] = helper.get_datasource_info( datasource_type, datasource_id, restore_location) if manifest["isProxyResource"]: restore_request["restore_target_info"][ "datasource_set_info"] = helper.get_datasourceset_info( datasource_type, datasource_id, restore_location) return restore_request
def restore_initialize_for_data_recovery_as_files(target_blob_container_url, target_file_name, datasource_type, source_datastore, restore_location, recovery_point_id=None, point_in_time=None, rehydration_priority=None, rehydration_duration=15): restore_request = {} restore_mode = None if recovery_point_id is not None and point_in_time is not None: raise CLIError( "Please provide either recovery point id or point in time parameter, not both." ) if recovery_point_id is not None: restore_request[ "object_type"] = "AzureBackupRecoveryPointBasedRestoreRequest" restore_request["recovery_point_id"] = recovery_point_id restore_mode = "RecoveryPointBased" if point_in_time is not None: restore_request[ "object_type"] = "AzureBackupRecoveryTimeBasedRestoreRequest" restore_request["recovery_point_time"] = point_in_time restore_mode = "PointInTimeBased" if recovery_point_id is None and point_in_time is None: raise CLIError( "Please provide either recovery point id or point in time parameter." ) manifest = helper.load_manifest(datasource_type) if manifest is not None and manifest[ "allowedRestoreModes"] is not None and restore_mode not in manifest[ "allowedRestoreModes"]: raise CLIError(restore_mode + " restore mode is not supported for datasource type " + datasource_type + ". Supported restore modes are " + ','.join(manifest["allowedRestoreModes"])) if source_datastore in manifest["policySettings"][ "supportedDatastoreTypes"]: restore_request["source_data_store_type"] = source_datastore if rehydration_priority: if rehydration_duration < 10 or rehydration_duration > 30: raise CLIError( "The allowed range of rehydration duration is 10 to 30 days." ) restore_request[ "object_type"] = "AzureBackupRestoreWithRehydrationRequest" restore_request["rehydration_priority"] = rehydration_priority restore_request["rehydration_retention_duration"] = "P" + str( rehydration_duration) + "D" else: raise CLIError( source_datastore + " datastore type is not supported for datasource type " + datasource_type + ". Supported datastore types are " + ','.join(manifest["policySettings"]["supportedDatastoreTypes"])) restore_request["restore_target_info"] = {} restore_request["restore_target_info"][ "object_type"] = "RestoreFilesTargetInfo" restore_request["restore_target_info"][ "restore_location"] = restore_location restore_request["restore_target_info"]["recovery_option"] = "FailIfExists" restore_request["restore_target_info"]["target_details"] = {} restore_request["restore_target_info"]["target_details"][ "url"] = target_blob_container_url restore_request["restore_target_info"]["target_details"][ "file_prefix"] = target_file_name restore_request["restore_target_info"]["target_details"][ "restore_target_location_type"] = "AzureBlobs" return restore_request
def restore_initialize_for_data_recovery(target_resource_id, datasource_type, source_datastore, restore_location, recovery_point_id=None, point_in_time=None, secret_store_type=None, secret_store_uri=None, rehydration_priority=None, rehydration_duration=15): restore_request = {} restore_mode = None if recovery_point_id is not None and point_in_time is not None: raise CLIError( "Please provide either recovery point id or point in time parameter, not both." ) if recovery_point_id is not None: restore_request[ "object_type"] = "AzureBackupRecoveryPointBasedRestoreRequest" restore_request["recovery_point_id"] = recovery_point_id restore_mode = "RecoveryPointBased" if point_in_time is not None: restore_request[ "object_type"] = "AzureBackupRecoveryTimeBasedRestoreRequest" restore_request["recovery_point_time"] = point_in_time restore_mode = "PointInTimeBased" if recovery_point_id is None and point_in_time is None: raise CLIError( "Please provide either recovery point id or point in time parameter." ) manifest = helper.load_manifest(datasource_type) if manifest is not None and manifest[ "allowedRestoreModes"] is not None and restore_mode not in manifest[ "allowedRestoreModes"]: raise CLIError(restore_mode + " restore mode is not supported for datasource type " + datasource_type + ". Supported restore modes are " + ','.join(manifest["allowedRestoreModes"])) if source_datastore in manifest["policySettings"][ "supportedDatastoreTypes"]: restore_request["source_data_store_type"] = source_datastore if rehydration_priority: if rehydration_duration < 10 or rehydration_duration > 30: raise CLIError( "The allowed range of rehydration duration is 10 to 30 days." ) restore_request[ "object_type"] = "AzureBackupRestoreWithRehydrationRequest" restore_request["rehydration_priority"] = rehydration_priority restore_request["rehydration_retention_duration"] = "P" + str( rehydration_duration) + "D" else: raise CLIError( source_datastore + " datastore type is not supported for datasource type " + datasource_type + ". Supported datastore types are " + ','.join(manifest["policySettings"]["supportedDatastoreTypes"])) restore_request["restore_target_info"] = {} restore_request["restore_target_info"]["object_type"] = "RestoreTargetInfo" restore_request["restore_target_info"][ "restore_location"] = restore_location restore_request["restore_target_info"]["recovery_option"] = "FailIfExists" restore_request["restore_target_info"][ "datasource_info"] = helper.get_datasource_info( datasource_type, target_resource_id, restore_location) if manifest["isProxyResource"]: restore_request["restore_target_info"][ "datasource_set_info"] = helper.get_datasourceset_info( datasource_type, target_resource_id, restore_location) if manifest["supportSecretStoreAuthentication"]: if secret_store_uri and secret_store_type: restore_request["restore_target_info"][ "datasource_auth_credentials"] = { "secret_store_resource": { "uri": secret_store_uri, "value": None, "secret_store_type": secret_store_type }, "object_type": "SecretStoreBasedAuthCredentials" } elif secret_store_uri or secret_store_type: raise CLIError( "Either secret store uri or secret store type not provided.") return restore_request