JSON Template Failing with Active deployment in loop - json

I'm trying to create a template which does multiple vm's in Azure and then encrypts the disks, I've managed to get it working with 2 vm's about 3 hours ago, however when I do three of more vm's in the loop I get the following error:
"code": "DeploymentFailed",
"message": "At least one resource deployment operation failed. Please list deployment operations for details. Please see https://aka.ms/arm-debug for usage details.",
"details": [
{
"code": "Conflict",
"message": "{\r\n \"error\": {\r\n \"code\": \"DeploymentActive\",\r\n \"message\": \"Unable to edit or replace deployment 'updatevm': previous deployment
from '12/29/2018 1:11:34 AM' is still active (expiration time is '1/5/2019 1:11:34 AM'). Please see https://aka.ms/arm-deploy for usage details.\"\r\n }\r\n}"
}
]
}
]
Is there a way of putting a pause so it waits for the updatevm extension to complete?
The section of code I have for the encryption is:
{
"name": "[concat(parameters('VMNames'),copyIndex(),'UpdateEncryptionSettings')]",
"type": "Microsoft.Resources/deployments",
"apiVersion": "2015-01-01",
"dependsOn": [
"[concat('Microsoft.Compute/virtualMachines/', parameters('VMNames'),copyIndex(1))]"
],
"properties": {
"mode": "Incremental",
"templateLink": {
"uri": "[concat(parameters('_artifactsLocation'),'/nestedtemplates/encryptVm.json',parameters('_artifactsLocationSasToken'))]",
"contentVersion": "1.0.0.0"
},
"parameters": {
"vmName": {
"value": "[concat(parameters('VMNames'), copyIndex(1))]"
},
"aadClientID": {
"value": "[parameters('aadClientID')]"
},
"aadClientSecret": {
"value": "[parameters('aadClientSecret')]"
},
"keyVaultName": {
"value": "[parameters('keyVaultName')]"
},
"keyVaultResourceGroup": {
"value": "[parameters('keyVaultResourceGroup')]"
},
"useExistingKek": {
"value": "[parameters('useExistingKek')]"
},
"keyEncryptionKeyURL": {
"value": "[parameters('keyEncryptionKeyURL')]"
},
"_artifactsLocation": {
"value": "[parameters('_artifactsLocation')]"
},
"_artifactsLocationSasToken": {
"value": "[parameters('_artifactsLocationSasToken')]"
}
}
}
},

make it depend on the previous extension, since you do not provide the exact code, its something like:
"dependsOn": [
"updatevm"
}
this didnt exactly work due to how the templates were structured, the answer was to use serial copy mode to only create one copy at a timeю
"copy": {
"name": "storagecopy",
"count": 4,
"mode": "serial",
"batchSize": 1
}
https://learn.microsoft.com/en-us/azure/azure-resource-manager/resource-group-create-multiple#resource-iteration

Related

Provisioning resource group and azure function at deployment level

I've written up the script below to do the following:
Provision a resource group
In a separate deployment:
Provision a storage account
Provision a server farm
Provision a function app
The problem lies in the setting of the app settings in the function app, when I'm setting up the AzureWebJobsStorage. The resourceId function fails to resolve the storage account. When looking at the documention for the resourceId function, it states:
When used with a subscription-level deployment, the resourceId() function can only retrieve the ID of resources deployed at that level. [docs]
But now I don't know how to resolve this!
Template:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"resourceGroupName": {
"type": "string"
},
"functionName": {
"type": "string"
},
"storageAccName": {
"type": "string"
},
"namingPrefix": {
"type": "string"
}
},
"variables": {
"resourceGroupLocation": "North Europe",
"planName": "[replace(concat(variables('resourceGroupLocation'), 'Plan'),' ','')]",
"resourceGroupName": "[concat(parameters('namingPrefix'), '-', parameters('resourceGroupName'))]",
"functionName": "[concat(parameters('namingPrefix'), '-', parameters('functionName'))]",
"storageAccName": "[toLower(concat(parameters('namingPrefix'), parameters('storageAccName')))]"
},
"resources": [
{
"type": "Microsoft.Resources/resourceGroups",
"apiVersion": "2018-05-01",
"location": "[variables('resourceGroupLocation')]",
"name": "[variables('resourceGroupName')]",
"properties": {}
},
{
"type": "Microsoft.Resources/deployments",
"apiVersion": "2019-05-01",
"name": "NestedTemplate",
"resourceGroup": "[variables('resourceGroupName')]",
"dependsOn": [
"[variables('resourceGroupName')]"
],
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2019-04-01",
"name": "[variables('storageAccName')]",
"location": "[variables('resourceGroupLocation')]",
"sku": {
"name": "Standard_LRS",
"tier": "Standard"
},
"kind": "Storage",
"properties": {
"networkAcls": {
"bypass": "AzureServices",
"virtualNetworkRules": [],
"ipRules": [],
"defaultAction": "Allow"
},
"supportsHttpsTrafficOnly": true,
"encryption": {
"services": {
"file": {
"enabled": true
},
"blob": {
"enabled": true
}
},
"keySource": "Microsoft.Storage"
}
}
},
{
"type": "Microsoft.Web/serverfarms",
"apiVersion": "2016-09-01",
"name": "[variables('planName')]",
"location": "[variables('resourceGroupLocation')]",
"sku": {
"name": "Y1",
"tier": "Dynamic",
"size": "Y1",
"family": "Y",
"capacity": 0
},
"kind": "functionapp",
"properties": {
"name": "[variables('planName')]",
"computeMode": "Dynamic",
"perSiteScaling": false,
"reserved": false,
"targetWorkerCount": 0,
"targetWorkerSizeId": 0
}
},
{
"type": "Microsoft.Web/sites",
"apiVersion": "2016-08-01",
"name": "[variables('functionName')]",
"location": "[variables('resourceGroupLocation')]",
"dependsOn": [
"[variables('planName')]",
"[variables('appInsightsName')]",
"[variables('storageAccName')]"
],
"kind": "functionapp",
"identity": {
"type": "SystemAssigned"
},
"properties": {
"enabled": true,
"hostNameSslStates": [
{
"name": "[concat(variables('functionName'), '.azurewebsites.net')]",
"sslState": "Disabled",
"hostType": "Standard"
},
{
"name": "[concat(variables('functionName'), '.scm.azurewebsites.net')]",
"sslState": "Disabled",
"hostType": "Repository"
}
],
"siteConfig": {
"appSettings": [
{
"name": "AzureWebJobsStorage",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccName'), ';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccName')), providers('Microsoft.Storage', 'storageAccounts').apiVersions[0]).key1)]"
},
{
"name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccName'), ';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccName')), providers('Microsoft.Storage', 'storageAccounts').apiVersions[0]).key1)]"
},
{
"name": "WEBSITE_CONTENTSHARE",
"value": "[variables('functionName')]"
},
{
"name": "FUNCTIONS_WORKER_RUNTIME",
"value": "node"
},
{
"name": "WEBSITE_NODE_DEFAULT_VERSION",
"value": "10.14.1"
},
{
"name": "FUNCTIONS_EXTENSION_VERSION",
"value": "~2"
}
]
},
"serverFarmId": "[variables('planName')]",
"reserved": false
}
}
]
}
}
}
]
}
Executed using following line:
New-AzDeployment -Location "North Europe" -TemplateFile $TemplateFilePath -TemplateParameterFile $ParametersFilePath -namingPrefix $namingPrefix;
Output
Resource Microsoft.Storage/storageAccounts 'testStorageAccount' failed with message '{
"error": {
"code": "ResourceNotFound",
"message": "The Resource 'Microsoft.Storage/storageAccounts/testStorageAccount' under resource group '<null>'
was not found."
}
}'
You've run into a few "limitations" in the template language that make this hard at the moment (we're working on improving both).
1) Inline nested deployments have the scope of the top-level deployment when evaluating template language expressions (anything in []) which is sometimes convenient (you can share variables for example) but more often than not causes some problem (like the resourceId function). ARM has always behaved this way but with the advent of subscription level deployments it's a bit more problematic (you run into it more). To get around this you can use linked templates - I know that's not always ideal but they will behave as expected.
2) the second thing you're running into is that list*() functions are evaluated immediately if ARM thinks the resource you're accessing is not within the same deployment. Due to #1, that's what ARM thinks in this case and why trying to concat() the resourceID still doesn't work.
Aside from that, stay away from the providers() function for apiVersions, it's not deterministic and the results of that function can change without you knowing it. The code you had in your original post for listKeys did work a while back and you might see it in samples floating around, but changes in the platform can break that function's behavior. Literal apiVersions are always better in ARM templates.
The docs are confusing and don't describe how resourceId() works at that level. It should really say:
When used in a subscription level deployment resourceId() can only get the resource IDs of resource groups (Microsoft.Resources/resourceGroups), policies (Microsoft.Authorization/policyAssignments), and role definitions (Microsoft.Authorization/roleDefinitions), as these are subscription level specific resources.
Since that's how it actually works. More docs here.
In terms of how to proceed from here, you'll simply need to deploy the resource groups in one template at the subscription level, and the resources in another template at the resource group level.
I hit this issue and found that they more recently support nested templates better by defining inner and outer scopes on the deployment resources and function scopes.
https://learn.microsoft.com/bs-latn-ba/azure/azure-resource-manager/templates/cross-scope-deployment?tabs=azure-cli#how-functions-resolve-in-scopes
https://www.youtube.com/watch?v=96XxVyxrhZI
For anyone who runs into this issue at a later date (probably myself) I was forced to create the resource group in my powershell script, and then use new-AzResourceGroupDeployment instead.
To accommodate this, the changes to the deployment template were minimal (I remove the resource group and brought the nested template one level up). However, I was also accessing the storage account key incorrectly. This has been updated in the code below.
$resourceGroup = Get-AzResourceGroup -Name $resourceGroupName -ErrorAction SilentlyContinue
if(!$resourceGroup)
{
Write-Host "Creating resource group '$resourceGroupName' in location '$resourceGroupLocation'";
New-AzResourceGroup -Name $resourceGroupName -Location $resourceGroupLocation
}
else{
Write-Host "Using existing resource group '$resourceGroupName'";
}
# Start the deployment
Write-Host "Starting deployment...";
if(Test-Path $parametersFilePath) {
New-AzResourceGroupDeployment -ResourceGroupName $resourceGroupName -TemplateFile $TemplateFilePath -TemplateParameterFile $parametersFilePath;
}
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"resourceGroupName": {
"type": "string"
},
"functionName": {
"type": "string"
},
"storageAccName": {
"type": "string"
},
"namingPrefix": {
"type": "string"
}
},
"variables": {
"resourceGroupLocation": "North Europe",
"planName": "[replace(concat(variables('resourceGroupLocation'), 'Plan'),' ','')]",
"resourceGroupName": "[concat(parameters('namingPrefix'), '-', parameters('resourceGroupName'))]",
"functionName": "[concat(parameters('namingPrefix'), '-', parameters('functionName'))]",
"storageAccName": "[toLower(concat(parameters('namingPrefix'), parameters('storageAccName')))]"
},
"resources": [
{
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2019-04-01",
"name": "[variables('storageAccName')]",
"location": "[variables('resourceGroupLocation')]",
"sku": {
"name": "Standard_LRS",
"tier": "Standard"
},
"kind": "Storage",
"properties": {
"networkAcls": {
"bypass": "AzureServices",
"virtualNetworkRules": [],
"ipRules": [],
"defaultAction": "Allow"
},
"supportsHttpsTrafficOnly": true,
"encryption": {
"services": {
"file": {
"enabled": true
},
"blob": {
"enabled": true
}
},
"keySource": "Microsoft.Storage"
}
}
},
{
"type": "Microsoft.Web/serverfarms",
"apiVersion": "2016-09-01",
"name": "[variables('planName')]",
"location": "[variables('resourceGroupLocation')]",
"sku": {
"name": "Y1",
"tier": "Dynamic",
"size": "Y1",
"family": "Y",
"capacity": 0
},
"kind": "functionapp",
"properties": {
"name": "[variables('planName')]",
"computeMode": "Dynamic",
"perSiteScaling": false,
"reserved": false,
"targetWorkerCount": 0,
"targetWorkerSizeId": 0
}
},
{
"type": "Microsoft.Web/sites",
"apiVersion": "2016-08-01",
"name": "[variables('functionName')]",
"location": "[variables('resourceGroupLocation')]",
"dependsOn": [
"[variables('planName')]",
"[variables('appInsightsName')]",
"[variables('storageAccName')]"
],
"kind": "functionapp",
"identity": {
"type": "SystemAssigned"
},
"properties": {
"enabled": true,
"hostNameSslStates": [
{
"name": "[concat(variables('functionName'), '.azurewebsites.net')]",
"sslState": "Disabled",
"hostType": "Standard"
},
{
"name": "[concat(variables('functionName'), '.scm.azurewebsites.net')]",
"sslState": "Disabled",
"hostType": "Repository"
}
],
"siteConfig": {
"appSettings": [
{
"name": "AzureWebJobsStorage",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccName'), ';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccName')), providers('Microsoft.Storage', 'storageAccounts').apiVersions[0]).keys[0].value)]"
},
{
"name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING",
"value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccName'), ';AccountKey=', listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccName')), providers('Microsoft.Storage', 'storageAccounts').apiVersions[0]).keys[0].value)]"
},
{
"name": "WEBSITE_CONTENTSHARE",
"value": "[variables('functionName')]"
},
{
"name": "FUNCTIONS_WORKER_RUNTIME",
"value": "node"
},
{
"name": "WEBSITE_NODE_DEFAULT_VERSION",
"value": "10.14.1"
},
{
"name": "FUNCTIONS_EXTENSION_VERSION",
"value": "~2"
}
]
},
"serverFarmId": "[variables('planName')]",
"reserved": false
}
}
]
}
Edited -
Sorry I jumped the gun earlier, the issue is with New-AzDeployment which is specifically for deploying subscription level resources.
https://learn.microsoft.com/en-us/powershell/module/az.resources/new-azdeployment?view=azps-2.7.0
Excerpts from the link above -
The New-AzDeployment cmdlet adds a deployment at the current
subscription scope. This includes the resources that the deployment
requires.
An Azure resource is a user-managed Azure entity. A resource can live
in a resource group, like database server, database, website, virtual
machine, or Storage account. Or, it can be a subscription level
resource, like role definition, policy definition, etc.
To add resources to a resource group, use the
New-AzResourceGroupDeployment which creates a deployment at a resource
group. The New-AzDeployment cmdlet creates a deployment at the current
subscription scope, which deploys subscription level resources.

How to fix failed VMSS deployment with error "unknown network allocation error"

I am trying to deploy a 3-tier architecture to Azure using the Azure PowerShell CLI and a customized ARM template with parameters. I am not having any issues with the powershell script or the template's validity.
Within the template, among other things are two Virtual Machine Scale Sets, one for the front-end and one for the back-end. Front-end is windows and back-end is red hat. The front-end is behind an application gateway while the back-end is behind a load balancer. What's weird is that the front-end VMSS is deploying no problem and all is well. The back-end VMSS fails every time I try to deploy it, with a vague "Unknown network allocation error" message that I have no idea how to debug (since it provides no specifics unlike all of my other error messages so far).
I based the ARM template on an exported template from a working model of this architecture in another resource group and modified the parameters and have spent a while cleaning up issues and errors with Azure's exported template. I have tried deleting and starting from scratch but it doesn't seem to fix this problem. I thought it was possible I reached the limit of free-subscription processors so I tried making the front-end VMSS dependent on the back-end VMSS so the back-end VMSS would be created first, but the same issue still happened.
Here is the back-end VMSS part of the template:
{
"type": "Microsoft.Compute/virtualMachineScaleSets",
"apiVersion": "2018-10-01",
"name": "[parameters('virtualMachineScaleSets_JakeAppBESS_name')]",
"location": "westus2",
"dependsOn": [
"[parameters('loadBalancers_JakeAppBESSlb_name')]"
],
"sku": {
"name": "Standard_B1ls",
"tier": "Standard",
"capacity": 1
},
"properties": {
"singlePlacementGroup": true,
"upgradePolicy": {
"mode": "Manual"
},
"virtualMachineProfile": {
"osProfile": {
"computerNamePrefix": "jakeappbe",
"adminUsername": "Jake",
"adminPassword": "[parameters('JakeApp_Password')]",
"linuxConfiguration": {
"disablePasswordAuthentication": false,
"provisionVMAgent": true
},
"secrets": []
},
"storageProfile": {
"osDisk": {
"createOption": "FromImage",
"caching": "ReadWrite",
"managedDisk": {
"storageAccountType": "Premium_LRS"
}
},
"imageReference": {
"publisher": "RedHat",
"offer": "RHEL",
"sku": "7.4",
"version": "latest"
}
},
"networkProfile": {
"networkInterfaceConfigurations": [
{
"name": "[concat(parameters('virtualMachineScaleSets_JakeAppBESS_name'), 'Nic')]",
"properties": {
"primary": true,
"enableAcceleratedNetworking": false,
"dnsSettings": {
"dnsServers": []
},
"enableIPForwarding": false,
"ipConfigurations": [
{
"name": "[concat(parameters('virtualMachineScaleSets_JakeAppBESS_name'), 'IpConfig')]",
"properties": {
"subnet": {
"id": "[concat('/subscriptions/', parameters('subscription_id'), '/resourceGroups/', parameters('resource_Group'), '/providers/Microsoft.Network/virtualNetworks/', parameters('virtualNetworks_JakeAppVnet_name'), '/subnets/BEsubnet')]"
},
"privateIPAddressVersion": "IPv4",
"loadBalancerBackendAddressPools": [
{
"id": "[concat('/subscriptions/', parameters('subscription_id'), '/resourceGroups/', parameters('resource_Group'), '/providers/Microsoft.Network/loadBalancers/', parameters('loadBalancers_JakeAppBESSlb_name'), '/backendAddressPools/bepool')]"
}
],
"loadBalancerInboundNatPools": [
{
"id": "[concat('/subscriptions/', parameters('subscription_id'), '/resourceGroups/', parameters('resource_Group'), '/providers/Microsoft.Network/loadBalancers/', parameters('loadBalancers_JakeAppBESSlb_name'), '/inboundNatPools/natpool')]"
}
]
}
}
]
}
}
]
},
"priority": "Regular"
},
"overprovision": true
}
},
For reference, here's the front-end VMSS's part of the template so you can compare and see that there aren't many differences:
` {
"type": "Microsoft.Compute/virtualMachineScaleSets",
"apiVersion": "2018-10-01",
"name": "[parameters('virtualMachineScaleSets_JakeAppFESS_name')]",
"location": "westus2",
"dependsOn": [
"[parameters('applicationGateways_JakeAppFE_AG_name')]",
],
"sku": {
"name": "Standard_B1ls",
"tier": "Standard",
"capacity": 1
},
"properties": {
"singlePlacementGroup": true,
"upgradePolicy": {
"mode": "Manual"
},
"virtualMachineProfile": {
"osProfile": {
"computerNamePrefix": "jakeappfe",
"adminUsername": "Jake",
"adminPassword": "[parameters('JakeApp_Password')]",
"windowsConfiguration": {
"provisionVMAgent": true,
"enableAutomaticUpdates": true
},
"secrets": []
},
"storageProfile": {
"osDisk": {
"createOption": "FromImage",
"caching": "ReadWrite",
"managedDisk": {
"storageAccountType": "Premium_LRS"
}
},
"imageReference": {
"publisher": "MicrosoftWindowsServer",
"offer": "WindowsServer",
"sku": "2016-Datacenter",
"version": "latest"
}
},
"networkProfile": {
"networkInterfaceConfigurations": [
{
"name": "[concat(parameters('virtualMachineScaleSets_JakeAppFESS_name'), 'Nic')]",
"properties": {
"primary": true,
"enableAcceleratedNetworking": false,
"dnsSettings": {
"dnsServers": []
},
"enableIPForwarding": false,
"ipConfigurations": [
{
"name": "[concat(parameters('virtualMachineScaleSets_JakeAppFESS_name'), 'IpConfig')]",
"properties": {
"subnet": {
"id": "[concat('/subscriptions/', parameters('subscription_id'), '/resourceGroups/', parameters('resource_Group'), '/providers/Microsoft.Network/virtualNetworks/', parameters('virtualNetworks_JakeAppVnet_name'), '/subnets/FEsubnet')]"
},
"privateIPAddressVersion": "IPv4",
"applicationGatewayBackendAddressPools": [
{
"id": "[concat('/subscriptions/', parameters('subscription_id'), '/resourceGroups/', parameters('resource_Group'), '/providers/Microsoft.Network/applicationGateways/', parameters('applicationGateways_JakeAppFE_AG_name'), '/backendAddressPools/appGatewayBackendPool')]"
}
]
}
}
]
}
}
]
},
"priority": "Regular"
},
"overprovision": true
}
},
I expected them to both behave similarly. Granted, back-end is RH linux while front-end is windows, and the front-end is behind an application gateway while the back-end is behind a load balancer, but this setup is working perfectly fine in my other resource group that was deployed through the portal instead of through ARM. But every time I try to deploy this I get this error:
New-AzureRmResourceGroupDeployment : 1:30:56 AM - Resource Microsoft.Compute/virtualMachineScaleSets 'ProdBESS' failed with message '{
"status": "Failed",
"error": {
"code": "ResourceDeploymentFailure",
"message": "The resource operation completed with terminal provisioning state 'Failed'.",
"details": [
{
"code": "NetworkingInternalOperationError",
"message": "Unknown network allocation error."
}
]
}
}'
Okay I finally figured out what the issue was, so if anyone searching finds this thread in the future having the same error:
Apparently the part of the template dealing with the load balancer for the VMSS (which was exported from azure portal) had two conflicting inbound nat pools (overlapping port ranges). Once I deleted the part of the template creating the conflicting extra nat pool my VMSS deployed properly without issue.
No idea at all why the azure portal exported me a template with an extra nat pool that had never existed (there was only 1 on the original LB I exported the template from).

Azure ARM Template - Running DSC script without triggering extension install?

I am trying to deploy a Active Directory forest with two DCs. I've managed to deploy the DCs and install the ADDS features on both VMs. The "PDC" had a DSC script that runs and configures the forest, again that works great. The issue I have is trying to run a second DSC script on the second DC, this script runs the ADDS configuration to promote the VM to a DC and join it to the forest. I've created a nested JSON template that gets called by the main template. But I am hitting this error:
"Multiple VMExtensions per handler not supported for OS type 'Windows'. VMExtension 'PrepareBDC' with handler 'Microsoft.Powershell.DSC' already added or specified in input."
I've spent the last hour or so whizzing around the internet looking for answers and everyone seems to say the same thing...you can't install the same extension twice. Ok, I can see why that would make sense, my question is can I configure the nested template so it doesn't try and install the extension, just uses what's already installed on the VM?
Main template snippet:
{
"type": "Microsoft.Compute/virtualMachines/extensions",
"name": "[concat(variables('dc2name'), '/PrepareDC2AD')]",
"apiVersion": "2018-06-01",
"location": "[resourceGroup().location]",
"dependsOn": [
"[resourceId('Microsoft.Compute/virtualMachines', variables('dc2name'))]"
],
"properties": {
"publisher": "Microsoft.Powershell",
"type": "DSC",
"typeHandlerVersion": "2.19",
"autoUpgradeMinorVersion": true,
"settings": {
"ModulesUrl": "[concat(parameters('Artifacts Location'), '/dsc/PrepareADBDC.zip', parameters('Artifacts Location SAS Token'))]",
"ConfigurationFunction": "PrepareADBDC.ps1\\PrepareADBDC",
"Properties": {
"DNSServer": "[variables('dc1ipaddress')]"
}
}
}
},
{
"name": "ConfiguringDC2",
"type": "Microsoft.Resources/deployments",
"apiVersion": "2016-09-01",
"dependsOn": [
"[concat('Microsoft.Compute/virtualMachines/',variables('dc1name'),'/extensions/CreateADForest')]",
"[concat('Microsoft.Compute/virtualMachines/',variables('dc2name'),'/extensions/PrepareDC2AD')]"
],
"properties": {
"mode": "Incremental",
"templateLink": {
"uri": "[concat(parameters('Artifacts Location'), '/nestedtemplates/configureADBDC.json', parameters('Artifacts Location SAS Token'))]",
"contentVersion": "1.0.0.0"
},
"parameters": {
"adBDCVMName": {
"value": "[variables('dc2name')]"
},
"location": {
"value": "[resourceGroup().location]"
},
"adminUsername": {
"value": "[parameters('Administrator User')]"
},
"adminPassword": {
"value": "[parameters('Administrator Password')]"
},
"domainName": {
"value": "[parameters('Domain Name')]"
},
"adBDCConfigurationFunction": {
"value": "ConfigureADBDC.ps1\\ConfigureADBDC"
},
"adBDCConfigurationModulesURL": {
"value": "[concat(parameters('Artifacts Location'), '/dsc/ConfigureADBDC.zip', parameters('Artifacts Location SAS Token'))]"
}
}
}
},
The nested template:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"adBDCVMName": {
"type": "string"
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]"
},
"adminUsername": {
"type": "string"
},
"adminPassword": {
"type": "securestring"
},
"domainName": {
"type": "string"
},
"adBDCConfigurationFunction": {
"type": "string"
},
"adBDCConfigurationModulesURL": {
"type": "string"
}
},
"resources": [
{
"type": "Microsoft.Compute/virtualMachines/extensions",
"name": "[concat(parameters('adBDCVMName'),'/PrepareBDC')]",
"apiVersion": "2016-03-30",
"location": "[parameters('location')]",
"properties": {
"publisher": "Microsoft.Powershell",
"type": "DSC",
"typeHandlerVersion": "2.21",
"autoUpgradeMinorVersion": true,
"forceUpdateTag": "1.0",
"settings": {
"modulesURL": "[parameters('adBDCConfigurationModulesURL')]",
"wmfVersion": "4.0",
"configurationFunction": "[parameters('adBDCConfigurationFunction')]",
"properties": {
"domainName": "[parameters('domainName')]",
"adminCreds": {
"userName": "[parameters('adminUsername')]",
"password": "privateSettingsRef:adminPassword"
}
}
},
"protectedSettings": {
"items": {
"adminPassword": "[parameters('adminPassword')]"
}
}
}
}
]
}
this error means exactly what it says: you cannot have multiple copies of the same extension, what you need to do is apply the same extension to the vm, all the inputs have to be the same. you can have a look at this example which does exactly that. This particular template installs the extension for the second time to join bdc to the domain.
But, I don't like that approach. I use Powershell DSC to just wait for the domain to get created and join the bdc to the domain in one go. you would use this powershell dsc snippet:
xWaitForADDomain DscForestWait {
DomainName = $DomainName
DomainUserCredential = $DomainCreds
RetryCount = $RetryCount
RetryIntervalSec = $RetryIntervalSec
}
Here's a complete example

how to use nested copy in Arm Template

I am creating multiple resource policies (backup policies in Recovery Service Vault) for multiple environments. I was able to create them for one environment, how do i replicate them using nested copy for QA.
They will have policy name as AZR-QA-SQL-1Hour-Policy-001
Any help is appreciated.
"variables": {
"sqlDevPolicyName": [
"[concat('AZR-DEV-SQL-1HOUR-POLICY-001')]",
"[concat('AZR-DEV-SQL-4HOUR-POLICY-001')]",
"[concat('AZR-DEV-SQL-8HOUR-POLICY-001')]"
]
}
}
"resources": [
{
"type": "Microsoft.RecoveryServices/vaults",
"apiVersion": "2018-01-10",
"name": "[parameters('vaultName')]",
"location": "[parameters('location')]",
"sku": {
"name": "RS0",
"tier": "Standard"
},
"properties": {}
},
{
"apiVersion": "2018-01-10",
"name": "[concat(parameters('vaultName'), '/', variables('sqlPolicyName')[copyIndex()])]",
"type": "Microsoft.RecoveryServices/vaults/backupPolicies",
"dependsOn": [
"[concat('Microsoft.RecoveryServices/vaults/', parameters('vaultName'))]"
],
"copy": {
"name": "policies",
"count": "[length(variables('sqlDevPolicyName'))]"
},
"location": "[parameters('location')]",
"properties": {
"backupManagementType": "AzureWorkload",
"protectedItemsCount": 0,
"settings": {
"isCompression": false,
"issqlcompression": false,
"timeZone": "[parameters('timeZone')]"
},
"subProtectionPolicy": [
{
"policyType": "Full",
"retentionPolicy": {
"retentionPolicyType": "LongTermRetentionPolicy",
"weeklySchedule": {
"daysOfTheWeek": [
"Sunday"
],
"retentionDuration": {
"count": 15,
"durationType": "Weeks"
},
"retentionTimes": "[parameters('scheduleRunTimes')]"
}
},
According to my understanding of what you are saying you need to do this:
"variables": {
"sqlQAPolicyName": [ // dont need concat() here
"AZR-QA-SQL-1HOUR-POLICY-001",
"AZR-QA-SQL-4HOUR-POLICY-001",
"AZR-QA-SQL-8HOUR-POLICY-001"
]
},
"resources": [
{
same thing here, just need to create it two times, as you now have 2 sets of resources.
and you need to use your QA variable to create backup policies for QA
...
}
]
at least this is how i see it

createUiDefinition.json for ARM Azure web app

I have created the ARM template for azure web app. I need to publish the ARM template to azure market place. I have used the azure publish portal https://publish.windowsazure.com/workspace/multi-resource-solutions for publishing the ARM template.
To on-board the ARM template to azure market place zip file must contain a mainTemplate.json and createUiDefinition.json. I found some samples for createUiDefination.json file in https://github.com/Azure/azure-quickstart-templates but all the createUiDefination.json is for VM. I am unable to find the samples or tutorials for createUiDefination.json for Azure web app.
I need to validate the azure web app site name is already exists or not. Also need to create or use the app service plan.
Is there is any tutorial or sample for creating createUiDefination.json for azure web app?
I need to validate the azure web app site name is already exists or
not.
This is not possible, you need to add to the site name a unique String, to ensure that the site name is globally unique.
For example you could use in your ARM template this function: uniqueString()
Similar question was answered by a Microsoft employee.
Also need to create or use the app service plan.
Add an App Service Plan to your Azure Resource Manager Template. For example like this:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"hostingPlanName": {
"type": "string",
"minLength": 1
},
"skuName": {
"type": "string",
"defaultValue": "F1",
"allowedValues": [
"F1",
"D1",
"B1",
"B2",
"B3",
"S1",
"S2",
"S3",
"P1",
"P2",
"P3",
"P4"
],
"metadata": {
"description": "Describes plan's pricing tier and capacity. Check details at https://azure.microsoft.com/en-us/pricing/details/app-service/"
}
},
"skuCapacity": {
"type": "int",
"defaultValue": 1,
"minValue": 1,
"metadata": {
"description": "Describes plan's instance count"
}
}
},
"variables": {
"webSiteName": "[concat('webSite', uniqueString(resourceGroup().id))]"
},
"resources": [
{
"apiVersion": "2015-08-01",
"name": "[parameters('hostingPlanName')]",
"type": "Microsoft.Web/serverfarms",
"location": "[resourceGroup().location]",
"tags": {
"displayName": "HostingPlan"
},
"sku": {
"name": "[parameters('skuName')]",
"capacity": "[parameters('skuCapacity')]"
},
"properties": {
"name": "[parameters('hostingPlanName')]"
}
},
{
"apiVersion": "2015-08-01",
"name": "[variables('webSiteName')]",
"type": "Microsoft.Web/sites",
"location": "[resourceGroup().location]",
"tags": {
"[concat('hidden-related:', resourceGroup().id, '/providers/Microsoft.Web/serverfarms/', parameters('hostingPlanName'))]": "Resource",
"displayName": "Website"
},
"dependsOn": [
"[resourceId('Microsoft.Web/serverfarms/', parameters('hostingPlanName'))]"
],
"properties": {
"name": "[variables('webSiteName')]",
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', parameters('hostingPlanName'))]"
}
}
]
}
Validating an app service's name is possible in createUiDefinition.json.
The crux of it is the Microsoft.Solutions.ArmApiControl, which can be used to call ARM apis as part of the validation of a text box. Here is an example:
{
"$schema": "https://schema.management.azure.com/schemas/0.1.2-preview/CreateUIDefinition.MultiVm.json#",
"handler": "Microsoft.Azure.CreateUIDef",
"version": "0.1.2-preview",
"parameters": {
"basics": [
{}
],
"steps": [
{
"name": "domain",
"label": "Domain Names",
"elements": [
{
"name": "domainInfo",
"type": "Microsoft.Common.InfoBox",
"visible": true,
"options": {
"icon": "Info",
"text": "Pick the domain name that you want to use for your app."
}
},
{
"name": "appServiceAvailabilityApi",
"type": "Microsoft.Solutions.ArmApiControl",
"request": {
"method": "POST",
"path": "[concat(subscription().id, '/providers/Microsoft.Web/checknameavailability?api-version=2021-02-01')]",
"body": "[parse(concat('{\"name\":\"', concat('', steps('domain').domainName), '\", \"type\": \"Microsoft.Web/sites\"}'))]"
}
},
{
"name": "domainName",
"type": "Microsoft.Common.TextBox",
"label": "Domain Name Word",
"toolTip": "The name of your app service",
"placeholder": "yourcompanyname",
"constraints": {
"validations": [
{
"regex": "^[a-zA-Z0-9]{4,30}$",
"message": "Alphanumeric, between 4 and 30 characters."
},
{
"isValid": "[not(equals(steps('domain').appServiceAvailabilityApi.nameAvailable, false))]",
"message": "[concat('Error with the url: ', steps('domain').domainName, '. Reason: ', steps('domain').appServiceAvailabilityApi.reason)]"
},
{
"isValid": "[greater(length(steps('domain').domainName), 4)]",
"message": "The unique domain suffix should be longer than 4 characters."
},
{
"isValid": "[less(length(steps('domain').domainName), 30)]",
"message": "The unique domain suffix should be shorter than 30 characters."
}
]
}
},
{
"name": "section1",
"type": "Microsoft.Common.Section",
"label": "URLs to be created:",
"elements": [
{
"name": "domainExamplePortal",
"type": "Microsoft.Common.TextBlock",
"visible": true,
"options": {
"text": "[concat('https://', steps('domain').domainName, '.azurewebsites.net - The main app service URL')]"
}
}
],
"visible": true
}
]
}
],
"outputs": {
"desiredDomainName": "[steps('domain').domainName]"
}
}
}
You can paste that in to the createUiDefinition.json sandbox azure provides to test it out.
To look at how to do an Azure App Service instead of a VM, look in to documentation like this and use it as the maintemplate.json in the app.zip package.