Search code examples
azure-eventhubazure-bicep

Event Hub Namepace parent reference in Bicep modules - not possible to pass to another module?


I've been asked to code Bicep modules - coming from a Terraform background I have a pre-determined way I think they should work here - but so far have failed at the first hurdle.

I have a few Azure Event Hub Namespaces to create, and within each namespace there will be multiple actual Event Hubs underneath each

My original design therefore was to be as follows... main.bicep file, a modules/ehns.bicep (generic module to create a EH Namespace) modules/eh.bicep (generic module to create EH under a EH Namespace)

This way I had 2 modules and could just call them to create multiples of each other and then re-use those modules elsewhere

This singular bicep code works...

resource eventhubnamespace 'Microsoft.EventHub/namespaces@2022-01-01-preview' = {
  name: 'evhns-stackoverflow-dev-uksouth-001'
  location: 'uksouth'
  sku: {
    name: 'Standard'
    tier: 'Standard'
  }
  properties: {
    isAutoInflateEnabled: true
    maximumThroughputUnits: 1
    minimumTlsVersion: '1.2'
  }
}

output eventhubnamespaceid string = eventhubnamespace.id

resource eventhub01 'Microsoft.EventHub/namespaces/eventhubs@2021-11-01' = {
  name: 'eventhub-01'
  parent: eventhubnamespace
  properties: {
    messageRetentionInDays: 7
    partitionCount: 1
  }
}

When creating modules...

modules/ehns.bicep file

param ehnsname string
param location string
param skuName string
param autoInflate bool
param maxThroughputUnits int

resource eventhubnamespace 'Microsoft.EventHub/namespaces@2022-01-01-preview' = {
  name: ehnsname
  location: location
  sku: {
    name: skuName
    tier: skuName
  }
  properties: {
    isAutoInflateEnabled: autoInflate
    maximumThroughputUnits: maxThroughputUnits
    minimumTlsVersion: '1.2'
  }
}
output eventhubnamespaceid string = eventhubnamespace.id

modules/eh.bicep file

param ehname string
param ehnsparent string
param messageretentionindays int
param partitionCount int

resource eventhub01 'Microsoft.EventHub/namespaces/eventhubs@2021-11-01' = {
  name: ehname
  parent: ehnsparent
  properties: {
    messageRetentionInDays: messageretentionindays
    partitionCount: partitionCount
  }
}

main.bicep file to run both modules...

module eventhubnamespace 'modules/ehns.bicep' = {
  name: 'deploy-eventHubnamespace'
  params: {
    ehnsname: 'evhns-stackoverflow-dev-uksouth-001'
    location: 'uksouth'
    skuName: 'Standard'
    autoInflate: true
    maxThroughputUnits: 1
  }
}

module eventhub01 'modules/eh.bicep' = {
  name: 'eventhub-01'
  params: {
    ehname: 'eventhub-01'
    ehnsparent: eventhubnamespace.outputs.eventhubnamespaceid
    messageretentionindays: 7
    partitionCount: 1
  }
}

This doesn't work because the module/eh.bicep doesn't like the way I am passing in the *parent *value from the ehns.bicep module.

The property "parent" expected a value of type "Microsoft.EventHub/namespaces" but the provided value is of type "string".bicep(BCP036)

There is no output from the ehns.bicep module that has the type Microsoft.EventHub/namespaces, it's only array/object/int/bool/string that are available

I take it this just isn't possible and I'm forced to create a single module for everything because the way the parent object needs to work?


Solution

  • The parent syntax in bicep requires the resource to be defined in the template - it can be an existing resource. The simple version of this for your scenario is to just pass in the name of the parent, not the full resource id. So....

    eh.bicep

    param ehname string
    param ehnsparentname string
    param messageretentionindays int
    param partitionCount int
    
    resource ehnsparent 'Microsoft.EventHub/namespaces@2022-01-01-preview' existing = {
      name: ehnsparentname
    }
    
    resource eventhub01 'Microsoft.EventHub/namespaces/eventhubs@2021-11-01' = {
      name: ehname
      parent: ehnsparent
      properties: {
        messageRetentionInDays: messageretentionindays
        partitionCount: partitionCount
      }
    }
    

    and then in main.bicep when you call the module

    module eventhub01 'modules/eh.bicep' = {
      name: 'eventhub-01'
      dependsOn: eventhubnamespace // dependsOn is needed when not using an output
      params: {
        ehname: 'eventhub-01'
        ehnsparentname: 'evhns-stackoverflow-dev-uksouth-001'  // just the name, not the full id property
        messageretentionindays: 7
        partitionCount: 1
      }
    }
    

    Whether you use an output or not is really a stylistic choice in the example you gave - you already know the name in main.bicep since you pass it into the other module... that said, if you don't use an output, you need to make sure there is an explicit dependsOn defined between the parent and the child modules.