必须使用 terraform-plugin-sdk/v2(如 v2.29.0),因 v1 已归档且与 Terraform 0.12+ 不兼容;需用 func() *schema.Provider 初始化,Go ≥ 1.18,并避免 v1/v2 混用。

为什么不用 terraform-plugin-sdk2 就会编译失败
新写的 Provider 如果还用 github.com/hashicorp/terraform-plugin-sdk(v1),Go build 会直接报错:找不到 schema.Schema 或 schema.Resource 类型。v1 SDK 已归档,Terraform 0.12+ 完全不兼容,连 go mod tidy 都会拉不下来依赖。
必须切到 github.com/hashicorp/terraform-plugin-sdk/v2,且初始化函数得用 func() *schema.Provider 返回值类型,不是 v1 的 ProviderFunc。
- 模块路径要写全:
github.com/hashicorp/terraform-plugin-sdk/v2@v2.29.0(别漏/v2) -
go.mod里不能同时存在 v1 和 v2 的 hashicorp 包,否则go build会冲突 - v2 要求 Go 版本 ≥ 1.18,低于这个版本会卡在
golang.org/x/exp/constraints导入错误
resourceCreate 函数里怎么正确返回 error 而不 panic
Terraform Provider 的 Create 方法签名是 func(*schema.ResourceData, interface{}) error,但很多人直接在内部调 log.Fatal 或 panic,结果整个 Terraform 进程崩溃,状态文件锁死、资源残留。
真正该做的是把底层错误包一层再返回:用 fmt.Errorf("create xxx failed: %w", err),让 Terraform 自己处理回滚和提示。如果想加上下文字段(比如 ID、请求体),就用 diag.Diagnostics + diag.FromErr。
立即学习“go语言免费学习笔记(深入)”;
- 不要用
log.Printf替代 error 返回——Terraform 不会感知日志,只会认为操作成功 - HTTP 请求失败时,优先检查
resp.StatusCode,别只看err == nil;4xx/5xx 响应体要读出来,不然err是nil但业务已失败 - 如果创建成功但后续读取(
Read)失败,Terraform 会标记资源为 “tainted”,此时Create里不该强行重试,而是干净返回nil
如何让 schema.TypeList 参数支持空数组而非 null
前端 HCL 写 tags = [],后端 *schema.ResourceData.Get("tags") 默认返回 nil,不是空 []interface{},导致 len() panic 或逻辑误判。
根本原因是 schema.Schema 缺少 DefaultFunc 或 ConflictsWith 干扰了默认行为。正确做法是在字段定义里显式加 MinItems: 0,并确保没配 Required: true 和 Default: nil 冲突。
- 声明时写:
"tags": {Type: schema.TypeList, Optional: true, MinItems: 0, Elem: &schema.Schema{Type: schema.TypeString}} - 取值时统一用
data.Get("tags").([]interface{}),而不是data.Get("tags").(map[string]interface{}) - 如果用了
schema.Schema.DiffSuppressFunc,注意它接收的 old/new 值可能是nil,需先判空再转 slice
provider.ConfigureFunc 里怎么安全传参给 resource
常见写法是把 client 实例塞进 meta interface{},然后每个 resourceXxx 函数里强制类型断言:client := meta.(*MyClient)。一旦断言失败(比如测试时传了 nil),运行时 panic,且堆栈不指向配置代码。
更稳的方式是定义一个带方法的结构体,在 ConfigureFunc 里初始化并返回指针,所有 resource 方法都接收该结构体指针作为 receiver,避免到处断言。
- 定义
type ProviderConfig struct { Client *http.Client; Token string },ConfigureFunc返回&ProviderConfig{...} - resource 方法签名改为
func (p *ProviderConfig) Create(...),调用时用p.Client.Do(...) - 测试时可直接 new 一个
ProviderConfig注入 mock client,不用构造interface{}中间层
类型安全这件事,在 Provider 里不是“可选优化”,是防止半夜收到告警说 “apply panic” 的第一道防线。










