How to properly use `outputs` in Azure Blueprints? - azure

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.

Related

Where is the value of deployment().name coming from in Azure Deployment?

As part of our template files, we have a variable defined partially by deployment method's deployment().name, similar to this:
"myVariable": "[concat(SOME_CUSTOM_STRING_HERE, deployment().name)]"
The variable is then used as the deployment label for our Classic Cloud Service resources which includes the build number.
{
"apiVersion": "2015-12-01",
"type": "deploymentSlots",
"name": "staging",
"properties": {
"deploymentLabel": "[variables('myVariable')]",
...
},
...
}
Perhaps deployment().name can be set and not defined by Azure, but I haven't been able I haven't been able to find it.
However, the variable's value is different under Cloud Service Extended Support. This time the value is a long hash and the name of the Cloud Service resource, even thought the definition remains as shown above. The variable is used in a tag:
{
"apiVersion": "2021-03-01",
"type": "Microsoft.Compute/cloudServices",
"name": "RESOURCE_NAME",
"location": "[LOCATION]",
"tags": {
"DeploymentLabel": "[variables('myVariable')]",
...
},
...
}
So did the value of deployment().name template function change for deployments of Extended Support version of cloud service? If not, can it be set and how?
From the Azure Devops side, if you are running the deployment the task itself has the deployment name like deployment mode. if its not provided, automatically it gets generated
deploymentMode: 'Incremental'
deploymentName: 'deploymentname'
if its powershell then please check the link below
https://learn.microsoft.com/en-us/azure/azure-resource-manager/templates/deploy-cli#azure-deployment-template-name
you set the name when you deploy a resource:
{
"apiVersion": "2021-03-01",
"type": "Microsoft.Compute/cloudServices",
"NAME": "MYRESOURCE",
"location": "[LOCATION]",
"tags": {
"DeploymentLabel": "[variables('myVariable')]",
...
},
...
}

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

Why is ARM deployment with integer parameters not picked up by Azure DevOps?

When I deploy in Azure DevOps the ARM template below I get an error due to an integer was expected, but a string was found. If I explicitly change the variables to values it will be properly picked up. Any idea what is going on here?
I have a Release Pipeline which deploys an ARM Template with parameters (not working, found string but integer was expected):
This works since I changed the variable values to explicit integers (working, but I want to use variable groups):
In the variable groups I have defined the name and values as:
FaultDomains 2
UpdateDomains 5
ARM Template:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "0.0.1.0",
"parameters": {
"AvailabilitySetName": {
"type": "string"
},
"FaultDomains": {
"type": "int"
},
"UpdateDomains": {
"type": "int"
}
},
"resources": [
{
"apiVersion": "2016-04-30-preview",
"type": "Microsoft.Compute/availabilitySets",
"name": "[parameters('AvailabilitySetName')]",
"location": "[resourceGroup().location]",
"properties": {
"platformUpdateDomainCount": "[parameters('UpdateDomains')]",
"platformFaultDomainCount": "[parameters('FaultDomains')]"
},
"sku": {
"name": "Aligned"
}
}
]
}
I tried to recreate the case and was able to deploy the availabilty set with given template using release pipeline,
Parameters
and make sure the parameteres are defined in the release variables.
NOTE: I used ARM TEMPLATE DEPLOYMENT task for deployment
deployment results

Azure ARM template GEN_PASSWORD placeholder not working

I'm trying to deploy simple resource group to Azure with ARM template. It consist of single virtual machine with public IP and nsg allowing accessing it via SSH. To secure access I'm setting admin user and password for VM, which are passed to template with parameters json. VM definition looks like this:
{
"type": "Microsoft.Compute/virtualMachines",
"apiVersion": "2018-10-01",
"name": "[variables('vmName')]",
"location": "[parameters('location')]",
"dependsOn": [
"[resourceId('Microsoft.Network/networkInterfaces', variables('networkInterfaceName'))]"
],
"properties": {
"hardwareProfile": {
"vmSize": "Standard_D2s_v3"
},
"osProfile": {
"computerName": "[variables('vmName')]",
"adminUsername": "[parameters('adminUsername')]",
"adminPassword": "[parameters('adminPassword')]",
"linuxConfiguration": {
"disablePasswordAuthentication": false
}
},
// ...
},
// ...
}
According to Azure quickstart templates repository for generating password I can use GEN-PASSWORD placeholder and GEN-UNIQUE to get unique alphanumeric string. That's why my parameters json looks like this:
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
// ...
"adminUsername": {
"value": "GEN_UNIQUE"
},
"adminPassword": {
"value": "GEN_PASSWORD"
}
}
}
However, whenever I try to deploy it (via Azure DevOps Pipeline) I got error that password is invalid:
2020-06-29T21:27:40.5401781Z ##[error]At least one resource deployment operation failed. Please list deployment operations for details. Please see https://aka.ms/DeployOperations for usage details.
2020-06-29T21:27:40.5416217Z ##[error]Details:
2020-06-29T21:27:40.5419655Z ##[error]InvalidParameter: The supplied password must be between 6-72 characters long and must satisfy at least 3 of password complexity requirements from the following:
1) Contains an uppercase character
2) Contains a lowercase character
3) Contains a numeric digit
4) Contains a special character
5) Control characters are not allowed
Can anyone help? I tried to find more info about these placeholders, but Azure GitHub repository that I linked above seems to be the only source.
The GEN* values are special placeholders that only work in the context of the Azure Resource Manager QuickStart Templates repository and its automated template validation.
I am afraid you cannot use these placeholders in your own custom Azure DevOps pipelines.

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.

Resources