/// <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; } } }
static private async Task RunAsync() { //--------------------------------------------------------------------------------------------------------------------- // Setting variables necessary for resources creation - change these to appropriated values related to your environment //--------------------------------------------------------------------------------------------------------------------- string subscriptionId = "<subscriptionId>"; string location = "eastus2"; string resourceGroupName = "anf01-rg"; string vnetName = "vnet-02"; string subnetName = "anf-sn"; string vnetResourceGroupName = "anf01-rg"; string anfAccountName = "anfaccount03"; string capacityPoolName = "Pool01"; string capacityPoolServiceLevel = "Standard"; long capacitypoolSize = 4398046511104; // 4TiB which is minimum size long volumeSize = 107374182400; // 100GiB - volume minimum size //---------------------------------------------------------------------------------------- // 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 //---------------------- // Setting up NetApp Files account body object NetAppAccount anfAccountBody = new NetAppAccount(location, null, anfAccountName); // Requesting account to be created WriteConsoleMessage("Requesting account to be created..."); var anfAccount = await anfClient.Accounts.CreateOrUpdateAsync(anfAccountBody, resourceGroupName, anfAccountName); WriteConsoleMessage($"\tAccount Resource Id: {anfAccount.Id}"); //----------------------- // Creating Capacity Pool //----------------------- // Setting up capacity pool body object CapacityPool capacityPoolBody = new CapacityPool() { Location = location.ToLower(), // Important: location needs to be lower case ServiceLevel = capacityPoolServiceLevel, Size = capacitypoolSize }; // Creating capacity pool WriteConsoleMessage("Requesting capacity pool to be created..."); var capacityPool = await anfClient.Pools.CreateOrUpdateAsync(capacityPoolBody, resourceGroupName, anfAccount.Name, capacityPoolName); WriteConsoleMessage($"\tCapacity Pool Resource Id: {capacityPool.Id}"); //------------------------ // Creating NFS 4.1 Volume //------------------------ // Creating export policy object VolumePropertiesExportPolicy exportPolicies = new VolumePropertiesExportPolicy() { Rules = new List <ExportPolicyRule> { new ExportPolicyRule() { AllowedClients = "0.0.0.0", Cifs = false, Nfsv3 = false, Nfsv41 = true, RuleIndex = 1, UnixReadOnly = false, UnixReadWrite = true } } }; // Creating volume body object string subnetId = $"/subscriptions/{subscriptionId}/resourceGroups/{vnetResourceGroupName}/providers/Microsoft.Network/virtualNetworks/{vnetName}/subnets/{subnetName}"; string volumeName = $"Vol-{anfAccountName}-{capacityPoolName}"; Volume volumeBody = new Volume() { ExportPolicy = exportPolicies, Location = location.ToLower(), ServiceLevel = capacityPoolServiceLevel, CreationToken = volumeName, SubnetId = subnetId, UsageThreshold = volumeSize, ProtocolTypes = new List <string>() { "NFSv4.1" } }; // Creating NFS 4.1 volume WriteConsoleMessage("Requesting volume to be created..."); var volume = await anfClient.Volumes.CreateOrUpdateAsync(volumeBody, resourceGroupName, anfAccount.Name, ResourceUriUtils.GetAnfCapacityPool(capacityPool.Id), volumeName); WriteConsoleMessage($"\tVolume Resource Id: {volume.Id}"); //------------------------ // Cleaning up //------------------------ //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}"); }
/// <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); }
/// <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}"); } }
static private async Task CreateANFCRRAsync() { //---------------------------------------------------------------------------------------- // Authenticating using service principal, refer to README.md file for requirement details //---------------------------------------------------------------------------------------- WriteConsoleMessage("Authenticating..."); 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 Primary Account //---------------------- // Setting up Primary NetApp Files account body object NetAppAccount anfPrimaryAccountBody = new NetAppAccount(primaryLocation, null, primaryAnfAccountName); WriteConsoleMessage($"Requesting Primary account to be created in {primaryLocation}"); var anfPrimaryAccount = await anfClient.Accounts.CreateOrUpdateAsync(anfPrimaryAccountBody, primaryResourceGroupName, primaryAnfAccountName); WriteConsoleMessage($"\tAccount Resource Id: {anfPrimaryAccount.Id}"); // Setting up capacity pool body object for Primary Account CapacityPool primaryCapacityPoolBody = new CapacityPool() { Location = primaryLocation.ToLower(), // Important: location needs to be lower case ServiceLevel = ServiceLevel.Premium, //Service level can be one of three levels -> { Standard, Premium, Ultra } Size = capacitypoolSize }; WriteConsoleMessage("Requesting capacity pool to be created for Primary Account"); var primaryCapacityPool = await anfClient.Pools.CreateOrUpdateAsync(primaryCapacityPoolBody, primaryResourceGroupName, anfPrimaryAccount.Name, primarycapacityPoolName); WriteConsoleMessage($"\tCapacity Pool Resource Id: {primaryCapacityPool.Id}"); // Creating export policy object VolumePropertiesExportPolicy exportPolicies = new VolumePropertiesExportPolicy() { Rules = new List <ExportPolicyRule> { new ExportPolicyRule() { AllowedClients = "0.0.0.0", Cifs = false, Nfsv3 = false, Nfsv41 = true, RuleIndex = 1, UnixReadOnly = false, UnixReadWrite = true } } }; // Creating primary volume body object string primarySubnetId = $"/subscriptions/{subscriptionId}/resourceGroups/{primaryResourceGroupName}/providers/Microsoft.Network/virtualNetworks/{primaryVNETName}/subnets/{primarySubnetName}"; Volume primaryVolumeBody = new Volume() { ExportPolicy = exportPolicies, Location = primaryLocation.ToLower(), ServiceLevel = ServiceLevel.Premium, //Service level can be one of three levels -> { Standard, Premium, Ultra } CreationToken = primaryVolumeName, SubnetId = primarySubnetId, UsageThreshold = volumeSize, ProtocolTypes = new List <string>() { "NFSv4.1" } }; // Creating NFS 4.1 volume WriteConsoleMessage($"Requesting volume to be created in {primarycapacityPoolName}"); var primaryVolume = await anfClient.Volumes.CreateOrUpdateAsync(primaryVolumeBody, primaryResourceGroupName, primaryAnfAccountName, ResourceUriUtils.GetAnfCapacityPool(primaryCapacityPool.Id), primaryVolumeName); WriteConsoleMessage($"\tVolume Resource Id: {primaryVolume.Id}"); WriteConsoleMessage($"Waiting for {primaryVolume.Id} to be available..."); await ResourceUriUtils.WaitForAnfResource <Volume>(anfClient, primaryVolume.Id); //---------------------- // Creating ANF Secondary Account //---------------------- // Setting up Secondary NetApp Files account body object NetAppAccount anfSecondaryAccountBody = new NetAppAccount(secondaryLocation, null, secondaryAnfAccountName); WriteConsoleMessage($"Requesting Secondary account to be created in {secondaryLocation}"); var anfSecondaryAccount = await anfClient.Accounts.CreateOrUpdateAsync(anfSecondaryAccountBody, secondaryResourceGroupName, secondaryAnfAccountName); WriteConsoleMessage($"\tAccount Resource Id: {anfSecondaryAccount.Id}"); // Setting up capacity pool body object for Secondary Account CapacityPool secondaryCapacityPoolBody = new CapacityPool() { Location = secondaryLocation.ToLower(), // Important: location needs to be lower case ServiceLevel = ServiceLevel.Standard, //Service level can be one of three levels -> { Standard, Premium, Ultra } Size = capacitypoolSize }; WriteConsoleMessage("Requesting capacity pool to be created for Secondary Account"); var secondaryCapacityPool = await anfClient.Pools.CreateOrUpdateAsync(secondaryCapacityPoolBody, secondaryResourceGroupName, anfSecondaryAccount.Name, secondarycapacityPoolName); WriteConsoleMessage($"\tCapacity Pool Resource Id: {secondaryCapacityPool.Id}"); // Creating secondary volume body object string secondarySubnetId = $"/subscriptions/{subscriptionId}/resourceGroups/{secondaryResourceGroupName}/providers/Microsoft.Network/virtualNetworks/{secondaryVNETName}/subnets/{secondarySubnetName}"; Volume secondaryVolumeBody = new Volume() { ExportPolicy = exportPolicies, Location = secondaryLocation.ToLower(), ServiceLevel = ServiceLevel.Standard, //Service level can be one of three levels -> { Standard, Premium, Ultra }, CreationToken = secondaryVolumeName, SubnetId = secondarySubnetId, UsageThreshold = volumeSize, ProtocolTypes = new List <string>() { "NFSv4.1" }, VolumeType = "DataProtection", DataProtection = new VolumePropertiesDataProtection() { Replication = new ReplicationObject() { EndpointType = "dst", RemoteVolumeRegion = primaryLocation, RemoteVolumeResourceId = primaryVolume.Id, ReplicationSchedule = "_10minutely" } } }; //------------------------------------------------------------- // Creating Data Replication Volume on the Destination Account //------------------------------------------------------------- // Creating NFS 4.1 Data Replication Volume WriteConsoleMessage("Adding Data Replication in Destination region..."); var dataReplicationVolume = await anfClient.Volumes.CreateOrUpdateAsync(secondaryVolumeBody, secondaryResourceGroupName, anfSecondaryAccount.Name, ResourceUriUtils.GetAnfCapacityPool(secondaryCapacityPool.Id), secondaryVolumeName); //Wait for Data Replication Volume to get be ready WriteConsoleMessage($"Waiting for {dataReplicationVolume.Id} to be available..."); await ResourceUriUtils.WaitForAnfResource <Volume>(anfClient, dataReplicationVolume.Id); //-------------------------- // Authorizing Source volume //-------------------------- AuthorizeRequest authRequest = new AuthorizeRequest() { RemoteVolumeResourceId = dataReplicationVolume.Id }; WriteConsoleMessage("Authorizing replication in Source region..."); await anfClient.Volumes.AuthorizeReplicationAsync(primaryResourceGroupName, primaryAnfAccountName, ResourceUriUtils.GetAnfCapacityPool(primaryCapacityPool.Id), primaryVolumeName, authRequest); WriteConsoleMessage("ANF Cross-Region Replication has completed successfully"); //----------------------------------------- // Clean up Resources //----------------------------------------- if (shouldCleanUp) { //Wait for replication status to be "Mirrored" WriteConsoleMessage("Checking replication status to become Mirrored before start deleting..."); await ResourceUriUtils.WaitForCompleteReplicationStatus(anfClient, dataReplicationVolume.Id); // Break the replication WriteConsoleMessage("Breaking the replication connection"); await anfClient.Volumes.BreakReplicationAsync(secondaryResourceGroupName, secondaryAnfAccountName, ResourceUriUtils.GetAnfCapacityPool(secondaryCapacityPool.Id), secondaryVolumeName); // Check if replication status is "Broken" WriteConsoleMessage("Checking replication status to become Broken... "); await ResourceUriUtils.WaitForBrokenReplicationStatus(anfClient, dataReplicationVolume.Id); // Delete replication and send confirmation to Source volume WriteConsoleMessage("Deleting the replication connection on the destination volume"); await anfClient.Volumes.DeleteReplicationAsync(secondaryResourceGroupName, secondaryAnfAccountName, ResourceUriUtils.GetAnfCapacityPool(secondaryCapacityPool.Id), secondaryVolumeName); // Delete secondary ANF resources WriteConsoleMessage("Deleting Secondary ANF resources..."); WriteConsoleMessage("Deleting Secondary Volume"); await anfClient.Volumes.DeleteAsync(secondaryResourceGroupName, secondaryAnfAccountName, ResourceUriUtils.GetAnfCapacityPool(secondaryCapacityPool.Id), secondaryVolumeName); // Wait for Data replication volume to be fully deleted await ResourceUriUtils.WaitForNoAnfResource <Volume>(anfClient, dataReplicationVolume.Id); // Delete secondary Capacity Pool WriteConsoleMessage("Deleting Secondary Capacity Pool"); await anfClient.Pools.DeleteAsync(secondaryResourceGroupName, secondaryAnfAccountName, ResourceUriUtils.GetAnfCapacityPool(secondaryCapacityPool.Id)); // wait for secondary Capacity Pool to be fully deleted await ResourceUriUtils.WaitForNoAnfResource <CapacityPool>(anfClient, secondaryCapacityPool.Id); // Delete Secondary ANF account WriteConsoleMessage("Deleting Secondary Account"); await anfClient.Accounts.DeleteAsync(secondaryResourceGroupName, secondaryAnfAccountName); // Delete primary ANF resources WriteConsoleMessage("Deleting Primary ANF resources..."); WriteConsoleMessage("Deleting Primary Volume"); await anfClient.Volumes.DeleteAsync(primaryResourceGroupName, primaryAnfAccountName, ResourceUriUtils.GetAnfCapacityPool(primaryCapacityPool.Id), primaryVolumeName); // Wait for primary Volume to be fully deleted await ResourceUriUtils.WaitForNoAnfResource <Volume>(anfClient, primaryVolume.Id); // Delete primary capacity pool WriteConsoleMessage("Deleting Primary Capacity Pool"); await anfClient.Pools.DeleteAsync(primaryResourceGroupName, primaryAnfAccountName, ResourceUriUtils.GetAnfCapacityPool(primaryCapacityPool.Id)); // Wait for primary capacity pool to be fully deleted await ResourceUriUtils.WaitForNoAnfResource <CapacityPool>(anfClient, primaryCapacityPool.Id); // Delete Primary ANF account WriteConsoleMessage("Deleting Primary Account"); await anfClient.Accounts.DeleteAsync(primaryResourceGroupName, primaryAnfAccountName); } }
private static async Task CreateANFAsync() { //---------------------------------------------------------------------------------------- // Authenticating using service principal, refer to README.md file for requirement details //---------------------------------------------------------------------------------------- WriteConsoleMessage("Authenticating..."); 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 //---------------------- WriteConsoleMessage($"Requesting ANF Account to be created in {location}"); var newAccount = await Creation.CreateOrUpdateANFAccountAsync(anfClient, resourceGroupName, location, anfAccountName); WriteConsoleMessage($"\tAccount Resource Id: {newAccount.Id}"); //---------------------- // Creating Snapshot Policy //---------------------- WriteConsoleMessage("Creating Snapshot policy ..."); var newSnapshotPolicy = await Creation.CreateANFSnapshotPolicy(anfClient, resourceGroupName, location, anfAccountName, snapshotPolicyName); WriteConsoleMessage($"\tSnapshot resource Id: {newSnapshotPolicy.Id}"); //---------------------- // Creating ANF Capacity Pool //---------------------- WriteConsoleMessage($"Requesting ANF Primary Capacity Pool to be created in {location}"); var newPool = await Creation.CreateOrUpdateANFCapacityPoolAsync(anfClient, resourceGroupName, location, anfAccountName, capacityPoolName, capacitypoolSize, capacityPoolServiceLevel); WriteConsoleMessage($"\tCapacity Pool Resource Id: {newPool.Id}"); //---------------------- // Creating ANF Volume //---------------------- WriteConsoleMessage($"Requesting ANF Volume to be created in {location} with Snapshot Policy {snapshotPolicyName} attached"); var newVolume = await Creation.CreateOrUpdateANFVolumeAsync(anfClient, resourceGroupName, location, anfAccountName, capacityPoolName, capacityPoolServiceLevel, anfVolumeName, subnetId, volumeSize, newSnapshotPolicy.Id); WriteConsoleMessage($"\tVolume Resource Id: {newVolume.Id}"); WriteConsoleMessage($"Waiting for {newVolume.Id} to be available..."); await ResourceUriUtils.WaitForAnfResource <Volume>(anfClient, newVolume.Id); //---------------------- // Updating Snapshot Policy //---------------------- WriteConsoleMessage("Updating Snapshot policy ..."); var currentSnapshotPolicy = await Update.UpdateANFSnapshotPolicy(anfClient, resourceGroupName, location, anfAccountName, snapshotPolicyName, newSnapshotPolicy.HourlySchedule); WriteConsoleMessage($"\tSnapshot resource has been updating successfully. Id: {currentSnapshotPolicy.Id}"); if (shouldCleanUp) { WriteConsoleMessage("-------------------------"); WriteConsoleMessage("Cleaning up ANF resources"); WriteConsoleMessage("-------------------------"); WriteConsoleMessage("waiting for snapshot policy to complete updating before start cleaning up resources."); Thread.Sleep(5000); // Deleting Volume in the secondary pool first WriteConsoleMessage("Deleting Volume..."); await Deletion.DeleteANFVolumeAsync(anfClient, resourceGroupName, anfAccountName, capacityPoolName, anfVolumeName); await ResourceUriUtils.WaitForNoAnfResource <Volume>(anfClient, newVolume.Id); // Deleting Primary Pool WriteConsoleMessage("Deleting Capacity Pool..."); await Deletion.DeleteANFCapacityPoolAsync(anfClient, resourceGroupName, anfAccountName, capacityPoolName); await ResourceUriUtils.WaitForNoAnfResource <CapacityPool>(anfClient, newPool.Id); //Deleting Snapshot Policy WriteConsoleMessage("Deleting Snapshot Policy ..."); await Deletion.DeleteANFSnapshotPolicy(anfClient, resourceGroupName, anfAccountName, snapshotPolicyName); //Deleting Account WriteConsoleMessage("Deleting Account ..."); await Deletion.DeleteANFAccountAsync(anfClient, resourceGroupName, anfAccountName); await ResourceUriUtils.WaitForNoAnfResource <NetAppAccount>(anfClient, newAccount.Id); } }
private static async Task CreateANFAsync() { //---------------------------------------------------------------------------------------- // Authenticating using service principal, refer to README.md file for requirement details //---------------------------------------------------------------------------------------- WriteConsoleMessage("Authenticating..."); 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}"); //---------------------------- // Get Certification encoding //---------------------------- var bytes = Encoding.UTF8.GetBytes(Utils.GetFileContent(rootCACertFullFilePath)); var encodedCertContent = Convert.ToBase64String(bytes); //---------------------- // Creating ANF Account //---------------------- WriteConsoleMessage($"Requesting ANF Account to be created in {location}"); var newAccount = await Creation.CreateOrUpdateANFAccountAsync(anfClient, resourceGroupName, location, anfAccountName, domainJoinUsername, domainJoinPassword, dnsList, adFQDN, smbServerNamePrefix, encodedCertContent); WriteConsoleMessage($"\tAccount Resource Id: {newAccount.Id}"); //---------------------- // Creating ANF Capacity Pool //---------------------- WriteConsoleMessage($"Requesting ANF Primary Capacity Pool to be created in {location}"); var newPrimaryPool = await Creation.CreateOrUpdateANFCapacityPoolAsync(anfClient, resourceGroupName, location, anfAccountName, capacityPoolName, capacitypoolSize, capacityPoolServiceLevel); WriteConsoleMessage($"\tCapacity Pool Resource Id: {newPrimaryPool.Id}"); //---------------------- // Creating ANF Volume //---------------------- WriteConsoleMessage($"Requesting ANF Volume to be created in {location}"); var newVolume = await Creation.CreateOrUpdateANFVolumeAsync(anfClient, resourceGroupName, location, anfAccountName, capacityPoolName, capacityPoolServiceLevel, anfVolumeName, subnetId, volumeSize); WriteConsoleMessage($"\tVolume Resource Id: {newVolume.Id}"); WriteConsoleMessage($"Waiting for {newVolume.Id} to be available..."); await ResourceUriUtils.WaitForAnfResource <Volume>(anfClient, newVolume.Id); //-------------------- // Clean Up Resources //-------------------- if (shouldCleanUp) { WriteConsoleMessage("-------------------------"); WriteConsoleMessage("Cleaning up ANF resources"); WriteConsoleMessage("-------------------------"); // Deleting Volume in the secondary pool first WriteConsoleMessage("Deleting Dual-Protocol Volume..."); await Deletion.DeleteANFVolumeAsync(anfClient, resourceGroupName, anfAccountName, capacityPoolName, anfVolumeName); await ResourceUriUtils.WaitForNoAnfResource <Volume>(anfClient, newVolume.Id); // Deleting Primary Pool WriteConsoleMessage("Deleting Capacity Pool..."); await Deletion.DeleteANFCapacityPoolAsync(anfClient, resourceGroupName, anfAccountName, capacityPoolName); await ResourceUriUtils.WaitForNoAnfResource <CapacityPool>(anfClient, newPrimaryPool.Id); //Deleting Account WriteConsoleMessage("Deleting Account ..."); await Deletion.DeleteANFAccountAsync(anfClient, resourceGroupName, anfAccountName); await ResourceUriUtils.WaitForNoAnfResource <NetAppAccount>(anfClient, newAccount.Id); } }
private static async Task CreateANFAsync() { //---------------------------------------------------------------------------------------- // Authenticating using service principal, refer to README.md file for requirement details //---------------------------------------------------------------------------------------- WriteConsoleMessage("Authenticating..."); 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 //---------------------- WriteConsoleMessage($"Requesting ANF Account to be created in {location}"); var newAccount = await Creation.CreateOrUpdateANFAccountAsync(anfClient, resourceGroupName, location, anfAccountName); WriteConsoleMessage($"\tAccount Resource Id: {newAccount.Id}"); //---------------------- // Creating ANF Primary Capacity Pool //---------------------- WriteConsoleMessage($"Requesting ANF Primary Capacity Pool to be created in {location}"); var newPrimaryPool = await Creation.CreateOrUpdateANFCapacityPoolAsync(anfClient, resourceGroupName, location, anfAccountName, primaryCapacityPoolName, capacitypoolSize, primaryCapacityPoolServiceLevel); WriteConsoleMessage($"\tAccount Resource Id: {newPrimaryPool.Id}"); //---------------------- // Creating ANF Secondary Capacity Pool //---------------------- WriteConsoleMessage($"Requesting ANF Secondary Capacity Pool to be created in {location}"); var newSecondaryPool = await Creation.CreateOrUpdateANFCapacityPoolAsync(anfClient, resourceGroupName, location, anfAccountName, secondaryCapacityPoolName, capacitypoolSize, SecondaryCapacityPoolServiceLevel); WriteConsoleMessage($"\tAccount Resource Id: {newSecondaryPool.Id}"); //---------------------- // Creating ANF Volume //---------------------- WriteConsoleMessage($"Requesting ANF Volume to be created in {location}"); var newVolume = await Creation.CreateOrUpdateANFVolumeAsync(anfClient, resourceGroupName, location, anfAccountName, primaryCapacityPoolName, primaryCapacityPoolServiceLevel, anfVolumeName, subnetId, volumeSize); WriteConsoleMessage($"\tAccount Resource Id: {newVolume.Id}"); WriteConsoleMessage($"Waiting for {newVolume.Id} to be available..."); await ResourceUriUtils.WaitForAnfResource <Volume>(anfClient, newVolume.Id); //---------------------------------- // Change ANF Volume's Capacity Pool //---------------------------------- WriteConsoleMessage("Performing Pool Change. Updating volume..."); await Update.ChangeVolumeCapacityPoolAsync(anfClient, resourceGroupName, anfAccountName, primaryCapacityPoolName, anfVolumeName, newSecondaryPool.Id); WriteConsoleMessage($"\tPool change is successful. Moved volume from {primaryCapacityPoolName} to {secondaryCapacityPoolName}"); //-------------------- // Clean Up Resources //-------------------- if (shouldCleanUp) { WriteConsoleMessage("-------------------------"); WriteConsoleMessage("Cleaning up ANF resources"); WriteConsoleMessage("-------------------------"); // Deleting Volume in the secondary pool first WriteConsoleMessage("Deleting Volume in the secondary Pool..."); var volume = await anfClient.Volumes.GetAsync(resourceGroupName, anfAccountName, secondaryCapacityPoolName, anfVolumeName); await Deletion.DeleteANFVolumeAsync(anfClient, resourceGroupName, anfAccountName, secondaryCapacityPoolName, anfVolumeName); await ResourceUriUtils.WaitForNoAnfResource <Volume>(anfClient, volume.Id); // Deleting Primary Pool WriteConsoleMessage("Deleting primary Pool..."); await Deletion.DeleteANFCapacityPoolAsync(anfClient, resourceGroupName, anfAccountName, primaryCapacityPoolName); await ResourceUriUtils.WaitForNoAnfResource <CapacityPool>(anfClient, newPrimaryPool.Id); // Deleting Secondary pool WriteConsoleMessage("Deleting secondary Pool..."); await Deletion.DeleteANFCapacityPoolAsync(anfClient, resourceGroupName, anfAccountName, secondaryCapacityPoolName); await ResourceUriUtils.WaitForNoAnfResource <CapacityPool>(anfClient, newSecondaryPool.Id); //Deleting Account WriteConsoleMessage("Deleting Account ..."); await Deletion.DeleteANFAccountAsync(anfClient, resourceGroupName, anfAccountName); await ResourceUriUtils.WaitForNoAnfResource <NetAppAccount>(anfClient, newAccount.Id); } }