Search code examples
goterraformprovider

Terraform Provider Development: tfstate updated even if update fails


So I was curious how to develop terraform providers and runned into an issue i cannot explain.

My CRUD pretty simple, I Create resource and Updating its meta data during lifespan, and Deleting it on destroy command.

func resourceCreate(d *schema.ResourceData, m any) error {
    id, err := uuid.GenerateUUID()
    if err != nil {
        return err
    }

    d.SetId(id)
    return nil
}

func resourceRead(d *schema.ResourceData, m any) error {
    return nil
}

func resourceUpdate(d *schema.ResourceData, m any) error {
    return errors.New("failed")
}

func resourceDelete(d *schema.ResourceData, m any) error {
    d.SetId("")
    return nil
}

As you can see Update function returns error, this is my question. I am intentionally failing proccess, but tfstate still updated (i am changing one variable in my resource declaration to see this change).

here is a full resource declaration

func demoResource() *schema.Resource {
    return &schema.Resource{
        Description: "descr",
        Create: resourceCreate,
        Read:   resourceRead,
        Update: resourceUpdate,
        Delete: resourceDelete,

        // CreateContext: demoResCreate,
        // ReadContext:   demoResRead,
        // UpdateContext: demoResUpdate,
        // DeleteContext: demoResDelete,
        Timeouts: &schema.ResourceTimeout{
            Create: schema.DefaultTimeout(10 * time.Minute),
            Update: schema.DefaultTimeout(10 * time.Minute),
            Delete: schema.DefaultTimeout(10 * time.Minute),
        },

        Schema: map[string]*schema.Schema{
            "name": {
                Type:        schema.TypeString,
                Required:    true,
                Description: "name",
            },
        },
    }
}

What am I missing? I don't think tfstate should be updated after I faield update operation, but it does. I tried both CRUD and CRUDContext methods, in both cases it acts same.

P/S/ terraform version Terraform v1.6.5, For provider development used hashicorp/terraform-plugin-sdk/v2/


Solution

  • looks like this is expected behaviour, according to that blog post:

    "If the Update callback returns with or without an error, the full state is saved."

    Also, I found some real working examples, and both of them return Read callback in the Update.

    Cloudflare provider, for example, and GitHub provider

    They both do it like:

    func resourceCloudflareAccountMemberUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
    
        return resourceCloudflareAccountMemberRead(ctx, d, meta)
    }