Azure: Cannot use output from Linked Template in IF condition - azure

I'm trying to deploy a Virtual network using ARM template with multiple subnets. I have a linked template which creates NSGs,route table and assigns it to a specific subnet. I'm using copy to create multiple subnets. Route table should be assigned to only one particular subnet. I control this using If condition. The issue here is i'm not able to use the linked template output in the If condition. It fails with below error.
'{
"error": {
"code": "InvalidTemplate",
"message": "Unable to process template language expressions for resource
'/subscriptions//resourceGroups//providers/Microsoft.Network/virtualNetworks/' at line '143' and column '9'. 'The provided
arguments for template language function 'if' is not valid: all arguments should be of type 'boolean'. Please see https://aka.ms/arm-template-expressions#if for usage details.'"
}
}'
Main Template (Subnet Creation snippet):-
"copy": [
{
"name": "subnets",
"count": "[length(parameters('subnetList'))]",
"input": {
"name": "[parameters('subnetList')[copyIndex('subnets')].name]",
"properties": {
"addressPrefix": "[parameters('subnetList')[copyIndex('subnets')].addressprefix]",
"networkSecurityGroup": "[if(equals(parameters('subnetList')[copyIndex('subnets')].name, 'GatewaySubnet'), json('null'), variables('nsgId'))]",
"routeTable": "[if(bool(parameters('subnetList')[copyIndex('subnets')].useRouteTable), reference('routeTableDeployment').outputs.resourceID.value, json('null'))]"
}
}
}
]
Route Table (Output snippet):-
"outputs": {
"resourceID": {
"type": "object",
"value": {
"id": "[resourceId('Microsoft.Network/routeTables', variables('routeTableName')]"
}
}
}
It works if I define a variable and pass it to if condition similar to nsg as below:-
"routeTableId": {
"id": "[resourceId('Microsoft.Network/routeTables', 'routeTableName')]"
}
"routeTable": "[if(bool(parameters('subnetList')[copyIndex('subnets')].useRouteTable), variables('routeTableId'), json('null'))]"

Related

BICEP - Parameter file variable assignment

I was following the repo for separate parameter file to each env as defined in the https://github.com/Azure/bicep/discussions/4586
I tried the separate parameters file for dev, stage, prod but the value assignment in main module variable remains flagged by intelligence even though it exists same param exist in the respective parameter file.
Other approach I tried is loadjson variable, but it does not show auto completion for items under subnet block as it stopes right after value.
Maybe I am overthinking and not applying the correct approach, Perhaps I should ignore intellisense and try deploying by applying parameter and hope it will auto pick correct value during the deployment param check.
Here is my parameter file and the same value applies to each env param json.
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"department": {
"value": "finance"
},
"saAccountCount": {
"value": 1
},
"vmCount": {
"value": 1
},
"locationIndex": { //idenx 1 = app server, 2=AD, 3=Tool server, 4= dchp server
"value": 1
},
"appRoleIndex": { //idenx 1 = westus2, 2= westus, 3= eastus, 4=centralus, 5=uswest3
"value": 1
},
"appRole": {
"value": {
"Applicatoin Server": "ap",
"Active Directory": "dc",
"Tool server": "tool",
"DHCP server": "dhcp"
}
},
"environment": {
"value": "dev"
},
"addressPrefixes": {
"value": [
"172.16.0.0/20"
]
},
"dnsServers": {
"value": [
"1.1.1.1",
"4.4.4.4"
]
},
"locationList": {
"value": {
"westus2": "azw2",
"westus": "azw",
"Eastus": "aze",
"CentralUS": "azc",
"westus3": "azw3"
}
},
"subnets": {
"value": [
{
"name": "frontend",
"subnetPrefix": "172.16.2.0/24",
"delegation": "Microsoft.Web/serverfarms",
"privateEndpointNetworkPolicies": "disabled",
"serviceEndpoints": [
{
"service": "Microsoft.KeyVault",
"locations": [
"*"
]
},
{
"service": "Microsoft.Web",
"locations": [
"*"
]
}
]
},
{
"name": "backend",
"subnetPrefix": "172.16.3.0/24",
"delegation": "Microsoft.Web/serverfarms",
"privateEndpointNetworkPolicies": "enabled",
"serviceEndpoints": [
{
"service": "Microsoft.KeyVault",
"locations": [
"*"
]
},
{
"service": "Microsoft.Web",
"locations": [
"*"
]
},
{
"service": "Microsoft.AzureCosmosDB",
"locations": [
"*"
]
}
]
}
]
}
}
}
You appear to be attempting to deploy an Azure Resource Management (ARM) template using a parameter file.
The parameter file is used to pass values to the ARM template during deployment. The parameter file must use the same types as the ARM template and can only include values for the ARM template's parameters.
You will receive an error if the parameter file contains extra parameters that do not match the ARM template's parameters.
In the same deployment process, you can use both inline parameters and a local parameter file. If you specify a parameter's value in both the local parameter file and inline, the inline value takes priority.
Refer to create a parameter file of an ARM template
About the different parameters file for dev, stage, and prod, it's likely that the parameter file is not correctly linked to the ARM template.
You can deploy the ARM template with the parameter file to determine if it will automatically select the proper value during the deployment parameter check.
Regarding the loadjson variable, it is possible that the loadjson variable is not properly formatted.
You can double-check the loadjson variable's format to ensure it's proper.
After a workaround on this, I created a sample parameter.json file for a webapp to deploy in a production environment and that worked for me.
Note: Alternatively, You can use az deployment group create with a parameters file and deploy into Azure to avoid these conflicts.

applicationGatewayBackendAddressPools configurations does not apply in virtual machine scale set

I have a VMSS which I deployed using ARM templates. This is the networkProfile block under VMSS resource section.
"networkProfile": {
"networkInterfaceConfigurations": [
{
"name": "[variables('nicName')]",
"properties": {
"primary": true,
"ipConfigurations": [
{
"name": "[concat(variables('VMSSName'), '-ipconfig')]",
"properties": {
"subnet": {
"id": "[variables('subnetRef')]"
},
"applicationGatewayBackendAddressPools": "[variables('AppGatewayBackendAddressPool')]"
}
}
]
}
}
]
},
In Variable section, if I use resourceId() function and provide values from parameters then it does not apply the configuration in VMSS. for example:
"AppGatewayBackendAddressPool": "[resourceId(parameters('VirtualNetworkResourceGroup'),'Microsoft.Network/applicationGateways/backendAddressPools', parameters('ApplicationGatewayName'), parameters('BackendAddressPool'))]",
I've also tried adding parameters('SubscriptionName') but the result is same.
"AppGatewayBackendAddressPool": "[resourceId(parameters('SubscriptionName') ,parameters('VirtualNetworkResourceGroup'),'Microsoft.Network/applicationGateways/backendAddressPools', parameters('ApplicationGatewayName'), parameters('BackendAddressPool'))]",
When I declare variable like below then it applies backendAddressPool configuration in Networking -> Load Balancing.
"AppGatewayBackendAddressPool": [
{ "id": "/subscriptions/<subscriptionId>/resourceGroups/<resourceGroupName>/providers/Microsoft.Network/applicationGateways/<applicationGatewayName>/backendAddressPools/<backendAddressPool>" }
],
Similar I'm doing with subnetRef like below and that is working fine.
"subnetRef": "[resourceId(parameters('VirtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks/subnets', parameters('VirtualNetworkName'), parameters('SubnetName'))]",
I want to parametrize the deployment by defining separate parameters.json file so I can attach applicationGatewayBackendAddressPools with different virtual machine scale sets.
This is how I achieved it by following Ked Mardemootoo answer.
IP configuration section under networkProfile of VMSS resource.
"ipConfigurations": [
{
"name": "[concat(variables('VMSSName'), '-ipconfig')]",
"properties": {
"subnet": {
"id": "[variables('subnetRef')]"
},
"applicationGatewayBackendAddressPools": [
{ "id": "[concat(parameters('AapplicationGatewayExternalid'), '/backendAddressPools/', parameters('BackendAddressPool'))]" }
]
}
}
]
Template file parameters:
"BackendAddressPool": {
"type": "string",
"metadata": {
"description": "Backend pool to host blue/green vmss."
}
},
"AapplicationGatewayExternalid": {
"type": "string",
"metadata": {
"description": "Application Gateway Id."
}
}
Now, ARM template is calling and referencing applicationGatewayBackendAddressPools attribute dynamically under VMSS' resource section.
I have these two parameters in parameters.json file where I can define values according to environment.
"BackendAddressPool": {
"value": "<backendPoolName>"
},
"AapplicationGatewayExternalid": {
"value": "/subscriptions/<subscriptionId>/resourceGroups/<resourceGroupName>/providers/Microsoft.Network/applicationGateways/<ApplicationGatewayName>"
}
Overriding template variables in release pipeline vars:
overriding template vars
Defining in pipeline vars
pipeline var
You seem to be missing the concat in the variables. Looking at the raw json on my end, this is how it's configured. See if you can do something similar, and convert the subnet name and backend address pool to variables.
"ipConfigurations": [
{
"name": "ip-vmss-name",
"properties": {
"primary": true,
"subnet": {
"id": "[concat(parameters('virtualNetworks_vnet_externalid'), '/subnets/snet-vm')]"
},
"privateIPAddressVersion": "IPv4",
"applicationGatewayBackendAddressPools": [
{
"id": "[concat(parameters('applicationGateways_agw_1_externalid'), '/backendAddressPools/be-addr-pool-vmss-1')]"
}
]
}
}
]
Nothing seems wrong with your variables/parameters call but applicationGatewayBackendAddressPools is not a valid attribute for neither VMSS nor Application Gateway.
You can do it check AKS and Application Gateway documentations. I achieve the same goal by setting backendAddressPools, which is in Application Gateway section, in different parameters.json files.

ARM Template - Creating a template for VirtualnetworkGateway combined in a single template

I have created a template which is meant to deploy a complete network solution, which includes 2-subnets, vnet, vnetgw and pubip. I am looking for a way to programmatically reference some of the resource id's such that it makes the template more dynamic and can be used as many times as possible. secondly, the templates generates an error on deployment which obviously is as a result of the the references i mentioned earlier. Pls see error below;
New-AzResourceGroupDeployment: Line | 3 |
New-AzResourceGroupDeployment -ResourceGroupName rg-vnet-dev -Templat
…
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| 19:05:58 - Resource Microsoft.Network/virtualNetworkGateways 'rgvnetdev-vnetgw' failed with message '{ "error": {
"code": "InvalidTemplate",
"message": "Unable to process template language expressions for resource
'/subscriptions/77dd2569-6341-4c72-880d-ef59413db99e/resourceGroups/rg-vnet-dev/providers/Microsoft.Network/virtualNetworkGateways/rgvnetdev-vnetgw'
at line '279' and column '9'. 'Unable to evaluate template language
function 'resourceId': the type
'Microsoft.Network/virtualNetworks/subnets' requires '2' resource name
argument(s). Please see
https://aka.ms/arm-template-expressions/#resourceid for usage
details.'",
"additionalInfo": [
{
"type": "TemplateViolation",
"info": {
"lineNumber": 279,
"linePosition": 9,
"path": ""
}
}
] } }
I will be happy to share the code, if this would assist in resolving my issue. The error relates to referencing the vnet dependson for creating vnetgw.
From the error message, it seems that referenced subnet id is invalid. This function resourceId format is
resourceId([subscriptionId], [resourceGroupName], resourceType, resourceName1, [resourceName2], ...)
In this case, you probably lacks the VNet name at line '279', the referenced subnet id should be like this:
"subnet": {
"id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('subnet1Name'))]"
},
{
"type": "Microsoft.Network/virtualNetworkGateways",
"apiVersion": "2019-12-01",
"name": "[variables('vnetgwname')]",
"location": "[parameters('Location')]",
"dependsOn": [
"[resourceId('Microsoft.Network/publicIPAddresses',variables('pubIp'))]",
"[resourceId('Microsoft.Network/virtualNetworks',variables('VNetName'))]"
],
"properties": {
"ipConfigurations": [
{
"name": "vnetgatewayconfig",
"properties": {
"publicIPAddress": {
"id": "[resourceId('Microsoft.Network/publicIPAddresses',variables('pubIp'))]"
},
"subnet": {
"id": "[resourceId('Microsoft.Network/virtualNetworks/subnets',variables('VNetName'),variables('Uniquegwsubnet'))]"
},
"privateIPAllocationMethod": "[parameters('publicIPAllocationMethod')]"
}
}
],
"sku": {
"name": "[parameters('sku')]",
"tier": "[parameters('sku')]"
},
"gatewayType": "[parameters('gatewayType')]",
"vpnType": "[parameters('VpnType')]",
"activeActive": false,
"enableBgp": false,
"vpnGatewayGeneration": "[parameters('vpnGatewayGeneration')]"
}
},

How to dynamically create Azure KeyVault reference in ARM template?

I'm using the following piece of code in my ARM template parameters file to retrieve the secret value from keyvault:
"parameters": {
"mailAccount": {
"reference": {
"keyVault": {
"id": "/subscriptions/GUID/resourceGroups/KeyVaultRG/providers/Microsoft.KeyVault/vaults/KeyVault"
},
"secretName": "mailAccount"
}
},
and in the template file:
"appSettings": [
{
"name": "mailAccount",
"value": "[parameters('mailAccount')]"
},
{
I'd like to know if it is possible to reference a KeyVault by its name using dynamically constructed object (i.e. not /subscriptions/GUID/resourceGroups/KeyVaultRG/providers/Microsoft.KeyVault/vaults/KeyVault but [resourceId(subscription().subscriptionId, resourcegroup().name, 'Microsoft.KeyVault/vaults', parameters('KeyVaultName'))]) or [resourceId('Microsoft.KeyVault/vaults', parameters('KeyVaultName'))] ?
In fact, the main objective is to be able to pass the different KeyVault names when deploying templates - where the similar values are stored.
The need to have several KeyVaults is justified by the resources (and cost) separation.
Now I see only validation errors saying ~ resourceId function cannot be used while referencing parameters.
I cannot use nested\linked templates (and output values).
What I am usually doing to avoid this limitation of the resourceId function is to define a variable with the value of the parameter, then using the variable instead in the resourceId function.
Example:
"parameters": {
"KeyVaultName": {
"type": "string",
"metadata": {
"description": "Key Vault Name"
}
}
},
"variables": {
"KeyVaultName": "[parameters('KeyVaultName')]"
}
Then when I am referencing the KeyVault resource I reference it using the variable like this:
"[resourceId('Microsoft.KeyVault/vaults', variables('KeyVaultName')]"

ARM - get VMSS's private IPs

I have a VMSS deployed with am ARM template.
I want add it's first VM's IP address to the output.
In the Azure Resource Explorer - I see resource as:
...
"ipConfigurations": [
{
"name": "jm-website-script-4-master-ip",
"id": "/subscriptions/0a4f2b9c-***-40b17ef8c3ab/resourceGroups/jm-website-script-4/providers/Microsoft.Compute/virtualMachineScaleSets/jm-website-script-4-master-vmss/virtualMachines/1/networkInterfaces/jm-website-script-4-master-nic/ipConfigurations/jm-website-script-4-master-ip",
"etag": "W/\"09be80d2-76f5-49fc-ad47-0ef836a3799a\"",
"properties": {
"provisioningState": "Succeeded",
"privateIPAddress": "10.0.0.5",
...
So I tried to add to the variables:
"masterVM": "[concat('Microsoft.Compute/virtualMachineScaleSets/jm-website-script-4-master-vmss/virtualMachines/1/networkInterfaces/jm-website-script-4-master-nic/ipConfigurations/jm-website-script-4-master-ip')]",
And then call in outputs:
"outputs": {
"MasterFirstIPConfig": {
"type": "string",
"value": "[reference(variables('masterVM').properties.privateIPAddress)]"
}
}
Which returns me an error:
The language expression property 'Microsoft.WindowsAzure.ResourceStack.Frontdoor.Expression.Expressions.JTokenExpression' can't be evaluated..
I guess something is completely wrong with my masterVM variable definition here, but can't get it.
UPD The solution
Thanks for the answer by 4c74356b41.
The solution looks like next:
variable definition:
"masterVM": "Microsoft.Compute/virtualMachineScaleSets/jm-website-script-4-master-vmss/virtualMachines/1/networkInterfaces/jm-website-script-4-master-nic"
outputs:
"outputs": {
"MasterFirstIPConfig": {
"type": "string",
"value": "[reference(variables('masterVM'),'2016-09-01').ipConfigurations[0].properties.privateIPAddress]"
}
}
Well, you are targeting the wrong resource. You should be targeting the networkInterface (and you don't need to concat in this case), you also have to reference it properly:
"masterVM": "Microsoft.Compute/virtualMachineScaleSets/jm-website-script-4-master-vmss/virtualMachines/1/networkInterfaces/jm-website-script-4-master-nic]"
And reference like so
"value": "[reference(variables('masterVM'),'2016-09-01').ipConfigurations[0].properties.privateIPAddress]"

Resources