azurecicdazure-bicepazure-monitoringinfrastructure-as-code

How can I define compile time constants in bicep configuration language?


I'm currently working on deploying multiple workbooks in Azure using Bicep. My goal is to create a resource workbook and deploy multiple instances of it. However, I've encountered an issue with the loadTextContent function, which only accepts hard-coded variables because they need to be compile-time constants as per the documentation.

Here is the current Bicep code I'm using:

resource workbook 'Microsoft.insights/workbooks@2021-03-08' = {
  name: lawWorkbookName
  location: location
  kind: 'shared'
  properties: {
    category: 'workbook'
    displayName: lawWorkbookDisplayName
    serializedData: loadTextContent('./workbook.json')
    sourceId: law.id
  }
  tags: {
    location: location
    logAnalyticsWorkspace: lawName
  }
}

Now I am trying to find a workaround, because I really do not want to repeat the resource definition. Does someone know how I can define compile time constants in bicep ?

I want to avoid repeating the resource definition for each workbook. Ideally, I would like to define compile-time constants and loop over them to load multiple workbooks. Here's a conceptual example of what I'm trying to achieve:

I would like to achieve something like this

var stringArray = [
  './workbook1.json'
  './workbook2.json'
]


resource workbook 'Microsoft.insights/workbooks@2021-03-08' = {
  name: lawWorkbookName
  location: location
  kind: 'shared'
  properties: {
    category: 'workbook'
    displayName: lawWorkbookDisplayName
    serializedData: for i in range(0, length(stringArray)) {
  loadTextContent(stringArray[i])
}
    sourceId: law.id
  }
  tags: {
    location: location
    logAnalyticsWorkspace: lawName
  }
}

Does anyone know how I can define compile-time constants in Bicep to achieve this? Any workarounds or alternative approaches would be greatly appreciated.

Additional links: This issue on GitHub


Solution

  • Using placeholders technique can be a workaround for this, injecting contents and other parameters at build time, giving an equivalent of compile-time constants. This is simpler when implementing with CI, where placeholders are slot in at pipeline run. For example is using replacetokens@5 task in Azure DevOps (similarly in other CIs).

    Instead of hardcoding the values you pass placeholders, which will be replaced by actual values during pipeline execution.

    resource workbook 'Microsoft.insights/workbooks@2021-03-08' = {
      name: lawWorkbookName
      location: location
      kind: 'shared'
      properties: {
        category: 'workbook'
        displayName: lawWorkbookDisplayName
        serializedData: loadTextContent("#{workbookFilePlaceholder}#")
        sourceId: law.id
      }
      tags: {
        location: location
        logAnalyticsWorkspace: lawName
      }
    }
    

    Tokens values are defined as Azure DevOps Pipeline variables.

    variables:
      workbookFilePlaceholder: './workbook1.json'
    

    Add the ReplaceTokens Task in the Pipeline

              - task: replacetokens@5
                name: Update_File
                displayName: Update File
                inputs:
                  targetFiles: pathoffile/name.bicep
                  encoding: auto
                  tokenPattern: default
                  writeBOM: true
                  escapeType: none
                  verbosity: detailed
                  actionOnMissing: warn
                  keepToken: false
                  actionOnNoFiles: warn
                  enableTransforms: false
                  enableRecursion: false
                  useLegacyPattern: false
                  enableTelemetry: false