public static void Print(ArmDisasterRecovery resource) { StringBuilder info = new StringBuilder(); info.Append("DisasterRecoveryPairing: ").Append(resource.Id) .Append("\n\tName: ").Append(resource.Name) .Append("\n\tAlternate name: ").Append(resource.AlternateName) .Append("\n\tPartner namespace: ").Append(resource.PartnerNamespace) .Append("\n\tNamespace role: ").Append(resource.Role); Utilities.Log(info.ToString()); }
public PSEventHubDRConfigurationAttributes(ArmDisasterRecovery drResource) { if (drResource != null) { Name = drResource.Name; Id = drResource.Id; Type = drResource.Type; ProvisioningState = drResource.ProvisioningState; PartnerNamespace = drResource.PartnerNamespace; Role = drResource.Role; AlternateName = drResource.AlternateName; } }
public PSServiceBusDRConfigurationAttributes(ArmDisasterRecovery drResource) { if (drResource != null) { Name = drResource.Name; Id = drResource.Id; Type = drResource.Type; ProvisioningState = drResource.ProvisioningState; PartnerNamespace = drResource.PartnerNamespace; Role = drResource.Role; AlternateName = drResource.AlternateName; PendingReplicationOperationsCount = drResource.PendingReplicationOperationsCount; } }
/// <summary> /// Creates or updates a new Alias(Disaster Recovery configuration) /// </summary> /// <param name='operations'> /// The operations group for this extension method. /// </param> /// <param name='resourceGroupName'> /// Name of the resource group within the azure subscription. /// </param> /// <param name='namespaceName'> /// The Namespace name /// </param> /// <param name='alias'> /// The Disaster Recovery configuration name /// </param> /// <param name='parameters'> /// Parameters required to create an Alias(Disaster Recovery configuration) /// </param> /// <param name='cancellationToken'> /// The cancellation token. /// </param> public static async Task <ArmDisasterRecovery> CreateOrUpdateAsync(this IDisasterRecoveryConfigsOperations operations, string resourceGroupName, string namespaceName, string alias, ArmDisasterRecovery parameters, CancellationToken cancellationToken = default(CancellationToken)) { using (var _result = await operations.CreateOrUpdateWithHttpMessagesAsync(resourceGroupName, namespaceName, alias, parameters, null, cancellationToken).ConfigureAwait(false)) { return(_result.Body); } }
/// <summary> /// Creates or updates a new Alias(Disaster Recovery configuration) /// </summary> /// <param name='operations'> /// The operations group for this extension method. /// </param> /// <param name='resourceGroupName'> /// Name of the resource group within the azure subscription. /// </param> /// <param name='namespaceName'> /// The Namespace name /// </param> /// <param name='alias'> /// The Disaster Recovery configuration name /// </param> /// <param name='parameters'> /// Parameters required to create an Alias(Disaster Recovery configuration) /// </param> public static ArmDisasterRecovery CreateOrUpdate(this IDisasterRecoveryConfigsOperations operations, string resourceGroupName, string namespaceName, string alias, ArmDisasterRecovery parameters) { return(operations.CreateOrUpdateAsync(resourceGroupName, namespaceName, alias, parameters).GetAwaiter().GetResult()); }
public virtual Response <ArmDisasterRecovery> CreateOrUpdate(string resourceGroupName, string namespaceName, string @alias, ArmDisasterRecovery parameters, CancellationToken cancellationToken = default) { using var scope = _clientDiagnostics.CreateScope("DisasterRecoveryConfigsOperations.CreateOrUpdate"); scope.Start(); try { return(RestClient.CreateOrUpdate(resourceGroupName, namespaceName, @alias, parameters, cancellationToken)); } catch (Exception e) { scope.Failed(e); throw; } }
//Azure Event Hub sample for managing geo disaster recovery pairing - // - Create two event hub namespaces // - Create a pairing between two namespaces // - Create an event hub in the primary namespace and retrieve it from the secondary namespace // - Retrieve the pairing connection string // - Fail over so that secondary namespace become primary. public static async Task RunSample(TokenCredential credential) { string region = "eastus"; string subscriptionId = Environment.GetEnvironmentVariable("AZURE_SUBSCRIPTION_ID"); string rgName = Utilities.RandomResourceName("rgeh", 15); string primaryNamespaceName = Utilities.RandomResourceName("ns", 15); string secondaryNamespaceName = Utilities.RandomResourceName("ns", 15); string geoDRName = Utilities.RandomResourceName("geodr", 14); string eventHubName = Utilities.RandomResourceName("eh", 14); bool isFailOverSucceeded = false; ArmDisasterRecovery pairing = null; var eventHubsManagementClient = new EventHubsManagementClient(subscriptionId, credential); var namespaces = eventHubsManagementClient.Namespaces; var eventHubs = eventHubsManagementClient.EventHubs; var consumerGroups = eventHubsManagementClient.ConsumerGroups; var disasterRecoveryConfigs = eventHubsManagementClient.DisasterRecoveryConfigs; try { await ResourceGroupHelper.CreateOrUpdateResourceGroup(rgName, region); // Create resource group for the namespaces and recovery pairings Utilities.Log($"Creating primary event hub namespace {primaryNamespaceName}"); var primaryResult = await namespaces.StartCreateOrUpdateAsync( rgName, primaryNamespaceName, new EHNamespace { Location = "southcentralus" }); var primaryNamespace = (await primaryResult.WaitForCompletionAsync()).Value; Utilities.Log("Primary event hub namespace created"); Utilities.Print(primaryNamespace); Utilities.Log($"Creating secondary event hub namespace {primaryNamespaceName}"); var secondaryResult = await namespaces.StartCreateOrUpdateAsync( rgName, secondaryNamespaceName, new EHNamespace { Location = "northcentralus" }); var secondaryNamespace = (await secondaryResult.WaitForCompletionAsync()).Value; Utilities.Log("Secondary event hub namespace created"); Utilities.Print(secondaryNamespace); // Create primary and secondary namespaces and recovery pairing Utilities.Log($"Creating geo-disaster recovery pairing {geoDRName}"); pairing = (await disasterRecoveryConfigs.CreateOrUpdateAsync( rgName, primaryNamespaceName, geoDRName, new ArmDisasterRecovery { PartnerNamespace = secondaryNamespace.Id } )).Value; while ((await disasterRecoveryConfigs.GetAsync(rgName, primaryNamespaceName, geoDRName)).Value.ProvisioningState != ProvisioningStateDR.Succeeded) { Utilities.Log("Wait for create disaster recovery"); Thread.Sleep(15 * 1000); if (pairing.ProvisioningState == ProvisioningStateDR.Failed) { throw new Exception("Provisioning state of the pairing is FAILED"); } } Utilities.Log($"Created geo-disaster recovery pairing {geoDRName}"); Utilities.Print(pairing); // Create an event hub and consumer group in primary namespace Utilities.Log("Creating an event hub and consumer group in primary namespace"); var primaryEventHub = (await eventHubs.CreateOrUpdateAsync( rgName, primaryNamespaceName, eventHubName, new Eventhub() )).Value; var primaryConsumerGroup = (await consumerGroups.CreateOrUpdateAsync( rgName, primaryNamespaceName, eventHubName, "consumerGrp1", new ConsumerGroup() )).Value; var eventHubInPrimaryNamespace = (await namespaces.GetAsync(rgName, primaryNamespaceName)).Value; Utilities.Log("Created event hub and consumer group in primary namespace"); Utilities.Print(eventHubInPrimaryNamespace); Utilities.Log("Waiting for 60 seconds to allow metadata to sync across primary and secondary"); Thread.Sleep(60 * 1000); // Wait for syncing to finish Utilities.Log("Retrieving the event hubs in secondary namespace"); var eventHubInSecondaryNamespace = (await namespaces.GetAsync(rgName, secondaryNamespaceName)).Value; Utilities.Log("Retrieved the event hubs in secondary namespace"); Utilities.Print(eventHubInSecondaryNamespace); // Retrieving the connection string var rules = await disasterRecoveryConfigs.ListAuthorizationRulesAsync(rgName, primaryNamespaceName, geoDRName).ToEnumerableAsync(); foreach (var rule in rules) { var key = (await disasterRecoveryConfigs.ListKeysAsync(rgName, primaryNamespaceName, geoDRName, rule.Name)).Value; Utilities.Print(key); } Utilities.Log("Initiating fail over"); var failOverResult = await disasterRecoveryConfigs.FailOverAsync(rgName, secondaryNamespaceName, geoDRName); Thread.Sleep(10 * 1000); while ((await disasterRecoveryConfigs.GetAsync(rgName, secondaryNamespaceName, geoDRName)).Value.ProvisioningState == ProvisioningStateDR.Accepted) { Utilities.Log("Wait for fail over"); Thread.Sleep(10 * 1000); } if ((await disasterRecoveryConfigs.GetAsync(rgName, secondaryNamespaceName, geoDRName)).Value.ProvisioningState == ProvisioningStateDR.Succeeded) { isFailOverSucceeded = true; Utilities.Log("Fail over initiated"); } else { Utilities.Log("Fail over is FAILED"); } } finally { try { try { // It is necessary to break pairing before deleting resource group if (pairing != null && !isFailOverSucceeded) { await disasterRecoveryConfigs.BreakPairingAsync(rgName, primaryNamespaceName, geoDRName); Thread.Sleep(10 * 1000); while ((await disasterRecoveryConfigs.GetAsync(rgName, primaryNamespaceName, geoDRName)).Value.ProvisioningState == ProvisioningStateDR.Accepted) { Thread.Sleep(10 * 1000); } if ((await disasterRecoveryConfigs.GetAsync(rgName, primaryNamespaceName, geoDRName)).Value.ProvisioningState == ProvisioningStateDR.Failed) { throw new Exception("Provisioning state of the break pairing is FAILED"); } } } catch (Exception ex) { Utilities.Log("Pairing breaking failed:" + ex.Message); } await ResourceGroupHelper.DeleteResourceGroup(rgName); } catch (NullReferenceException) { Utilities.Log("Did not create any resources in Azure. No clean up is necessary"); } catch (Exception ex) { Utilities.Log(ex); } } }
private async Task <int> CreatePairingAsync(string[] args) { var config = LoadConfig(args[1]); var client = await GetClientAsync(config); // 1. Create Primary Namespace (optional) await CreateOrUpdateNamespaceAsync( client, config.PrimaryResourceGroupName, config.PrimaryNamespace, config.PrimaryNamespaceLocation, config.SkuName); //// 2. Create Secondary Namespace (optional if you already have an empty namespace available) await CreateOrUpdateNamespaceAsync( client, config.SecondaryResourceGroupName, config.SecondaryNamespace, config.SecondaryNamespaceLocation, config.SkuName); // 3. Pair the namespaces to enable DR. // If you re-run this program while namespaces are still paired this operation will fail with a bad request. // This is because we block all updates on secondary namespaces once it is paired ArmDisasterRecovery adr = await client.DisasterRecoveryConfigs.CreateOrUpdateAsync( config.PrimaryResourceGroupName, config.PrimaryNamespace, config.Alias, new ArmDisasterRecovery() { PartnerNamespace = config.SecondaryNamespace }); while (adr.ProvisioningState != ProvisioningStateDR.Succeeded) { Console.WriteLine($"Waiting for DR to be setup. Current State: {adr.ProvisioningState}"); adr = await client.DisasterRecoveryConfigs.GetAsync( config.PrimaryResourceGroupName, config.PrimaryNamespace, config.Alias); await Task.Delay(TimeSpan.FromSeconds(30)); } Console.WriteLine($"Pairing namespaces completed. Details: {Environment.NewLine}{adr.ToJson()}"); // Perform verifications (optional) const string eventHubName = "myEH1"; const string consumerGroupName = "myEH1-CG1"; const int syncingDelay = 60; // Create an event hub and a consumer group within it. This is metadata and this metadata info replicates to the secondary namespace // since we have established the Geo DR pairing earlier. await client.EventHubs.CreateOrUpdateAsync(config.PrimaryResourceGroupName, config.PrimaryNamespace, eventHubName, new Eventhub()); await client.ConsumerGroups.CreateOrUpdateAsync(config.PrimaryResourceGroupName, config.PrimaryNamespace, eventHubName, consumerGroupName, new ConsumerGroup()); Console.WriteLine($"Waiting for {syncingDelay}s to allow metadata to sync across primary and secondary..."); await Task.Delay(TimeSpan.FromSeconds(syncingDelay)); // Verify that EventHubs and Consumer groups are present in secondary var accessingEHFromSecondary = await client.EventHubs.GetAsync(config.SecondaryResourceGroupName, config.SecondaryNamespace, eventHubName); Console.WriteLine($"{accessingEHFromSecondary.Name} successfully replicated"); var accessingCGFromSecondary = await client.ConsumerGroups.GetAsync(config.SecondaryResourceGroupName, config.SecondaryNamespace, eventHubName, consumerGroupName); Console.WriteLine($"{accessingCGFromSecondary.Name} successfully replicated"); return(0); }
static async Task CreatePairing() { // https://msdn.microsoft.com/en-us/library/azure/dn790557.aspx#bk_portal string token = await GetAuthorizationHeaderAsync().ConfigureAwait(false); TokenCredentials creds = new TokenCredentials(token); ServiceBusManagementClient client = new ServiceBusManagementClient(creds) { SubscriptionId = subscriptionId }; // 1. Create Primary Namespace (optional) Console.WriteLine("Create or update namespace 1"); var namespaceParams = new SBNamespace { Location = "South Central US", Sku = new SBSku { Name = SkuName.Premium, Capacity = 1 } }; var namespace1 = await client.Namespaces.CreateOrUpdateAsync(resourceGroupName, geoDRPrimaryNS, namespaceParams) .ConfigureAwait(false); // 2. Create Secondary Namespace (optional if you already have an empty namespace available) Console.WriteLine("Create or update namespace 2"); var namespaceParams2 = new SBNamespace { Location = "North Central US", Sku = new SBSku { Name = SkuName.Premium, Capacity = 1 } }; // If you re-run this program while namespaces are still paired this operation will fail with a bad request. // this is because we block all updates on secondary namespaces once it is paired var namespace2 = await client.Namespaces.CreateOrUpdateAsync(resourceGroupName, geoDRSecondaryNS, namespaceParams2) .ConfigureAwait(false); // 3. Pair the namespaces to enable DR. Console.WriteLine("Starting Pairing"); ArmDisasterRecovery drStatus = await client.DisasterRecoveryConfigs.CreateOrUpdateAsync( resourceGroupName, geoDRPrimaryNS, alias, new ArmDisasterRecovery { PartnerNamespace = namespace2.Id, AlternateName = alternateName }) // Note: The additional, optional parameter AlternateName is resposible for using the namespace name as alias and renaming the primary namespace. .ConfigureAwait(false); while (drStatus.ProvisioningState != ProvisioningStateDR.Succeeded) { Console.WriteLine("Waiting for DR to be setup. Current State: " + drStatus.ProvisioningState); drStatus = client.DisasterRecoveryConfigs.Get( resourceGroupName, geoDRPrimaryNS, alias); Thread.CurrentThread.Join(TimeSpan.FromSeconds(30)); } Console.WriteLine("Creating test entities to show pairing."); await client.Topics.CreateOrUpdateAsync(resourceGroupName, geoDRPrimaryNS, "myTopic", new SBTopic()) .ConfigureAwait(false); await client.Subscriptions.CreateOrUpdateAsync(resourceGroupName, geoDRPrimaryNS, "myTopic", "myTopic-Sub1", new SBSubscription()) .ConfigureAwait(false); // Sleeping to allow metadata to sync across primary and secondary await Task.Delay(TimeSpan.FromSeconds(60)); Console.WriteLine("Initial setup complete. Please see in the portal if all resources have been created as expected."); Console.WriteLine("Try creating a few additional entities in the primary in the portal."); Console.WriteLine("Press enter to exit."); Console.ReadLine(); }
static async Task MainAsync() { // https://msdn.microsoft.com/en-us/library/azure/dn790557.aspx#bk_portal string token = await GetAuthorizationHeaderAsync().ConfigureAwait(false); TokenCredentials creds = new TokenCredentials(token); ServiceBusManagementClient client = new ServiceBusManagementClient(creds) { SubscriptionId = subscriptionId }; //// 1. Create Primary Namespace (optional) var namespaceParams = new SBNamespace { Location = "South Central US", Sku = new SBSku { Name = SkuName.Premium, Capacity = 1 } }; var namespace1 = await client.Namespaces.CreateOrUpdateAsync(resourceGroupName, geoDRPrimaryNS, namespaceParams) .ConfigureAwait(false); //// 2. Create Secondary Namespace (optional if you already have an empty namespace available) var namespaceParams2 = new SBNamespace { Location = "North Central US", Sku = new SBSku { Name = SkuName.Premium, Capacity = 1 } }; //// If you re-run this program while namespaces are still paired this operation will fail with a bad request. //// this is because we block all updates on secondary namespaces once it is paired var namespace2 = await client.Namespaces.CreateOrUpdateAsync(resourceGroupName, geoDRSecondaryNS, namespaceParams2) .ConfigureAwait(false); // 3. Pair the namespaces to enable DR. ArmDisasterRecovery drStatus = await client.DisasterRecoveryConfigs.CreateOrUpdateAsync( resourceGroupName, geoDRPrimaryNS, alias, new ArmDisasterRecovery { PartnerNamespace = geoDRSecondaryNS }) .ConfigureAwait(false); while (drStatus.ProvisioningState != ProvisioningStateDR.Succeeded) { Console.WriteLine("Waiting for DR to be setup. Current State: " + drStatus.ProvisioningState); drStatus = client.DisasterRecoveryConfigs.Get( resourceGroupName, geoDRPrimaryNS, alias); Thread.CurrentThread.Join(TimeSpan.FromSeconds(30)); } await client.Topics.CreateOrUpdateAsync(resourceGroupName, geoDRPrimaryNS, "myTopic", new SBTopic()) .ConfigureAwait(false); await client.Subscriptions.CreateOrUpdateAsync(resourceGroupName, geoDRPrimaryNS, "myTopic", "myTopic-Sub1", new SBSubscription()) .ConfigureAwait(false); // sleeping to allow metadata to sync across primary and secondary await Task.Delay(TimeSpan.FromSeconds(60)); // 6. Failover. Note that this Failover operations is ALWAYS run against the secondary ( because primary might be down at time of failover ) // client.DisasterRecoveryConfigs.FailOver(resourceGroupName, geoDRSecondaryNS, alias); // other possible DR operations // 7. Break Pairing // client.DisasterRecoveryConfigs.BreakPairing(resourceGroupName, geoDRPrimaryNS, alias); // 8. Delete DR config (alias) // note that this operation needs to run against the namespace that the alias is currently pointing to // client.DisasterRecoveryConfigs.Delete(resourceGroupName, geoDRPrimaryNS, alias); }