1
votes

I have an resource group ARM template that I use to create an application gateway that is configured for url routing. It sends traffic to different Web Apps in that resource group based on url path rules. I deploy the base resource group ARM template, and then each web app has its own ARM template that setups a Web App on an App Service Plan. I am trying to figure out how to add a rule to an existing Url Path Map on an Application Gateway without defining the whole application gateway in every template. This way, I can simply add web apps and have them "register" on to the application gateway with a particular path rule.

I considered doing a linked template where my base template would have all of the shared resources (databases, app service plan, and app gateway), but even with a linked template, I don't think I can add a rule to the application gateway.

Update So I modified my template by adding a reference to the existing application gateway, and then adding variables for the new BackEndPoolAddress and new Path Rule. It ends up like this (abbreviated to only relevant parts):

 "variables": {
    "appGateway": "[reference(concat('Microsoft.Network/applicationGateways/', 'appGateWay-', uniqueString(resourceGroup().id)), '2017-06-01')]",
    "pathRule": {
      "name": "[concat(parameters('websiteName'), '- RoutingRule')]",
      "properties": {
        "paths": [
          "[parameters('routingRule')]"
        ],
        "backendAddressPool": {
          "id": "[concat(variables('appGateway').id, '/backendAddressPools/',parameters('websiteName'), 'BackEndPool')]"
        },
        "backendHttpSettings": {
          "id": "[variables('appGateway').backendHttpSettingsCollection[0]]"
        }
      }
    },
    "backendPool": {
      "name": "[concat(parameters('websiteName'), 'BackEndPool')]",
      "properties": {
        "IpAddress": "[reference(variables('webSiteName')).defaultHostName]"
      }
    }
  },
 "resources": [
  ...
    {
      "apiVersion": "2017-06-01",
      "name": "[variables('appGateway').name]",
      "type": "Microsoft.Network/applicationGateways",
      "location": "[resourceGroup().location]",
      "properties": {
        "backendAddressPools": "[concat(variables('appGateway').backendAddressPools, variables('backendPool'))]",
        "urlPathMaps": [
          {
            "name": "[variables('appGateway').urlPathMaps[0]]",
            "pathRules": "[concat(variables('appGateway').urlPathMaps[0].pathRules, variables('pathRule'))]"
          }
        ]
      }
    }
  ],

However I get a template validation error saying I can't use the Reference function in the Variables section. If I don't add it in the variables section, how can I build the correct paths for the pool and pathRule in my variables section?

2
Hi Mike. Can you please share some insights as to how you got it working via nested template route. I am trying to achieve the below using nested template: Have a separate template file for each application and call all of them from the main. Any help appreciated. Thanks. - Avi
@Avi I actually switched from ARM to CLI recently, so I don't have that code anymore, but it was really easy to do with the CLI because it is idempotent. I will add an answer below showing how I update my load balancer with a simple Azure CLI script that runs each time my deployment runs. - Mike

2 Answers

1
votes

you can achieve this using the reference() function, array manipulation and nested templates (might work even without those, worst case you will need them). example:

"outputs": {
    "httpListeners": {
        "type": "array",
        "value": "[reference('application_gateway_id', '2018-08-01', 'Full').properties.httpListeners]"
    }
}

Will return you array or httpListeners. you can get all the relevant application gateway properties and add new (additional) properties with the concat() and assign the result to the property (properties):

"httpListeners": "[concat(reference('application_gateway_id', '2018-08-01', 'Full').properties.httpListeners, variables('newListener'))]"

you just need to make sure 2 deployments dont start at the same time, one might overwrite the other

0
votes

Here is the solution I finally ended up with using the Azure CLI. This script is idempotent and runs during my release process.

echo "Logging into AKS Cluster"
az aks get-credentials --resource-group $RESOURCEGROUP_NAME --name $AKSNAME

echo "Get the created service's ip address"
SERVICEIP=$(kubectl get service --namespace $AKSNAMESPACE $APPNAME-service -o jsonpath="{.status.loadBalancer.ingress[0].ip}")


echo "Creating backend pool - IP $SERVICEIP"
az network application-gateway address-pool create \
  --gateway-name $APPGATEWAYNAME \
  --resource-group $RESOURCEGROUP_NAME \
  --name "$APPNAME-pool" \
  --servers $SERVICEIP

echo "Creating probe"
az network application-gateway probe create \
    --gateway-name $APPGATEWAYNAME \
    --name "$APPNAME-probe" \
    --path $APPPROBE \
    --resource-group $RESOURCEGROUP_NAME \
    --protocol Http \
    --resource-group $RESOURCEGROUP_NAME \
    --host-name-from-http-settings true 

echo "Creating HTTP Settings"
az network application-gateway http-settings create \
    --gateway-name $APPGATEWAYNAME \
    --name "$APPNAME-settings" \
    --port 80 \
    --resource-group $RESOURCEGROUP_NAME \
    --host-name-from-backend-pool \
    --probe "$APPNAME-probe" \
    --protocol Http



echo "Creating URL Path Map"
az network application-gateway url-path-map rule create \
    --gateway-name $APPGATEWAYNAME \
    --name "$APPNAME-rule" \
    --paths $RULEPATH \
    --path-map-name $RULENAME \
    --resource-group $RESOURCEGROUP_NAME \
    --http-settings "$APPNAME-settings" \
    --address-pool "$APPNAME-pool"