Nested types.Object and redundant AttrTypes

Hello folks,

I’m new to plugin development for Terraform, and also new to Go, so bear with me…

I’m using the new Framework API for my provisioning plugin, and trying to wrap my head around best practices and how to properly implement the Schema.

The issue I have right now is with working with types.Object. It seems to be the correct approach when dealing with elements having a fixed set of properties to describe them.

I decided to implement my Attribute like this :

				"cifs": {
					Optional: true,
					Type: types.ObjectType{
						AttrTypes: map[string]attr.Type{
							"ad_domain": types.ObjectType{
								AttrTypes: map[string]attr.Type{
									"fqdn":                types.StringType,
									"organizational_unit": types.StringType,
								},
							},
							"enabled": types.BoolType,
							"name":    types.StringType,
						},
					},
				},

It translates to the JSON structure I get from REST API.

What I don’t understand, is how to properly set CIFS attributes in my data source.

The following method works, but seems to be extremely redundant, as I have to repeat the whole AttrTypes for each nested level, it does look really weird :

cifs := types.Object{
			Attrs: map[string]attr.Value{
				"ad_domain": types.Object{
					Attrs: map[string]attr.Value{
						"fqdn":                types.String{Value: SVM.CIFS.ADDomain.FQDN},
						"organizational_unit": types.String{Value: SVM.CIFS.ADDomain.OrganizationalUnit},
					},
					AttrTypes: map[string]attr.Type{
						"fqdn":                types.StringType,
						"organizational_unit": types.StringType,
					},
				},
				"enabled": types.Bool{Value: SVM.CIFS.Enabled},
				"name":    types.String{Value: SVM.CIFS.Name},
			},
			AttrTypes: map[string]attr.Type{
				"ad_domain": types.ObjectType{
					AttrTypes: map[string]attr.Type{
						"fqdn":                types.StringType,
						"organizational_unit": types.StringType,
					},
				},
				"enabled": types.BoolType,
				"name":    types.StringType,
			},
		}
		data.CIFS = cifs

As you can see, I have to specify AttrTypes both for the root Attr (with all the deep child attributes), and again into the child node "ad_domain".

What is the best practice in situations like this ?

I can change types.Object in the model struct by *CIFSDataSourceModel, but I’m wondering if that’s the right approach, using the following struct :

type SVMDataSourceModel struct {
[...]
	CIFS                *CIFSDataSourceModel       `tfsdk:"cifs"`
[...]
}

type CIFSDataSourceModel struct {
	ADDomain ADDomainDataSourceModel `tfsdk:"ad_domain"`
	Enabled  types.Bool              `tfsdk:"enabled"`
	Name     types.String            `tfsdk:"name"`
}

type ADDomainDataSourceModel struct {
	FQDN               types.String `tfsdk:"fqdn"`
	OrganizationalUnit types.String `tfsdk:"organizational_unit"`
}

I hope some of this makes any sense !

I have to repeat the whole AttrTypes for each nested level, it does look really weird

I’ve been doing (and wondering) the same thing. Though I’ve tightened it up with a helper function like this:

	cifs := types.Object{
		Attrs: map[string]attr.Value{
			"ad_domain": types.Object{
				AttrTypes: adDomainAttrs(),
				Attrs: map[string]attr.Value{
					"fqdn":                types.String{Value: SVM.CIFS.ADDomain.FQDN},
					"organizational_unit": types.String{Value: SVM.CIFS.ADDomain.OrganizationalUnit},
				},
			},
			"enabled": types.Bool{Value: SVM.CIFS.Enabled},
			"name":    types.String{Value: SVM.CIFS.Name},
		},
		AttrTypes: map[string]attr.Type{
			"ad_domain": types.ObjectType{AttrTypes: adDomainAttrs()},
			"enabled": types.BoolType,
			"name":    types.StringType,
		},
	}
	data.CIFS = cifs
func adDomainAttrs() map[string]attr.Type {
	return map[string]attr.Type{
		"fqdn":                types.StringType,
		"organizational_unit": types.StringType,
	}
}