diff --git a/src/AzureCloudServiceBus/AzureCloudServiceBusResource.cs b/src/AzureCloudServiceBus/AzureCloudServiceBusResource.cs index 5f19be31..8123682f 100644 --- a/src/AzureCloudServiceBus/AzureCloudServiceBusResource.cs +++ b/src/AzureCloudServiceBus/AzureCloudServiceBusResource.cs @@ -1,8 +1,8 @@ -using System; -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Diagnostics; using System.Linq; -using System.Text; +using System.Text; using System.Threading.Tasks; using Microsoft.Azure.ServiceBus; using Squadron.AzureCloud; @@ -10,12 +10,12 @@ using Xunit.Abstractions; using Xunit.Sdk; -namespace Squadron +namespace Squadron { /// - /// Defines a Azure Cloud ServiceBus namespace + /// Defines a Azure Cloud ServiceBus namespace /// - /// Option to initialize the resource + /// Option to initialize the resource public class AzureCloudServiceBusResource : AzureResource, IAsyncLifetime where TOptions : AzureCloudServiceBusOptions, @@ -26,10 +26,10 @@ public class AzureCloudServiceBusResource private ServiceBusModel _serviceBusModel; private readonly IMessageSink _messageSink; - /// - /// Initializes a new instance of the class. - /// - /// The message sink. + /// + /// Initializes a new instance of the class. + /// + /// The message sink. public AzureCloudServiceBusResource(IMessageSink messageSink) { _messageSink = messageSink; @@ -54,11 +54,11 @@ public ITopicClient GetTopicClient(string name, } - /// - /// Creates a new topic - /// - /// The builder. - /// Client to access the created topic + /// + /// Creates a new topic + /// + /// The builder. + /// Client to access the created topic public async Task CreateTopicAsync(Action configure) { var builder = ServiceBusTopicBuilder.New(); @@ -133,9 +133,9 @@ private string GetQueue(string name) return queue.CreatedName; } - /// - /// Initialize the resource - /// + /// + /// Initialize the resource + /// public override async Task InitializeAsync() { await base.InitializeAsync(); @@ -149,7 +149,7 @@ public override async Task InitializeAsync() } private void BuildOptions() - { + { var builder = ServiceBusOptionsBuilder.New(); var options = new TOptions(); options.Configure(builder); @@ -158,7 +158,7 @@ private void BuildOptions() } private void InitializeServiceBusManager() - { + { _serviceBusManager = new ServiceBusManager( AzureConfig.Credentials, new AzureResourceIdentifier @@ -170,17 +170,22 @@ private void InitializeServiceBusManager() } private async Task PrepareNamespaceAsync() - { + { if (_serviceBusModel.Namespace == null) { _serviceBusModel.ProvisioningMode = ServiceBusProvisioningMode.CreateAndDelete; _serviceBusModel.Namespace = await - _serviceBusManager.CreateNamespaceAsync(AzureConfig.DefaultLocation); + _serviceBusManager.CreateRandomNamespaceAsync(AzureConfig.DefaultLocation); + } + else if (_serviceBusModel.ProvisioningMode == ServiceBusProvisioningMode.CreateIfNotExists) + { + _serviceBusModel.Namespace = await + _serviceBusManager.CreateNamespaceIfNotExistsAsync(AzureConfig.DefaultLocation, _serviceBusModel.Namespace); } } private async Task PrepareQueuesAsync() - { + { foreach (ServiceBusQueueModel queue in _serviceBusModel.Queues) { if (_serviceBusModel.ProvisioningMode == ServiceBusProvisioningMode.UseExisting) @@ -196,7 +201,7 @@ private async Task PrepareQueuesAsync() } private async Task PrepareTopicsAsync() - { + { foreach (ServiceBusTopicModel topic in _serviceBusModel.Topics) { _messageSink.OnMessage( @@ -220,8 +225,8 @@ private async Task CreateTopicAsync(ServiceBusTopicModel topic) } /// - /// Cleans up the resource - /// + /// Cleans up the resource + /// public async Task DisposeAsync() { try @@ -248,5 +253,5 @@ public async Task DisposeAsync() //do not fail test } } - } -} + } +} diff --git a/src/AzureCloudServiceBus/Model/ServiceBusModel.cs b/src/AzureCloudServiceBus/Model/ServiceBusModel.cs index 22ea1503..92544f46 100644 --- a/src/AzureCloudServiceBus/Model/ServiceBusModel.cs +++ b/src/AzureCloudServiceBus/Model/ServiceBusModel.cs @@ -4,60 +4,65 @@ namespace Squadron { - /// - /// Azure ServiceBus model - /// - public class ServiceBusModel + /// + /// Azure ServiceBus model + /// + public class ServiceBusModel { - /// - /// Gets or sets the namespace. - /// - /// - /// The namespace. - /// + /// + /// Gets or sets the namespace. + /// + /// + /// The namespace. + /// public string Namespace { get; set; } - /// - /// Gets or sets the topics. - /// - /// - /// The topics. - /// + /// + /// Gets or sets the topics. + /// + /// + /// The topics. + /// public List Topics { get; set; } = new List(); - /// - /// Gets or sets the queues. - /// - /// - /// The queues. - /// + /// + /// Gets or sets the queues. + /// + /// + /// The queues. + /// public List Queues { get; set; } = new List(); - /// - /// Gets or sets the provisioning mode. - /// - /// - /// The provisioning mode. - /// + /// + /// Gets or sets the provisioning mode. + /// + /// + /// The provisioning mode. + /// internal ServiceBusProvisioningMode ProvisioningMode { get; set; } = ServiceBusProvisioningMode.UseExisting; } - /// - /// Defines ServiceBUs provisioning modes - /// + /// + /// Defines ServiceBUs provisioning modes + /// internal enum ServiceBusProvisioningMode { - /// - /// The uan existing Azure resource - /// + /// + /// The uan existing Azure resource + /// UseExisting, - /// - /// Provision and delete resource - /// - CreateAndDelete + /// + /// Provision and delete resource + /// + CreateAndDelete, + + /// + /// Create or update resource + /// + CreateIfNotExists } } diff --git a/src/AzureCloudServiceBus/ServiceBusManager.cs b/src/AzureCloudServiceBus/ServiceBusManager.cs index 36223056..331a6f2a 100644 --- a/src/AzureCloudServiceBus/ServiceBusManager.cs +++ b/src/AzureCloudServiceBus/ServiceBusManager.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; -using System.Text; +using System.Linq; using System.Threading.Tasks; using Microsoft.Azure.Management.ServiceBus; using Microsoft.Azure.Management.ServiceBus.Models; @@ -38,11 +38,47 @@ private async Task EnsureAuthenticatedAsync() } } - internal async Task CreateNamespaceAsync(string location) + internal async Task CreateRandomNamespaceAsync(string location) { await EnsureAuthenticatedAsync(); var ns = $"squadron-{Guid.NewGuid().ToString("N").Substring(8)}"; + return await CreateNamespaceAsync(location, ns); + } + + internal async Task CreateNamespaceIfNotExistsAsync(string location, string serviceBusNamespace) + { + await EnsureAuthenticatedAsync(); + + if (await CheckServiceBusNamespaceExists(serviceBusNamespace) == false) + return await CreateNamespaceAsync(location, serviceBusNamespace); + + _identifier.Name = serviceBusNamespace; + return serviceBusNamespace; + } + + private async Task CheckServiceBusNamespaceExists(string serviceBusNamespace) + { + var serviceBusNamespaces = new List(); + + var listByResourceGroupAsync = await _client.Namespaces.ListByResourceGroupAsync(_identifier.ResourceGroupName); + serviceBusNamespaces.AddRange(listByResourceGroupAsync); + + var nextPageLink = listByResourceGroupAsync.NextPageLink; + while (nextPageLink != null) + { + listByResourceGroupAsync = await _client.Namespaces.ListByResourceGroupNextAsync(nextPageLink); + nextPageLink = listByResourceGroupAsync.Any(x => x.Name == serviceBusNamespace) ? + null : + listByResourceGroupAsync.NextPageLink; + serviceBusNamespaces.AddRange(listByResourceGroupAsync); + } + + return serviceBusNamespaces.Any(x => x.Name == serviceBusNamespace); + } + + private async Task CreateNamespaceAsync(string location, string ns) + { var pars = new SBNamespace { Sku = new SBSku(SkuName.Standard), @@ -50,7 +86,7 @@ internal async Task CreateNamespaceAsync(string location) }; SBNamespace res = await _client.Namespaces - .CreateOrUpdateAsync(_identifier.ResourceGroupName, ns, pars); + .CreateOrUpdateAsync(_identifier.ResourceGroupName, ns, pars); _identifier.Name = res.Name; return res.Name; diff --git a/src/AzureCloudServiceBus/ServiceBusOptionsBuilder.cs b/src/AzureCloudServiceBus/ServiceBusOptionsBuilder.cs index d2c60d6b..8112c21f 100644 --- a/src/AzureCloudServiceBus/ServiceBusOptionsBuilder.cs +++ b/src/AzureCloudServiceBus/ServiceBusOptionsBuilder.cs @@ -4,19 +4,19 @@ namespace Squadron { - /// - /// ServiceBusOptions builder - /// + /// + /// ServiceBusOptions builder + /// public class ServiceBusOptionsBuilder : AzureResourceOptionsBuilder { private ServiceBusModel _model = new ServiceBusModel(); private List _topics = new List(); private List _queues = new List(); - /// - /// Creates a new empty builder - /// - /// + /// + /// Creates a new empty builder + /// + /// public static ServiceBusOptionsBuilder New() => new ServiceBusOptionsBuilder(); @@ -26,23 +26,37 @@ private ServiceBusOptionsBuilder() } - /// - /// Namespace - /// - /// The namespace. - /// + /// + /// Namespace + /// + /// The namespace. + /// public ServiceBusOptionsBuilder Namespace(string ns) + { + return Namespace(ns, createIfNotExists: false); + } + + /// + /// Namespace + /// + /// The namespace. + /// creates namespace if doesn't exist. + /// + public ServiceBusOptionsBuilder Namespace(string ns, bool createIfNotExists) { _model.Namespace = ns; + _model.ProvisioningMode = createIfNotExists + ? ServiceBusProvisioningMode.CreateIfNotExists + : ServiceBusProvisioningMode.UseExisting; return this; } - /// - /// Adds a topic. - /// - /// The topic name. - /// + /// + /// Adds a topic. + /// + /// The topic name. + /// public ServiceBusTopicBuilder AddTopic(string name) { var topicBuilder = ServiceBusTopicBuilder.New(name); @@ -51,11 +65,11 @@ public ServiceBusTopicBuilder AddTopic(string name) } - /// - /// Adds a queue. - /// - /// The queue name. - /// + /// + /// Adds a queue. + /// + /// The queue name. + /// public ServiceBusQueueBuilder AddQueue(string name) { var queueBuilder = new ServiceBusQueueBuilder(name); @@ -64,10 +78,10 @@ public ServiceBusQueueBuilder AddQueue(string name) } - /// - /// Builds the options - /// - /// + /// + /// Builds the options + /// + /// public ServiceBusModel Build() { foreach (ServiceBusTopicBuilder tb in _topics)