Handling dependencies in Azure Resource Manager Linked Templates - azure

Azure Resource Manager (ARM) Templates have the ability to use Linked Templates. These linked templates can define additional resources to create during an ARM template deployment.
ARM templates support dependencies which ensure some resources are created before others are.
I would like to specify a dependency in a linked template for a resource created in the master template. If I include the dependency in the Linked Template, it looks like this:
"resources": [
{
"apiVersion": "2015-08-01",
"type": "Microsoft.Web/sites/hostNameBindings",
"name": "[concat(parameters('siteName'),'/', parameters('fqdn'))]",
"dependsOn": [
"[concat('Microsoft.Web/sites/', parameters('siteName'))]"
],
"properties": {
"siteName": "[parameters('siteName')]"
}
}
]
While the dependsOn appears correct, the a resource is created at Microsoft.Web/sites/{siteNameParameter}, deploying the ARM template outputs the following error message:
InvalidTemplate : Deployment template validation failed: 'The resource 'Microsoft.Web/sites/blahblahblahblah' is not defined in the template. Please see https://aka.ms/arm-template for usage details.'.
I am currently defining this dependency in the master template when I define the linked template call. This seems brittle and easy to break. Is there a better way than defining dependencies in the master ARM template?
{
"apiVersion": "2015-01-01",
"name": "SomeName",
"type": "Microsoft.Resources/deployments",
"dependsOn": [
"[concat('Microsoft.Web/sites/', parameters('siteName'))]"
],
"properties": {
"mode": "Incremental",
"templateLink": {
"uri": "https://tempuri.org/supersecrettemplatepath/azuredeploy.json",
"contentVersion": "1.0.0.0"
},
"parameters":
{
"fqdn": {
"value": "www.tempuri.org"
},
"siteName": {
"value": "[parameters('siteName')]"
}
}
}
}

You can define the dependency either way - both are valid. Putting the dependency on the deployment resource (your second approach) will mean that the entire nested deployment is not started until the web site is provisioned. If you wanted to kick some things off in parallel, then you would put the dependency in the nested template (your first approach). That may or may not matter for your scenario, but that's a key difference.
dependsOn requires a resourceId - and as the error is trying to say, if the resource is not defined in the template you need more detail in the resourceId, in this case, you need the resourceGroup (maybe the subscription, but I doubt it). So for example you can use:
"dependsOn": [
"[resourceId(resourceGroup().name, 'Microsoft.Web/sites', parameters('siteName'))]"
],

The dependsOn needs the name of the linked deployment, not one of the resources in it.
e.g.:
dependsOn: "Microsoft.Resources/deployments/myExternalTemplate"

"dependsOn": [
"[resourceId(subscription().subscriptionId, resourceGroup().name, 'Microsoft.Web/sites', parameters('siteName'))]"
],

Related

The specified name is not available Azure EventHub namespace

I have tried to deploy an ARM template with new EventHub Namespace. But it is failing with the BadRequest error, The specified name isn't available.. But the name has not used previously in anything under that resource group. When I tried to create a similar resource manually from the portal it is working fine. So it should not be a privileges' issue. Can anyone suggest my issue here please?
{
"type": "Microsoft.EventHub/namespaces",
"apiVersion": "2021-11-01",
"name": "xxxx-xxxx-xxx-000",
"location": "[variables('location')]",
"sku": {
"name": "Standard",
"tier": "Standard",
"capacity": 1
},
"properties": {
"isAutoInflateEnabled": false,
"maximumThroughputUnits": 0
}
}
We have tried the same in our environment to create an eventhub namespace with name similar to yours and it works fine .
Below is the workaround we followed;
In the same name that we will be trying to deploy through ARM created in portal and then trying to deploy through ARM and got the same issue.
Yes its a known issue we can expect , To ensure that we need to provide the name which is globally unique and not by any resource group ,Not only at your resource group ,this name should not use anywhere(Azure) .
Make sure that if you have created it through portal and trying with ARM again , please delete the previous one if you are owner of that namespace. And try again with same name after deletion.
We have provided the namespace just similar to you to check whether this value is passed or not and it works successfully.
template.json
"resources": [
{
"type": "Microsoft.EventHub/namespaces",
"apiVersion": "2022-01-01-preview",
"name": "[parameters('namespaces_ajletter_test_111_something_name')]",
"location": "Central India",
"sku": {
"name": "Standard",
"tier": "Standard",
"capacity": 1
},
OUTPUT SCREENSHOT FOR REFERENCE:-
For more information please refer the below links:-
MICROSOFT DOCUMENTATION| EventHub ARM EXCEPTION & Create EventHub Namespace using ARM Template .

Azure Functions ARM Template deploy deletes Functions

I've got an ARM template (included below) to deploy an Azure Function App. I deploy it with:
az group deployment create --resource-group my-group --template-file my-function-app.json
This works and I can then deploy my functions successfully using the VS Code plugin or Azure Functions Core Tools.
However, if I then re-deploy the ARM template (for example to update an application setting) then I lose my functions and need to re-deploy them again. Is this expected behaviour? It's not what I observe when deploying e.g. a Web App via an ARM template. Is there something specific I can do when deploying an ARM template for a Function App to preserve my deployed functions?
my-function-app.json:
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
...
},
"variables": {
...
},
"resources": [
{
"apiVersion": "2015-08-01",
"type": "Microsoft.Web/sites",
"name": "[variables('collectorFunctionAppName')]",
"location": "[parameters('location')]",
"kind": "functionapp",
"properties": {
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]",
"siteConfig": {
"appSettings": [
{
...
}
]
}
}
}
],
"outputs": {}
}
Are you deploying your function as a package? If so, make sure you set this setting in your template, since it will be removed when you redeploy otherwise:
{
"name": "WEBSITE_RUN_FROM_PACKAGE",
"value": "1"
}
You could try "--mode incremental" parameter although that should be the default when it is not provided.
Yes that should be the expected behavior.
ARM Template is a declarative deployment meaning anytime you deploy it will overwrite anything you have with new template information. The template should always include everything you need.

Since it's not possible to create Blob container in Azure ARM, then how can I enable Archive using ARM?

According to the documentation I can enable the Azure Event Hubs Archive feature using an Azure Resource Manager template. The template takes a blobContainerName argument:
"The blob container where you want your event data be archived."
But afaik it's not possible to create a blob container using an ARM template, then how am I supposed to enable the Archive feature on an Event Hub?
The purpose of the ARM template is to provision everything from scratch, not to manually create some of the resources using the portal.
It wasn't possible before to create containers in your storage account, but this has been changed. New functionality has been added to the ARM template for Storage Accounts which enable you to create containers.
To create a storage account with a container called theNameOfMyContainer, add this to your resources block of the ARM template.
{
"name": "[parameters('storageAccountName')]",
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2018-02-01",
"location": "[resourceGroup().location]",
"kind": "StorageV2",
"sku": {
"name": "Standard_LRS",
"tier": "Standard"
},
"properties": {
"accessTier": "Hot"
},
"resources": [{
"name": "[concat('default/', 'theNameOfMyContainer')]",
"type": "blobServices/containers",
"apiVersion": "2018-03-01-preview",
"dependsOn": [
"[parameters('storageAccountName')]"
],
"properties": {
"publicAccess": "Blob"
}
}]
}
To my knowledge, you can use None, Blob or Container for your publicAccess.
It's still not possible to create Queues and Tables, but hopefull this will be added soon.
Just like you said, there is no way to create a blob in Azure ARM Template, so the only logical answer to this question is: supply existing blob at deployment time. One way to do that would be to create a blob with powershell and pass it as a parameter to ARM Deployment.

Azure ARM templates - using the output of other deployments

What I am interested in is reading the output parameters of another deployment in a different resource group.
My ARM templates are something like:
platform.json - sets up the DNS, virtual networks and security
storage.json - sets up databases and other stores
app.json - sets up the web app/api
Each is deployed in different resource groups as they have different life cycles. However, when I deploy the app.json I want to pull in the outputs of the latest platform and storage deployments and use them to configure the app.
Linked templates are not a solution as the linked templates end up deployed in the same resource group as the app which defeats the purpose of segregating your resources in resource groups.
Is there any way I can read the output parameters of a deployment from a different resource group? if not, is Azure planning to support it?
I know there is a way to get the resources by id, using the resourceId function, and look at their properties but I am trying to avoid doing that to not get into a resource reference spagetti.
I know this is an old question but for others who come along, as of 03/12/18 you can definitely do this.
You need to ensure your output is formatted as per the Microsoft documentation for output variables which broadly has the format
"outputs": {
"resourceID": {
"type": "string",
"value": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('publicIPAddresses_name'))]"
}
}
You can then use these outputs in your templates by referencing the deployment using a resource reference which has the format
reference(resourceName or resourceIdentifier, [apiVersion], ['Full'])
Note that you will need to provide the api version, as the deployment may use a different api version to the one your parent template uses.
Your reference would then look something like the following
{
"comments": "This would have an output named myOutput you want to use",
"apiVersion": "2017-05-10",
"type": "Microsoft.Resources/deployments",
"name": "my-deployment",
"resourceGroup": "...",
"properties": {
"mode": "Incremental",
"templateLink": {
"uri": "...",
"contentVersion": "1.0.0.0"
},
"parameters": { }
},
{
"comments": "This makes use of myOutput from my-deployment",
"apiVersion": "2017-05-10",
"type": "Microsoft.Resources/deployments",
"name": "my-dependent-deployment",
"properties": {
"mode": "Incremental",
"templateLink": {
"uri": "...",
"contentVersion": "1.0.0.0"
},
"parameters": {
"myValueFromAnotherDeployment": { "value": "[reference('my-deployment', '2017-05-10').outputs.myOutput.value]" }
}
}
}
Note the slightly awkward "repackaging" of the value, where we use myOutput.value as the input to the dependent deployment, and put that in an object with the key "value": "....". This is because ARM parameters must have a 'value' property in order to be valid.
You'll get invalid template errors if you try to use the output directly (because output variables have a 'type' and this is not an allowed key in a parameter). That's why you need to get the value property and then put it back into the value in downstream templates.
How are you doing your deployments? In PowerShell you can do something like:
(Get-AzureResourceGroupDeployment NameOfResourceGroup).Outputs.NameOfOuputProperty.Value
And that will give you the output of the most recent deployment. You can also throw the entire deployment object into a var and have at it that way.
$d = Get-AzureResourceGroupDeployment NameOfResourceGroup
Which would be faster if you needed a many output properties.
That help?
Update for AzureRM cmdlet
The syntax is largely the same:
(Get-AzureRmResourceGroupDeployment -ResourceGroupName NameOfResourceGroup -Name NameOfDeployment).Outputs.NameOfOutputProperty.value
If you have multiple deployments you can use:
Get-AzureRmResourceGroupDeployment -ResourceGroupName NameOfResourceGroup
To see them all and see what the names are...
Are you using Azure DevOps Release Pipelines? You could just set the output to be created as variables so you can re-use them in the same or a different stage.
We use these extensions on our projects
ARM Outputs
https://github.com/keesschollaart81/vsts-arm-outputs
VSTS replacetokens
https://github.com/qetza/vsts-replacetokens-task

Autoscaling IaaS VMs in ARM mode from a template

I've created an template-based deployment that over-provisions a number of Linux VMs. I'd like to autoscale them as per classic instances, where Azure will turn on/turn off instances according to CPU load.
Is this possible with ARM mode? And if not, is there a suggested alternative method? The only examples I can find are around using Application Insights and PaaS functionality. I've got a Python app running in Docker on Ubuntu hosts.
For IaaS, you must use virtual machine scale sets to use autoscale, else you need to stick with PaaS (web apps).
For this you would first need to create an availability group for the VMs. The resource decleration in the ARM template looks something like this:
{
"type": "Microsoft.Compute/availabilitySets",
"name": "[variables('availabilitySetName')]",
"apiVersion": "2015-05-01-preview",
"location": "[parameters('location')]",
"properties": {
"platformFaultDomainCount": "2"
}
}
Then for the virtual machine resource the decliration in the ARM Template would look something like this:
{
"apiVersion": "2015-05-01-preview",
"type": "Microsoft.Compute/virtualMachines",
"name": "[concat(variables('vmName'), '0')]",
"location": "[parameters('location')]",
"dependsOn": [
"[concat('Microsoft.Storage/storageAccounts/', parameters('newStorageAccountName'))]",
"[concat('Microsoft.Network/networkInterfaces/', variables('nicName'), '0')]",
"[concat('Microsoft.Compute/availabilitySets/', variables('availabilitySetName'))]"
],
"properties": {
"availabilitySet": {
"id": "[resourceId('Microsoft.Compute/availabilitySets', variables('availabilitySetName'))]"
},
...},
The quckstart templates are a good ref: https://raw.githubusercontent.com/azure/azure-quickstart-templates/master/201-2-vms-2-FDs-no-resource-loops/azuredeploy.json
Once you have two or more VMs of the same size in an availability set, you would configure autoscale using microsoft.insights/autoscalesettings, which I beleive you referenced in the question. This is done at the cloud service so it will work similar to PaaS... like so:
{
"apiVersion": "2014-04-01",
"name": "[concat(variables('vmName'), '-', resourceGroup().name)]",
"type": "microsoft.insights/autoscalesettings",
"location": "East US",
...},
A pretty good example is here: https://raw.githubusercontent.com/Azure/azure-quickstart-templates/6abc9f320e39d9d75dffb60846e88ab80d3ff33a/201-web-app-sql-database/azuredeploy.json
I also setup autoscale using the portal first and reviewed ARMExplorer to get a better idea of how things should look in my code. ARMExplorer is here: Azure Resource Explorer

Resources