一个 Terraform 资源与多个 API 组交互是常见的还是应该 1:1 映射?

Is it common for a Terraform resource to interact with multiple API groups or it should be 1:1 mapping?

上下文:我正在开发一个 TF 提供程序并通过 HashiCorp 的 tutorial

我正在尝试提出一个资源定义,但不知道该选择哪一个。

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

resource "foo" "bar" {
  name = "alex"
  endpoint = "https://api.stripe.com" # unique for every bar
}
Schema: map[string]*schema.Schema{
    "name": {
        Type:         schema.TypeString,
        Required:     true,
    },
    "district_id": {
        Type:        schema.TypeString,
        Required:    true,
    },
},


resource "foo" "bar" {
  name = "alex"
  district_id = "NE53DE" # unique for every bar
}

#1 的优点是它遵循 API,为了执行 CRUD 操作,TF Provider 可以只与一个 API 组交互(1:1 映射到 API组和资源)。

#2 的优点是它更具可读性,但为了调用 API Group #1 我们仍然需要找出端点,因此 TF Provider 必须调用 API Group #2 来检索该端点。

在开发 TF Provider 时,这些选项中哪个更常用?

不幸的是,您在这里讨论的可能是 Terraform 提供商开发中最关键的部分:关于如何最好地将 Terraform 的 provider-agnostic 生命周期模型转换为特定真实 API.

密切关注远程 API 设计的一大优势在于,将来对 API 设计的扩展不太可能使您的提供程序设计无效。如果提供者是由不直接与设计 API 的团队合作的人设计的,那么这一点尤其重要,因为提供者开发人员通常无法预测 API 的可能性API 设计团队在考虑新 use-cases.

时通常遵循哪些设计原则?

但是,正如您所指出的,real-world API 通常不是为了方便直接使用而设计的,而是旨在公开原始构建块,假设其他人会构建合适的 use-case 具体 抽象在上面。 Terraform 提供程序开发人员最终会在这里陷入困境,因为他们通常还试图提供通用解决方案(而不是 专注于特定 use-case),但也想设计在 Terraform 语言中使用起来相对方便的东西。

我无法提供具体的建议,因为没有足够的上下文来了解您正在设计的 API 或您为提供商设计的目标,但我至少可以提供一个潜在的妥协机会:数据来源.

除了表示 Terraform 直接管理远程系统中某些对象的托管资源类型外,Terraform 还支持 data 资源类型(简称“数据源”),出现在 Terraform 语言中为 data blocks。这些本质上是特定模块的外部依赖模型,我指的是模块期望其他人已经创建的对象,并且模块需要声明它自己管理的对象(它的托管 资源)。

如果从“地区 ID”到“端点”的映射在某种意义上可以被视为外部对象,那么数据源可以帮助填补此处的空白。不用太担心它是否真的 远程系统中的一个 first-class 对象;这里重要的是 Terraform 模块作者将其视为一个模块是否合理,这样他们就可以将您的“找出端点”需求表示为数据资源:

data "foo_district_endpoint" "example" {
  district_id = "NE53DE"
}

resource "foo" "bar" {
  name     = "alex"
  endpoint = data.foo_district_endpoint.example.endpoint
}

这就明确了您描述的这种需要,即发出 API 请求以根据地区 ID 确定端点,而不是将其隐藏为 foo 的实现细节。使其显式化的一个重要优点是,查找它的模块不一定总是使用它的模块;对于使用 Module Composition 模式的配置,这两个需求可能会被分成两个较小的模块,因此 endpoint 值将使用输出值和输入变量从一个流向另一个。

你描述的两种可能性和我添加的第三种可能性都是针对不同情况的有效且合理的设计。虽然我不能告诉你哪一个最适合你的具体情况,但我希望这篇评论至少能给你一些需要考虑的事情,以帮助你自己做出决定。