Due to separation of duty I need to split an existing ARM template into two single templates - one for the resource and one for the logging
the original templates looks like this:
"resources": [
{ // https://learn.microsoft.com/en-us/azure/templates/microsoft.datafactory/factories
"type": "Microsoft.DataFactory/factories",
"name": "[variables('dataFactoryName')]",
"apiVersion": "[variables('apiVersion')]",
"location": "[resourceGroup().location]",
"tags": {},
"identity": {
"type": "SystemAssigned"
},
"properties": {},
"resources": [
{
"type": "providers/diagnosticSettings",
"name": "[concat('Microsoft.Insights/', variables('logSettingName'))]",
"dependsOn": [
"[resourceId('Microsoft.DataFactory/factories', variables('dataFactoryName'))]"
],
"apiVersion": "2017-05-01-preview",
"location": "[resourceGroup().location]",
"tags": {},
"properties": {
"name": "[variables('logSettingName')]",
"workspaceId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('logAnalyticsObject').resourceGroup, '//providers/Microsoft.OperationalInsights/workspaces/', parameters('logAnalyticsObject').name)]",
"logs": "[parameters('logAnalyticsObject').adfv2.logs]",
"metrics": "[parameters('logAnalyticsObject').adfv2.metrics]"
}
}
]
}
The first part is quite easy, I just remove the sub-resource but how to get the second part (resource with "type": "providers/diagnosticSettings") correctly so it can be deployed from a different template?
Is this possible at all or are these strongly tied together?
I already tried different things like
"type": "Microsoft.DataFactory/factories/providers/diagnosticSettings",
"name": "[concat('Microsoft.Insights/', variables('name'))]",
but ended up with error messages like this:
Unable to process template language expressions for resource '/subscriptions/fb1e20c4-0878-4949-ac10-f92a9ac35db4/resourceGroups/swe-sdp-dv0
-rgp-adp/providers/Microsoft.Resources/deployments/DataFactory_LogAnalytics_Resource' at line '67' and column '5'. 'Unable to evaluate template language
function 'resourceId': function requires exactly one multi-segmented argument which must be resource type including resource provider namespace. Current
function arguments 'fb1e20c4-0878-4949-ac10-f92a9ac35db4,swe-sdp-dv0-rgp-anl,Microsoft.Insights,swe-sdp-dv0-oms-001'. Please see
https://aka.ms/arm-template-expressions/#resourceid for usage details.
I think to make it work I would need the right combination of "type", "name" and probably also "dependsOn"
ok, according to this, you would need to do this:
"type": "Microsoft.DataFactory/factories/providers/diagnosticSettings",
"name": "[concat(variables('dataFactoryName'), '/Microsoft.Insights/', variables('name'))]",
you dont need dependsOn, because resources are under different templates.
Related
I try to create an ARM Template for building the ground structure with ManagementGroups
and Subscriptions. My current problem is that I can't create nested Management Groups,
did somebody already something similiar?
I already have seen this Doc Article:
https://learn.microsoft.com/en-us/azure/templates/microsoft.management/managementgroups?tabs=json
See https://learn.microsoft.com/en-us/azure/azure-resource-manager/templates/deploy-to-management-group?tabs=azure-cli#management-group
You need to specify properties.details.parent.id:
"resources": [
{
"name": "[parameters('mgName')]",
"type": "Microsoft.Management/managementGroups",
"apiVersion": "2020-05-01",
"scope": "/",
"location": "eastus",
"properties": {
"details": {
"parent": {
"id": "[tenantResourceId('Microsoft.Management/managementGroups', parameters('parentMG'))]"
}
}
}
}
],
For the life of me I can't seem to get the dependsOn section to properly structure a dependency on the staging slot. I'm getting the following error:
Unable to evaluate template language function 'resourceId': function requires exactly one multi-segmented argument which must be resource type including resource provider namespace. Current function arguments 'Microsoft.Web/sites/slots,web01/staging'
I've tried numerous ways but they all end up with the same error, below one of the options I've tried:
"dependsOn": [
"[concat(resourceId('Microsoft.Web/sites/slots', parameters('webappName')), '/staging')]"
],
And
"dependsOn": [
"[resourceId('Microsoft.Web/sites/slots', concat(parameters('webappName')), '/staging'))]"
],
Does anyone know how I can solve this issue?
It is not necessary to use the concat function, the resourceId itself accepts several parameters to form the name: https://learn.microsoft.com/en-us/azure/azure-resource-manager/templates/template-functions-resource#resourceid
Here and example that how we use this in my work, to create a config for the slot.
"apiVersion": "2015-08-01",
"condition": "[equals(parameters('CreateSlot'), 'true')]",
"name": "appsettings",
"type": "config",
"dependsOn": [
"[resourceId('Microsoft.Web/sites', variables('functionAppName'))]",
"[resourceId('Microsoft.Web/sites/slots', variables('functionAppName'), parameters('SlotName'))]"
],
"properties": {
"AzureWebJobsDashboard": "[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2015-05-01-preview').key1)]"
]
I am creating ARM template which takes in hash table of subnets and creates those. However, it looks that I need to wait for the first subnet to be ready before creating the second etc. But I do not know how I could depend on the previous subnet in copy loop. My template resource looks like this currently:
{
"apiVersion": "2018-06-01",
"type": "Microsoft.Network/virtualNetworks/subnets",
"name": "[concat(parameters('vnetName') , '/' , parameters('subnets').settings[copyIndex()].name)]",
"location": "[variables('location')]",
"copy": {
"name": "subnetLoop",
"count": "[variables('subnetcount')]"
},
"dependsOn": ["[parameters('vnetName')]",
"[resourceId(variables('rgname'), 'Microsoft.Network/virtualNetworks/subnets', parameters('vNetName'), parameters('subnets').settings[copyIndex()].name)]"
],
"properties": {
"addressPrefix": "[parameters('subnets').settings[copyIndex()].addressPrefix]",
}
Which does not work because the first subnet cannot reference itself.
you can use "mode": "serial" to workaround that.
"copy": {
"name": "subnetLoop",
"count": "[variables('subnetcount')]",
"mode": "serial"
},
https://learn.microsoft.com/en-us/azure/azure-resource-manager/resource-group-create-multiple#resource-iteration
but you really need to look at properties loop, check this link:
https://learn.microsoft.com/en-us/azure/architecture/building-blocks/extending-templates/objects-as-parameters#using-a-property-object-in-a-copy-loop
I am trying to get a arm template running and have hit an issue with the virtualnetwork creation.
azuredeploy.json
"virtualNetworkName": {
"type": "string",
"metadata": {
"description": "Name of virtual network to be created"
},
"defaultValue": "autohav2VNET"
},
vnet-net.json
"resources": [
{
"name": "[parameters('virtualNetworkName')]",
"type": "Microsoft.Network/virtualNetworks",
"location": "[parameters('location')]",
"apiVersion": "2015-06-15",
"properties": {
"addressSpace": {
"addressPrefixes": [
"[parameters('virtualNetworkAddressRange')]"
]
},
"subnets": "[parameters('subnets')]"
}
}
]
The issue I am getting is that the vnet gets created with an appendix such as this: autohav2VNETl5g
So when this gets used to create a loadblancer, the names doe not match the defined parameter and the creation fails.
..../virtualNetworks/AUTOHAV2VNET referenced by resource .... /Microsoft.Network/loadBalancers/sqlLoadBalancer was not found.
Any suggestions?
with the data given it impossible to be sure why this is happening. you are probably passing in a value to the parameter virtualNetworkName. because if you wouldn't, than the vnet name would be: autohav2VNET.
ARM templates do not append anything anywhere just because they are arm templates. they only do what you designed them to do.
to help with debugging: how you are invoking the template and full template + full parameters file.
I have written a ARM template that dynamically builds out the app settings based on a JSON object parameter. This allows for adding any app setting without having to modify the template:
parameters.json
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"app_settings": {
"value": {
"keyvalue_pairs": [
{
"name": "appsetting1",
"value": "value"
},
{
"name": "ApplicationInsights:InstrumentationKey",
"value": ""
}
]
}
}
}
}
chopped down working template.json file
"resources": [
{
"comments": "",
"type": "microsoft.insights/components",
"kind": "web",
"name": "[variables('app_service_name')]",
"apiVersion": "2014-04-01",
"location": "[resourceGroup().location]",
"tags": {
"[variables('hiddenlink_app_service')]": "Resource"
},
"scale": null,
"properties": {
"ApplicationId": "[variables('app_service_name')]"
}
},
{
"apiVersion": "2015-08-01",
"name": "[concat(variables('app_service_name'),'/stage-slot')]",
"type": "Microsoft.Web/sites/slots",
"tags": {
"displayName": "stage-slot"
},
"location": "[resourceGroup().location]",
"dependsOn": [
"[resourceId('Microsoft.Web/Sites', variables('app_service_name'))]"
],
"properties": {
"clientAffinityEnabled": false,
"siteConfig": {
"copy": [
{
"name": "appSettings",
"count": "[length(parameters('app_settings').keyvalue_pairs)]",
"input": {
"name": "[parameters('app_settings').keyvalue_pairs[copyIndex('appSettings')].name]",
"value": "[parameters('app_settings').keyvalue_pairs[copyIndex('appSettings')].value]"
}
}
]
}
}
}
I now try and conditionally reference the app insights instrumentation key on my app settings hoping to override the app insights instrumentationkey from the resource.
"siteConfig": {
"copy": [
{
"name": "appSettings",
"count": "[length(parameters('app_settings').keyvalue_pairs)]",
"input": {
"name": "[parameters('app_settings').keyvalue_pairs[copyIndex('appSettings')].name]",
"value": "[if(equals(parameters('app_settings').keyvalue_pairs[copyIndex('appSettings')].name,'ApplicationInsights:InstrumentationKey'),reference(variables('appInsightsResource')).InstrumentationKey,parameters('app_settings').keyvalue_pairs[copyIndex('appSettings')].value)]"
}
}
]
}
This started throwing errors saying the if statement needs a boolean first parameter, but I didnt see anything wrong with it so I tried the following snippet and it worked so it leads me to believe that the use of the "reference()" inside a conditional isnt valid:
"siteConfig": {
"copy": [
{
"name": "appSettings",
"count": "[length(parameters('app_settings').keyvalue_pairs)]",
"input": {
"name": "[parameters('app_settings').keyvalue_pairs[copyIndex('appSettings')].name]",
"value": "[if(equals(parameters('app_settings').keyvalue_pairs[copyIndex('appSettings')].name,'ApplicationInsights:InstrumentationKey'),'testvalue',parameters('app_settings').keyvalue_pairs[copyIndex('appSettings')].value)]"
}
}
]
}
Additionally if I remove the whole "if()" and explicitly put "reference(variables('appInsightsResource')).InstrumentationKey" into the value, it outputs the right value so I know that this reference() call works but seems to break down when added inside an "if()" conditional statement.
The question is, is there any way to get this to work? I am trying to dynamically set the Instrumentation key while keeping in tact the ability to pass in a JSON object for my app settings
I'm seeing extremely confusing results with copy properties construct in general. most of the times is blows up with absolutely cryptic errors.
You won’t be able to use the reference() function in the count property – the copy loop is expanded at compile time – reference is evaluated at run-time. also, today I cant reproduce my working example, but i had a working example of reference function working in a copy properties, without if() though. You might want to create a bare minimum example showing how this doesnt work (so only 1 resource ideally). If that doesnt work you might want to raise an issue on github and\or azure feedback
You might be able to work around this by using nested deployments. but generally using properties copy in a clever way is a bit of a pain, due to compile\runtime issues.