Search code examples
terraformterraform0.12+

Terraform Provider Framework RequireReplace on List Nested


On my resource I have a list with nested objects. On a particular object, if certain fields change, I’d like to replace the resource. For this I’m using a RequireReplace plan modifier for those particular fields. The issue I’m running into is that adding a new object to the list triggers a replace because it sees the fields as having changed. How do I solve this? I’m using the plugin framework sdk(https://developer.hashicorp.com/terraform/plugin/framework).

This was my initial approach

func (r *myResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
    resp.Schema = schema.Schema{
        Attributes: map[string]schema.Attribute{
            "name": schema.StringAttribute{},
            "obj": schema.SingleNestedAttribute{
                Required: true,
                Attributes: map[string]schema.Attribute{
                    "example_list": schema.ListNestedAttribute{
                        NestedObject: schema.NestedAttributeObject{
                            Attributes: map[string]schema.Attribute{
                                "nested_name": schema.StringAttribute{
                                    PlanModifiers: []planmodifier.List{
                                        stringplanmodifier.RequiresReplace(),
                                    },
                                },
                                "another_nested_field": schema.StringAttribute{
                                    PlanModifiers: []planmodifier.List{
                                        stringplanmodifier.RequiresReplace(),
                                    },
                                },
                            },
                        },
                    },
                },
            },
        },
    }
}

Solution

  • I solved this by using a listplanmodifier.RequiresReplaceIf on the list itself instead of on the individual objects in the list. By doing this you have access to the entire list's prior state and current proposed plan. This way you can then compare each object(assumming they have some sort of unique identifier like a name) and decide if the change requires a replace.

    Example:

    func (r *myResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
        resp.Schema = schema.Schema{
            Attributes: map[string]schema.Attribute{
                "name": schema.StringAttribute{
                },
                "obj": schema.SingleNestedAttribute{
                    Required: true,
                    Attributes: map[string]schema.Attribute{
                        "example_list": schema.ListNestedAttribute{
                            NestedObject: schema.NestedAttributeObject{
                                Attributes: map[string]schema.Attribute{
                                    "nested_name": schema.StringAttribute{
                                    },
                                    "another_nested_field": schema.StringAttribute{
                                    },
                                },
                            },
                            PlanModifiers: []planmodifier.List{
                                listplanmodifier.RequiresReplaceIf(func(ctx context.Context, req planmodifier.ListRequest, resp *listplanmodifier.RequiresReplaceIfFuncResponse) {}, "", ""),
                            },
                        },
                    },
                },
            },
        }
    }