- OpenTofu 内部结构
- 模块注册表协议
模块注册表协议
模块注册表协议是 OpenTofu CLI 用于发现有关可安装模块的元数据并定位所选模块的发布包的协议。
该协议的主要实现是公共 OpenTofu 注册表,位于 registry.opentofu.org
。通过编写和部署你自己的协议实现,你可以创建一个单独的注册表来分发你自己的模块,作为在公共 OpenTofu 注册表上发布它们的替代方法。
模块地址
每个 OpenTofu 模块都与一个关联地址相关联。模块地址具有语法 hostname/namespace/name/system
,其中
hostname
是提供此模块的模块注册表的主机名。namespace
是命名空间的名称,在特定主机名上是唯一的,可以包含一个或多个以某种方式相关的模块。在公共 OpenTofu 注册表中,“命名空间”表示打包和分发模块的组织。name
是模块名称,通常命名模块旨在创建的抽象。system
是模块主要针对的远程系统的名称。对于多云抽象,可以有多个模块,其地址仅在“系统”方面有所不同,以反映抽象的特定于提供商的实现,例如registry.opentofu.org/hashicorp/consul/aws
与registry.opentofu.org/hashicorp/consul/azurerm
。系统名称通常与官方提供商地址的类型部分匹配,例如上面示例中的aws
或azurerm
,但这并非必需,因此你可以使用对你的特定注册表的组织有意义的任何系统关键字。
模块地址的 hostname/
部分(包括其斜杠分隔符)是可选的,如果省略,则默认为 registry.opentofu.org/
。
例如
hashicorp/consul/aws
是registry.opentofu.org/hashicorp/consul/aws
的简写,它是在公共注册表上用于在 Amazon Web Services 中部署 Consul 集群的模块。example.com/awesomecorp/consul/happycloud
是一个假设的模块,发布在第三方注册表上。
如果你打算共享你为所有 OpenTofu 用户开发的模块,请考虑将其发布到公共 OpenTofu 注册表 中,以使你的模块更易于发现。你只需要在希望发布地址包含你控制下的不同主机名的模块时才实现此模块注册表协议。
模块版本
每个不同的模块地址都与其关联的一组版本相关联,每个版本都与一个关联的版本号相关联。OpenTofu 假设版本号遵循 语义版本控制 2.0 约定,其中模块的用户界面行为作为“公共 API”。
每个 module
块可以选择模块的不同版本,即使多个块具有相同的源地址。
服务发现
模块注册表协议从 OpenTofu CLI 使用 OpenTofu 的远程服务发现协议 开始,其中模块地址中的主机名充当“用户界面主机名”。
模块注册表协议的服务标识符是 modules.v1
。其关联的字符串值是以下部分中定义的相对 URL 的基本 URL。
例如,仅实现模块注册表协议的主机的服务发现文档可能包含以下内容
{
"modules.v1": "/tofu/modules/v1/"
}
如果给定的 URL 是相对 URL,则 OpenTofu 会将其解释为相对于发现文档本身。特定的模块注册表协议端点被定义为相对于给定基本 URL 的 URL,因此指定的基本 URL 通常应以斜杠结尾,以确保这些相对路径按预期解析。
以下部分描述模块注册表必须实现的各种操作才能与 OpenTofu CLI 的模块安装程序兼容。指示的 URL 都相对于从服务发现中获得的 URL,如上所述。我们使用提供商注册表的假设 URL,假设调用者已经在假设的 registry.example.io
上执行了服务发现以了解基本 URL。
URL 使用以下约定:以冒号 :
为前缀的路径部分是动态选择的值的占位符,而所有其他路径部分都是文字。例如,在 :namespace/:type/versions
中,前两个路径部分是占位符,而第三个部分实际上是字符串“versions”。
列出特定模块的可用版本
这是解析模块源的主要端点,返回给定完全限定模块的可用版本。
方法 | 路径 | 产生 |
---|---|---|
GET | :namespace/:name/:system/versions | application/json |
参数
-
namespace
(string: <required>)
- 模块所属的用户或组织。这是必需的,并在 URL 路径中指定。 -
name
(string: <required>)
- 模块的名称。这是必需的,并在 URL 路径中指定。 -
system
(string: <required>)
- 目标系统的名称。这是必需的,并在 URL 路径中指定。
示例请求
$ curl 'https://registry.opentofu.org/v1/modules/hashicorp/consul/aws/versions'
示例响应
响应中的 modules
数组始终包含请求的模块作为第一个元素。
OpenTofu 不使用此列表的其他元素。但是,第三方实现应始终使用单元素列表以实现向前兼容性。
每个返回的模块都包含一个可用版本的数组,OpenTofu 会将这些版本与配置中给出的任何版本约束进行匹配。
{
"modules": [
{
"versions": [
{"version": "1.0.0"},
{"version": "1.1.0"},
{"version": "2.0.0"}
]
}
]
}
返回 404 Not Found
表示没有可用的模块与请求的命名空间、名称和目标系统匹配。
下载特定模块版本的源代码
此端点为单个目标系统下载指定版本的模块。
方法 | 路径 | 产生 |
---|---|---|
GET | :namespace/:name/:system/:version/download | application/json |
参数
-
namespace
(string: <required>)
- 模块所属的用户。这是必需的,并作为 URL 路径的一部分指定。 -
name
(string: <required>)
- 模块的名称。这是必需的,并在 URL 路径中指定。 -
system
(string: <required>)
- 目标系统的名称。这是必需的,并在 URL 路径中指定。 -
version
(string: <required>)
- 模块的版本。这是必需的,并作为 URL 路径的一部分指定。
示例请求
$ curl -i 'https://registry.opentofu.org/v1/modules/foo/bar/baz/0.0.1/download'
示例响应
成功响应包含可以下载模块版本源代码的位置。
它预期在 JSON 编码的正文中作为键 location
的值找到。
HTTP/2 200
Content-Length: 81
{"location": "git::https://github.com/foo/terraform-baz-bar?ref=v0.0.1"}
在没有响应正文的情况下,OpenTofu 将使用 X-Terraform-Get
头作为模块位置
HTTP/2 204 No Content
Content-Length: 0
X-Terraform-Get: git::https://github.com/foo/terraform-baz-bar?ref=v0.0.1
如果从注册服务器收到正文和 X-Terraform-Get
头,OpenTofu 将优先读取响应正文内容。
模块位置值接受与 OpenTofu 配置中 module
块中的 source
参数相同的值,如 模块源 中所述,但它不能递归引用另一个模块注册地址。模块位置的值可以是相对 URL,以 /
、./
或 ../
开头表示,在这种情况下,它相对于下载端点的完整 URL 解析以生成 HTTP URL 模块源。