8

I have an ARM template which conditionally creates a resource:

    {
  "type": "Microsoft.Storage/storageAccounts",
  "sku": {
    "name": "Standard_GRS",
    "tier": "Standard"
  },
  "kind": "BlobStorage",
  "name": "[variables('storageAccounts_name')]",
  "condition": "[equals(parameters('is_Not_Development'), 'True')]",
  "apiVersion": "2017-06-01",
  "location": "[resourceGroup().location]",
  "scale": null,
  "properties": {
    "accessTier": "Hot"
  },
  "dependsOn": []
},

In my output parameters I have the following which causes an error if the resource is not created:

    "storageAccountConnectionString": {
  "type": "string",
  "value": "[Concat('DefaultEndpointsProtocol=https;AccountName=',variables('StorageAccounts_name'),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('StorageAccounts_name')), providers('Microsoft.Storage', 'storageAccounts').apiVersions[0]).keys[0].value)]"
},

I have tried this:

    "storageAccountConnectionString": {
  "type": "string",
  "condition": "[equals(parameters('is_Not_Development'), 'True')]",
  "value": "[Concat('DefaultEndpointsProtocol=https;AccountName=',variables('StorageAccounts_name'),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('StorageAccounts_name')), providers('Microsoft.Storage', 'storageAccounts').apiVersions[0]).keys[0].value)]"
},

with the condition clause but this is not recognised. How can I make the output parameter conditional?

UPDATE:

I have tried the following:

    "storageAccountConnectionString": {
  "type": "string",
  "value": "[if(equals(parameters('is_Not_Development'),'False'),'null',Concat('DefaultEndpointsProtocol=https;AccountName=',variables('StorageAccounts_name'),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('StorageAccounts_name')), providers('Microsoft.Storage', 'storageAccounts').apiVersions[0]).keys[0].value))]"
},

but it gives me the same error message, it must be evaluating both true and false conditions.

johnstaveley
  • 1,400
  • 1
  • 22
  • 46
  • 1
    My experiences with the IF statement in Azure ARM templates is pretty bad. (See https://stackoverflow.com/questions/45923848/can-i-have-an-arm-template-resource-with-a-copy-array-of-0-to-n). Basically, both sides of the IF (true/false) get evaluated. There currently is no way to work around this that I have discovered. – Christopher G. Lewis Sep 21 '17 at 15:36
  • 1
    I added an Azure UserVoice item for this: https://feedback.azure.com/forums/34192--general-feedback/suggestions/31538470-arm-template-if-function-should-not-evaluate-both – Christopher G. Lewis Sep 21 '17 at 16:18
  • Here's a feature request to solve this problem: https://feedback.azure.com/forums/281804-azure-resource-manager/suggestions/19492006-conditional-output-from-arm-template – jschmitter Feb 08 '18 at 18:02

2 Answers2

9

There is a trick to solve this issue and we use it successfully.

Let's see for example how the following template returns a value only if the corresponding resource has been deployed.

"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "appInsightsLocation": {
      "type": "string",
      "defaultValue": "",
      "allowedValues": [
        "",
        "northeurope",
        "westeurope"
      ]
    }
  },
  "variables": {
    "appInsightsName": "exampleAppInsights",
    "planName": "example-plan",
    "appInsightsEnabled": "[if(greater(length(parameters('appInsightsLocation')), 0), 'true', 'false')]",
    "appInsightsOrPlanResource": "[if(bool(variables('appInsightsEnabled')), concat('Microsoft.Insights/components/', variables('appInsightsName')), concat('Microsoft.Web/serverFarms/', variables('planName')))]",
    "appInsightsKeyOrPlanName": "[if(bool(variables('appInsightsEnabled')), 'InstrumentationKey', 'name')]"
  },
  "resources": [
    {
      "comments": "The example service plan",
      "apiVersion": "2015-08-01",
      "type": "Microsoft.Web/serverfarms",
      "location": "[resourceGroup().location]",
      "name": "[variables('planName')]",
      "sku": {
        "name": "B1",
        "capacity": 1
      },
      "properties": {
        "numberOfWorkers": 1,
        "name": "[variables('planName')]"
      }
    },
    {
      "comments": "The application insights instance",
      "apiVersion": "2014-04-01",
      "condition": "[bool(variables('appInsightsEnabled'))]",
      "type": "Microsoft.Insights/components",
      "location": "[parameters('appInsightsLocation')]",
      "name": "[variables('appInsightsName')]",
      "properties": {}
    }
  ],
  "outputs": {
    "appInsightsKey": {
      "value": "[if(bool(variables('appInsightsEnabled')), reference(variables('appInsightsOrPlanResource'))[variables('appInsightsKeyOrPlanName')], '')]",
      "type": "string"
    }
  }

The template declares two resources. One app service plan and one Application Insights instance. The AppInsights instance is deployed only if the location parameter is not empty string. So the instrumentation key of this instance is also returned only if it has been created.

To achieve this we also need a resource that is always present. In our case this is the service plan. We use this resource to get the reference when AppInsights is not deployed. This could be any azure resource of course.

The trick happens on the two variables appInsightsOrPlanResource and appInsightsKeyOrPlanName we declare. When appInsightsLocation is provided then those two variables end up referencing the key of the instance which is returned from the output.

When appInsightsLocation is not provided on the other hand those two variables contain a valid reference to the service plan that is not used but it's valid. We need to do this one because if function evaluates always both sides. An empty string is returned from the output in this case though.

xabikos
  • 195
  • 11
  • The `if` condition on the output `value` worked for me. When condition is true, it returns the resource information. When false, the empty string is returned. – Stringfellow Feb 27 '19 at 22:44
  • That's a good answer, but it's out of date now that arm templates support conditional outputs. – Vince Bowdren Feb 15 '21 at 14:53
2

I know this is an old question, but in case anyone arrives here, it looks like MSFT has fixed this in two ways now.

In Feb 2019 they fixed the 'if' evaluation to only evaluate the true side.
https://feedback.azure.com/forums/281804-azure-resource-manager/suggestions/31538470-arm-template-if-function-should-not-evaluate-both

In August 2019 they added support for condition: in the outputs. https://feedback.azure.com/forums/281804-azure-resource-manager/suggestions/19492006-conditional-output-from-arm-template

https://learn.microsoft.com/en-us/azure/azure-resource-manager/resource-group-authoring-templates#outputs

Looks like as long as you're at Azure CLI version 2.0.72 you'll have access to these changes. I just tested both on 2.0.76 and they appear to work.

tpankake
  • 366
  • 2
  • 3