Search code examples
azureazureservicebusazure-resource-managerazure-bicep

How to create a nested resource based on a condition in a bicep file?


I have a bicep file that accepts a param topic object object that looks like this:

name: 'topic name'
subscriptions: [
  {
    name: 'subscriptionName'
    ruleName: 'name of the rule'
  }
]

Next I am going to create the resources:

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

resource topicResource 'Microsoft.ServiceBus/namespaces/topics@2021-11-01' = {
  parent: servicebus

  name: topic.topicName
}

resource subscriptions 'Microsoft.ServiceBus/namespaces/topics/subscriptions@2021-11-01' = [for obj in topic.subscriptions: {
  parent: topicResource

  name: obj.name
}]

resource rules 'Microsoft.ServiceBus/namespaces/topics/subscriptions/rules@2021-11-01' = [for (obj, i) in topic.subscriptions: {
  parent: subscriptions[i]

  name: obj.ruleName
  properties: {
    filterType: 'CorrelationFilter'
    correlationFilter: {
      label: obj.ruleName
    }
  }
}]

In some situations I don't want to create the rules resource. This is based on the ruleName property. If this property is empty, I don't want to create the resource.

But when I try to apply this condition, I get an error message:

{"code": "InvalidTemplate", "target": "[...]", "message": "Deployment template validation failed: 'The template resource '[..]' for type 'Microsoft.ServiceBus/namespaces/topics/subscriptions/rules' at line '1' and column '1763' has incorrect segment lengths. A nested resource type must have identical number of segments as its resource name. A root resource type must have segment length one greater than its resource name. Please see https://aka.ms/arm-template/#resources for usage details.'.", "additionalInfo": [{"type": "TemplateViolation", "info": {"lineNumber": 1, "linePosition": 1763, "path": "properties.template.resources[2].type"}}]}

What I think this error message is telling me, is that you need the same number of iterations as the parent, which in this case is subscriptions and because of the loop condition of the 'child' resource, the number now is decreased by one (which is odd to me, because why not continue with the next item in the array and increase the index with one... but ok).

So my question is, how can I skip the resource creation when ruleName is empty?

This is what I've tried and what gives the error above:

resource rules 'Microsoft.ServiceBus/namespaces/topics/subscriptions/rules@2021-11-01' = [for (obj, i) in topic.subscriptions: if (!empty(obj.ruleName)) {


Solution

  • The condition if (!empty(obj.ruleName)) will be converted to an ARM condition property.
    Even if the resource won't be deployed it is still present in the generated ARM.
    This mean the name property in the generated ARM is missing a segment:

    topic-name/subscription-name/empty-rule-name
    

    You will have to add the same condition (as a workaround) on the name property as well:

    name: !empty(obj.ruleName) ? obj.ruleName : 'whatever'
    

    In your code, it should look like that:

    resource rules 'Microsoft.ServiceBus/namespaces/topics/subscriptions/rules@2021-11-01' = [for (obj, i) in topic.subscriptions: if (!empty(obj.ruleName)) {
      parent: subscriptions[i]
      name: !empty(obj.ruleName) ? obj.ruleName : 'whatever'
      properties: {
        filterType: 'CorrelationFilter'
        correlationFilter: {
          label: obj.ruleName
        }
      }
    }]