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/
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)
}