'How do I create multiple topics/queues in multiple servicebuses with bicep?

I don't quite understand the relationship between parent and child components when working with bicep and more specifically arrays. The error I get is this: Deployment template validation failed: 'The resource 'Microsoft.Resources/deployments/p6vklkczz4qlm' at line '54' and column '9' is defined multiple times in a template.

The error is quite clear I just don't understand the solution I guess.

main.bicep

param servicebuses array = [
  'servicebus_dev'
  'servicebus_acc'
  'servicebus_prod'
]

resource servicebusNamespace 'Microsoft.ServiceBus/namespaces@2021-11-01' = [for servicebus in servicebuses: {
  location: location
  name: servicebus
  sku:{
    name: 'Standard' 
    }  
}]

module topicModule 'topicsModule.bicep' = [for servicebus in servicebuses:{
  name: uniqueString('topic')
  params:{
    parentResource: servicebus
  }
}]

topicsModule.bicep

param topics array = [
  'topic1'
  'topic2'
  'topic3'
]

param parentResource string

resource topicResource 'Microsoft.ServiceBus/namespaces/topics@2021-11-01' = [for topic in topics : {
  name: topic
  }]


Solution 1:[1]

Creating the topics in a module makes it a bit cumbersome. You have to fetch the namespace using the existing keyword and then you can add a parent relationship to your topic to create it within the given namespace.

resource servicebusNamespace 'Microsoft.ServiceBus/namespaces@2021-11-01' existing = {
  name: parentResource
}

resource topicResource 'Microsoft.ServiceBus/namespaces/topics@2021-11-01' = [for topic in topics : {
  parent: servicebusNamespace
  name: topic
      }]

Then you have to make your topicModules name dependent on the selected servicebus and also add a dependsOn for the servicebus namespace so that bicep will know to deploy the namespace first.

module topicModule 'topicsModule.bicep' = [for servicebus in servicebuses:{
  name: uniqueString(servicebus)
  dependsOn:[
    servicebusNamespace
  ]
  params:{
    parentResource: servicebus
  }
}] 

I guess you replaced your real service bus namespace names with dummy values but just in case, make sure to use a name thats more likely to be globally unique and don't use the _ character, it is not allowed in the name of a service bus namespace.

Solution 2:[2]

Additionally to the accepted answer.

A topic is a sub resource of service namespace so the resource name looks like that:
servicebus-namespace-name/topic-name

topicsModule.bicep file:

param servicebusName string

param topics array = [
  'topic1'
  'topic2'
  'topic3'
]

resource topicResource 'Microsoft.ServiceBus/namespaces/topics@2021-11-01' = [for topic in topics: {
  name: '${servicebusName}/${topic}'
}]

In the main file, you can just invoke the module like that:

module topicModule 'topicsModule.bicep' = [for (servicebus, i) in servicebuses: {
  name: uniqueString(servicebus)
  params: {
    servicebusName: servicebusNamespace[i].name
  }
}]

Here you don't need to specify the dependsOn as it is automatically generated by bicep at compile time.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 JustAGuy
Solution 2 Thomas