Search code examples
azureazureservicebusazure-resource-managerazure-bicepinfrastructure-as-code

A nested resource cannot appear inside of a resource with a for-expression


I want to generate an ESB with bicep and several topics. Each topic could have one or more subscriptions. These are defined inside this list.

var topics = [{
  name: 'topic.one'
  subscriptions: [ 'esm', 'erp', 'pms' ]
}, {
  name: 'topic.two'
  subscriptions: [ 'esm' ]
}, {
  name: 'topic.three'
  subscriptions: [ 'erp', 'insights' ]
}, {
  name: 'topic.four'
  subscriptions: [ 'pms', 'cmdb']
}, {
  name: 'topic.five'
  subscriptions: [ 'billing', 'custom', 'erp', 'dax' ]
}]

When I create the resource the easiest and most dynamic solution will create a loop inside a loop like below.

resource sb_events 'Microsoft.ServiceBus/namespaces@2022-01-01-preview' = {
  name: 'servicebus-events'
  location: 'westeurope'
  sku: {
    capacity: 1
    name: 'Standard'
    tier: 'Standard'
  }

  resource topic_resources 'topics' = [for topic in topics: {
    name: topic.name  

    resource subscription_resources 'subscriptions' = [for subscription in topic.subscriptions: {
      name: subscription
      properties: vSubscriptionProperties
    }]
  }]
}

But this gives me next error:

A nested resource cannot appear inside of a resource with a for-expression. bicep(BCP160)

When this code looks logic, the bicep compiler don't accept this. How could I fix this?


Solution

  • Bicep does not support nested loop for the moment:

    You could have a module that creates a topic and subscriptions:

    // sb-topic-and-subscriptions.bicep
    param namespaceName string
    param topicName string
    param subscriptionNames array
    param vSubscriptionProperties  object
    
    resource namespace 'Microsoft.ServiceBus/namespaces@2022-01-01-preview' existing = {
      name: namespaceName
    }
    
    resource topic 'Microsoft.ServiceBus/namespaces/topics@2022-01-01-preview' = {
      parent: namespace
      name: topicName
    
      resource subscriptions 'subscriptions' = [for sub in subscriptionNames: {
        name: sub
        properties: vSubscriptionProperties
      }]
    }
    

    Then you can invoke it from your main:

    ...
    // loop and create all the topics and subscription.
    module topicsModule 'sb-topic-and-subscriptions.bicep' = [for topic in topics: {
      name: topic.name
      params: {
        namespaceName: 'servicebus-events'
        subscriptionNames: topic.subscriptions
        topicName:  topic.name
        vSubscriptionProperties: vSubscriptionProperties
      }
    }]