PSArm
PSArm copied to clipboard
Make resource referencing easier
Today to reference one resource from another I have to embed the ARM the hard way:
Resource 'MyResource' -Provider Microsoft.Network -Type 'virtualNetworks/subnets' -ApiVersion 2019-11-01 {
properties {
addressPrefix 10.0.0.0/24
}
}
Resource (concat $namePrefix '-nic') -ApiVersion 2019-11-01 -Provider Microsoft.Network -Type networkInterfaces {
properties {
ipConfigurations {
name 'myConfig'
properties {
privateIPAllocationMethod -Value Dynamic
subnet {
# HERE: This is cumbersome
id (resourceId 'Microsoft.Network/networkInterfaces' (concat $vnetNamespace $namePrefix '-subnet'))
}
}
}
}
}
Instead we need a really simple way to use the referential object concept to embed a reference from one resource to another.
We have the IArmReferenceable
interface and concept to power this, the question is simply how to make it.
Forcing users to assign a prior resource to a variable is a bad experience, but is the most straightforward way. Otherwise resources could automagically define variables based in some way on their name, but their name might not be known at publication time, it might clobber another variable and it's not discoverable in any case.
Thinking of the editing experience is there not a way we can as the template is being written (in vscode I am assuming here) that we could have a dynamically expanding variable that you can tabcomplete all these types of painful things from something like this
$ARM.Resource.MyResource.ResourceID
Or is that going to be unworkable?
$ARM.Resource.MyResource.ResourceID
That's an interesting idea.
There are two challenges:
- The actual template won't exist yet, so we'd need to create a variable that can dynamically accommodate these assignments, enter them as sort of slots in the template and then after the template is evaluated do a pass over it and fill them in. That's possible but requires a combination of the magic of the way we do ARM parameters and the way we do ARM functions
- It's allowed to name resources with an ARM expression that isn't statically known (like
[concat(variables('x'), '-subnet')]
), which makes theMyResource
part tricky. Whereas if the resource is defined with a variable in some way, it becomes easy to pass around by reference.
One way I could imagine is like this:
Resource ... -ResourceVariable myResource {
}
...
subnet {
id $myResource
}
It's allowed to name resources with an ARM expression that isn't statically known (like [concat(variables('x'), '-subnet')]), which makes the MyResource part tricky. Whereas if the resource is defined with a variable in some way, it becomes easy to pass around by reference.
This is one reason why when I've been writing ARM templates lately I try and write them like this upfront (simplified example)
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"myparam": {
"type": "string",
"metadata": {
"description": "description"
}
},
"VMConfig": {
"type": "object",
"metadata": {
"description": "description"
}
}
},
"functions": [],
"variables": {
"Var1": "[concat(parameters('myparam'), '-',deployment().location)]",
"Deployments": {
"Names": {
"VM": "[concat('VM-',variables('Var1'))]"
},
"APIVersions": {
"Compute": "2019-07-01"
}
}
},
"resources": [
{
"name": "[variables('Deployments').Names.VM]",
"type": "Microsoft.Compute/virtualMachines",
"apiVersion": "[variables('Deployments').APIVersions.Compute]",
"location": "[resourceGroup().location]",
"dependsOn": [
],
"tags": {
},
"properties": {
"hardwareProfile": {
"vmSize": "[parameters('VMConfig').hardwareProfile.vmSize]"
},
"osProfile": "[parameters('VMConfig').osProfile]",
"storageProfile": "[parameters('VMConfig').storageProfile]",
"networkProfile": "[parameters('VMConfig').networkProfile]",
"diagnosticsProfile": "[parameters('VMConfig').diagnosticsProfile]"
}
}
],
"outputs": {}
}
This allows for the object being passed through to optionally be tested outside to this that said, I make heavy use of Linked Templates for code reusability whereas others may use other methods
This is potentially a separate feature but once this exists I think it’s not a crazy jump to support automatic dependencies. Coming from terraform, this makes the config a lot more streamlined and for a human is obvious. If I create a vnet and a subnet and the subnet is in that vnet it’s obvious that a dependency exists there