Implementing Configurable Framework configurable List Attribute

Hello,

I’m trying to write a provider with the framework. I’m learning by going over the hashicups tutorial and reading the documentation.

I’m having a problem implementing a resource with a list attribute . I have no doubt that stems from ignorance on my part, but my best efforts and reading the documentation, googling and looking for examples have just left me depleted.

This is the model:

type GroupMembershipResourceModel struct {
	Action                types.Int64          `tfsdk:"action"` // 0 to add account to group, 1 to remove account from grouop
	Environment           types.String         `tfsdk:"environment"`
	Resource              types.String         `tfsdk:"resource"` //Domain
	ResourceName          types.String         `tfsdk:"resourcename"`
	GroupNames            types.List           `tfsdk:"groupnames"`
	EmployeeID            types.String         `tfsdk:"employeeid"` // owner of the account
	BusinessJustification types.String         `tfsdk:"businessjustification"`
	Account               types.String         `tfsdk:"account"` // account
	RequesterEmployeeID   types.String         `tfsdk:"requesteremployeeid"`
	ByPassApproval        types.Bool           `tfsdk:"bypassapproval"`
	ByPassNotification    types.Bool           `tfsdk:"bypassnotification"`
	ExpirationDate        types.String         `tfsdk:"expirationdate"` // optional if the intention is to allow Permanent access and the requested group allows Permanent
}

This is my schema - groupnames being the troublesome part.

func (r *groupMembershipResource) Schema(_ context.Context, sr resource.SchemaRequest, resp *resource.SchemaResponse) {
        resp.Schema = schema.Schema{
                Attributes: map[string]schema.Attribute{
                        "account": schema.StringAttribute{
                                Description: "The name of the account",
                                Required:    true,
                        },
                        **"groupnames": schema.ListAttribute{**
**                                Description: "List of group names to add or remove from account."**,
                                ElementType: types.StringType,
                                Required:    true,
                        },
                        "action": schema.Int64Attribute{
                                Description: "0 to add groups to account; 1 to remove accounts from groups",
                                Required:    true,
                        },
                        "resource": schema.StringAttribute{
                                Description: "Domain",
                                Required:    true,
                        },
                        "resourcename": schema.StringAttribute{
                                Required: true,
                        },
                        "employeeid": schema.StringAttribute{
                                Computed: true,
                        },
                        "businessjustification": schema.StringAttribute{
                                Required: true,
                        },
                        "environment": schema.StringAttribute{
                                Computed: true,
                                PlanModifiers: []planmodifier.String{
                                        stringplanmodifier.UseStateForUnknown(),
                                },
                        },
                        "requesteremployeeid": schema.StringAttribute{
                                Required: true,
                        },
                        "bypassapproval": schema.BoolAttribute{
                                Required: true,
                        },
                        "bypassnotification": schema.BoolAttribute{
                                Required: true,
                        },
                        "expirationdate": schema.StringAttribute{
                                Optional: true,
                        },
                },
        }
}

relevant tf configuration:

resource "secureiam_groupmembership" "t20" {
  account             = "redacted_string"
  action              = 0
  businessjustification = "testing terraform workflow"
  resource            = "MS"
  resourcename        = "MS"
  groupnames          = ["redacted_group1", "redacted_group2"]
  requesteremployeeid = "000497972"
  bypassapproval      = true
  bypassnotification  = true
}

Scenario would be - the existing groupnames for secureiam_groupmembership.t20 is [“redacted_group1”] and is in the state file as such.

The intent is that after apply, the groupnames would be [“readacted_group1”, redacted_group2"]

I.E - groupnames should be configurable.

(This won’t be my final implementation - I don’t think this is semantically correct with the ‘action’ attribute I send to our API, but I’ll concentrate on that later).

Here is my plan output - indicated it will do what I want it to do.

  # secureiam_groupmembership.t20 will be updated in-place
  ~ resource "secureiam_groupmembership" "t20" {
      ~ employeeid            = "001245448" -> (known after apply)
      ~ groupnames            = [
            "redacted_group1",
          + "redacgted_group2",
        ]
        # (9 unchanged attributes hidden)
    }

And here is my error:

│ Error: Provider produced inconsistent result after apply
│ 
│ When applying changes to secureiam_groupmembership.t20, provider "provider[\"terraform-registry.blabla/blabla/secureiam\"]" produced an unexpected new
│ value: .groupnames: element 1 has vanished.
│ 
│ This is a bug in the provider, which should be reported in the provider's own issue tracker.
╵

From the output I’ve generated - the resource’s READ function returns and doesn’t even get into the CREATE function.

The READ function gets the current current groupnames from the api and updates the state with it.

So I need to know how to have a configurable List Attribute modify it. Any help appreciated! Thanks for reading!

If you’ve already got state for this object, Create() won’t run. The object has been created. You should be looking at Update().

Thank you, and massive face palm. Oh my goodness!