So, you’ve started to work with Bicep rather than ARM…now lets say you want to deploy a Web App.

That’s not too bad.

param webappName string
param location string = resourceGroup().location
param hostingPlanName string

resource serverFarm 'Microsoft.Web/serverfarms@2020-06-01' = {
  name: hostingPlanName
  location: location
  sku: {
    name: 'S1'
    tier: 'Standard'
  }
}

resource webapp 'Microsoft.Web/sites@2020-06-01' = {
  name: webappName
  location: location
  kind: 'app'
  properties: {
    serverFarmId: serverFarm.id
    siteConfig: {
      alwaysOn: true
    }
  }
}

Now, say we need to link Application Insights to the app when we deploy it. You’d just need to add in the InstrumentationKey for Application Insights to a property of the webapp:

resource webapp 'Microsoft.Web/sites@2020-06-01' = {
  name: webappName
  location: location
  kind: 'app'
  properties: {
    serverFarmId: serverFarm.id
    siteConfig: {
      alwaysOn: true
      appSettings: [
        {
          name: 'APPINSIGHTS_INSTRUMENTATIONKEY'
          value: InstrumentationKey
        }
      ]
    }
  }
}

So where does the value for that come from? In certain environments we already have Application Insights deployed (for example in production). In this case we can just add a few lines to reference the existing resource and pull out the value in our template.

resource existingAppInsights 'Microsoft.Insights/components@2020-02-02' existing = {
  name: appInsightsName
  scope: resourceGroup(appInsightsRG)
}

resource webapp 'Microsoft.Web/sites@2020-06-01' = {
  name: webappName
  location: location
  kind: 'app'
  properties: {
    serverFarmId: serverFarm.id
    siteConfig: {
      alwaysOn: true
      appSettings: [
        {
          name: 'APPINSIGHTS_INSTRUMENTATIONKEY'
          value: existingAppInsights.properties.InstrumentationKey
        }
      ]
    }
  }
}

Note that we declare the resource and use the existing keyword. The scope is used to search the correct Azure resource group (in this case) for an Application Insights deployment. We can then use this reference to get the value of the InstrumentationKey and set it to a value in appSettings.

Now, that’s great for an environment where a resource already exists, but let’s say Dev (for reasons) doesn’t have a permanent resource for the above code to find. Running the template would fail when the reference to the existing Application Insights fails to find an instance.

In this case, you’d want your template to create an instance and use that to get a value for InstrumentationKey. So the template would look something like this:

module appInsights '/modules/appinsights.bicep' = {
  name: appInsightsName
  params: {
    applicationInsightsName: appInsightsName
    location: location
    logAnalyticsNamespaceName: logAnalyticsNamespaceName
    workspaceSKU: workspaceSKU
  }
}

resource webapp 'Microsoft.Web/sites@2020-06-01' = {
  name: webappName
  location: location
  kind: 'app'
  properties: {
    serverFarmId: serverFarm.id
    siteConfig: {
      alwaysOn: true
      appSettings: [
        {
          name: 'APPINSIGHTS_INSTRUMENTATIONKEY'
          value: appInsights.outputs.InstrumentationKey
        }
      ]
    }
  }
}

Here you use a module to create an Application Insights instance and pull the InstrumentationKey from the module outputs.

So the aim was to combine both these into a single bicep file that would enable the code to either create an instance or use the existing instance to grab the value that we need. Sounds simple, but after many attempts the only way to do this was by introducing another variable. This was used to determine if the environment that we were using need to create or reference an existing instance.

So the template became:

param webappName string
param location string = resourceGroup().location
param hostingPlanName string
param appInsightsName string
param appInsightsRG string
param logAnalyticsNamespaceName string
param workspaceSKU string
param aiExists bool

resource existingAppInsights 'Microsoft.Insights/components@2020-02-02' existing = if (aiExists) {
  name: appInsightsName
  scope: resourceGroup(appInsightsRG)
}

module appInsights '/modules/appinsights.bicep' = if (!aiExists){
  name: appInsightsName
  params: {
    applicationInsightsName: appInsightsName
    location: location
    logAnalyticsNamespaceName: logAnalyticsNamespaceName
    workspaceSKU: workspaceSKU
  }
}

var InstrumentationKey = (aiExists) ? existingAppInsights.properties.InstrumentationKey : appInsights.outputs.InstrumentationKey

resource webapp 'Microsoft.Web/sites@2020-06-01' = {
  name: webappName
  location: location
  kind: 'app'
  properties: {
    serverFarmId: serverFarm.id
    siteConfig: {
      alwaysOn: true
      appSettings: [
        {
          name: 'APPINSIGHTS_INSTRUMENTATIONKEY'
          value: InstrumentationKey
        }
      ]
    }
  }
}

Note the var InstrumentationKey value. We use a conditional with the aiExists to determine which value of the InstrumentationKey we use. All the parameters need to have values supplied. For the ones that don’t matter for that particular run, we can just supply dummy values as they won’t do anything.

If it’s not straightforward to get decide if the Application Insights exists before hand, you could run a simple Azure CLI/Powershell script to search and then return the correct boolean value before running the template in your pipeline.