terraform-provider-azapi icon indicating copy to clipboard operation
terraform-provider-azapi copied to clipboard

Feature request: support provider functions

Open ms-henglu opened this issue 1 year ago • 2 comments

To support functions like

  1. parse azure resource id
  2. build azure resource id

refs: https://developer.hashicorp.com/terraform/plugin/framework/functions/concepts

ms-henglu avatar Jun 19 '24 06:06 ms-henglu

Other considerations here @ms-henglu can we do them? 3. location listing 4. flatten map function to simplify for each expressions General guidance by Terraform is to avoid anything that requires calls to the provider itself, which we should keep in mind. @matt-FFFFFF for FYI

stemaMSFT avatar Jun 27 '24 18:06 stemaMSFT

Locations could work like this:

https://registry.terraform.io/modules/Azure/regions/azurerm/latest

Merging date from locations API and compute provider to determine if a location has zones support.

We should cache the API response in the provider to adhere to HashiCorp's recommendation. This means we get consistent results. Plus the data won't change that frequently.

matt-FFFFFF avatar Jun 27 '24 22:06 matt-FFFFFF

@stemaMSFT @grayzu

Hello! Looking for any suggestions on the function to build Azure resource IDs. I think there are two options:

  1. Allow users to provide parentID, resource type, and name to construct the resource ID, as described in this guide. Pros: quite straightforward & less parameters needed Cons: users may not know what the parent id is?

  2. Allow users to provide resource type, name, and other specifics like subscription ID and resource group name etc..., and use those to construct the parentID internally, which is then used to build the full resource ID. Pros: referring to more specific names that user knows about Cons: too many parameters & a lot of cases to think about in building the parent id internally

hqhqhqhqhqhqhqhqhqhqhq avatar Jul 10 '24 03:07 hqhqhqhqhqhqhqhqhqhqhq

@hqhqhqhqhqhqhqhqhqhqhq I think it would make sense to do option 1, since that would be consistent with the behavior of AzAPI (as parent_id is already a parameter in resource definitions). It keeps consistent with Azure as well, which is what we're aiming for philosophically with AzAPI.

stemaMSFT avatar Jul 10 '24 21:07 stemaMSFT

I think we could have a few functions.

The option 1 as mentioned above plus dedicated functions for the four major scopes in azure:

Tenant - just need resource type and name

Management group - need MG id plus resource type and name

Subscription - need sub id, resource type and name

Resource group - sub id, RG name, resource type and name

For more complex scenarios we can use the parent id option and maybe nest the functions?

matt-FFFFFF avatar Jul 10 '24 21:07 matt-FFFFFF

@matt-FFFFFF would you mind elaborating on why you prefer four separate functions compared to one function to construct resource IDs generically? Maybe with some scenarios. Would help us understand which direction to take.

stemaMSFT avatar Jul 24 '24 05:07 stemaMSFT

@matt-FFFFFF would you mind elaborating on why you prefer four separate functions compared to one function to construct resource IDs generically? Maybe with some scenarios. Would help us understand which direction to take.

@stemaMSFT

Thinking more I think this could be one function, with a variadic input.

E.g.

provider::azapi::resource_id("resource_group", "<subscription id>", "<resource group name>", "<resource type>", "<resource name>")

provider::azapi::resource_id("management_group", "<management group id>", "<resource type>", "<resource name>")

provider::azapi::resource_id("tenant", "<resource type>", "<resource name>")

provider::azapi::resource_id("parent", "<parent resource id>" , "<resource type>", "<resource name>")

And so on. As long as each mode was identified by the first input I think that would work.

matt-FFFFFF avatar Jul 26 '24 09:07 matt-FFFFFF

Makes sense to me. @ms-henglu if you don't have any other concerns, I think we can move forward with this approach.

stemaMSFT avatar Jul 29 '24 17:07 stemaMSFT

Hi @matt-FFFFFF ,

Thanks for the suggestions! But unfortunately variadic function is supported by the Terraform provider function.

How about the below design proposed by @hqhqhqhqhqhqhqhqhqhqhq https://github.com/Azure/terraform-provider-azapi/pull/553#issue-2408065215

ms-henglu avatar Jul 31 '24 05:07 ms-henglu

@matt-FFFFFF @stemaMSFT Adding to above, I think the difference lies where the scope is defined. We can:

  1. Put it a part of the function e.g. build_management_group_scope_resource_id

pros:

  • no need for users to manually input "management_group" as a param
  • easier to implement such function as the number of parameters are fixed

cons:

  • more functions to maintain
  • may need more functions if more scope types were introduced later
  1. Use a generic function, and let user give the scope type, e.g. provider::azapi::resource_id("management_group", "", "", "")

pros:

  • one single goto function for users

cons:

  • user have explicity input the scope type, e,.g. "management_group"
  • may become more complex given that different scopes needs different number of parameters

personally think having multiple functions can be more suitable, especially that it's not likely for more scope types to be introduced anytime soon, so it really just need 4-5 more functions

hqhqhqhqhqhqhqhqhqhqhq avatar Jul 31 '24 06:07 hqhqhqhqhqhqhqhqhqhqhq

I just noticed that the bicep/ARM templates have similar functions: https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/bicep-functions-resource#subscriptionresourceid

So I'm proposing the following functions which are similar with the bicep's.

The # 1 function is just the provider function implementation of the azapi_resource_id data source. And the rest of them allow user to build the resource ID with only the "name" part, for example, the management group name, resource group name and each resource name. Users don't need to worry about the ID format.

And to support nested resource under different deployed scope, the last argument of these functions is a list of string. More details please see the below examples:

  1. resourceId(resourceType, parentId, name)

    Example:

resourceId("Microsoft.Network/virtualNetworks", "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg1", "vnet1")
= "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg1/providers/Microsoft.Network/virtualNetworks/vnet1"
  1. tenantResourceId(resourceType, [resourceName1, resourceName2, ...])

    Example:

tenantResourceId("Microsoft.Billing/billingAccounts/billingProfiles", ["ba1", "bp1"])
= "/providers/Microsoft.Billing/billingAccounts/ba1/billingProfiles/bp1"
  1. subscriptionResourceId(subscriptionId, resourceType, [resourceName1, resourceName2, ...])

    Example:

subscriptionResourceId("00000000-0000-0000-0000-000000000000", "Microsoft.Resources/resourceGroups", ["rg1"])
= "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg1"
  1. managementGroupResourceId(managementGroupName, resourceType, [resourceName1, resourceName2, ...])

    Example:

managementGroupResourceId("mg1", "Microsoft.Billing/billingAccounts/billingProfiles", ["ba1", "bp1"])
= "/providers/Microsoft.Management/managementGroups/mg1/providers/Microsoft.Billing/billingAccounts/ba1/billingProfiles/bp1"
  1. extensionResourceId(resourceId, extensionName, [resourceName1, resourceName2, ...])

    Example:

extensionResourceId("/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg1/providers/Microsoft.Network/virtualNetworks/vnet1", "Microsoft.Authorization/locks", ["mylock"])
= "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg1/providers/Microsoft.Network/virtualNetworks/vnet1/providers/Microsoft.Authorization/locks/mylock"
  1. resourceGroupResourceId(subscriptionId, resourceGroupName, resourceType, [resourceName1, resourceName2, ...])

    Example:

resourceGroupResourceId("00000000-0000-0000-0000-000000000000", "rg1", "Microsoft.Network/virtualNetworks/subnets", ["vnet1", "subnet1"])
= "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg1/providers/Microsoft.Network/virtualNetworks/vnet1/subnets/subnet1"

ms-henglu avatar Aug 06 '24 06:08 ms-henglu

Completed via https://github.com/Azure/terraform-provider-azapi/pull/553

ms-henglu avatar Sep 03 '24 01:09 ms-henglu