def wait_for_no_anf_resource(client, resourceId, intervalInSec=10, retries=60): for i in range(0, retries): time.sleep(intervalInSec) try: if resource_uri_utils.is_anf_snapshot(resourceId): client.snapshots.get( resource_uri_utils.get_resource_group(resourceId), resource_uri_utils.get_anf_account(resourceId), resource_uri_utils.get_anf_capacity_pool(resourceId), resource_uri_utils.get_anf_volume(resourceId), resource_uri_utils.get_anf_snapshot(resourceId) ) elif resource_uri_utils.is_anf_volume(resourceId): client.volumes.get( resource_uri_utils.get_resource_group(resourceId), resource_uri_utils.get_anf_account(resourceId), resource_uri_utils.get_anf_capacity_pool(resourceId), resource_uri_utils.get_anf_volume(resourceId) ) elif resource_uri_utils.is_anf_capacity_pool(resourceId): client.pools.get( resource_uri_utils.get_resource_group(resourceId), resource_uri_utils.get_anf_account(resourceId), resource_uri_utils.get_anf_capacity_pool(resourceId) ) elif resource_uri_utils.is_anf_account(resourceId): client.accounts.get( resource_uri_utils.get_resource_group(resourceId), resource_uri_utils.get_anf_account(resourceId) ) except CloudError as ex: break
def wait_for_anf_resource(client, resource_id, interval_in_sec=10, retries=60, replication=None): """Waits for specific anf resource start existing This function checks if a specific ANF resource that was recently created is already being able to be polled. It breaks the wait if resource is found or if polling reached out maximum retries. Args: client (NetAppManagementClient): Azure Resource Provider Client designed to interact with ANF resources resource_id (string): Resource Id of the resource to be checked upon interval_in_sec (int): Interval used between checks retires (int): Number of times a poll will be performed """ for i in range(0, retries): time.sleep(interval_in_sec) try: if resource_uri_utils.is_anf_snapshot(resource_id): client.snapshots.get( resource_uri_utils.get_resource_group(resource_id), resource_uri_utils.get_anf_account(resource_id), resource_uri_utils.get_anf_capacity_pool(resource_id), resource_uri_utils.get_anf_volume(resource_id), resource_uri_utils.get_anf_snapshot(resource_id)) elif resource_uri_utils.is_anf_volume(resource_id): volume = client.volumes.get( resource_uri_utils.get_resource_group(resource_id), resource_uri_utils.get_anf_account(resource_id), resource_uri_utils.get_anf_capacity_pool(resource_id), resource_uri_utils.get_anf_volume(resource_id)) if replication == True: if volume.data_protection == None: continue elif resource_uri_utils.is_anf_capacity_pool(resource_id): client.pools.get( resource_uri_utils.get_resource_group(resource_id), resource_uri_utils.get_anf_account(resource_id), resource_uri_utils.get_anf_capacity_pool(resource_id)) elif resource_uri_utils.is_anf_account(resource_id): client.accounts.get( resource_uri_utils.get_resource_group(resource_id), resource_uri_utils.get_anf_account(resource_id)) break except ResourceNotFoundError as ex: pass
def wait_for_no_anf_resource(client, resource_id, interval_in_sec=10, retries=60): """Waits for specific anf resource don't exist This function checks if a specific ANF resource that was recently delete stops existing. It breaks the wait if resource is not found anymore or if polling reached out maximum retries. Args: client (AzureNetAppFilesManagementClient): Azure Resource Provider Client designed to interact with ANF resources resource_id (string): Resource Id of the resource to be checked upon interval_in_sec (int): Interval used between checks retires (int): Number of times a poll will be performed """ for i in range(0, retries): time.sleep(interval_in_sec) try: if resource_uri_utils.is_anf_snapshot(resource_id): client.snapshots.get( resource_uri_utils.get_resource_group(resource_id), resource_uri_utils.get_anf_account(resource_id), resource_uri_utils.get_anf_capacity_pool(resource_id), resource_uri_utils.get_anf_volume(resource_id), resource_uri_utils.get_anf_snapshot(resource_id) ) elif resource_uri_utils.is_anf_volume(resource_id): client.volumes.get( resource_uri_utils.get_resource_group(resource_id), resource_uri_utils.get_anf_account(resource_id), resource_uri_utils.get_anf_capacity_pool(resource_id), resource_uri_utils.get_anf_volume(resource_id) ) elif resource_uri_utils.is_anf_capacity_pool(resource_id): client.pools.get( resource_uri_utils.get_resource_group(resource_id), resource_uri_utils.get_anf_account(resource_id), resource_uri_utils.get_anf_capacity_pool(resource_id) ) elif resource_uri_utils.is_anf_account(resource_id): client.accounts.get( resource_uri_utils.get_resource_group(resource_id), resource_uri_utils.get_anf_account(resource_id) ) except CloudError as ex: break
def run_example(): """Azure NetApp Files SDK management example.""" print("Azure NetAppFiles Python SDK Sample") print("Sample project that performs CRUD management operations with Azure NetApp Files SDK with Python") print("-----------------------------------------------------------------------------------------------") # Creating the Azure NetApp Files Client with an Application # (service principal) token provider credentials, subscription_id = sample_utils.get_credentials() anf_client = AzureNetAppFilesManagementClient( credentials, subscription_id) # Creating an Azure NetApp Account console_output('Creating Azure NetApp Files account ...') account = None try: account = create_account( anf_client, RESOURCE_GROUP_NAME, ANF_ACCOUNT_NAME, LOCATION) console_output( '\tAccount successfully created, resource id: {}'.format( account.id)) except CloudError as ex: console_output( 'An error ocurred. Error details: {}'.format(ex.message)) raise # Creating a Capacity Pool console_output('Creating Capacity Pool ...') capacity_pool = None try: capacity_pool = create_capacitypool_async( anf_client, RESOURCE_GROUP_NAME, account.name, CAPACITYPOOL_NAME, CAPACITYPOOL_SERVICE_LEVEL, CAPACITYPOOL_SIZE, LOCATION) console_output('\tCapacity Pool successfully created, resource id: {}' .format(capacity_pool.id)) except CloudError as ex: console_output( 'An error ocurred. Error details: {}'.format(ex.message)) raise # Creating a Volume # # Note: With exception of Accounts, all resources with Name property # returns a relative path up to the name and to use this property in # other methods, like Get for example, the argument needs to be # sanitized and just the actual name needs to be used (the hierarchy # needs to be cleaned up in the name). # Capacity Pool Name property example: "pmarques-anf01/pool01" # "pool01" is the actual name that needs to be used instead. Below you # will see a sample function that parses the name from its # resource id: resource_uri_utils.get_anf_capacity_pool() console_output('Creating a Volume ...') subnet_id = '/subscriptions/{}/resourceGroups/{}/providers/Microsoft.Network/virtualNetworks/{}/subnets/{}'\ .format(subscription_id, VNET_RESOURCE_GROUP_NAME, VNET_NAME, SUBNET_NAME) volume = None try: pool_name = resource_uri_utils.get_anf_capacity_pool(capacity_pool.id) volume = create_volume(anf_client, RESOURCE_GROUP_NAME, account.name, pool_name, VOLUME_NAME, VOLUME_USAGE_QUOTA, CAPACITYPOOL_SERVICE_LEVEL, subnet_id, LOCATION) console_output('\tVolume successfully created, resource id: {}' .format(volume.id)) except CloudError as ex: console_output( 'An error ocurred. Error details: {}'.format(ex.message)) raise # Creating a snapshot console_output('Creating a Snapshot ...') snapshot = None try: volume_name = resource_uri_utils.get_anf_volume(volume.id) snapshot = create_snapshot(anf_client, RESOURCE_GROUP_NAME, account.name, pool_name, VOLUME_NAME, SNAPSHOT_NAME, LOCATION) sample_utils.wait_for_anf_resource(anf_client, snapshot.id) console_output( '\tSnapshot successfully created, resource id: {}' .format(snapshot.id)) except CloudError as ex: console_output( 'An error ocurred. Error details: {}'.format(ex.message)) raise # Creating a new volume from snapshot # # Note: SnapshotId is not the actual resource Id of the snapshot, this # value is the unique identifier (guid) of the snapshot, represented # by the SnapshotId instead. console_output('Creating New Volume from Snapshot ...') volume_from_snapshot = None try: new_volume_name = "Vol-{}".format( resource_uri_utils.get_anf_snapshot(snapshot.id)) volume_from_snapshot = create_volume_from_snapshot(anf_client, RESOURCE_GROUP_NAME, account.name, pool_name, volume, snapshot.snapshot_id, new_volume_name) console_output('\tNew volume from snapshot successfully created, resource id: {}'.format( volume_from_snapshot.id)) except CloudError as ex: console_output( 'An error ocurred. Error details: {}'.format(ex.message)) raise # Updating a Capacity Pool console_output('Performing updates on Capacity Pool and Volume...') new_capacity_pool_size_tib = 10 console_output('\tChanging Capacity Pools size from {}TiB to {}TiB'.format( sample_utils.get_bytes_in_tib(capacity_pool.size), new_capacity_pool_size_tib)) try: capacity_pool_patch = CapacityPoolPatch(location=capacity_pool.location, service_level=capacity_pool.service_level, size=sample_utils.get_tib_in_bytes(new_capacity_pool_size_tib)) capacity_pool = anf_client.pools.update(capacity_pool_patch, RESOURCE_GROUP_NAME, account.name, resource_uri_utils.get_anf_capacity_pool(capacity_pool.id)) console_output('\t\tCapacity Pool successfully updated, new size {}TiB, resource id: {}'.format( sample_utils.get_bytes_in_tib(capacity_pool.size), capacity_pool.id)) except CloudError as ex: console_output( 'An error ocurred. Error details: {}'.format(ex.message)) raise # Volume updates: resize and adding a new export policy new_volume_size_tib = 1 console_output('\tChanging volume size from {}TiB to {}TiB'.format( sample_utils.get_bytes_in_tib(volume.usage_threshold), new_volume_size_tib)) # Getting list of export policies and adding a new one at the end rule_list = sorted(volume.export_policy.rules, key=lambda r: r.rule_index, reverse=True) # Currently, ANF's volume export policy supports up to 5 rules export_policies_patch = None if len(rule_list) <= 4: rule_list.append(ExportPolicyRule( allowed_clients="10.0.0.4/32", cifs=False, nfsv3=True, nfsv41=False, rule_index=rule_list[0].rule_index + 1, unix_read_only=False, unix_read_write=True)) export_policies_patch = VolumePatchPropertiesExportPolicy( rules=rule_list) if export_policies_patch is None: volume_patch = VolumePatch( location=volume.location, service_level=volume.service_level, usage_threshold=sample_utils.get_tib_in_bytes(new_volume_size_tib)) else: volume_patch = VolumePatch( location=volume.location, service_level=volume.service_level, usage_threshold=sample_utils.get_tib_in_bytes(new_volume_size_tib), export_policy=export_policies_patch) try: updated_volume = anf_client.volumes.update(volume_patch, RESOURCE_GROUP_NAME, account.name, resource_uri_utils.get_anf_capacity_pool( capacity_pool.id), resource_uri_utils.get_anf_volume(volume.id)) console_output('\t\tVolume successfully updated, new size: {}TiB, export policy count: {}, resource id: {}' .format(sample_utils.get_bytes_in_tib(updated_volume.usage_threshold), len(updated_volume.export_policy.rules), updated_volume.id)) except CloudError as ex: console_output( 'An error ocurred. Error details: {}'.format(ex.message)) raise # Retrieving resources console_output('Performing retrieval operations ...') # Accounts # Getting a list of ANF Accounts console_output('\tListing accounts...') account_list = None try: account_list = list(anf_client.accounts.list(RESOURCE_GROUP_NAME)) for i, retrieved_account in enumerate(account_list): console_output('\t\t{} - Account Name: {}, Id: {}' .format(i, retrieved_account.name, retrieved_account.id)) except CloudError as ex: console_output( 'An error ocurred. Error details: {}'.format(ex.message)) raise # Getting a single ANF Account console_output('\tGetting a single account...') try: retrieved_account = anf_client.accounts.get( RESOURCE_GROUP_NAME, account.name) console_output('\t\tAccount Name: {}, Id: {}'.format( retrieved_account.name, retrieved_account.id)) except CloudError as ex: console_output( 'An error ocurred. Error details: {}'.format(ex.message)) raise # Capacity Pools # Getting a list of capacity pools from an account console_output('\tListing capacity pools from account {}...' .format(account.name)) capacitypool_list = None try: capacitypool_list = list(anf_client.pools.list(RESOURCE_GROUP_NAME, resource_uri_utils.get_anf_account(account.id))) for i, retrieved_pool in enumerate(capacitypool_list): console_output('\t\t{} - Capacity Pool Name: {}, Id: {}' .format(i, retrieved_pool.name, retrieved_pool.id)) except CloudError as ex: console_output( 'An error ocurred. Error details: {}'.format(ex.message)) raise # Getting a single capacity pool console_output('\tGetting a single capacity pool...') try: retrieved_pool = anf_client.pools.get(RESOURCE_GROUP_NAME, resource_uri_utils.get_anf_account( account.id), resource_uri_utils.get_anf_capacity_pool(capacity_pool.id)) console_output('\t\tCapacity Pool Name: {}, Id: {}'.format( retrieved_pool.name, retrieved_pool.id)) except CloudError as ex: console_output( 'An error ocurred. Error details: {}'.format(ex.message)) raise # Volumes # Getting a list of volumes from a capacity pool console_output('\tListing volumes from capacity pool {}...'.format( capacity_pool.name)) volume_list = None try: volume_list = list(anf_client.volumes.list(RESOURCE_GROUP_NAME, resource_uri_utils.get_anf_account( account.id), resource_uri_utils.get_anf_capacity_pool(capacity_pool.id))) for i, retrieved_volume in enumerate(volume_list): console_output('\t\t{} - Volume Name: {}, Id: {}' .format(i, retrieved_volume.name, retrieved_volume.id)) except CloudError as ex: console_output( 'An error ocurred. Error details: {}'.format(ex.message)) raise # Getting a single volume console_output('\tGetting a single volume...') try: retrieved_volume = anf_client.volumes.get(RESOURCE_GROUP_NAME, resource_uri_utils.get_anf_account( account.id), resource_uri_utils.get_anf_capacity_pool( capacity_pool.id), resource_uri_utils.get_anf_volume(volume.id)) console_output('\t\tVolume Name: {}, Id: {}'.format( retrieved_volume.name, retrieved_volume.id)) except CloudError as ex: console_output( 'An error ocurred. Error details: {}'.format(ex.message)) raise # Snapshots # Getting a list of snapshots from volume console_output( '\tListing snapshots from from volume {}...'.format(volume.name)) snapshot_list = None try: snapshot_list = list(anf_client.snapshots.list(RESOURCE_GROUP_NAME, resource_uri_utils.get_anf_account( account.id), resource_uri_utils.get_anf_capacity_pool( capacity_pool.id), resource_uri_utils.get_anf_volume(volume.id))) for i, retrieved_snapshot in enumerate(snapshot_list): console_output('\t\t{} - Snapshot Name: {}, Id: {}' .format(i, retrieved_snapshot.name, retrieved_snapshot.id)) except CloudError as ex: console_output( 'An error ocurred. Error details: {}'.format(ex.message)) raise # Getting a single snapshot console_output('\tGetting a single snapshot...') try: retrieved_snapshot = anf_client.snapshots.get(RESOURCE_GROUP_NAME, resource_uri_utils.get_anf_account( account.id), resource_uri_utils.get_anf_capacity_pool( capacity_pool.id), resource_uri_utils.get_anf_volume( volume.id), resource_uri_utils.get_anf_snapshot(snapshot.id)) console_output('\t\tSnapshot Name: {}, Id: {}'.format( retrieved_snapshot.name, retrieved_snapshot.id)) except CloudError as ex: console_output( 'An error ocurred. Error details: {}'.format(ex.message)) raise # Cleaning up. This process needs to start the cleanup from the innermost # resources down in the hierarchy chain in our case # Snapshots->Volumes->Capacity Pools->Accounts if SHOULD_CLEANUP: console_output('Cleaning up...') # Cleaning up snapshot console_output( "\tWaiting for 1 minute to let the snapshot used to create a new \ volume to complete the split operation therefore not being locked...") time.sleep(60) console_output("\tDeleting Snapshot {}...".format( resource_uri_utils.get_anf_snapshot(snapshot.id))) try: anf_client.snapshots.delete(RESOURCE_GROUP_NAME, account.name, resource_uri_utils.get_anf_capacity_pool( capacity_pool.id), resource_uri_utils.get_anf_volume( volume.id), resource_uri_utils.get_anf_snapshot(snapshot.id)).wait() # ARM Workaround to wait the deletion complete/propagate sample_utils.wait_for_no_anf_resource(anf_client, snapshot.id) console_output('\t\tDeleted Snapshot: {}'.format(snapshot.id)) except CloudError as ex: console_output( 'An error ocurred. Error details: {}'.format(ex.message)) raise # Cleaning up volumes # Note: Volume deletion operations at the RP level are executed # serially console_output("\tDeleting Volumes...") try: volume_ids = [volume.id, volume_from_snapshot.id] for volume_id in volume_ids: console_output("\t\tDeleting {}".format(volume_id)) anf_client.volumes.delete(RESOURCE_GROUP_NAME, account.name, resource_uri_utils.get_anf_capacity_pool( capacity_pool.id), resource_uri_utils.get_anf_volume(volume_id)).wait() sample_utils.wait_for_no_anf_resource(anf_client, volume_id) console_output('\t\tDeleted Volume: {}'.format(volume_id)) except CloudError as ex: console_output( 'An error ocurred. Error details: {}'.format(ex.message)) raise # Cleaning up Capacity Pool console_output("\tDeleting Capacity Pool {} ...".format( resource_uri_utils.get_anf_capacity_pool(capacity_pool.id))) try: anf_client.pools.delete(RESOURCE_GROUP_NAME, account.name, resource_uri_utils.get_anf_capacity_pool( capacity_pool.id)).wait() sample_utils.wait_for_no_anf_resource(anf_client, capacity_pool.id) console_output( '\t\tDeleted Capacity Pool: {}'.format(capacity_pool.id)) except CloudError as ex: console_output( 'An error ocurred. Error details: {}'.format(ex.message)) raise # Cleaning up Account console_output("\tDeleting Account {} ...".format(account.name)) try: anf_client.accounts.delete(RESOURCE_GROUP_NAME, account.name) sample_utils.wait_for_no_anf_resource(anf_client, account.id) console_output('\t\tDeleted Account: {}'.format(account.id)) except CloudError as ex: console_output( 'An error ocurred. Error details: {}'.format(ex.message)) raise
def run_example(): """Azure NetApp Files Cross-Region Replication (CRR) SDK management example""" print_header( "Azure NetApp Files Python CRR SDK Sample - Sample " "project that creates a primary ANF Account, Capacity Pool, and an " "NFS v4.1 Volume. Then it creates secondary resources and a " "Data Replication Volume.") # Authenticating using service principal, refer to README.md file for requirement details credentials, subscription_id = get_credentials() console_output( "Instantiating a new Azure NetApp Files management client...") anf_client = NetAppManagementClient(credentials, subscription_id) console_output("Creating Primary ANF Resources...") # Creating ANF Primary Account console_output("Creating Primary Account...") primary_account = None try: primary_account = create_account(anf_client, PRIMARY_RESOURCE_GROUP_NAME, PRIMARY_ANF_ACCOUNT_NAME, PRIMARY_LOCATION) console_output( "\tAccount successfully created. Resource id: {}".format( primary_account.id)) except AzureError as ex: console_output("An error occurred while creating Account: {}".format( ex.message)) raise # Creating Primary Capacity Pool console_output("Creating Primary Capacity Pool...") primary_capacity_pool = None try: primary_capacity_pool = create_capacity_pool( anf_client, PRIMARY_RESOURCE_GROUP_NAME, primary_account.name, PRIMARY_CAPACITY_POOL_NAME, CAPACITY_POOL_SIZE, PRIMARY_LOCATION) console_output( "\tCapacity Pool successfully created. Resource id: {}".format( primary_capacity_pool.id)) except AzureError as ex: console_output( "An error occurred while creating Capacity Pool: {}".format( ex.message)) raise # Creating Primary Volume console_output("Creating Primary Volume...") primary_subnet_id = '/subscriptions/{}/resourceGroups/{}/providers/Microsoft.Network/virtualNetworks/{}/subnets/{}'.format( subscription_id, PRIMARY_RESOURCE_GROUP_NAME, PRIMARY_VNET_NAME, PRIMARY_SUBNET_NAME) primary_volume = None try: pool_name = resource_uri_utils.get_anf_capacity_pool( primary_capacity_pool.id) primary_volume = create_volume(anf_client, PRIMARY_RESOURCE_GROUP_NAME, primary_account.name, pool_name, PRIMARY_VOLUME_NAME, VOLUME_SIZE, primary_subnet_id, PRIMARY_LOCATION) console_output("\tVolume successfully created. Resource id: {}".format( primary_volume.id)) except AzureError as ex: console_output("An error occurred while creating Volume: {}".format( ex.message)) raise # Wait for primary volume to be ready console_output("Waiting for {} to be available...".format( resource_uri_utils.get_anf_volume(primary_volume.id))) wait_for_anf_resource(anf_client, primary_volume.id) console_output("Creating Secondary ANF Resources...") # Creating ANF Secondary Account console_output("Creating Secondary Account...") secondary_account = None try: secondary_account = create_account(anf_client, SECONDARY_RESOURCE_GROUP_NAME, SECONDARY_ANF_ACCOUNT_NAME, SECONDARY_LOCATION) console_output( "\tAccount successfully created. Resource id: {}".format( secondary_account.id)) except AzureError as ex: console_output("An error occurred while creating Account: {}".format( ex.message)) raise # Creating Secondary Capacity Pool console_output("Creating Secondary Capacity Pool...") secondary_capacity_pool = None try: secondary_capacity_pool = create_capacity_pool( anf_client, SECONDARY_RESOURCE_GROUP_NAME, secondary_account.name, SECONDARY_CAPACITY_POOL_NAME, CAPACITY_POOL_SIZE, SECONDARY_LOCATION) console_output( "\tCapacity Pool successfully created. Resource id: {}".format( secondary_capacity_pool.id)) except AzureError as ex: console_output( "An error occurred while creating Capacity Pool: {}".format( ex.message)) raise # Creating Secondary Volume console_output("Creating Secondary Volume...") secondary_subnet_id = '/subscriptions/{}/resourceGroups/{}/providers/Microsoft.Network/virtualNetworks/{}/subnets/{}'.format( subscription_id, SECONDARY_RESOURCE_GROUP_NAME, SECONDARY_VNET_NAME, SECONDARY_SUBNET_NAME) data_replication_volume = None try: replication_object = ReplicationObject( endpoint_type="dst", remote_volume_region=PRIMARY_LOCATION, remote_volume_resource_id=primary_volume.id, replication_schedule="hourly") data_protection_object = VolumePropertiesDataProtection( replication=replication_object) pool_name = resource_uri_utils.get_anf_capacity_pool( secondary_capacity_pool.id) data_replication_volume = create_volume( anf_client, SECONDARY_RESOURCE_GROUP_NAME, secondary_account.name, pool_name, SECONDARY_VOLUME_NAME, VOLUME_SIZE, secondary_subnet_id, SECONDARY_LOCATION, data_protection_object) console_output("\tVolume successfully created. Resource id: {}".format( data_replication_volume.id)) except AzureError as ex: console_output("An error occurred while creating Volume: {}".format( ex.message)) raise # Wait for data replication volume to be ready console_output("Waiting for {} to be available...".format( resource_uri_utils.get_anf_volume(data_replication_volume.id))) wait_for_anf_resource(anf_client, data_replication_volume.id) console_output("Authorizing replication in source region...") # Authorize replication between the two volumes authorization_replication_body = AuthorizeRequest( remote_volume_resource_id=data_replication_volume.id) anf_client.volumes.begin_authorize_replication( resource_uri_utils.get_resource_group(primary_account.id), resource_uri_utils.get_anf_account(primary_account.id), resource_uri_utils.get_anf_capacity_pool(primary_capacity_pool.id), resource_uri_utils.get_anf_volume(primary_volume.id), authorization_replication_body).wait() # Wait for replication to initialize on source volume wait_for_anf_resource(anf_client, primary_volume.id, replication=True) console_output("\tSuccessfully authorized replication in source region") # """ # Cleanup process. For this process to take effect please change the value of # CLEANUP_RESOURCES global variable to 'True' # Note: Volume deletion operations at the RP level are executed serially # """ if CLEANUP_RESOURCES: # The cleanup process starts from the innermost resources down in the hierarchy chain. # In this case: Volumes -> Capacity Pools -> Accounts console_output("Cleaning up resources") # Cleaning up volumes console_output("Deleting Volumes...") # We need to break and then remove the replication attached to the destination # volume before we can delete either volume in a replication. As a result, volumes # must be deleted in the order of destination and then source in this code. # First, we check if the volume is a destination volume and act accordingly. # Note that we need to delete the replication using the destination volume's id # This erases the replication for both destination and source volumes. try: volume_ids = [data_replication_volume.id, primary_volume.id] for volume_id in volume_ids: resource_group = resource_uri_utils.get_resource_group( volume_id) account_name = resource_uri_utils.get_anf_account(volume_id) pool_name = resource_uri_utils.get_anf_capacity_pool(volume_id) volume_name = resource_uri_utils.get_anf_volume(volume_id) current_volume = anf_client.volumes.get( resource_group, account_name, pool_name, volume_name) # If the volume is a destination volume, the replication must be broken and deleted if current_volume.data_protection.replication is not None and \ (current_volume.data_protection.replication.endpoint_type == "dst" or current_volume.data_protection.replication.additional_properties["endPointType"] == "Dst"): console_output( "Deleting replication on Volume {}".format(volume_id)) try: wait_for_mirror_state(anf_client, resource_group, account_name, pool_name, volume_name, mirror_state.MIRRORED) anf_client.volumes.begin_break_replication( resource_group, account_name, pool_name, volume_name).wait() except AzureError as e: if e.status_code == 404: # If replication is not found then the volume can be safely deleted. Therefore we pass on this error and proceed to delete the volume pass else: # Throw all other exceptions console_output( "An error occurred while breaking replication: {}" .format(e.message)) raise try: wait_for_mirror_state(anf_client, resource_group, account_name, pool_name, volume_name, mirror_state.BROKEN) anf_client.volumes.begin_delete_replication( resource_group, account_name, pool_name, volume_name).wait() # Wait for replication to finish deleting wait_for_no_anf_resource(anf_client, volume_id, replication=True) console_output( "\tSuccessfully deleted replication on Volume {}". format(volume_id)) except AzureError as e: if e.status_code == 404: # If replication is not found then the volume can be safely deleted. Therefore we pass on this error and proceed to delete the volume pass else: # Throw all other exceptions console_output( "An error occurred while deleting replication: {}" .format(e.message)) raise console_output("Deleting Volume {}".format(volume_id)) anf_client.volumes.begin_delete(resource_group, account_name, pool_name, volume_name).wait() # ARM workaround to wait for the deletion to complete wait_for_no_anf_resource(anf_client, volume_id) console_output( "\tSuccessfully deleted Volume {}".format(volume_id)) except AzureError as ex: console_output( "An error occurred while deleting volumes: {}".format( ex.message)) raise # Cleaning up capacity pools console_output("Deleting Capacity Pools...") try: pool_ids = [primary_capacity_pool.id, secondary_capacity_pool.id] for pool_id in pool_ids: resource_group = resource_uri_utils.get_resource_group(pool_id) account_name = resource_uri_utils.get_anf_account(pool_id) pool_name = resource_uri_utils.get_anf_capacity_pool(pool_id) console_output("Deleting Capacity Pool {}".format(pool_id)) anf_client.pools.begin_delete(resource_group, account_name, pool_name).wait() # ARM workaround to wait for the deletion to complete wait_for_no_anf_resource(anf_client, pool_id) console_output( "\tSuccessfully deleted Capacity Pool {}".format(pool_id)) except AzureError as ex: console_output( "An error occurred while deleting capacity pools: {}".format( ex.message)) raise # Cleaning up accounts console_output("Deleting Accounts...") try: account_ids = [primary_account.id, secondary_account.id] for account_id in account_ids: resource_group = resource_uri_utils.get_resource_group( account_id) account_name = resource_uri_utils.get_anf_account(account_id) console_output("Deleting Account {}".format(account_id)) anf_client.accounts.begin_delete(resource_group, account_name).wait() # ARM workaround to wait for the deletion to complete wait_for_no_anf_resource(anf_client, account_id) console_output( "\tSuccessfully deleted Account {}".format(account_id)) except AzureError as ex: console_output( "An error occurred while deleting accounts: {}".format( ex.message)) raise console_output("ANF Cross-Region Replication has completed successfully")