Beispiel #1
0
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
Beispiel #2
0
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
Beispiel #3
0
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
Beispiel #5
0
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")