Does terraform plugin framework mapType support complex data structure (object) as value?

Hello,

We’re currently encountering a problem with the implementation of TypeSet in the legacy SDK for Terraform, which mirrors the issue described in this forum post: TypeSet is not picking up correct changes - Terraform - HashiCorp Discuss

The crux of the issue is that when we run a terraform plan, we would prefer to see changes to elements in the TypeSet displayed rather than the addition or removal of elements. We recognize that this is more of a display issue, but it’s causing us significant frustration due to the high number of attributes in our data source.

We’re considering transitioning from the legacy Terraform SDK to the Terraform plugin framework, provided that the aforementioned issue can be resolved. Therefore, I have the following inquiries:

  1. Does the setType in the Terraform plugin framework support the modification of existing elements?
  2. Does the mapType in the Terraform plugin framework support complex objects as values? I believe this is the case based on my reading of the Terraform documentation, but I’d like confirmation.
  3. Does the mapType in the Terraform plugin framework maintain an unordered collection of elements?
  4. Assuming that mapType supports complex objects as values in the Terraform plugin framework, would a change in the object be expected in the plan, or would it be the same as the addition and removal in TypeSet?

For instance, if I were to alter the following:

resource "project" "foo" {
        name  = "a project"
        role "owner1" {
            description = "foo"
            size = "xl"
       }
      role "owner2" {
            description = "abc"
            size = "xxx"
      }
}

to this (note the change in the order of roles and the size for owner1):

resource "project" "foo" {
        name  = "a project"
        role "owner1" {
            description = "foo"
            size = "xxl"
       }
      role "owner2" {
            description = "abc"
            size = "xxx"
      }
}

Would the plan look like this?

  ~ resource "project" "foo" {
     
       ~role "owner1" {
            description = "foo" 
            size = "xl" ~ "xxl"
      }
    }

Thank you for your assistance. Your insights will guide our decision-making process.

Hi @instaclustr-wenbodu,

Yes, you are correct that the display of the diff is entirely rendered in the CLI, and can’t be affected by the provider implementation.

  • Does the setType in the Terraform plugin framework support the modification of existing elements?

I think this is the crux of the issue for you, you can always modify elements within a set, but that action removes the old element and creates a new element. A set type (generically, not related to Terraform) is simply an unordered collection of elements. Because the elements have no order, they are only identified by their value, so there is no way to correlate if an element is the result of a change to a previous element, or another value entirely.

For a simple abstract example, say we have a set of two tuples (purposely not using terraform syntax), and they both get updates, from:

{(a, a), (a, b)}

to:

{(a, c), (a, d)}

There is no way to know whether to show the change as

(a, a) => (a, c)
(a, b) => (a, d)

or

(a, b) => (a, c)
(a, a) => (a, d)

Terraform trying to guess does no good, because it is very likely to be wrong in many cases, and incorrect diffs are far more misleading.

  • Does the mapType in the Terraform plugin framework support complex objects as values? I believe this is the case based on my reading of the Terraform documentation, but I’d like confirmation.

A map can contain nested objects

  • Does the mapType in the Terraform plugin framework maintain an unordered collection of elements?

A “map” data structure generally has no order, but the elements are correlated by the key, so order does not matter. The issue with a set is that there is no way to correlate individual elements between two distinct sets, but in a map you have a key to index the value. FWIW maps are basically rendered the same as objects.

Hi @jbardin ,

Thanks for your reply.

I still need help for the last question:

Assuming that mapType supports complex objects as values in the Terraform plugin framework, would a change in the object be expected in the plan, or would it be the same as the addition and removal in TypeSet?

In that case, if I have a map like this:

{a1: {b1:c1, d1:e1}, a2: {b2:c2, d2:e2}}

note the element of the map is a dict itself (similar to object).
if I change it to:
a2: {b2:c2, d2:e3}}
will the change show as:
~ a2: {b2:c2, d2:e2}}=> a2: {b2:c2, d2:e3}}
not:

- a2: {b2:c2, d2:e2}}
+ a2: {b2:c2, d2:e3}}

We are concerned about the behaviour of map when changing the object attribute on how the plan will be displayed.

Apology I do understand this question can be answered by experimenting with terraform framework plugin. However, we want some validation before pulling the trigger.

Thanks!

Yes, it will show an update, because the map key ensures we can compare the before and after values. The formatting should be the same as block objects, and show the changes to individual attributes, something more like

~ "a2" = {
    ~ d2 = "e2" -> "e3"
      # (1 unchanged attribute hidden)
      },
1 Like

Thanks @jbardin , this is incredibly helpful!