Related
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.
I have a JSON ARM template which creates multiple vms through a loop, I thought I could add encryptvm at the end of the loop and it would encrypt all the disks.
However it keeps failing with a strange error
The full json is here:
https://pastebin.com/embed_iframe/Lxmb7Y42
I've used both these parameters.
, parameters('VMNames'), copyIndex(1))]",
and
, parameters('VMNames'))]"
but neither seems to work.
All I'm doing essentially is adding the following resource section in:
"resources": [
{
"name": "[concat(parameters('VMNames'),'UpdateEncryptionSettings)']",
"type": "Microsoft.Resources/deployments",
"apiVersion": "2015-01-01",
"dependsOn": [
"[concat('Microsoft.Compute/virtualMachines/', parameters('VMNames'))]"
],
"properties": {
"mode": "Incremental",
"templateLink": {
"uri": "[concat(parameters('_artifactsLocation'),'/nestedtemplates/encryptVm.json',parameters('_artifactsLocationSasToken'))]",
"contentVersion": "1.0.0.0"
},
"parameters": {
"vmName": {
"value": "[parameters('VMNames')]"
},
"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')]"
}
}
}
},
{
"apiVersion": "2017-05-10",
"name": "[concat(parameters('VMNames'),'recoveryServicesVault')]",
"type": "Microsoft.Resources/deployments",
"resourceGroup": "[parameters('recoveryServicesVaultResourceGroup')]",
"dependsOn": [
"[concat('Microsoft.Compute/virtualMachines/', parameters('VMNames'))]"
// "[resourceId('Microsoft.Resources/deployments/', concat(parameters('VMNames'), copyIndex(1),'UpdateEncryptionSettings'))]"
],
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"name": "[concat(parameters('recoveryServicesVaultName'), '/', 'Azure', '/', variables('rsvV2vm'), resourceGroup().name, ';', parameters('VMNames'))]",
"apiVersion": "2017-07-01",
"type": "Microsoft.RecoveryServices/vaults/backupFabrics/backupProtectionIntent",
"properties": {
"friendlyName": "[concat(parameters('VMNames'), copyIndex(1), 'BackupIntent')]",
"protectionIntentItemType": "AzureResourceItem",
"policyId": "[resourceId(parameters('recoveryServicesVaultResourceGroup'), 'Microsoft.RecoveryServices/vaults/backupPolicies', parameters('recoveryServicesVaultName'), parameters('recoveryServicesVaultBackupPolicyName'))]",
"sourceResourceId": "[resourceId(resourceGroup().name, 'Microsoft.Compute/virtualMachines', parameters('VMNames'))]"
}
}
]
}
}
}
]
Can't see where I'm going wrong. Maybe I've added it in the wrong place, but checking on JSON validator tools online and everything seems fine.
this template is due to the fact you are defining your deployment once for each vm, but you are giving each deployment the same name:
"name": "[concat(parameters('VMNames'),'UpdateEncryptionSettings')]",
"type": "Microsoft.Resources/deployments",
you need to add copyIndex() function to this name
I have the below script, whch is a section of a script I'm using to deploy a vnet. However it fails to create a the vnet, any idea where I might be going wrong?
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"client": {
"type": "string",
"maxLength": 3,
"metadata": {
"description": "Client name - max 3 chars"
}
},
"environment": {
"type": "string",
"maxLength": 3,
"metadata": {
"description": "Environment name - max 3 chars"
}
},
"businessUnit": {
"type": "string",
"maxLength": 3,
"metadata": {
"description": "Business Unit name - max 3 chars"
}
},
"appName": {
"type": "string",
"maxLength": 3,
"metadata": {
"description": "App name - max 3 chars"
}
},
"addressPrefix": {
"type": "string",
"metadata": {
"description": "The address space in CIDR notation for the new virtual network."
}
},
"subnetName1": {
"type": "string",
"metadata": {
"description": "The name of the first subnet in the new virtual network."
}
},
"subnetName2": {
"type": "string",
"metadata": {
"description": "The name of the first subnet in the new virtual network."
}
},
"gatewaySubnet": {
"type": "string",
"defaultValue": "GatewaySubnet",
"allowedValues": [
"GatewaySubnet"
],
"metadata": {
"description": "The name of the subnet where Gateway is to be deployed. This must always be named GatewaySubnet."
}
},
"subnetPrefix1": {
"type": "string",
"metadata": {
"description": "The address range in CIDR notation for the first subnet."
}
},
"subnetPrefix2": {
"type": "string",
"metadata": {
"description": "The address range in CIDR notation for the first subnet."
}
},
"gatewaySubnetPrefix": {
"type": "string",
"metadata": {
"description": "The address range in CIDR notation for the Gateway subnet. For ExpressRoute enabled Gateways, this must be minimum of /28."
}
},
"dnsServerAddress": {
"type": "array",
"metadata": {
"Description": "The DNS address(es) of the DNS Server(s) used by the VNET"
}
},
"dnsServerAddressUpdateDns": {
"type": "array",
"metadata": {
"Description": "The DNS address(es) of the DNS Server(s) used by the VNET"
}
},
"vpnClientAddressPoolPrefix": {
"type": "string",
"metadata": {
"description": "The IP address range from which VPN clients will receive an IP address when connected. Range specified must not overlap with on-premise network."
}
},
"vmMfaName1privateIPAddress": {
"type": "string",
"metadata": {
"description": "The IP address of the MFA server."
}
},
"vmMfaName2privateIPAddress": {
"type": "string",
"metadata": {
"description": "The IP address of the MFA server."
}
},
"vmMfaLbIpAddress1": {
"type": "string",
"metadata": {
"description": "The IP address of the RADIUS server."
}
},
"radiusServerSecret": {
"type": "string",
"metadata": {
"description": "The secret of the RADIUS server."
}
},
"omsWorkSpaceResourceGroup": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "Workspace Resource Group"
}
},
"omsWorkSpaceName": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "Workspace Resource Name"
}
},
"omsWorkspaceStorageAccount": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "Storage Account of OMS Workspace"
}
}
},
"variables": {
"apiVersion": "2015-06-15",
"vnetApiVersion": "2017-10-01",
"virtualNetworkPeeringApiVersion": "2017-10-01",
"routeTableApiVersion": "2017-10-01",
"locksApiVersion": "2017-04-01",
"virtualNetworkName": "[tolower(concat('vnet-', parameters('client'), '-', parameters('environment'), '-', parameters('businessUnit'), '-', parameters('appName')))]",
"vnetID": "[resourceId('Microsoft.Network/virtualNetworks',variables('virtualNetworkName'))]",
"gatewaySubnetRef": "[concat(variables('vnetID'),'/subnets/',parameters('gatewaySubnet'))]",
"virtualNetworkGatewayName": "[tolower(concat('vng-', parameters('client'), '-', parameters('environment'), '-', parameters('businessUnit'), '-', parameters('appName')))]",
"gatewaySku": "vpngw1",
"gatewayPublicIPName": "[tolower(concat('pip-', parameters('client'), '-', parameters('environment'), '-', parameters('businessUnit'), '-', parameters('appName')))]",
"vpnClientProtocols": "IkeV2",
"subnetName1": "[tolower(concat('sub-', parameters('client'), '-', parameters('environment'), '-', parameters('businessUnit'), '-', parameters('appName'), '-', parameters('subnetName1')))]",
"routeTable1": "[tolower(concat('udr-', variables('subnetName1')))]",
"networkSecurityGroup1": "[tolower(concat('nsg-', variables('subnetName1')))]",
"subnetName2": "[tolower(concat('sub-', parameters('client'), '-', parameters('environment'), '-', parameters('businessUnit'), '-', parameters('appName'), '-', parameters('subnetName2')))]",
"routeTable2": "[tolower(concat('udr-', variables('subnetName2')))]",
"networkSecurityGroup2": "[tolower(concat('nsg-', variables('subnetName2')))]"
},
"resources": [
{
"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
}
},
{
"name": "[variables('networkSecurityGroup1')]",
"apiVersion": "[variables('apiVersion')]",
"type": "Microsoft.Network/networkSecurityGroups",
"location": "[resourceGroup().location]",
"dependsOn": [
"[concat('Microsoft.Network/routeTables/', variables('routeTable1'))]"
],
"properties": {
"securityRules": [
{
"name": "AllowInboundAnyAddressSpace",
"properties": {
"priority": 100,
"protocol": "*",
"access": "Allow",
"direction": "Inbound",
"sourceAddressPrefix": "[parameters('addressPrefix')]",
"sourcePortRange": "*",
"destinationAddressPrefix": "*",
"destinationPortRange": "*"
}
},
{
"name": "AllowInboundHttpsMfaServer1",
"properties": {
"priority": 101,
"protocol": "Tcp",
"access": "Allow",
"direction": "Inbound",
"sourceAddressPrefix": "*",
"sourcePortRange": "*",
"destinationAddressPrefix": "[parameters('vmMfaName1privateIPAddress')]",
"destinationPortRange": "443"
}
},
{
"name": "AllowInboundHttpsMfaServer2",
"properties": {
"priority": 102,
"protocol": "Tcp",
"access": "Allow",
"direction": "Inbound",
"sourceAddressPrefix": "*",
"sourcePortRange": "*",
"destinationAddressPrefix": "[parameters('vmMfaName2privateIPAddress')]",
"destinationPortRange": "443"
}
},
{
"name": "AllowOutboundAnyAddressSpace",
"properties": {
"priority": 100,
"protocol": "*",
"access": "Allow",
"direction": "Outbound",
"sourceAddressPrefix": "*",
"sourcePortRange": "*",
"destinationAddressPrefix": "[parameters('addressPrefix')]",
"destinationPortRange": "*"
}
}
]
}
},
{
"type": "microsoft.network/networksecuritygroups/providers/diagnosticSettings",
"name": "[concat(variables('networkSecurityGroup1'), '/Microsoft.Insights/service')]",
"dependsOn": [
"[concat('Microsoft.Network/networksecuritygroups/', variables('networkSecurityGroup1'))]"
],
"apiVersion": "2017-05-01-preview",
"properties": {
"name": "service",
"storageAccountId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('omsWorkSpaceResourceGroup'), '/providers/Microsoft.Storage/storageAccounts/', parameters('omsWorkspaceStorageAccount'))]",
"workspaceId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('omsWorkSpaceResourceGroup'), '/providers/Microsoft.OperationalInsights/workspaces/', parameters('omsWorkSpaceName'))]",
"logs": [
{
"category": "NetworkSecurityGroupEvent",
"enabled": true,
"retentionPolicy": {
"days": 365,
"enabled": true
}
},
{
"category": "NetworkSecurityGroupRuleCounter",
"enabled": true,
"retentionPolicy": {
"days": 365,
"enabled": true
}
}
]
}
},
{
"name": "[variables('networkSecurityGroup2')]",
"apiVersion": "[variables('apiVersion')]",
"type": "Microsoft.Network/networkSecurityGroups",
"location": "[resourceGroup().location]",
"dependsOn": [
"[concat('Microsoft.Network/routeTables/', variables('routeTable2'))]"
],
"properties": {
"securityRules": [
{
"name": "AllowInboundAnyAddressSpace",
"properties": {
"priority": 100,
"protocol": "*",
"access": "Allow",
"direction": "Inbound",
"sourceAddressPrefix": "[parameters('addressPrefix')]",
"sourcePortRange": "*",
"destinationAddressPrefix": "*",
"destinationPortRange": "*"
}
},
{
"name": "AllowOutboundAnyAddressSpace",
"properties": {
"priority": 100,
"protocol": "*",
"access": "Allow",
"direction": "Outbound",
"sourceAddressPrefix": "*",
"sourcePortRange": "*",
"destinationAddressPrefix": "[parameters('addressPrefix')]",
"destinationPortRange": "*"
}
}
]
}
},
{
"type": "microsoft.network/networksecuritygroups/providers/diagnosticSettings",
"name": "[concat(variables('networkSecurityGroup2'), '/Microsoft.Insights/service')]",
"dependsOn": [
"[concat('Microsoft.Network/networksecuritygroups/', variables('networkSecurityGroup2'))]"
],
"apiVersion": "2017-05-01-preview",
"properties": {
"name": "service",
"storageAccountId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('omsWorkSpaceResourceGroup'), '/providers/Microsoft.Storage/storageAccounts/', parameters('omsWorkspaceStorageAccount'))]",
"workspaceId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('omsWorkSpaceResourceGroup'), '/providers/Microsoft.OperationalInsights/workspaces/', parameters('omsWorkSpaceName'))]",
"logs": [
{
"category": "NetworkSecurityGroupEvent",
"enabled": true,
"retentionPolicy": {
"days": 365,
"enabled": true
}
},
{
"category": "NetworkSecurityGroupRuleCounter",
"enabled": true,
"retentionPolicy": {
"days": 365,
"enabled": true
}
}
]
}
},
{
"name": "[variables('virtualNetworkName')]",
"apiVersion": "[variables('vnetApiVersion')]",
"type": "Microsoft.Network/virtualNetworks",
"location": "[resourceGroup().location]",
"dependsOn": [
"[concat('Microsoft.Network/routeTables/', variables('routeTable1'))]",
"[concat('Microsoft.Network/routeTables/', variables('routeTable2'))]",
"[concat('Microsoft.Network/networksecuritygroups/', variables('networkSecurityGroup1'))]",
"[concat('Microsoft.Network/networksecuritygroups/', variables('networkSecurityGroup2'))]"
],
"properties": {
"addressSpace": {
"addressPrefixes": [
"[parameters('addressPrefix')]"
]
},
"dhcpOptions": {
"dnsServers": "[parameters('dnsServerAddress')]"
},
"subnets": [
{
"name": "[variables('subnetName1')]",
"properties": {
"addressPrefix": "[parameters('subnetPrefix1')]",
"networkSecurityGroup": {
"id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('networkSecurityGroup1'))]"
},
"routeTable": {
"id": "[resourceId('Microsoft.Network/routeTables', variables('routeTable1'))]"
},
"serviceEndpoints": [
{
"service": "Microsoft.Storage",
"locations": [
"[resourceGroup().location]"
]
},
{
"service": "Microsoft.Sql",
"locations": [
"[resourceGroup().location]"
]
}
]
}
},
{
"name": "[variables('subnetName2')]",
"properties": {
"addressPrefix": "[parameters('subnetPrefix2')]",
"networkSecurityGroup": {
"id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('networkSecurityGroup2'))]"
},
"routeTable": {
"id": "[resourceId('Microsoft.Network/routeTables', variables('routeTable2'))]"
},
"serviceEndpoints": [
{
"service": "Microsoft.Storage",
"locations": [
"[resourceGroup().location]"
]
},
{
"service": "Microsoft.Sql",
"locations": [
"[resourceGroup().location]"
]
}
]
}
},
{
"name": "[parameters('gatewaySubnet')]",
"properties": {
"addressPrefix": "[parameters('gatewaySubnetPrefix')]"
}
}
]
},
"resources": [
{
"name": "[concat(variables('virtualNetworkName'), '/Microsoft.Authorization/', variables('virtualNetworkName'), '-LockDoNotDelete')]",
"type": "Microsoft.Network/virtualNetworks/providers/locks",
"apiVersion": "[variables('locksApiVersion')]",
"dependsOn": [
"[variables('virtualNetworkName')]"
],
"properties": {
"level": "CanNotDelete",
"notes": "Resource Lock - Do Not Delete!",
"owners": [
]
}
}
]
},
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Network/publicIPAddresses",
"name": "[variables('gatewayPublicIPName')]",
"location": "[resourceGroup().location]",
"properties": {
"publicIPAllocationMethod": "Dynamic"
}
},
{
"apiVersion": "2015-06-15",
"type": "Microsoft.Network/virtualNetworkGateways",
"name": "[variables('virtualNetworkGatewayName')]",
"location": "[resourceGroup().location]",
"dependsOn": [
"[concat('Microsoft.Network/publicIPAddresses/', variables('gatewayPublicIPName'))]",
"[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]"
],
"properties": {
"ipConfigurations": [
{
"properties": {
"privateIPAllocationMethod": "Dynamic",
"subnet": {
"id": "[variables('gatewaySubnetRef')]"
},
"publicIPAddress": {
"id": "[resourceId('Microsoft.Network/publicIPAddresses',variables('gatewayPublicIPName'))]"
}
},
"name": "vnetGatewayConfig"
}
],
"sku": {
"name": "[variables('gatewaySku')]",
"tier": "[variables('gatewaySku')]"
},
"gatewayType": "Vpn",
"vpnType": "RouteBased",
"enableBgp": "false",
"vpnClientConfiguration": {
"vpnClientAddressPool": {
"addressPrefixes": [
"[parameters('vpnClientAddressPoolPrefix')]"
]
},
"vpnClientProtocols": [
"[variables('vpnClientProtocols')]"
],
"radiusServerAddress": "[parameters('vmMfaLbIpAddress1')]",
"radiusServerSecret": "[parameters('radiusServerSecret')]"
}
}
}
]
}
This is used to create a vnet and subnets before vm's are deployed to it.
I can't see where I'm going wrong, I'm baffled ..Any help would be appreciated Thanks
So, without you showing the exact error text, its pretty hard to tell what goes wrong exactly, i do have to admit template quality is mediocre. The most common error is wrong dependsOn property. Your typical dependsOn:
"[concat('Microsoft.Network/networksecuritygroups/', variables('networkSecurityGroup1'))]"
Proper dependsOn:
"[resourceId('Microsoft.Network/networksecuritygroups/', variables('networkSecurityGroup1'))]"
You also have lots of places that could be improved, for example, why do you have parameter for gateway subnet name? It always is gatewaysubnet. You cannot change it. you are using prefixes for resource types instead of suffixes, you construct resource names in variables section and various other things which are used only once (for the most part) in the template (so just a waste of space). using concat() instead of resourceId() in many places:
"storageAccountId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('omsWorkSpaceResourceGroup'), '/providers/Microsoft.Storage/storageAccounts/', parameters('omsWorkspaceStorageAccount'))]",
"storageAccountId": "[resourceId(parameters('omsWorkSpaceResourceGroup'), 'Microsoft.Storage/storageAccounts', parameters('omsWorkspaceStorageAccount'))]",
second option is almost 2 times shorter...
I saw the question was marked as 'answered' this morning so i did post my yesterday finding, but since you are still having issue i will post them.
Yes, the template is not the greatest, seems it was put together by copying bit and piece from different templates.
With that been said i focused on the Network section that you mentioned you have issues with. Extract the network section, tweak a little to make up for missing parameters and variables and tried to deploy it. Noticed 2 issues
Issues
dnsserveraddress and dnsserveraddressupdatedns parameters had 'type' as array that did not really accepted any valid input.
Also got error that address space CIDR Notation you provided 10.10.2.0/22 is an invalid CIDR Notation.
Resolution
Once i correct both i was able to deploy the network section without any issues
Tweak JSON i used just to deploy VNet.
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"addressPrefix": {
"type": "String",
"metadata": {
"description": "The address space in CIDR notation for the new virtual network."
}
},
"subnetName1": {
"type": "String",
"metadata": {
"description": "The name of the first subnet in the new virtual network."
}
},
"subnetName2": {
"type": "String",
"metadata": {
"description": "The name of the first subnet in the new virtual network."
}
},
"gatewaySubnet": {
"defaultValue": "GatewaySubnet",
"allowedValues": [
"GatewaySubnet"
],
"type": "String",
"metadata": {
"description": "The name of the subnet where Gateway is to be deployed. This must always be named GatewaySubnet."
}
},
"subnetPrefix1": {
"type": "String",
"metadata": {
"description": "The address range in CIDR notation for the first subnet."
}
},
"subnetPrefix2": {
"type": "String",
"metadata": {
"description": "The address range in CIDR notation for the first subnet."
}
},
"gatewaySubnetPrefix": {
"type": "String",
"metadata": {
"description": "The address range in CIDR notation for the Gateway subnet. For ExpressRoute enabled Gateways, this must be minimum of /28."
}
},
"dnsServerAddress": {
"type": "String",
"metadata": {
"Description": "The DNS address(es) of the DNS Server(s) used by the VNET"
}
},
"dnsServerAddressUpdateDns": {
"type": "String",
"metadata": {
"Description": "The DNS address(es) of the DNS Server(s) used by the VNET"
}
}
},
"variables": {
"apiVersion": "2015-06-15",
"vnetApiVersion": "2017-10-01",
"virtualNetworkPeeringApiVersion": "2017-10-01",
"routeTableApiVersion": "2017-10-01",
"locksApiVersion": "2017-04-01",
"virtualNetworkName": "[tolower(concat('vnet-Test'))]",
"vnetID": "[resourceId('Microsoft.Network/virtualNetworks',variables('virtualNetworkName'))]",
"gatewaySubnetRef": "[concat(variables('vnetID'),'/subnets/',parameters('gatewaySubnet'))]",
"subnetName1": "[tolower(concat('sub-', parameters('subnetName1')))]",
"routeTable1": "[tolower(concat('udr-', variables('subnetName1')))]",
"networkSecurityGroup1": "[tolower(concat('nsg-', variables('subnetName1')))]",
"subnetName2": "[tolower(concat('sub-', parameters('subnetName2')))]",
"routeTable2": "[tolower(concat('udr-', variables('subnetName2')))]",
"networkSecurityGroup2": "[tolower(concat('nsg-', variables('subnetName2')))]"
},
"resources": [
{
"type": "Microsoft.Network/routeTables",
"name": "[variables('routeTable1')]",
"apiVersion": "[variables('routeTableApiVersion')]",
"location": "[resourceGroup().location]",
"properties": {
"routes": [],
"disableBgpRoutePropagation": false
}
},
{
"type": "Microsoft.Network/routeTables",
"name": "[variables('routeTable2')]",
"apiVersion": "[variables('routeTableApiVersion')]",
"location": "[resourceGroup().location]",
"properties": {
"routes": [],
"disableBgpRoutePropagation": false
}
},
{
"type": "Microsoft.Network/networkSecurityGroups",
"name": "[variables('networkSecurityGroup1')]",
"apiVersion": "[variables('apiVersion')]",
"location": "[resourceGroup().location]",
"properties": {
"securityRules": [
{
"name": "AllowInboundAnyAddressSpace",
"properties": {
"priority": 100,
"protocol": "*",
"access": "Allow",
"direction": "Inbound",
"sourceAddressPrefix": "[parameters('addressPrefix')]",
"sourcePortRange": "*",
"destinationAddressPrefix": "*",
"destinationPortRange": "*"
}
},
{
"name": "AllowOutboundAnyAddressSpace",
"properties": {
"priority": 100,
"protocol": "*",
"access": "Allow",
"direction": "Outbound",
"sourceAddressPrefix": "*",
"sourcePortRange": "*",
"destinationAddressPrefix": "[parameters('addressPrefix')]",
"destinationPortRange": "*"
}
}
]
},
"dependsOn": [
"[concat('Microsoft.Network/routeTables/', variables('routeTable1'))]"
]
},
{
"type": "Microsoft.Network/networkSecurityGroups",
"name": "[variables('networkSecurityGroup2')]",
"apiVersion": "[variables('apiVersion')]",
"location": "[resourceGroup().location]",
"properties": {
"securityRules": [
{
"name": "AllowInboundAnyAddressSpace",
"properties": {
"priority": 100,
"protocol": "*",
"access": "Allow",
"direction": "Inbound",
"sourceAddressPrefix": "[parameters('addressPrefix')]",
"sourcePortRange": "*",
"destinationAddressPrefix": "*",
"destinationPortRange": "*"
}
},
{
"name": "AllowOutboundAnyAddressSpace",
"properties": {
"priority": 100,
"protocol": "*",
"access": "Allow",
"direction": "Outbound",
"sourceAddressPrefix": "*",
"sourcePortRange": "*",
"destinationAddressPrefix": "[parameters('addressPrefix')]",
"destinationPortRange": "*"
}
}
]
},
"dependsOn": [
"[concat('Microsoft.Network/routeTables/', variables('routeTable2'))]"
]
},
{
"type": "Microsoft.Network/virtualNetworks",
"name": "[variables('virtualNetworkName')]",
"apiVersion": "[variables('vnetApiVersion')]",
"location": "[resourceGroup().location]",
"properties": {
"addressSpace": {
"addressPrefixes": [
"[parameters('addressPrefix')]"
]
},
"dhcpOptions": {
"dnsServers": "[parameters('dnsServerAddress')]"
},
"subnets": [
{
"name": "[variables('subnetName1')]",
"properties": {
"addressPrefix": "[parameters('subnetPrefix1')]",
"networkSecurityGroup": {
"id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('networkSecurityGroup1'))]"
},
"routeTable": {
"id": "[resourceId('Microsoft.Network/routeTables', variables('routeTable1'))]"
},
"serviceEndpoints": [
{
"service": "Microsoft.Storage",
"locations": [
"[resourceGroup().location]"
]
},
{
"service": "Microsoft.Sql",
"locations": [
"[resourceGroup().location]"
]
}
]
}
},
{
"name": "[variables('subnetName2')]",
"properties": {
"addressPrefix": "[parameters('subnetPrefix2')]",
"networkSecurityGroup": {
"id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('networkSecurityGroup2'))]"
},
"routeTable": {
"id": "[resourceId('Microsoft.Network/routeTables', variables('routeTable2'))]"
},
"serviceEndpoints": [
{
"service": "Microsoft.Storage",
"locations": [
"[resourceGroup().location]"
]
},
{
"service": "Microsoft.Sql",
"locations": [
"[resourceGroup().location]"
]
}
]
}
},
{
"name": "[parameters('gatewaySubnet')]",
"properties": {
"addressPrefix": "[parameters('gatewaySubnetPrefix')]"
}
}
]
},
"resources": [
{
"type": "Microsoft.Network/virtualNetworks/providers/locks",
"name": "[concat(variables('virtualNetworkName'), '/Microsoft.Authorization/', variables('virtualNetworkName'), '-LockDoNotDelete')]",
"apiVersion": "[variables('locksApiVersion')]",
"properties": {
"level": "CanNotDelete",
"notes": "Resource Lock - Do Not Delete!",
"owners": []
},
"dependsOn": [
"[variables('virtualNetworkName')]"
]
}
],
"dependsOn": [
"[concat('Microsoft.Network/routeTables/', variables('routeTable1'))]",
"[concat('Microsoft.Network/routeTables/', variables('routeTable2'))]",
"[concat('Microsoft.Network/networksecuritygroups/', variables('networkSecurityGroup1'))]",
"[concat('Microsoft.Network/networksecuritygroups/', variables('networkSecurityGroup2'))]"
]
}
]
}
Hope this helps.
I created a task that talks to a REST API to retreive the values for 2 picklists.
Filling the first dropdown box works fine, when using just the jsonpath.
Based on the first picklist I'd like to retreive values of the second list.
I've tried some variations and I'm trying something like this:
The json which I receive in the first rest call is similar to:
{
"id": "45",
"href": "https://selfservice/api/configurations/45/",
"name": "Type",
"description": "",
"version": "0.0.4",
"attributes": [
{
"value": {
"sdk-object": {
"type": "ConfigurationElement",
"id": "56"
}
},
"type": "ConfigurationElement",
"name": "win"
},
{
"value": {
"sdk-object": {
"type": "ConfigurationElement",
"id": "57"
}
},
"type": "ConfigurationElement",
"name": "lin"
}
]
}
I try to show the attributes name in the list and need the id of the attribute in the second picklist.
I created the following datasourcebindings in the task.json. Of course, the targets exist in the task.
task.json:
{
"id": "GUID",
"name": "Spinup",
"friendlyName": "Create environment",
"description": "Starts Workflow to create an environment. ___ The following placeholders are created deplending on the template and can be used in the rest of the release:**XLDEnvironment** and **testAgentHostname**",
"category": "Deploy",
"author": "***",
"version": {
"Major": 0,
"Minor": 0,
"Patch": 33
},
"minimumAgentVersion": "1.95.3",
"inputs": [
{
"label": "Endpoint",
"name": "connectedServiceName",
"required": true,
"type": "connectedService:server",
"helpMarkDown": "endpoint to connect to."
},
{
"name": "stage",
"type": "string",
"label": "Stage",
"defaultValue": "$(Release.EnvironmentName)",
"required": true,
"helpMarkDown": "Stage of the release, default value is based on the pipeline."
},
{
"name": "releaseName",
"type": "string",
"label": "Environment name",
"defaultValue": "$(Release.ReleaseName)",
"required": true,
"helpMarkDown": "Name of the environment that will be created."
},
{
"name": "owner",
"type": "string",
"label": "Owner of the environment",
"defaultValue": "***",
"required": true,
"helpMarkDown": "It is common to use the initials of the product owner in this field. There has to be a valid AD user owner of each environment. This can also be set by using a variable through the pipeline."
},
{
"name": "group",
"type": "string",
"label": "Group of the owner",
"defaultValue": "",
"required": true,
"helpMarkDown": "group that owns the environment. groups can be requested by the infrastructure department. Example: ****"
},
{
"name": "platform",
"type": "pickList",
"label": "Platform (OS)",
"defaultValue": "",
"required": true,
"helpMarkDown": "Choose the type of the target platform."
},
{
"name": "size",
"type": "pickList",
"label": "Environment Template",
"defaultValue": "",
"required": true,
"helpMarkDown": "Size of the environment to create."
}
],
"dataSourceBindings": [
{
"dataSourceName": "GetCEPlatformType",
"endpointId": "$(connectedServiceName)",
"target": "platform",
"selector": "jsonpath:$.attributes[*].name",
"keySelector": "jsonpath:$.attributes[*].value.sdk-object.id"
},
{
"dataSourceName": "GetCEPlatformSize",
"endpointId": "$(connectedServiceName)",
"target": "size",
"parameters": {
"platformTypeId": "$(platform)"
}
}
],
"instanceNameFormat": "Spin up $(size) $(platform) environment",
"execution": {
"PowerShell3": {
"target": "$(currentDirectory)\\task.ps1",
"argumentFormat": "",
"workingDirectory": "$(currentDirectory)"
}
}
}
vss-extension.json:
{
"manifestVersion": 1,
"id": "*****",
"name": "Release Tasks",
"version": "1.0.1",
"publisher": "***",
"targets": [
{
"id": "Microsoft.VisualStudio.Services"
}
],
"description": "Tools to contact ***. Includes a task to spin up a platform and a task to remove the platform.",
"categories": [
"Build and release"
],
"icons": {
"default": "images/extension-icon.png"
},
"files": [
{
"path": "RemoveEnvironment"
},
{
"path": "SpinUpEnvironment"
}
],
"contributions": [
{
"id": "******",
"type": "ms.vss-distributed-task.task",
"targets": [
"ms.vss-distributed-task.tasks"
],
"properties": {
"name": "RemoveEnvironment"
}
},
{
"id": "*********",
"type": "ms.vss-distributed-task.task",
"targets": [
"ms.vss-distributed-task.tasks"
],
"properties": {
"name": "SpinUpEnvironment"
}
},
{
"description": "Service Endpoint type for all connections",
"id": "endpoint-type",
"properties": {
"authenticationSchemes": [
{
"inputDescriptors": [
{
"description": "Username",
"id": "username",
"inputMode": "textbox",
"name": "Username",
"validation": {
"dataType": "string",
"isRequired": true
}
},
{
"description": "Password",
"id": "password",
"inputMode": "passwordbox",
"isConfidential": true,
"name": "Password",
"validation": {
"dataType": "string",
"isRequired": false
}
}
],
"type": "ms.vss-endpoint.endpoint-auth-scheme-basic"
}
],
"dataSources": [
{
"endpointUrl": "api/configurations/*****/",
"name": "GetCEPlatformType",
"resultSelector": "jsonpath:$.attributes[*].name"
},
{
"endpointUrl": "api/configurations/$(platformTypeId)/",
"name": "GetCEPlatformSize",
"resultSelector": "jsonpath:$.attributes[*].name"
}
],
"displayName": "*****",
"helpMarkDown": "Enter the url and credentials to connect to the endpoint.",
"name": "server",
"url": {
"displayName": "Server URL",
"helpText": "Url for the server to connect to."
}
},
"targets": [
"ms.vss-endpoint.endpoint-types"
],
"type": "ms.vss-endpoint.service-endpoint-type"
}
]
}
Sadly I can't get this to work. The datasources exist in the endpoint, but I'm not sure what to do with the resultSelector.
Does anyone have an idea on how to get this to work? The documentation on this isn't too good.
I'm not familiar with mustache, but in the mustache test tool this seems to work.
Thoughts are appreciated!
Try with this in the first data source:
{
"dataSourceName": "dsList1",
"endpointId": "$(connectedServiceName)",
"target": "list1",
"selector": "jsonpath:$.attributes[*].name",
"keySelector": "jsonpath:$.attributes[*].value.sdk-object.id"
}
Update:
You were trying to use "platformTypeId" in vss-extension.json file while it was defined in task.json, this cause the error message you mentioned in the comment.
By the way, I just noticed that you are using "dataSourceBindings", then you cannot use "selector" and "KeySelector" to parse the result since they are used for "sourceDefinitions".
To achieve the feature you want with "dataSourceBindings", you can definition the endpoint url in the task.json directly instead of defining datasource in endpoint contribution.
So you can move the datasources section in the vss-extension.json file first, and then in the task.json file, change to following:
"dataSourceBindings": [
{
"endpointId": "$(connectedServiceName)",
"endpointURL": "api/configurations/*****/",
"target": "platform",
"resultselector": "jsonpath:$.attributes[*]",
"resultTemplate": "{ \"Value\" : \"{{{value.id}}}\", \"DisplayValue\" : \"{{{name}}}\" }"
},
{
"endpointId": "$(connectedServiceName)",
"endpointURL": "api/configurations/$(platformTypeId)/",
"target": "size"
}
],
Facing following issues while performing vagrant up with azure provider
"response": {
"body": "{\"error\":{\"code\":\"InvalidTemplate\",\"message\":\"Deployment template validation failed: 'The value fo
r the template parameter 'adminPassword' at line '1' and column '306' is not provided. Please see https://aka.ms/arm-dep
loy/#parameter-file for usage details.'.\"}}",
Template file:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"vaults_VaultVagrant_name": {
"defaultValue": "VaultVagrant",
"type": "String"
},
"AdminPassword":{
"type":"securestring"
}
},
"variables": {},
"resources": [
{
"type": "Microsoft.KeyVault/vaults",
"name": "[parameters('vaults_VaultVagrant_name')]",
"apiVersion": "2015-06-01",
"location": "eastus",
"tags": {},
"properties": {
"sku": {
"family": "A",
"name": "standard"
},
"tenantId": "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy",
"accessPolicies": [
{
"tenantId": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"objectId": "1efb1891-8ad4-4f69-9e0d-f5849e6f8c98",
"permissions": {
"keys": [
"get",
"create",
"delete",
"list",
"update",
"import",
"backup",
"restore"
],
"secrets": [
"all"
]
}
}
],
"enabledForDeployment": true
},
"resources": [],
"dependsOn": []
}
]
}
Parameter
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"AdminPassword": {
"reference": {
"keyVault": {
"id":"/subscriptions/xxxxxxxxxxxxxxxxxxxxxxxxx/resourceGroups/azurevag/providers/Microsoft.KeyVault/vaults/VaultVagrant"
},
"secretName": "vagrant"
}
}
}
}
I am deploying both files from local machine as like in below
azure group deployment create -f "c:\MyTemplates\example.json" -e
"c:\MyTemplates\example.params.json" -g examplegroup -n
exampledeployment
ISSUE:After deployment is successfully created checked the deployment script in azure portal where both the files look like below
TemplateFile
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"vaults_VaultVagrant_name": {
"defaultValue": "VaultVagrant",
"type": "String"
}
},
"variables": {},
"resources": [
{
"comments": "Generalized from resource: '/subscriptions/214d050d-5430-4fd8-bb08-8152128a07b9/resourceGroups/azurevag/providers/Microsoft.KeyVault/vaults/VaultVagrant'.",
"type": "Microsoft.KeyVault/vaults",
"name": "[parameters('vaults_VaultVagrant_name')]",
"apiVersion": "2015-06-01",
"location": "eastus",
"tags": {},
"properties": {
"sku": {
"family": "A",
"name": "standard"
},
"tenantId": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"accessPolicies": [
{
"tenantId": "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy",
"objectId": "1efb1891-8ad4-4f69-9e0d-f5849e6f8c98",
"permissions": {
"keys": [
"get",
"create",
"delete",
"list",
"update",
"import",
"backup",
"restore"
],
"secrets": [
"all"
]
}
}
],
"enabledForDeployment": true
},
"resources": [],
"dependsOn": []
}
]
}
Note: Parameter adminpassword is missed after deployment
Parameter file:
parameter file is empty.
How the values(admin password) are missed after deployment?