Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Arm Template conditional output parameters

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.

like image 614
johnstaveley Avatar asked Aug 31 '17 11:08

johnstaveley


People also ask

What is the maximum parameters allowed in an ARM template?

You're limited to 256 parameters in a template. You can reduce the number of parameters by using objects that contain multiple properties. Name of the parameter.

What should we use to capture the result or values returned in a deployment?

You use outputs when you need to return values from the deployed resources. The format of each output value must resolve to one of the data types. We recommend Bicep because it offers the same capabilities as ARM templates and the syntax is easier to use. To learn more, see outputs.


1 Answers

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.

like image 122
xabikos Avatar answered Oct 22 '22 00:10

xabikos