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