Terraform Provider开发疑问:更新失败后tfstate仍被更新
Terraform Provider Update失败后tfstate仍被更新的问题解决
我在开发Terraform Provider时遇到一个问题:故意让Update函数返回错误,但修改资源的name字段后,tfstate中的值还是被更新了。我的CRUD逻辑很简单,相关代码如下:
创建、Read、Update、Delete函数:
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 }
资源声明:
func demoResource() *schema.Resource { return &schema.Resource{ Description: "descr", Create: resourceCreate, Read: resourceRead, Update: resourceUpdate, Delete: resourceDelete, 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", }, }, } }
使用的Terraform版本是v1.6.5,基于hashicorp/terraform-plugin-sdk/v2开发。
问题原因
核心原因是你没有正确实现Read函数。
Terraform的资源生命周期逻辑中:
- 当你修改配置后,Terraform会先将配置中的新值同步到
schema.ResourceData对象中 - 调用Update函数执行远程资源更新
- 无论Update成功还是失败,Terraform都会紧接着调用Read函数,用来从远程资源拉取真实状态并覆盖本地tfstate
你的Read函数直接返回nil,没有任何从远程获取真实状态并更新d的逻辑,所以Terraform会认为d中当前的(已被修改的)值就是资源的真实状态,进而将其写入tfstate。
解决方案
必须正确实现Read函数,确保它能从远程资源获取最新的真实属性值,然后通过d.Set()将这些值同步到schema.ResourceData中。
例如,假设你的远程资源可以通过ID查询到真实的name值,修改后的Read函数应该类似这样:
func resourceRead(d *schema.ResourceData, m any) error { // 替换为实际调用远程服务API获取真实数据的逻辑 remoteName := "原始的name值" // 将真实值设置回d,覆盖之前的修改 if err := d.Set("name", remoteName); err != nil { return fmt.Errorf("failed to set name: %w", err) } return nil }
这样,当Update函数返回错误后,Read函数会从远程拉取未被修改的真实值,Terraform就会用这个值更新tfstate,从而恢复到更新前的状态。
另外需要注意:
- 在Update函数中,不要在操作失败的情况下修改
d中的任何值,确保d的状态在失败时保持一致 - 始终确保Read函数能准确反映远程资源的真实状态,这是Terraform状态一致性的核心保障
内容的提问来源于stack exchange,提问作者Oleg Butuzov
相关产品推荐
相关产品推荐

