Azure Resource Template: language expression is not supported - azure

I'm creating an Azure resource template and getting this validation error when I specify tags:
New-AzureResourceGroupDeployment : Error 1: Code=InvalidTemplate;
Message=Deployment template validation failed: 'The template resource
'hosting-plan' at line '86' and column '10' is not valid: Template
language expression '[parameters('intranetConnectivity')]' is not
supported..'.
Here's the relevant section of the template:
"parameters": {
"intranetConnectivity": {
"type": "bool",
"defaultValue": false
},
...
}
"name": "[parameters('siteName')]",
"type": "Microsoft.Web/sites",
"location": "[parameters('siteLocation')]",
"tags": {
"[concat('hidden-related:', resourceGroup().id, '/providers/Microsoft.Web/serverfarms/', parameters('hostingPlanName'))]": "Resource",
"ServiceModel": "[parameters('serviceModel')]",
"IntranetConnectivity": "[parameters('intranetConnectivity')]",
"Environment": "[parameters('environment')]"
},
I thought maybe the parameter name was too long, but I get the same error regardless of the parameter name.

It turned out that it didn't like me using a boolean parameter in a string value. I changed the parameter definition to string and everything works.
"intranetConnectivity": {
"type": "string",
"allowedValues": [
"true",
"false"
],
"defaultValue": "false"
},

Just to clarify Tags only support string values, not anything else. Check the limitations
Not all resource types support tags. To determine if you can apply a tag to a resource type, see Tag support for Azure resources.
Each resource or resource group can have a maximum of 50 tag
name/value pairs. If you need to apply more tags than the maximum
allowed number, use a JSON string for the tag value. The JSON string
can contain many values that are applied to a single tag name. A
resource group can contain many resources that each have 50 tag
name/value pairs.
The tag name is limited to 512 characters, and the tag value is
limited to 256 characters. For storage accounts, the tag name is
limited to 128 characters, and the tag value is limited to 256
characters.
Generalized VMs don't support tags.
Tags applied to the resource group are not inherited by the resources
in that resource group.
Tags can't be applied to classic resources such as Cloud Services.
Tag names can't contain these characters: <, >, %, &, \, ?, /

Related

Azure ARM template for Automation Account Variable - cant use paramets as value

I am trying to create an ARM template for my runbook with additional variables ab packages.
I want to have the values of Automation Account Variables as parameters of ARM template.
When I am using the documentation syntax I am getting the variables value as "[parameters(parameterName)] instead the value of the parameter
when I am not using the syntax code I just get this error:
Invalid JSON - Kindly check the value of the variable
This is the ARM template resource code:
{
"apiVersion": "2020-01-13-preview",
"type": "Microsoft.Automation/automationAccounts/variables",
"name": "[concat(parameters('AutomationAccount'), '/blobContainerName')]",
"location": "[parameters('automationRegion')]",
"properties": {
"description": "output container name",
"isEncrypted": false,
"value": "\"[parameters('blobContainerName')]\""
}
}
how its looks like in the variables after deployment:
Try the following:
"properties": {
"value": "[concat('\"', parameters('blobContainerName'), '\"')]"
},
You need to use concat to join the strings

Concat variable with string in Azure ARM Template

I feel really dump right now but I just can't get this to work. Kind of new to ARM Templates so sorry for my ignorance.
I am trying to use a parameters.json with New-AzResourceGroupDeployment but I want to dynamically feed it in the VMName.
I am trying to use this for the NSG name:
"value": "[concat(variables('vmName'),'-nsg')]"
But I get back an error of:
New-AzResourceGroupDeployment: 6:39:21 AM - Error:
Code=InvalidResourceName; Message=Resource name
[concat(variables('vmName'),'-nsg')] is invalid. The name can be up to
80 characters long. It must begin with a word character, and it must
end with a word character or with ''. The name may contain word
characters or '.', '-', ''.
What am I missing?
Where do you use the Concat function? Because ARM template functions are only available in the ARM template itself, not in the .parameters.json file.
Edit as a response:
It really depends on the use case but I would do something like this in the main ARM template if the 'nsg' value does not change for the given ARM template. If it does then define a second parameter 'vmsuffix' and concat both parameters into the full VMname.
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"VmName": {
"type": "string",
"defaultValue": ""
}
},
"variables": {
"FullVmName": "[concat(parameters('VmName'), 'nsg')]"
},
"resources": [
{
...
## Use the [variables('FullVmName') somewhere here
}
]
}

How to properly use `outputs` in Azure Blueprints?

I have a misunderstanding how blueprint outputs works and how to properly import values from one artifact to another.
Let me describe my attempts to get variable from artifact:
I have created two artifacts inside resource groups:
I have tried to transfer variables like vnet_name, vnet_addresses from VNET artifact to SUBNET_AKS artifact using the following syntax:
VNET:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
........
"outputs": {
"vnet_name_output": {
"type": "string",
"value": "[variables('vnet_name')]"
},
"vnet_ip_range_output": {
"type": "string",
"value": "[parameters('vnet_ip_range')]"
},
"vnet_path_output": {
"type": "string",
"value": "[resourceId('Microsoft.Network/virtualNetworks', variables('vnet_name'))]"
}
}
}
Next step was to add output variable to SUBNET_AKS artifacts:
"resources": [
{
"apiVersion": "2018-04-01",
"type": "Microsoft.Network/virtualNetworks/subnets",
"name": "[concat(artifacts('VNET').outputs.vnet_name_output, '/', concat(parameters('deployment_prefix'),'-aks-subnet'))]",
But the following error appears:
Deployment template validation failed: 'The template resource '[concat(artifacts('VNET').outputs.vnet_name_output, '/', concat(parameters('deployment_prefix'),'-aks-subnet'))]' at line '27' and column '9' is not valid: The template function 'artifacts' is not valid. Please see https://aka.ms/arm-template-expressions for usage details.. Please see https://aka.ms/arm-template-expressions for usage details.'.
How can I understand how outputs parameters should properly work in Azure Blueprint definition?
Azure Blueprint is just an orchestration layer responsible for the ordering and deployment of artifact(s). ARM templates are one of three valid types - policyAssignment and roleAssignment are the other two.
This means you have two "template" artifacts: VNET and SUBNET_AKS. Each one should be treated like an actor / black-box, meaning you can only use functions available to ARM templates. If you need a parameter from the Blueprint it must come in as a parameter.
That is why you are getting that particular syntax error. The artifacts() function is only available to Blueprints.
Instead, you need to update your ARM template so that it specifies a named output value. In your Azure Blueprint, you can reference the output of a prior artifact as an input parameter to a subsequent Blueprint artifact.
Hopefully these code snippets and docs can point you in the right direction.

How to check the resource exists in the arm template

How do i identify the azure resource is exists or not in the ARM templates by the resource type and identifier
It is actually kind of possible. You can use resource group tags to mark a current deployed version and skip deployment if the tag is set. All this could be achieved via linked template.
Note that we don't check for resource existence per se but we still allow writing ARM template that could contain one time initialization templates. The last will restore the resource if resource group was deleted and resources were lost (given that you created the resource group again). You can extend this to support per-resource tags which will be more useful in some cases.
The template that starts the deployment may look like this:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"DeploymentTemplateLink": {
"type": "string"
},
"DeploymentVersion": {
"defaultValue": 1,
"type": "int"
}
},
"variables": {
"rgWithDefaultVersion": {
"tags": {
"Version": "0"
}
}
},
"resources": [
{
"type": "Microsoft.Resources/deployments",
"apiVersion": "2017-05-10",
"name": "DeploymentTemplate",
"condition": "[less(int(union(variables('rgWithDefaultVersion'), resourceGroup()).tags['Version']), parameters('DeploymentVersion'))]",
"properties": {
"mode": "Incremental",
"templateLink": {
"uri": "[parameters('DeploymentTemplateLink')]",
"contentVersion": "1.0.0.0"
},
"parameters": {
"DeploymentVersion": {
"value": "[parameters('DeploymentVersion')]"
}
}
}
}
]
}
The linked template's condition looks into tags and returns true only if current version (stored in the tag) is less than the requested one. You don't actually have to maintain versioning: just don't set the DeploymentVersion parameter and it will deploy only for the first time. If you decide to redeploy anyway you have always an option to increase the version, which will cause deployment of the linked template (aka "main deployment").
The main deployment template is on you, but it should contain a tags resource in order to maintain the logic.
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"DeploymentVersion": {
"defaultValue": 1,
"type": "int"
}
},
"variables": {},
"resources": [
{
"type": "Microsoft.Resources/tags",
"name": "default",
"apiVersion": "2019-10-01",
"dependsOn": [],
"properties": {
"tags": {
"Version": "[string(parameters('DeploymentVersion'))]"
}
}
}
]
}
Remark for those who didn't understand the union() and rgWithDefaultVersion thing. ARM template deployment will fail if referenced object doesn't contain a property. In our case we have two such properties: 'tags' and 'Version'. 'Tags' will exist only if particular resource group has or ever had tags. 'Version' will exist only after we already wrote it once (in the main deployment). Therefore before we access them we perform union() operation on returned object with a proper default one, ensuring that we can safely access the mentioned properties.
there is no way of doing that in an arm template. you can use some external source (like powershell) to determine that and pass in parameter with appropriate value, alternatively you can use tags to figure that out (have a tag that represents an existence\absence of a resource).
Resource Manager provides the following functions for getting resource values: Resource functions for Azure Resource Manager templates
You could wrap your template with a piece of powershell\whatever, that would determine if the resource exists, and pass in the parameter value depending on that and use a conditional statement in the template that would decide what to do based on the input (but the input has to come from elsewhere)
I needed a solution to this recently to basically do an incremental update to a SQL server. Since you can't do this; the template will fail with a NameAlreadyExists error.
So I needed to check the resource doesn't exist and only create if it doesn't.
Add a "condition" check for the azure resource id exists; don't create if it does.
{
...
"condition": "[empty(resourceId('[resourceGroup().id]', 'Microsoft.SQL/servers', parameters('serverName')))]",
...
}
You can do this for any resource type.

ARM template, Incorrect Segment Lengths

I'm trying to build an ARM template and keep getting the error:
'The template resource 'udr-sub-w05-w05-w05-agw-10.10.10.32/27' for type
'Microsoft.Network/routeTables' at line '141' and column '5' has incorrect segment lengths. A nested resource type must have identical number of segments as its resource name. A root resource type must
have segment length one greater than its resource name.
The nested template for create route tables code is below:
{
"name": "[variables('routeTable1')]",
"type": "Microsoft.Network/routeTables",
"apiVersion": "[variables('routeTableApiVersion')]",
"location": "[resourceGroup().location]",
"properties": {
"routes": [
],
"disableBgpRoutePropagation": false
}
},
{
"name": "[variables('routeTable2')]",
"type": "Microsoft.Network/routeTables",
"apiVersion": "[variables('routeTableApiVersion')]",
"location": "[resourceGroup().location]",
"properties": {
"routes": [
],
"disableBgpRoutePropagation": false
}
},
Any idea where this is going wrong? I've spent some time googling and my understanding is the "TYPE" should have one less segment than the "NAME", which I believe it has
"name": "[variables('routeTable1')]",
"type": "Microsoft.Network/routeTables",
Route table one variables
"routeTable1": "[tolower(concat('udr-', variables('subnetName1')))]",
"routeTable2": "[tolower(concat('udr-', variables('subnetName2')))]",
Thanks
Your route table name contains /, hence it thinks you are trying to create a sub resource and asks you to provide its type (you only provide parent resource type). remove the /27 thing or replace it with -27 or something like that.

Resources