1

I'm currently working with a solution that uses an Azure Application Gateway deployed with ARM/Bicep. Over time, other applications are deployed that use this AppGw, so rules/backend pools/listeners are created for those applications at their deployment time via Az CLI (outside of the central infra IaC pipeline/process). When it comes to redeploying/updating the central AppGw, I have the classic problem of the ARM/Bicep template overwriting all of these extra additions, as the AppGw is a single resource and as the changes are not in the ARM/Bicep file they are removed.

I have worked around this problem in the past by checking for AppGw existence, outputting the existing rules/pools/etc. and then incorporating them into the ARM/Bicep JSON before it is redeployed. This has worked fine but the AppGw is now getting so large/complex that I am hitting Bash character limits when deploying updates via Azure Devops build pipelines. As such, I am looking for a better way to handle this issue. I have also tried outputting the existing config to file and ingesting via file load in Azure Bicep, but I need to deploy multiple AppGws across the globe with different configs so due to compile time file reference restrictions in Bicep, this doesn't work for me.

I need to ensure that my baseline template file for the AppGw, which sets core things like TLS level or diagnostic settings, is honoured in some way while not overwriting the amendments that happen from separate deployment processes.

My question is whether I can incorporate/merge the state of this existing AppGw with my baseline template, either using Azure Bicep or retooling to something like Pulumi/Terraform if this exposes the functionality. The kind of approach I was thinking of would be:

  • Pipeline CLI task checks if AppGw already exists
  • If NO, then deploy using baseline template with bare bones requirements
  • If YES, then fetch existing backend pools/listeners/etc. (or fetch overall state)
  • Compare to template IaC file
  • Merge state, ensuring core settings from IaC file are applied (i.e. diagnostic settings, TLS level, etc.), while existing backend pools/listeners/etc. are retained

I am aware, but not experienced with, Pulumi's concept of ignoreChanges and transformations. I wasn't sure if that covered the use case here. What I am trying to achieve here may be in conflict with the purpose of these declarative languages, but just thought I'd ask to see if someone else had any thoughts.

Thanks very much in advance!

Carv
  • 23
  • 4
  • Depending on how complex your architecture ends up, you will keep having this issue show up if you attempt to use Bicep alone. For our team, we moved to Terraform that is premised on state comparison. – Goldie Oct 13 '22 at 21:24

1 Answers1

0

Using Bicep, you could always retrieve existing configuration if the app gateway already exists. Here is a sample using httpListeners.

You could define a app-gateway.bicep module like that:

param appGatewayName string
param location string = resourceGroup().location
...
param httpListeners array

resource appGateway 'Microsoft.Network/applicationGateways@2020-11-01' = {
  name: appGatewayName
  location: location
  ...
  properties: {
    ...    
    httpListeners: httpListeners
  }
}

Then from your main.bicep file, use the default or existing config:

param appGateWayExists bool
param appGatewayName string
...

// Get existing app gateway if existing
resource existing 'Microsoft.Network/applicationGateways@2020-11-01' existing = if (appGateWayExists) {
  name: appGatewayName
}

// Deploy app gateway
module appgateway './app-gateway.bicep' = {
  name: 'app-gateway'
  params: {
    appGatewayName: appGatewayName
    ...
    // Use existing configuration if exists
    httpListeners: appGateWayExists ? existing.properties.httpListeners : [
      {
        // default listener configuration
      }
    ]
  }
}

Then you could invoke it like that:

$appGatewayName = "<app-gateway-name>"
$appGatewayExists = (az resource list --name "$appGatewayName" --query '[].[id]' | ConvertFrom-Json).Length -gt 0
az deployment group create `
  --resource-group "<resource-group-name>" `
  ...
  --parameters `
  appGateWayExists=$appGatewayExists `
  appGatewayName="$appGatewayName" `
  ...
Thomas
  • 24,234
  • 6
  • 81
  • 125
  • Thanks for the response Thomas. This is a workable solution to identify the presence of the existing resource elements and put them in when missing, or use the existing ones (I've used this before... why it didn't come to mind!). What it doesn't do is offer me the ability to merge the two. Say for example, if I need a default backend HTTP setting that must always be there, but was missing from an existing appgw that had other backend HTTP settings. The code at current would see it already exists and assume it was correct. I've tried union/concat, but I get duplicate errors. Any thoughts? – Carv Jul 18 '22 at 16:34
  • Yeah union only merge simple array. I tried that as well in the past but didn't work. Tbh I would fix the existing app gateways with the desired configuration then for future deployment you'll be good => assuming all the new changes to app gateway will be done using pipeline. – Thomas Jul 18 '22 at 20:27