Terraform-plugin-framework map of different value types

Hi,

I’m developing a terraform provider using the GitHub - hashicorp/terraform-plugin-framework: A next-generation framework for building Terraform providers.. I need a tfsdk.Attribute that’s a map with multiple value types, so I can’t use types.MapType as ElemType shoulbe be defined and all elements must have the same type.

I’ve been searching for this, but I can’t find how to make this work.

Any help?

Thanks.

Hi @jorgemarey :wave:

In terms of attributes, schema.ObjectAttribute is available for data source, provider and resource.

If this is not what you had in mind could your provide a code snippet illustrating the schema that you are trying to implement or where in your code you have the requirement you described?

Hi @bendbennett, thanks for your answer. I’m trying to create a resource that has a field that is a map of elements with different value types (in golang types a map[string]interface)

The terraform code is something on the lines:

resource "custom_resource" "test" {
  name            = "my-name"
  description  = "test desription"
  vars = {
    foo = "bar"
    test = true
    meta = {
        a = "b"
    }
  }
}

Doing the implementation:

// customResourceModel maps the resource schema data.
type customResourceModel struct {
	Name           types.String           `tfsdk:"name"`
	Description       types.String           `tfsdk:"description"
	Vars           map[string]interface{} `tfsdk:"vars"`  # What to set here?
}

// GetSchema defines the schema for the resource.
func (r *myCustomResource) GetSchema(_ context.Context) (tfsdk.Schema, diag.Diagnostics) {
	return tfsdk.Schema{
		Description: "Manages a custom resource",
		Attributes: map[string]tfsdk.Attribute{
			"name": {
				Description: "Name for the custom resource.",
				Type:        types.StringType,
				Optional:    true,
			},
			"description": {
				Description: "Description",
				Type:        types.StringType,
				Required:    true,
			},
			"vars": {
				Description: "Variables to provide on the resource",
				Type: types.MapType{ 
					ElemType: types.StringType,  # Need values of different types.
				},
				Optional: true,
			},
		},
	}, nil
}

What type should I use in this case? Do I need to create a custom attribute?

Thanks

Hi @jorgemarey :wave:

Thank you for providing some additional context and some code snippets. Can I just check which version of terraform-plugin-framework you are using to develop your terraform provider? I believe that the latest version is v1.3.3 and would recommend updating to this version if possible.

If you are using protocol version 6 then you will have access to nested attributes in which case one option would be to use a single nested attribute for vars.

			"vars": schema.SingleNestedAttribute{
				Optional: true,
				Attributes: map[string]schema.Attribute{
					"foo": schema.StringAttribute{
						/* ... */
					},
					"test": schema.BoolAttribute{
						/* ... */
					},
				},
			},
type customResourceModel struct {
	Name           types.String           `tfsdk:"name"`
	Description    types.String           `tfsdk:"description"`
	Vars           types.Object           `tfsdk:"vars"` 
}

If you are restricted to using protocol version 5, then you could use an object attribute for vars.

			"vars": schema.ObjectAttribute{
				/ * ... */
				AttributeTypes: map[string]attr.Type{
					"foo":    types.StringType,
					"test":   types.BoolType,
					/* ... */
				},
			},
type customResourceModel struct {
	Name           types.String           `tfsdk:"name"`
	Description    types.String           `tfsdk:"description"`
	Vars           types.Object           `tfsdk:"vars"` 
}

Hi @bendbennett, thanks for your answer.
What should I do if I don’t know the keys? I need something on that is: any string key to any value.

A Go map[string]interface{} would be equivalent to a Terraform map(any) (in a Terraform configuration input variable type).

Problem is, I think the Terraform Go libraries for authoring plugins might not have support for defining a map(any) resource parameter - they want you to be more specific.

Hi @jorgemarey,

Your only option in this case might be to use a dynamic pseudo type from terraform-plugin-go along with muxing. There is currently an open issue on terraform-plugin-framework for Support Dynamic Type/Attributes that discusses this. But until such time that this is added to the framework it may be necessary to use terraform-plugin-go along with muxing.

Hi @bendbennett,

I see. Thanks a lot for letting me know the options. I’ll see what I do.