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());
        }
Пример #2
0
 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;
     }
 }
Пример #3
0
 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;
     }
 }
Пример #4
0
 /// <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);
     }
 }
Пример #5
0
 /// <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());
 }
Пример #6
0
 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);
                }
            }
        }
Пример #8
0
        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);
        }
Пример #9
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();
        }
Пример #10
0
        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);
        }