@@ -964,11 +964,14 @@ type locationStructFieldCtx struct {
964964 Name * properties.NameVariant
965965 TerraformType string
966966 Type string
967+ AsIdentity bool
967968 Tags []string
968969}
969970
970971type locationStructCtx struct {
971972 StructName string
973+ XpathName * properties.NameVariant
974+ TopLevel bool
972975 Fields []locationStructFieldCtx
973976}
974977
@@ -982,6 +985,7 @@ func getLocationStructsContext(names *NameProvider, spec *properties.Normalizati
982985 // Create the top location structure that references other locations
983986 topLocation := locationStructCtx {
984987 StructName : fmt .Sprintf ("%sLocation" , names .StructName ),
988+ TopLevel : true ,
985989 }
986990
987991 for _ , data := range spec .OrderedLocations () {
@@ -993,6 +997,7 @@ func getLocationStructsContext(names *NameProvider, spec *properties.Normalizati
993997 Name : data .Name ,
994998 TerraformType : structName ,
995999 Type : structType ,
1000+ AsIdentity : true ,
9961001 Tags : []string {tfTag },
9971002 })
9981003
@@ -1022,13 +1027,15 @@ func getLocationStructsContext(names *NameProvider, spec *properties.Normalizati
10221027 paramTag = "`tfsdk:\" name\" `"
10231028 }
10241029 fields = append (fields , locationStructFieldCtx {
1025- Name : name ,
1026- Type : "types.String" ,
1027- Tags : []string {paramTag },
1030+ Name : name ,
1031+ Type : "types.String" ,
1032+ AsIdentity : true ,
1033+ Tags : []string {paramTag },
10281034 })
10291035 }
10301036
10311037 location := locationStructCtx {
1038+ XpathName : data .Name ,
10321039 StructName : structName ,
10331040 Fields : fields ,
10341041 }
@@ -2483,8 +2490,8 @@ func RenderLocationsPangoToState(names *NameProvider, spec *properties.Normaliza
24832490}
24842491
24852492const locationsStateToPango = `
2486- {
24872493var terraformLocation {{ .TerraformStructName }}
2494+ {
24882495resp.Diagnostics.Append({{ $.Source }}.As(ctx, &terraformLocation, basetypes.ObjectAsOptions{})...)
24892496if resp.Diagnostics.HasError() {
24902497 return
@@ -2998,6 +3005,112 @@ func RenderStructs(resourceTyp properties.ResourceType, schemaTyp properties.Sch
29983005 return processTemplate (dataSourceStructs , "render-structs" , data , commonFuncMap )
29993006}
30003007
3008+ const identityModelTmpl = `
3009+ type {{ .StructName }} struct {
3010+ {{- range .Fields }}
3011+ {{ .Name }} {{ .Type }} ` + "`" + `tfsdk:"{{ .Tag }}"` + "`" + `
3012+ {{ end }}
3013+ }
3014+ `
3015+
3016+ func RenderIdentityModel (names * NameProvider , spec * properties.Normalization ) (string , error ) {
3017+ if spec .TerraformProviderConfig .Ephemeral || spec .TerraformProviderConfig .ResourceType == properties .TerraformResourceCustom {
3018+ return "" , nil
3019+ }
3020+
3021+ if spec .TerraformProviderConfig .SkipResource {
3022+ return "" , nil
3023+ }
3024+
3025+ type fieldCtx struct {
3026+ Name string
3027+ Type string
3028+ Tag string
3029+ }
3030+
3031+ type context struct {
3032+ StructName string
3033+ Fields []fieldCtx
3034+ }
3035+
3036+ fields := []fieldCtx {
3037+ {Name : "Name" , Type : "types.String" , Tag : "name" },
3038+ {Name : "Location" , Type : "types.String" , Tag : "location" },
3039+ }
3040+
3041+ data := context {
3042+ StructName : fmt .Sprintf ("%sResourceIdentityModel" , names .StructName ),
3043+ Fields : fields ,
3044+ }
3045+
3046+ return processTemplate (identityModelTmpl , "render-identity-model" , data , commonFuncMap )
3047+ }
3048+
3049+ const identitySchemaTmpl = `
3050+ func (o {{ .StructName }}) IdentitySchema(_ context.Context, _ resource.IdentitySchemaRequest, resp *resource.IdentitySchemaResponse) {
3051+ resp.IdentitySchema = identityschema.Schema{
3052+ Attributes: map[string]identityschema.Attribute{
3053+ {{- range .Fields }}
3054+ "{{ .Name }}": {{ .Type }}{
3055+ {{- if .RequiredForImport }}
3056+ RequiredForImport: true,
3057+ {{- else if .OptionalForImport }}
3058+ OptionalForImport: true,
3059+ {{- end }}
3060+ },
3061+ {{- end }}
3062+ },
3063+ }
3064+ }
3065+ `
3066+
3067+ func RenderIdentitySchema (names * NameProvider , spec * properties.Normalization ) (string , error ) {
3068+ if spec .TerraformProviderConfig .Ephemeral || spec .TerraformProviderConfig .ResourceType == properties .TerraformResourceCustom {
3069+ return "" , nil
3070+ }
3071+
3072+ if spec .TerraformProviderConfig .SkipResource {
3073+ return "" , nil
3074+ }
3075+
3076+ type fieldCtx struct {
3077+ Name string
3078+ Type string
3079+ RequiredForImport bool
3080+ OptionalForImport bool
3081+ }
3082+
3083+ type context struct {
3084+ StructName string
3085+ Fields []fieldCtx
3086+ }
3087+
3088+ fields := []fieldCtx {
3089+ {Name : "name" , Type : "identityschema.StringAttribute" , RequiredForImport : true },
3090+ {Name : "location" , Type : "identityschema.StringAttribute" , RequiredForImport : true },
3091+ }
3092+
3093+ data := context {
3094+ StructName : fmt .Sprintf ("%sResource" , names .StructName ),
3095+ Fields : fields ,
3096+ }
3097+
3098+ return processTemplate (identitySchemaTmpl , "render-identity-model" , data , commonFuncMap )
3099+
3100+ }
3101+
3102+ const identityWriterTmpl = `
3103+
3104+ `
3105+
3106+ func RenderIdentityWriter (names * NameProvider , spec * properties.Normalization ) (string , error ) {
3107+ if spec .TerraformProviderConfig .Ephemeral {
3108+ return "" , nil
3109+ }
3110+
3111+ return processTemplate (identitySchemaTmpl , "render-identity-model" , nil , nil )
3112+ }
3113+
30013114const attributeTypesTmpl = `
30023115{{- range .Structs }}
30033116func (o *{{ .StructName }}{{ .ModelOrObject }}) AttributeTypes() map[string]attr.Type {
@@ -3105,6 +3218,83 @@ func RenderLocationAttributeTypes(names *NameProvider, spec *properties.Normaliz
31053218 return processTemplate (locationAttributeTypesTmpl , "render-location-structs" , data , commonFuncMap )
31063219}
31073220
3221+ const locationAsIdentityTmpl = `
3222+ {{- define "topLevelLocation" }}
3223+ {{- range $.Specs }}
3224+ {{- if not .TopLevel }}{{- continue }}{{- end }}
3225+ {{- range .Fields }}
3226+ if !o.{{ .Name.CamelCase }}.IsNull() {
3227+ var location {{ .TerraformType }}
3228+ diags := o.{{ .Name.CamelCase }}.As(ctx, &location, basetypes.ObjectAsOptions{})
3229+ if diags.HasError() {
3230+ return types.StringNull(), diags
3231+ }
3232+
3233+ identity, innerDiags := location.Identity(ctx)
3234+ diags.Append(innerDiags...)
3235+ if diags.HasError() {
3236+ return types.StringNull(), diags
3237+ }
3238+
3239+ formatted := fmt.Sprintf("/{{ .Name.Dashed }}%s", identity.ValueString())
3240+ return types.StringValue(formatted), nil
3241+ }
3242+ {{- end }}
3243+ {{- end }}
3244+ return types.StringNull(), diag.Diagnostics{diag.NewAttributeErrorDiagnostic(
3245+ path.Root("location"),
3246+ "Location Attribute is Not Set",
3247+ "The 'location' attribute must be configured with a non-empty value.",
3248+ )}
3249+ {{- end }}
3250+
3251+ {{- define "location" }}
3252+ identity := []string{""}
3253+ {{- range .Fields }}
3254+ {{- if not .AsIdentity }}{{- continue }}{{- end }}
3255+ {
3256+ value := fmt.Sprintf("{{ .Name.Dashed }}=\"%s\"", o.{{ .Name.CamelCase }}.ValueString())
3257+ identity = append(identity, value)
3258+ }
3259+ {{- end }}
3260+ return types.StringValue(strings.Join(identity, "/")), nil
3261+ {{- end }}
3262+
3263+ {{- range .Specs }}
3264+ func (o *{{ .StructName }}) Identity(ctx context.Context) (types.String, diag.Diagnostics) {
3265+ {{- if .TopLevel }}
3266+ {{- template "topLevelLocation" Map "Specs" $.Specs }}
3267+ {{- else }}
3268+ {{- template "location" . }}
3269+ {{- end }}
3270+ }
3271+ {{- end }}
3272+ `
3273+
3274+ func RenderLocationAsIdentityGetter (names * NameProvider , spec * properties.Normalization ) (string , error ) {
3275+ if spec .TerraformProviderConfig .Ephemeral || spec .TerraformProviderConfig .ResourceType == properties .TerraformResourceCustom {
3276+ return "" , nil
3277+ }
3278+
3279+ if spec .TerraformProviderConfig .SkipResource {
3280+ return "" , nil
3281+ }
3282+
3283+ type context struct {
3284+ StructName string
3285+ Specs []locationStructCtx
3286+ }
3287+
3288+ locations := getLocationStructsContext (names , spec )
3289+
3290+ data := context {
3291+ StructName : names .StructName ,
3292+ Specs : locations ,
3293+ }
3294+
3295+ return processTemplate (locationAsIdentityTmpl , "render-location-as-identity" , data , commonFuncMap )
3296+ }
3297+
31083298const customTemplateForFunction = `
31093299o.{{ .Function }}Custom(ctx, req, resp)
31103300`
0 commit comments