/// <summary>
        /// Function used to wait for a specific ANF resource complete its deletion and ARM caching gets cleared
        /// </summary>
        /// <typeparam name="T">Resource Types as Snapshot, Volume, CapacityPool, and NetAppAccount</typeparam>
        /// <param name="client">ANF Client</param>
        /// <param name="resourceId">Resource Id of the resource being waited for being deleted</param>
        /// <param name="intervalInSec">Time in seconds that the sample will poll to check if the resource got deleted or not. Defaults to 10 seconds.</param>
        /// <param name="retries">How many retries before exting the wait for no resource function. Defaults to 60 retries.</param>
        /// <returns></returns>
        static public async Task WaitForNoAnfResource <T>(AzureNetAppFilesManagementClient client, string resourceId, int intervalInSec = 10, int retries = 60)
        {
            for (int i = 0; i < retries; i++)
            {
                System.Threading.Thread.Sleep(TimeSpan.FromSeconds(intervalInSec));

                try
                {
                    if (typeof(T) == typeof(Snapshot))
                    {
                        var resource = await client.Snapshots.GetAsync(ResourceUriUtils.GetResourceGroup(resourceId),
                                                                       ResourceUriUtils.GetAnfAccount(resourceId),
                                                                       ResourceUriUtils.GetAnfCapacityPool(resourceId),
                                                                       ResourceUriUtils.GetAnfVolume(resourceId),
                                                                       ResourceUriUtils.GetAnfSnapshot(resourceId));
                    }
                    else if (typeof(T) == typeof(Volume))
                    {
                        var resource = await client.Volumes.GetAsync(ResourceUriUtils.GetResourceGroup(resourceId),
                                                                     ResourceUriUtils.GetAnfAccount(resourceId),
                                                                     ResourceUriUtils.GetAnfCapacityPool(resourceId),
                                                                     ResourceUriUtils.GetAnfVolume(resourceId));
                    }
                    else if (typeof(T) == typeof(CapacityPool))
                    {
                        var resource = await client.Pools.GetAsync(ResourceUriUtils.GetResourceGroup(resourceId),
                                                                   ResourceUriUtils.GetAnfAccount(resourceId),
                                                                   ResourceUriUtils.GetAnfCapacityPool(resourceId));
                    }
                    else if (typeof(T) == typeof(NetAppAccount))
                    {
                        var resource = await client.Accounts.GetAsync(ResourceUriUtils.GetResourceGroup(resourceId),
                                                                      ResourceUriUtils.GetAnfAccount(resourceId));
                    }
                }
                catch (Exception ex)
                {
                    // The following HResult is thrown if no resource is found
                    if (ex.HResult == -2146233088)
                    {
                        break;
                    }
                    throw;
                }
            }
        }
Пример #2
0
        /// <summary>
        /// Removes all created resources
        /// </summary>
        /// <returns></returns>
        public static async Task RunCleanupTasksSampleAsync(ProjectConfiguration config, AzureNetAppFilesManagementClient anfClient)
        {
            //
            // Cleaning up snapshots
            //
            Utils.WriteConsoleMessage("Cleaning up snapshots...");
            List <Task> snapshotCleanupTasks = new List <Task>();

            foreach (ModelNetAppAccount anfAcct in config.Accounts)
            {
                if (anfAcct.CapacityPools != null)
                {
                    foreach (ModelCapacityPool pool in anfAcct.CapacityPools)
                    {
                        if (pool.Volumes != null)
                        {
                            foreach (ModelVolume volume in pool.Volumes)
                            {
                                IEnumerable <Snapshot> anfSnapshotList = await CommonSdk.ListResourceAsync <Snapshot>(anfClient, config.ResourceGroup, anfAcct.Name, pool.Name, volume.Name);

                                if (anfSnapshotList != null && anfSnapshotList.Count() > 0)
                                {
                                    // Snapshot Name property (and other ANF's related nested resources) returns a relative path up to the name
                                    // and to use this property with DeleteAsync for example, the argument needs to be sanitized and just the
                                    // actual name needs to be used.
                                    // Snapshot Name poperty example: "pmarques-anf01/pool01/pmarques-anf01-pool01-vol01/test-a"
                                    // "test-a" is the actual name that needs to be used instead. Below you will see a sample function that
                                    // parses the name from snapshot resource id
                                    snapshotCleanupTasks.AddRange(anfSnapshotList.ToList().Select(
                                                                      async snapshot =>
                                    {
                                        await anfClient.Snapshots.DeleteAsync(config.ResourceGroup, anfAcct.Name, pool.Name, volume.Name, ResourceUriUtils.GetAnfSnapshot(snapshot.Id));
                                        Utils.WriteConsoleMessage($"\tDeleted snapshot: {snapshot.Id}");
                                    }).ToList());
                                }
                            }
                        }
                    }
                }
            }

            await WaitForTasksCompletion(snapshotCleanupTasks).ConfigureAwait(false);

            //
            // Cleaning up all volumes
            //
            // Note: Volume deletion operations at the RP level are executed serially
            Utils.WriteConsoleMessage("Cleaning up Volumes...");
            foreach (ModelNetAppAccount anfAcct in config.Accounts)
            {
                if (anfAcct.CapacityPools != null)
                {
                    foreach (ModelCapacityPool pool in anfAcct.CapacityPools)
                    {
                        if (pool.Volumes != null)
                        {
                            IEnumerable <Volume> anfVolumeList = await CommonSdk.ListResourceAsync <Volume>(anfClient, config.ResourceGroup, anfAcct.Name, pool.Name);

                            if (anfVolumeList != null && anfVolumeList.Count() > 0)
                            {
                                foreach (Volume volume in anfVolumeList)
                                {
                                    try
                                    {
                                        await anfClient.Volumes.DeleteAsync(config.ResourceGroup, anfAcct.Name, pool.Name, ResourceUriUtils.GetAnfVolume(volume.Id));

                                        Utils.WriteConsoleMessage($"\tDeleted volume: {volume.Id}");
                                    }
                                    catch (Exception ex)
                                    {
                                        Utils.WriteErrorMessage($"An error ocurred while deleting volume {volume.Id}.\nError message: {ex.Message}");
                                        throw;
                                    }
                                }
                            }
                        }
                        else
                        {
                            Utils.WriteConsoleMessage($"\tNo volumes defined for Account: {anfAcct.Name}, Capacity Pool: {pool.Name}");
                        }
                    }
                }
            }

            //
            // Cleaning up capacity pools
            //
            Utils.WriteConsoleMessage("Cleaning up capacity pools...");
            List <Task> poolCleanupTasks = new List <Task>();

            foreach (ModelNetAppAccount anfAcct in config.Accounts)
            {
                if (anfAcct.CapacityPools != null)
                {
                    poolCleanupTasks.AddRange(anfAcct.CapacityPools.Select(
                                                  async pool =>
                    {
                        CapacityPool anfPool = await GetResourceAsync <CapacityPool>(anfClient, config.ResourceGroup, anfAcct.Name, pool.Name);
                        if (anfPool != null)
                        {
                            await anfClient.Pools.DeleteAsync(config.ResourceGroup, anfAcct.Name, ResourceUriUtils.GetAnfCapacityPool(anfPool.Id));
                            Utils.WriteConsoleMessage($"\tDeleted volume: {anfPool.Id}");
                        }
                    }).ToList());
                }
            }

            await WaitForTasksCompletion(poolCleanupTasks).ConfigureAwait(false);

            //
            // Cleaning up accounts
            //
            Utils.WriteConsoleMessage("Cleaning up accounts...");
            List <Task> accountCleanupTasks = new List <Task>();

            if (config.Accounts != null)
            {
                accountCleanupTasks.AddRange(config.Accounts.Select(
                                                 async account =>
                {
                    NetAppAccount anfAccount = await GetResourceAsync <NetAppAccount>(anfClient, config.ResourceGroup, account.Name);
                    if (anfAccount != null)
                    {
                        await anfClient.Accounts.DeleteAsync(config.ResourceGroup, anfAccount.Name);
                        Utils.WriteConsoleMessage($"\tDeleted account: {anfAccount.Id}");
                    }
                }).ToList());
            }

            await WaitForTasksCompletion(accountCleanupTasks).ConfigureAwait(false);
        }
Пример #3
0
        /// <summary>
        /// Executes Snapshot related operations
        /// </summary>
        /// <returns></returns>
        public static async Task RunSnapshotOperationsSampleAsync(ProjectConfiguration config, AzureNetAppFilesManagementClient anfClient)
        {
            //
            // Creating snapshot from first volume of the first capacity pool
            //
            Utils.WriteConsoleMessage("Performing snapshot operations");

            Utils.WriteConsoleMessage("\tCreating snapshot...");

            string snapshotName = $"Snapshot-{Guid.NewGuid()}";

            Snapshot snapshotBody = new Snapshot()
            {
                Location = config.Accounts[0].Location
            };

            Snapshot snapshot = null;

            try
            {
                snapshot = await anfClient.Snapshots.CreateAsync(
                    snapshotBody,
                    config.ResourceGroup,
                    config.Accounts[0].Name,
                    config.Accounts[0].CapacityPools[0].Name,
                    config.Accounts[0].CapacityPools[0].Volumes[0].Name,
                    snapshotName);

                Utils.WriteConsoleMessage($"Snapshot successfully created. Snapshot resource id: {snapshot.Id}");
            }
            catch (Exception ex)
            {
                Utils.WriteErrorMessage($"An error occured while creating a snapshot of volume {config.Accounts[0].CapacityPools[0].Volumes[0].Name}.\nError message: {ex.Message}");
                throw;
            }

            //
            // Creating a volume from snapshot
            //
            Utils.WriteConsoleMessage("\tCreating new volume from snapshot...");

            string newVolumeName = $"Vol-{ResourceUriUtils.GetAnfSnapshot(snapshot.Id)}";

            Volume snapshotVolume = null;

            try
            {
                snapshotVolume = await anfClient.Volumes.GetAsync(
                    ResourceUriUtils.GetResourceGroup(snapshot.Id),
                    ResourceUriUtils.GetAnfAccount(snapshot.Id),
                    ResourceUriUtils.GetAnfCapacityPool(snapshot.Id),
                    ResourceUriUtils.GetAnfVolume(snapshot.Id));
            }
            catch (Exception ex)
            {
                Utils.WriteErrorMessage($"An error occured trying to obtain information about volume ({ResourceUriUtils.GetAnfVolume(snapshot.Id)}) from snapshot {snapshot.Id}.\nError message: {ex.Message}");
                throw;
            }

            Volume newVolumeFromSnapshot = null;

            try
            {
                // Notice that 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.
                Volume volumeFromSnapshotBody = new Volume()
                {
                    SnapshotId     = snapshot.SnapshotId,
                    ExportPolicy   = snapshotVolume.ExportPolicy,
                    Location       = snapshotVolume.Location,
                    ProtocolTypes  = snapshotVolume.ProtocolTypes,
                    ServiceLevel   = snapshotVolume.ServiceLevel,
                    UsageThreshold = snapshotVolume.UsageThreshold,
                    SubnetId       = snapshotVolume.SubnetId,
                    CreationToken  = newVolumeName
                };

                newVolumeFromSnapshot = await anfClient.Volumes.CreateOrUpdateAsync(
                    volumeFromSnapshotBody,
                    config.ResourceGroup,
                    config.Accounts[0].Name,
                    config.Accounts[0].CapacityPools[0].Name,
                    newVolumeName);

                Utils.WriteConsoleMessage($"Volume successfully created from snapshot. Volume resource id: {newVolumeFromSnapshot.Id}");
            }
            catch (Exception ex)
            {
                Utils.WriteErrorMessage($"An error occured while creating a volume ({newVolumeName}) from snapshot {snapshot.Id}.\nError message: {ex.Message}");
                throw;
            }
        }
        static private async Task RunAsync()
        {
            //---------------------------------------------------------------------------------------------------------------------
            // Setting variables necessary for resources creation - change these to appropriated values related to your environment
            //---------------------------------------------------------------------------------------------------------------------
            bool   cleanup                  = false;
            string subscriptionId           = "[Subscription Id]";
            string location                 = "[Location]";
            string resourceGroupName        = "[Resource group name where ANF resources will be created]";
            string vnetName                 = "[Existing Vnet Name]";
            string subnetName               = "[Existing Subnet where ANF volumes will be created]";
            string vnetResourceGroupName    = "[Vnet Resource Group Name]";
            string anfAccountName           = "[ANF Account Name]";
            string capacityPoolName         = "[ANF Capacity Pool Name]";
            string capacityPoolServiceLevel = "Standard";    // Valid service levels are: Standard, Premium and Ultra
            long   capacitypoolSize         = 4398046511104; // 4TiB which is minimum size
            long   volumeSize               = 107374182400;  // 100GiB - volume minimum size

            // SMB/CIFS related variables
            string domainJoinUsername  = "******";
            string dnsList             = "[DNS Ip Address]";         // Please notice that this is a comma-separated string
            string adFQDN              = "[Active Directory FQDN]";
            string smbServerNamePrefix = "[SMB Server Name Prefix]"; // this needs to be maximum 10 characters in length and during the domain join process a random string gets appended.

            //------------------------------------------------------------------------------------------------------
            // Getting Active Directory Identity's password (from identity that has rights to domain join computers)
            //------------------------------------------------------------------------------------------------------
            Console.WriteLine("Please type Active Directory's user password that will domain join ANF's SMB server and press [ENTER]:");

            string DomainJoinUserPassword = Utils.GetConsolePassword();

            // Basic validation
            if (string.IsNullOrWhiteSpace(DomainJoinUserPassword))
            {
                throw new Exception("Invalid password, password cannot be null or empty string");
            }

            //----------------------------------------------------------------------------------------
            // Authenticating using service principal, refer to README.md file for requirement details
            //----------------------------------------------------------------------------------------
            WriteConsoleMessage("Authenticating...");
            var credentials = await ServicePrincipalAuth.GetServicePrincipalCredential("AZURE_AUTH_LOCATION");

            //------------------------------------------
            // Instantiating a new ANF management client
            //------------------------------------------
            WriteConsoleMessage("Instantiating a new Azure NetApp Files management client...");
            AzureNetAppFilesManagementClient anfClient = new AzureNetAppFilesManagementClient(credentials)
            {
                SubscriptionId = subscriptionId
            };

            WriteConsoleMessage($"\tApi Version: {anfClient.ApiVersion}");

            //----------------------
            // Creating ANF Account
            //----------------------
            NetAppAccount anfAccount = await GetResourceAsync <NetAppAccount>(anfClient, resourceGroupName, anfAccountName);

            if (anfAccount == null)
            {
                // Setting up Active Directories Object
                // Despite of this being a list, currently ANF accepts only one Active Directory object and only one Active Directory should exist per subscription.
                List <ActiveDirectory> activeDirectories = new List <ActiveDirectory>()
                {
                    new ActiveDirectory()
                    {
                        Dns           = dnsList,
                        Domain        = adFQDN,
                        Username      = domainJoinUsername,
                        Password      = DomainJoinUserPassword,
                        SmbServerName = smbServerNamePrefix
                    }
                };

                // Setting up NetApp Files account body  object
                NetAppAccount anfAccountBody = new NetAppAccount()
                {
                    Location          = location.ToLower(), // Important: location needs to be lower case,
                    ActiveDirectories = activeDirectories
                };

                // Requesting account to be created
                WriteConsoleMessage("Creating account...");
                anfAccount = await anfClient.Accounts.CreateOrUpdateAsync(anfAccountBody, resourceGroupName, anfAccountName);
            }
            else
            {
                WriteConsoleMessage("Account already exists...");
            }
            WriteConsoleMessage($"\tAccount Resource Id: {anfAccount.Id}");

            //-----------------------
            // Creating Capacity Pool
            //-----------------------
            CapacityPool capacityPool = await GetResourceAsync <CapacityPool>(anfClient, resourceGroupName, anfAccountName, capacityPoolName);

            if (capacityPool == null)
            {
                // Setting up capacity pool body  object
                CapacityPool capacityPoolBody = new CapacityPool()
                {
                    Location     = location.ToLower(),
                    ServiceLevel = capacityPoolServiceLevel,
                    Size         = capacitypoolSize
                };

                // Creating capacity pool
                WriteConsoleMessage("Creating capacity pool...");
                capacityPool = await anfClient.Pools.CreateOrUpdateAsync(capacityPoolBody, resourceGroupName, anfAccount.Name, capacityPoolName);
            }
            else
            {
                WriteConsoleMessage("Capacity pool already exists...");
            }
            WriteConsoleMessage($"\tCapacity Pool Resource Id: {capacityPool.Id}");

            //------------------------
            // Creating SMB Volume
            //------------------------
            string volumeName = $"Vol-{anfAccountName}-{capacityPoolName}";

            Volume volume = await GetResourceAsync <Volume>(anfClient, resourceGroupName, anfAccountName, ResourceUriUtils.GetAnfCapacityPool(capacityPool.Id), volumeName);

            if (volume == null)
            {
                string subnetId = $"/subscriptions/{subscriptionId}/resourceGroups/{vnetResourceGroupName}/providers/Microsoft.Network/virtualNetworks/{vnetName}/subnets/{subnetName}";

                // Creating volume body object
                Volume volumeBody = new Volume()
                {
                    Location       = location.ToLower(),
                    ServiceLevel   = capacityPoolServiceLevel,
                    CreationToken  = volumeName,
                    SubnetId       = subnetId,
                    UsageThreshold = volumeSize,
                    ProtocolTypes  = new List <string>()
                    {
                        "CIFS"
                    }                                             // Despite of this being a list, only one protocol is supported at this time
                };

                // Creating SMB volume
                // Please notice that the SMB Server gets created at this point by using information stored in ANF Account resource about Active Directory
                WriteConsoleMessage("Creating volume...");
                volume = await anfClient.Volumes.CreateOrUpdateAsync(volumeBody, resourceGroupName, anfAccount.Name, ResourceUriUtils.GetAnfCapacityPool(capacityPool.Id), volumeName);
            }
            else
            {
                WriteConsoleMessage("Volume already exists...");
            }
            WriteConsoleMessage($"\tVolume Resource Id: {volume.Id}");

            //// Outputs SMB Server Name
            WriteConsoleMessage($"\t====> SMB Server FQDN: {volume.MountTargets[0].SmbServerFqdn}");

            //------------------------
            // Cleaning up
            //------------------------
            if (cleanup)
            {
                WriteConsoleMessage("Cleaning up created resources...");

                WriteConsoleMessage("\tDeleting volume...");
                await anfClient.Volumes.DeleteAsync(resourceGroupName, anfAccount.Name, ResourceUriUtils.GetAnfCapacityPool(capacityPool.Id), ResourceUriUtils.GetAnfVolume(volume.Id));

                // Adding a final verification if the resource completed deletion since it may have a few secs between ARM the Resource Provider be fully in sync
                await WaitForNoAnfResource <Volume>(anfClient, volume.Id);

                Utils.WriteConsoleMessage($"\t\tDeleted volume: {volume.Id}");

                WriteConsoleMessage("\tDeleting capacity pool...");
                await anfClient.Pools.DeleteAsync(resourceGroupName, anfAccount.Name, ResourceUriUtils.GetAnfCapacityPool(capacityPool.Id));
                await WaitForNoAnfResource <CapacityPool>(anfClient, capacityPool.Id);

                Utils.WriteConsoleMessage($"\t\tDeleted capacity pool: {capacityPool.Id}");

                WriteConsoleMessage("\tDeleting account...");
                await anfClient.Accounts.DeleteAsync(resourceGroupName, anfAccount.Name);
                await WaitForNoAnfResource <NetAppAccount>(anfClient, anfAccount.Id);

                Utils.WriteConsoleMessage($"\t\tDeleted account: {anfAccount.Id}");
            }
        }