Open richeney opened 6 years ago
@tombuildsstuff thanks for pointing this out to me ... I might try creating a PR for this on the weekend... am I correct in assuming it should be implemented as a data resource?
Late to the party, but there might be a quick workaround with azurerm_client_config
.
Should also help with https://github.com/hashicorp/terraform-provider-azurerm/issues/5691 and https://github.com/hashicorp/terraform-provider-azurerm/pull/12323
Might need tweaks for multi-provider setup, but still not too bad. Feel free to improve this one.
# assuming there is a list of all_resources
locals {
all_resources = [
{
name = "resource-1"
rg_name = "rg-name-1"
},
{
name = "resource-2"
rg_name = "rg-name-2"
}
]
all_resource_ids = merge(
# forming resource id string by hand, since this is not supported in azurerm_resources data source yet
# "id" = "/subscriptions/xyz/resourceGroups/rgname/providers/Microsoft.Network/virtualNetworks/abc"
{
for k, v in data.azurerm_resources.target_resources : v.name => {
name = v.name,
id = join("/", [
# subscription
"/subscriptions",
data.azurerm_client_config.current.subscription_id,
# resource groups
"resourceGroups",
v.resource_group_name,
# providers (resource type)
"providers",
v.resources[0].type,
// name
v.resources[0].name
]),
}
},
)
}
# get all resources
data "azurerm_resources" "target_resources" {
for_each = { for value in local.all_resources :
value.name => value
}
resource_group_name = each.value.rg_name
name = each.value.name
}
# get current azure client config
data "azurerm_client_config" "current" {
}
I created a temporary provider while waiting for support from azurerm
https://registry.terraform.io/providers/AdamCoulterOz/azurehelpers/latest
data "azurehelpers_resource_id" "example" {
resource_id = "resourceId"
}
it lets you access the following:
data.azurehelpers_resource_id.example.subscription_id
data.azurehelpers_resource_id.example.resource_group_name
data.azurehelpers_resource_id.example.provider_namespace
data.azurehelpers_resource_id.example.resource_type
data.azurehelpers_resource_id.example.name
data.azurehelpers_resource_id.example.parent_resources
data.azurehelpers_resource_id.example.full_resource_type
@tombuildsstuff, how are those new parsers going?
Thanks @AdamCoulterOz ,
After disappointing azurerm_resources, I must admit your provider helped me.
azurerm_resources
is very inconsistent & unreliable during deployments. I don't find resources even minutes after their creation. sleep
& other depends_on
hacks didn't improve as well.
Looks like Azure APIs behave differently for read
& create
/update
functions depending on the node they end up. Atleast in North Europe I see this randomness.
If you could tweak your provider a bit further to fetch version from APIs & append to full_resource_type
, azapi_resource
data provider could be used which I find very reliable.
My stop-gap data resource explicitly doesn't try to get the resource, it just parses the ID, because a user won't always have read permission at every scope. Maybe only at the child scope. I can have access to a resource, but not it's resource group for example.
I was thinking of cleaning it up a little and submitting it as a PR to the new azapi provider. They have a nice way of passing in the resource type so it could return a cleaner map of fields.
Exactly! Parsing is all I need in my child module. The prime reason is create
/update
functions use parent resource ID & always worked.
Before I used the data provider to parse RG, type in the child module which failed randomly due to eventual consistency problems.
In my case, child modules refer to private endpoint resource & calling resources are managed resources like storage account, key vault etc.,
Please don't do the cleanup :)
Yep, there is no need to read the resourceIds from Azure. This is purely string manipulation which is why I originally suggested a string function as a possibility.
Ideally using the azurerm provider model would extend the set of functions with Azure specific functions - e.g. resourceid()
- as well as the azurerm data sources and resource types, but I don't think the provider framework allows that.
@richeney
Ideally using the azurerm provider model would extend the set of functions with Azure specific functions - e.g. resourceid() - as well as the azurerm data sources and resource types, but I don't think the provider framework allows that.
yeah, having dug into this we likely won't be adding a resourceid
function for this - instead I think we'd likely look towards something like generating a Data Source for each Resource ID (hypothetically, azurerm_resource_group_id
, or similar)
So, now that Terraform core supports exposing provider functions (https://github.com/hashicorp/terraform/pull/34394) - perhaps time to revisit this one?
100% agree. Parsing the Azure resource IDs is a perfect use case for a provider function.
@BHoggs @richeney
FWIW we've spent some time thinking about this recently, but unfortunately a generic Resource ID parsing function would quickly become problematic/a source of user configuration issues due the random recasings that happen in the Azure API, and whilst we're working to get a handle on those, for that reason we'd be unlikely to ship a generic function. It's worth noting that there's also some of the more problematic scenarios, such as Resource IDs containing multiple segments of the same name (e.g. two providers
segments) or scoped Resource IDs which make things interesting - and as such you ultimately need context of what you're parsing when you're parsing it, and is why we're moving away from the generic Resource ID functions internally in favour of a function with context of what it's parsing.
That said, I suspect having functions to generate a Resource ID would be useful (e.g. template_resource_group_id("subscriptionid", "resourcegroup")
and an associated parse function (e.g. parse_resource_group_id("")
) could be useful - as such whilst we won't likely add a generic Resource ID interpolation/parsing function - this route would likely make more sense.
All that to say, we should look into this, but a generic Resource ID interpolation/parsing function is unfortunately more problematic than it first appears, even if it's be useful in the happy path - and so it's more likely this'd ship in the form of more specific Resource ID interpolation/parsing functions, rather than as a generic Resource ID function.
Thanks!
For reference, ARM / Bicep have the following functions that generate resourceIds in this space:
These all generate the different scope level resourceIDs. Some use defaults from context for parameters such as subscription when unspecified.
Community Note
Description
The Azure resource IDs are a fixed format, and it would be useful to have an function to convert from the full string to a map of the constituent parts.
An Azure specific interpolation function (or perhaps data source), which takes an argument of either:
"resourceId"
[ "subscriptionId", "resourceGroupName", "Microsoft.Provider/type", "resourceName" ]
(If possible, make the first two in the list optional. If resource group is not specified then default to the resource group for the current resource stanza (if that context is held). If subscription is not specified then default to the current subscription.)
The function is pure string manipulation (unless subscription / resource group defaults are possible), but it would help massively.
Example resourceids
For a resource group, resource and sub-resource
Output map
Using /subscriptions/2d31be49-d999-4415-bb65-8aec2c90ba62/resourceGroups/rgname/providers/Microsoft.Network/virtualNetworks/resname as the input example, then the output map would look something like:
If there is a subresource (e.g. subnets) then the resource value should be everything after the resource provider namespace, e.g. "resname/subnets/subresname"
New or Affected Resource(s)
Potential Terraform Configuration
References
0000