Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

azurerm resourceid interpolation function #1466

Open
richeney opened this issue Jun 29, 2018 · 13 comments
Open

azurerm resourceid interpolation function #1466

richeney opened this issue Jun 29, 2018 · 13 comments

Comments

@richeney
Copy link
Contributor

richeney commented Jun 29, 2018

Community Note

  • Please vote on this issue by adding a 馃憤 reaction to the original issue to help the community and maintainers prioritize this request
  • Please do not leave "+1" or "me too" comments, they generate extra noise for issue followers and do not help prioritize the request
  • If you are interested in working on this issue or have submitted a pull request, please leave a comment

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:

  1. a string for an Azure "resourceId"
  2. a list for [ "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

/subscriptions/2d31be49-d999-4415-bb65-8aec2c90ba62/resourceGroups/rgname
/subscriptions/2d31be49-d999-4415-bb65-8aec2c90ba62/resourceGroups/rgname/providers/Microsoft.Network/virtualNetworks/resname
/subscriptions/2d31be49-d999-4415-bb65-8aec2c90ba62/resourceGroups/rgname/providers/Microsoft.Network/virtualNetworks/resname/subnets/subresname

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:

  "id"                   = "/subscriptions/2d31be49-d999-4415-bb65-8aec2c90ba62/resourceGroups/rgname/providers/Microsoft.Network/virtualNetworks/resname"
  "subscription"         = "2d31be49-d999-4415-bb65-8aec2c90ba62"
  "resource_group"       = "rgname"
  "namespace"            = "Microsoft.Network/virtualNetworks"
  "resource"             = "resname"
  "subscription_scope"   = "/subscriptions/2d31be49-d999-4415-bb65-8aec2c90ba62"
  "resource_group_scope" = "/subscriptions/2d31be49-d999-4415-bb65-8aec2c90ba62/resourceGroups/rgname"
}

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)

  • azurerm_XXXXX

Potential Terraform Configuration

# Copy-paste your Terraform configurations here - for large Terraform configs,
# please use a service like Dropbox and share a link to the ZIP file. For
# security, you can also encrypt the files using our GPG public key.

References

  • #0000
@AdamCoulterOz
Copy link
Contributor

@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?

@avishnyakov
Copy link

Late to the party, but there might be a quick workaround with azurerm_client_config.
Should also help with #5691 and #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" {
}

@AdamCoulterOz
Copy link
Contributor

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 tombuildsstuff self-assigned this Nov 26, 2021
@AdamCoulterOz
Copy link
Contributor

@tombuildsstuff, how are those new parsers going?

@harshavmb
Copy link
Contributor

harshavmb commented Nov 7, 2022

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.

@AdamCoulterOz
Copy link
Contributor

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.

@harshavmb
Copy link
Contributor

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 :)

@richeney
Copy link
Contributor Author

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.

@tombuildsstuff
Copy link
Member

@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)

@BHoggs
Copy link
Contributor

BHoggs commented Apr 15, 2024

So, now that Terraform core supports exposing provider functions (hashicorp/terraform#34394) - perhaps time to revisit this one?

@richeney
Copy link
Contributor Author

100% agree. Parsing the Azure resource IDs is a perfect use case for a provider function.

@tombuildsstuff
Copy link
Member

@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!

@richeney
Copy link
Contributor Author

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants