@@ -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,132 @@ 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 (resourceTyp properties.ResourceType , names * NameProvider , spec * properties.Normalization ) (string , error ) {
3017+ switch resourceTyp {
3018+ case properties .ResourceUuid , properties .ResourceUuidPlural , properties .ResourceEntryPlural :
3019+ return "" , nil
3020+ case properties .ResourceConfig , properties .ResourceCustom :
3021+ return "" , nil
3022+ case properties .ResourceEntry :
3023+ }
3024+
3025+ if spec .TerraformProviderConfig .Ephemeral {
3026+ return "" , nil
3027+ }
3028+
3029+ if spec .TerraformProviderConfig .SkipResource {
3030+ return "" , nil
3031+ }
3032+
3033+ type fieldCtx struct {
3034+ Name string
3035+ Type string
3036+ Tag string
3037+ }
3038+
3039+ type context struct {
3040+ StructName string
3041+ Fields []fieldCtx
3042+ }
3043+
3044+ var fields []fieldCtx
3045+ if spec .HasEntryName () {
3046+ fields = []fieldCtx {
3047+ {Name : "Name" , Type : "types.String" , Tag : "name" },
3048+ {Name : "Location" , Type : "types.String" , Tag : "location" },
3049+ }
3050+ } else {
3051+ fields = []fieldCtx {
3052+ {Name : "Config" , Type : "types.String" , Tag : "config" },
3053+ {Name : "Location" , Type : "types.String" , Tag : "location" },
3054+ }
3055+ }
3056+
3057+ data := context {
3058+ StructName : names .IdentityModelStructName (),
3059+ Fields : fields ,
3060+ }
3061+
3062+ return processTemplate (identityModelTmpl , "render-identity-model" , data , commonFuncMap )
3063+ }
3064+
3065+ const identitySchemaTmpl = `
3066+ func (o {{ .StructName }}) IdentitySchema(_ context.Context, _ resource.IdentitySchemaRequest, resp *resource.IdentitySchemaResponse) {
3067+ resp.IdentitySchema = identityschema.Schema{
3068+ Attributes: map[string]identityschema.Attribute{
3069+ {{- range .Fields }}
3070+ "{{ .Name }}": {{ .Type }}{
3071+ {{- if .RequiredForImport }}
3072+ RequiredForImport: true,
3073+ {{- else if .OptionalForImport }}
3074+ OptionalForImport: true,
3075+ {{- end }}
3076+ },
3077+ {{- end }}
3078+ },
3079+ }
3080+ }
3081+ `
3082+
3083+ func RenderIdentitySchema (resourceTyp properties.ResourceType , names * NameProvider , spec * properties.Normalization ) (string , error ) {
3084+ switch resourceTyp {
3085+ case properties .ResourceUuid , properties .ResourceUuidPlural , properties .ResourceEntryPlural :
3086+ return "" , nil
3087+ case properties .ResourceConfig , properties .ResourceCustom :
3088+ return "" , nil
3089+ case properties .ResourceEntry :
3090+ }
3091+
3092+ if spec .TerraformProviderConfig .Ephemeral {
3093+ return "" , nil
3094+ }
3095+
3096+ if spec .TerraformProviderConfig .SkipResource {
3097+ return "" , nil
3098+ }
3099+
3100+ type fieldCtx struct {
3101+ Name string
3102+ Type string
3103+ RequiredForImport bool
3104+ OptionalForImport bool
3105+ }
3106+
3107+ type context struct {
3108+ StructName string
3109+ Fields []fieldCtx
3110+ }
3111+
3112+ var fields []fieldCtx
3113+ if spec .HasEntryName () {
3114+ fields = []fieldCtx {
3115+ {Name : "name" , Type : "identityschema.StringAttribute" , RequiredForImport : true },
3116+ {Name : "location" , Type : "identityschema.StringAttribute" , RequiredForImport : true },
3117+ }
3118+ } else {
3119+ fields = []fieldCtx {
3120+ {Name : "config" , Type : "identityschema.StringAttribute" , RequiredForImport : true },
3121+ {Name : "location" , Type : "identityschema.StringAttribute" , RequiredForImport : true },
3122+ }
3123+ }
3124+
3125+ data := context {
3126+ StructName : fmt .Sprintf ("%sResource" , names .StructName ),
3127+ Fields : fields ,
3128+ }
3129+
3130+ return processTemplate (identitySchemaTmpl , "render-identity-model" , data , commonFuncMap )
3131+
3132+ }
3133+
30013134const attributeTypesTmpl = `
30023135{{- range .Structs }}
30033136func (o *{{ .StructName }}{{ .ModelOrObject }}) AttributeTypes() map[string]attr.Type {
@@ -3101,6 +3234,91 @@ func RenderLocationAttributeTypes(names *NameProvider, spec *properties.Normaliz
31013234 return processTemplate (locationAttributeTypesTmpl , "render-location-structs" , data , commonFuncMap )
31023235}
31033236
3237+ const locationAsIdentityTmpl = `
3238+ {{- define "topLevelLocation" }}
3239+ {{- range $.Specs }}
3240+ {{- if not .TopLevel }}{{- continue }}{{- end }}
3241+ {{- range .Fields }}
3242+ if !o.{{ .Name.CamelCase }}.IsNull() {
3243+ var location {{ .TerraformType }}
3244+ diags := o.{{ .Name.CamelCase }}.As(ctx, &location, basetypes.ObjectAsOptions{})
3245+ if diags.HasError() {
3246+ return types.StringNull(), diags
3247+ }
3248+
3249+ identity, innerDiags := location.Identity(ctx)
3250+ diags.Append(innerDiags...)
3251+ if diags.HasError() {
3252+ return types.StringNull(), diags
3253+ }
3254+
3255+ formatted := fmt.Sprintf("/{{ .Name.Dashed }}%s", identity.ValueString())
3256+ return types.StringValue(formatted), nil
3257+ }
3258+ {{- end }}
3259+ {{- end }}
3260+ return types.StringNull(), diag.Diagnostics{diag.NewAttributeErrorDiagnostic(
3261+ path.Root("location"),
3262+ "Location Attribute is Not Set",
3263+ "The 'location' attribute must be configured with a non-empty value.",
3264+ )}
3265+ {{- end }}
3266+
3267+ {{- define "location" }}
3268+ identity := []string{""}
3269+ {{- range .Fields }}
3270+ {{- if not .AsIdentity }}{{- continue }}{{- end }}
3271+ {
3272+ value := fmt.Sprintf("{{ .Name.Dashed }}[\"%s\"]", o.{{ .Name.CamelCase }}.ValueString())
3273+ identity = append(identity, value)
3274+ }
3275+ {{- end }}
3276+ return types.StringValue(strings.Join(identity, "/")), nil
3277+ {{- end }}
3278+
3279+ {{- range .Specs }}
3280+ func (o *{{ .StructName }}) Identity(ctx context.Context) (types.String, diag.Diagnostics) {
3281+ {{- if .TopLevel }}
3282+ {{- template "topLevelLocation" Map "Specs" $.Specs }}
3283+ {{- else }}
3284+ {{- template "location" . }}
3285+ {{- end }}
3286+ }
3287+ {{- end }}
3288+ `
3289+
3290+ func RenderLocationAsIdentityGetter (resourceTyp properties.ResourceType , names * NameProvider , spec * properties.Normalization ) (string , error ) {
3291+ switch resourceTyp {
3292+ case properties .ResourceUuid , properties .ResourceUuidPlural , properties .ResourceEntryPlural :
3293+ return "" , nil
3294+ case properties .ResourceConfig , properties .ResourceCustom :
3295+ return "" , nil
3296+ case properties .ResourceEntry :
3297+ }
3298+
3299+ if spec .TerraformProviderConfig .Ephemeral {
3300+ return "" , nil
3301+ }
3302+
3303+ if spec .TerraformProviderConfig .SkipResource {
3304+ return "" , nil
3305+ }
3306+
3307+ type context struct {
3308+ StructName string
3309+ Specs []locationStructCtx
3310+ }
3311+
3312+ locations := getLocationStructsContext (names , spec )
3313+
3314+ data := context {
3315+ StructName : names .StructName ,
3316+ Specs : locations ,
3317+ }
3318+
3319+ return processTemplate (locationAsIdentityTmpl , "render-location-as-identity" , data , commonFuncMap )
3320+ }
3321+
31043322const customTemplateForFunction = `
31053323o.{{ .Function }}Custom(ctx, req, resp)
31063324`
0 commit comments