Framework: Map of MapNested possible?

I’d like to write a resource which looks like this:

resource "thing" "x" {
  two_dimensional_map = {
    A = {   // A is an arbitrary map key
      a = { // a is an arbitrary map key
        object_val_1 = ""
        object_val_2 = ""
      }
      b = { // b is an arbitrary map key
        object_val_1 = ""
        object_val_2 = ""
      }
    }
    B = {   // B is an arbitrary map key
      a = { // a is an arbitrary map key
        object_val_1 = ""
        object_val_2 = ""
      }
      b = { // b is an arbitrary map key
        object_val_1 = ""
        object_val_2 = ""
      }
    }
  }
}

I guess this would be a two-dimensional MapNestedObject?

The following resource schema mostly gets me there:

func (o *thing) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
	resp.Schema = schema.Schema{
		Attributes: map[string]schema.Attribute{
			"two_dimensional_map": schema.MapAttribute{
				ElementType: types.MapType{
					ElemType: types.ObjectType{
						AttrTypes: map[string]attr.Type{
							"object_val_1": types.StringType,
							"object_val_2": types.StringType,
						},
					},
				},
			},
		},
	}
}

The problem is that the innermost object is expressed merely as a types.ObjectType{}. There’s no way to describe it as a map[string]schema.Attribute.

The result is the object’s attributes don’t support Validators, can’t be marked as Optional, and won’t have documentation rendered by tfplugindocs via MarkdownDescription.

Is there a way to express a schema which includes a Map of MapNested attributes?

Hey there @hQnVyLRx :wave:,

Is there a way to express a schema which includes a Map of MapNested attributes?

Short answer to your question is no, there’s no way to describe a two-dimensional map where an underlying object can define Computed/Optional/Required fields, validators, descriptions, etc.

The schema you provided is the closest you can get to a multi-dimensional map.


Deeper dive, in case future readers are interested

It’s not actually a terraform-plugin-framework implementation detail, but a Terraform plugin protocol detail that restricts what we can do here. Schema attributes in the protocol can be defined with either type (MapAttribute, StringAttribute) or nested_type (SingleNested, MapNested). A nested type comprises of a NestingMode and attributes of an object (NestedObject.), so the only representation you can have for nested attributes are:

  • List of objects
  • Map of object
  • Set of object
  • Object

That’s to say if we wanted to fully model a multi-dimensional map, we’d need to make changes to both Terraform core, the plugin protocol, and the SDKs to support a new NestingMode.

A partial solution to your problem that is a limitation of terraform-plugin-framework today could be to add support for optional object attributes, which would eventually be defined in the type field. It’s actually already supported in our lower-level SDK terraform-plugin-go, we would just need to expose that in terraform-plugin-framework. This wouldn’t expose the object in the schema, but would allow defining a two-dimensional map’s object attributes as optional in type itself.

A similar request was made in reference to provider functions, which is particularly interesting because there are no attribute/nested attribute concepts with functions, so optional object attributes would potentially help there as well.

1 Like

Thanks very much for the thorough explanation, @austin.valle.

1 Like