hashicorp / terraform-plugin-framework-timeouts

Convenience functions and types for timeouts, for use with terraform-plugin-framework
Mozilla Public License 2.0
8 stars 2 forks source link

Getting a panic can't use tftypes.Object[] as tftypes.Object["create":tftypes.String] #49

Closed do87 closed 1 year ago

do87 commented 1 year ago

Terraform CLI and Framework Versions

Terraform 1.4.5

github.com/hashicorp/terraform-plugin-framework v1.2.0 github.com/hashicorp/terraform-plugin-framework-timeouts v0.3.1 github.com/hashicorp/terraform-plugin-framework-validators v0.10.0 github.com/hashicorp/terraform-plugin-go v0.15.0 github.com/hashicorp/terraform-plugin-sdk/v2 v2.24.1

Terraform Plugin Framework Code

// Bucket is the schema model
type Bucket struct {
    ...
    Timeouts               timeouts.Value `tfsdk:"timeouts"`
}

// Schema returns the terraform schema structure
func (r *Resource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
    resp.Schema = schema.Schema{
        Attributes: map[string]schema.Attribute{
            "id": schema.StringAttribute{
                Description: "Specifies the resource ID",
                Computed:    true,
            },

            "name": schema.StringAttribute{
                Description: "Bucket name",
                Required:    true,
                PlanModifiers: []planmodifier.String{
                    stringplanmodifier.RequiresReplace(),
                },
            },
...

            "timeouts": timeouts.Attributes(ctx, timeouts.Opts{
                Create: true,
            }),
        },
    }
}

// Create - lifecycle function
func (r Resource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
    var bucket Bucket
    diags := req.Plan.Get(ctx, &bucket)
    resp.Diagnostics.Append(diags...)
    if resp.Diagnostics.HasError() {
        return
    }

    createTimeout, diags := bucket.Timeouts.Create(ctx, 10*time.Minute)
    resp.Diagnostics.Append(diags...)
    if resp.Diagnostics.HasError() {
        return
    }
...
}

Terraform Configuration

resource "stackit_object_storage_bucket" "example" {
    name                      = "..."
}

// timeouts isn't event specified yet..

Expected Behavior

I'm expecting createTimeout to be a duration without panic or errors

Actual Behavior

panic: AttributeName("timeouts"): can't use tftypes.Object[] as tftypes.Object["create":tftypes.String]

goroutine 271 [running]: github.com/hashicorp/terraform-plugin-go/tftypes.NewValue(...) /Users/orende/projects/go/pkg/mod/github.com/hashicorp/terraform-plugin-go@v0.15.0/tftypes/value.go:273 github.com/hashicorp/terraform-plugin-framework/internal/reflect.FromStruct({0x1e8f360, 0xc00042cd50}, {0x1e94618?, 0xc0004913b0?}, {0x1c87e60?, 0xc0000f0420?, 0xffffffffffffffff?}, {{0x25ca4b0, 0x0, 0x0}}) /Users/orende/projects/go/pkg/mod/github.com/hashicorp/terraform-plugin-framework@v1.2.0/internal/reflect/struct.go:207 +0xa55 github.com/hashicorp/terraform-plugin-framework/internal/reflect.FromValue({0x1e8f360, 0xc00042cd50}, {0x1e92ad8?, 0xc0004913b0}, {0x1c87e60, 0xc0000f0420}, {{0x25ca4b0?, 0x257f510?, 0x0?}}) /Users/orende/projects/go/pkg/mod/github.com/hashicorp/terraform-plugin-framework@v1.2.0/internal/reflect/outof.go:54 +0x95b github.com/hashicorp/terraform-plugin-framework/internal/fwschemadata.(Data).Set(0xc000220ce0, {0x1e8f360, 0xc00042cd50}, {0x1c87e60, 0xc0000f0420}) /Users/orende/projects/go/pkg/mod/github.com/hashicorp/terraform-plugin-framework@v1.2.0/internal/fwschemadata/data_set.go:15 +0x9a github.com/hashicorp/terraform-plugin-framework/tfsdk.(State).Set(0xc0005f6910, {0x1e8f360?, 0xc00042cd50?}, {0x1c87e60?, 0xc0000f0420?}) /Users/orende/projects/go/pkg/mod/github.com/hashicorp/terraform-plugin-framework@v1.2.0/tfsdk/state.go:61 +0x165 github.com/SchwarzIT/terraform-provider-stackit/stackit/internal/resources/object-storage/bucket.Resource.Create({0xc0004675f0, {{0x1d20baa, 0x2d}, {0x1d2451d, 0x30}, {0x1d25603, 0x31}, {0xc0001704c0, 0x1e}}}, {0x1e8f360, ...}, ...) /Users/orende/projects/go/src/github.com/SchwarzIT/terraform-provider-stackit/stackit/internal/resources/object-storage/bucket/actions.go:41 +0x3c5 github.com/hashicorp/terraform-plugin-framework/internal/fwserver.(Server).CreateResource(0xc000228000, {0x1e8f360, 0xc00042cd50}, 0xc0002213b0, 0xc000221350) /Users/orende/projects/go/pkg/mod/github.com/hashicorp/terraform-plugin-framework@v1.2.0/internal/fwserver/server_createresource.go:97 +0x598 github.com/hashicorp/terraform-plugin-framework/internal/fwserver.(Server).ApplyResourceChange(0xc000221508?, {0x1e8f360, 0xc00042cd50}, 0xc0005f6500, 0xc000221508) /Users/orende/projects/go/pkg/mod/github.com/hashicorp/terraform-plugin-framework@v1.2.0/internal/fwserver/server_applyresourcechange.go:54 +0x4a8 github.com/hashicorp/terraform-plugin-framework/internal/proto6server.(Server).ApplyResourceChange(0xc000228000, {0x1e8f360?, 0xc00042cc60?}, 0xc0005f6410) /Users/orende/projects/go/pkg/mod/github.com/hashicorp/terraform-plugin-framework@v1.2.0/internal/proto6server/server_applyresourcechange.go:52 +0x41a github.com/hashicorp/terraform-plugin-go/tfprotov6/tf6server.(server).ApplyResourceChange(0xc00049ca00, {0x1e8f360?, 0xc00042c480?}, 0xc000192310) /Users/orende/projects/go/pkg/mod/github.com/hashicorp/terraform-plugin-go@v0.15.0/tfprotov6/tf6server/server.go:816 +0x574 github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/tfplugin6._Provider_ApplyResourceChange_Handler({0x1cb1900?, 0xc00049ca00}, {0x1e8f360, 0xc00042c480}, 0xc000192150, 0x0) /Users/orende/projects/go/pkg/mod/github.com/hashicorp/terraform-plugin-go@v0.15.0/tfprotov6/internal/tfplugin6/tfplugin6_grpc.pb.go:419 +0x170 google.golang.org/grpc.(Server).processUnaryRPC(0xc0001f5a40, {0x1e94f98, 0xc000368000}, 0xc00053a000, 0xc0000f46f0, 0x258e020, 0x0) /Users/orende/projects/go/pkg/mod/google.golang.org/grpc@v1.54.0/server.go:1345 +0xdf3 google.golang.org/grpc.(Server).handleStream(0xc0001f5a40, {0x1e94f98, 0xc000368000}, 0xc00053a000, 0x0) /Users/orende/projects/go/pkg/mod/google.golang.org/grpc@v1.54.0/server.go:1722 +0xa36 google.golang.org/grpc.(Server).serveStreams.func1.2() /Users/orende/projects/go/pkg/mod/google.golang.org/grpc@v1.54.0/server.go:966 +0x98 created by google.golang.org/grpc.(Server).serveStreams.func1 /Users/orende/projects/go/pkg/mod/google.golang.org/grpc@v1.54.0/server.go:964 +0x28a

Steps to Reproduce

  1. terraform apply

Logs

No response

Additional Information

Code of Conduct

bendbennett commented 1 year ago

Hi @do87 👋

Sorry you ran into trouble here.

Can I just confirm that you are encountering this panic when running terraform apply? The reason I ask is that I am unable to reproduce the issue you describe with the configuration that you have supplied. However, if I run terraform import I see the panic that you describe for the reasons outlined in Import timeout attribute panic.

do87 commented 1 year ago

@bendbennett it actually happened during acceptance tests run but I tried running locally using terraform apply and it happened too

Saved the plan to: plan

To perform exactly these actions, run the following command to apply:
    terraform apply "plan"
stackit_object_storage_project.example: Creating...
stackit_object_storage_project.example: Creation complete after 0s [id=db080e37-9e33-4380-abed-37f658bcd544]
stackit_object_storage_bucket.example: Creating...
╷
│ Error: Request cancelled
│ 
│ The plugin6.(*GRPCProvider).ApplyResourceChange request was cancelled.
╵

Stack trace from the terraform-provider-stackit plugin:

panic: AttributeName("timeouts"): can't use tftypes.Object[] as tftypes.Object["create":tftypes.String]

Update:

Thanks for the provided issue @bendbennett After adding

    state.Timeouts = timeouts.Value{
        Object: types.ObjectNull(map[string]attr.Type{
            "create": types.StringType,
        }),
    }

in create & read the problem didn't return I wonder if upgrading to terraform-plugin-framework v1.2.0 and using the 'Default' field will solve this issue

Update 2: To create a general solution I wrote:

func Timeouts(ctx context.Context, opts timeouts.Opts) schema.SingleNestedAttribute {
    timeout := timeouts.Attributes(ctx, opts).(schema.SingleNestedAttribute)
    attr := map[string]attr.Type{}
    if opts.Create {
        attr["create"] = types.StringType
    }
    if opts.Read {
        attr["read"] = types.StringType
    }
    if opts.Update {
        attr["update"] = types.StringType
    }
    if opts.Delete {
        attr["delete"] = types.StringType
    }
    timeout.Computed = true
    timeout.Default = objectdefault.StaticValue(
        types.ObjectNull(attr),
    )
    return timeout
}
bflad commented 1 year ago

For anyone following as an FYI and to cross-reference issues:

github-actions[bot] commented 1 year ago

I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues. If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.