From 497ed16c6f3931e4d0405ea94590d02265208c02 Mon Sep 17 00:00:00 2001 From: Matt Bush Date: Thu, 30 May 2024 17:25:35 -0700 Subject: [PATCH] Use FormattedIdentifierFromProvider external name config So that crossplane doesn't initialize the external name with the incorrect value before updating it to the correct value. Signed-off-by: Matt Bush --- config/externalname.go | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/config/externalname.go b/config/externalname.go index 8f2fda5ab6..2b96cd763d 100644 --- a/config/externalname.go +++ b/config/externalname.go @@ -1111,9 +1111,9 @@ var TerraformPluginSDKExternalNameConfigs = map[string]config.ExternalName{ // eks // // import EKS access entry using the cluster_name and principal_arn separated by a colon (:). - "aws_eks_access_entry": config.TemplatedStringAsIdentifier("", "{{ .parameters.cluster_name }}:{{ .parameters.principal_arn }}"), + "aws_eks_access_entry": FormattedIdentifierFromProviderWithIdentifierFields(":", "cluster_name", "principal_arn"), // import EKS access entry using the cluster_name principal_arn and policy_arn separated by a (#) which the tf provider docs incorrectly describe as a colon. - "aws_eks_access_policy_association": config.TemplatedStringAsIdentifier("", "{{ .parameters.cluster_name }}#{{ .parameters.principal_arn }}#{{ .parameters.policy_arn }}"), + "aws_eks_access_policy_association": FormattedIdentifierFromProviderWithIdentifierFields("#", "cluster_name", "principal_arn", "policy_arn"), // "aws_eks_addon": config.TemplatedStringAsIdentifier("addon_name", "{{ .parameters.cluster_name }}:{{ .external_name }}"), // my_cluster:my_eks_addon "aws_eks_addon": FormattedIdentifierFromProvider(":", "cluster_name", "addon_name"), @@ -2970,6 +2970,12 @@ func getPermissionSetId(tfstate map[string]any) (string, error) { // IDs that use elements from the parameters in a certain string format. // It should be used in cases where all information in the ID is gathered from // the spec and not user defined like name. For example, zone_id:vpc_id. +// +// TODO: This should set keys as IdentifierFields, because if they're missing observe-only resources won't work. +// But that would remove them from spec.initProvider, which would be a breaking schema change for existing resources +// that we don't have a good way to handle yet. +// +// For new resources, prefer using FormattedIdentifierFromProviderWithIdentifierFields instead. func FormattedIdentifierFromProvider(separator string, keys ...string) config.ExternalName { e := config.IdentifierFromProvider e.GetIDFn = func(_ context.Context, _ string, parameters map[string]interface{}, _ map[string]interface{}) (string, error) { @@ -2990,6 +2996,19 @@ func FormattedIdentifierFromProvider(separator string, keys ...string) config.Ex return e } +// FormattedIdentifierFromProviderWithIdentifierFields is a helper function to construct Terraform +// IDs that use elements from the parameters in a certain string format. +// It should be used in cases where all information in the ID is gathered from +// the spec and not user defined like name. For example, zone_id:vpc_id. +// This function sets the keys as IdentifierFields, which means that they are always required, even for observe-only +// resources. Because the id is constructed exclusively from the keys, omitting them (even if the external name +// annotation is set) leaves the provider unable to find the terraform id to use to observe the resource. +func FormattedIdentifierFromProviderWithIdentifierFields(separator string, keys ...string) config.ExternalName { + e := FormattedIdentifierFromProvider(separator, keys...) + e.IdentifierFields = append(e.IdentifierFields, keys...) + return e +} + // FormattedIdentifierUserDefinedNameLast is used in cases where the ID is constructed // using some of the spec fields as well as a field that users use to name the // resource. For example, vpc_id:cluster_name where vpc_id comes from spec