mirror of
https://github.com/opentffoundation/opentf.git
synced 2025-12-19 17:59:05 -05:00
Signed-off-by: Nathan Baulch <nathan.baulch@gmail.com> Signed-off-by: Christian Mesh <christianmesh1@gmail.com> Co-authored-by: Christian Mesh <christianmesh1@gmail.com>
221 lines
8.7 KiB
Plaintext
221 lines
8.7 KiB
Plaintext
---
|
|
description: |-
|
|
The module registry protocol is implemented by a host intending to be the
|
|
host of one or more OpenTofu modules, specifying which modules are available
|
|
and where to find their distribution packages.
|
|
---
|
|
|
|
# Module Registry Protocol
|
|
|
|
The module registry protocol is what OpenTofu CLI uses to discover metadata
|
|
about modules available for installation and to locate the distribution
|
|
package for a selected module.
|
|
|
|
The primary implementation of this protocol is the public
|
|
[OpenTofu Registry](https://registry.opentofu.org/) at `registry.opentofu.org`.
|
|
By writing and deploying your own implementation of this protocol, you can
|
|
create a separate registry to distribute your own modules, as an alternative to
|
|
publishing them on the public OpenTofu Registry.
|
|
|
|
## Module Addresses
|
|
|
|
Each OpenTofu module has an associated address. A module address has the
|
|
syntax `hostname/namespace/name/system`, where:
|
|
|
|
- `hostname` is the hostname of the module registry that serves this module.
|
|
- `namespace` is the name of a namespace, unique on a particular hostname, that
|
|
can contain one or more modules that are somehow related. On the public
|
|
OpenTofu Registry the "namespace" represents the organization that is
|
|
packaging and distributing the module.
|
|
- `name` is the module name, which generally names the abstraction that the
|
|
module is intending to create.
|
|
- `system` is the name of a remote system that the module is primarily written
|
|
to target. For multi-cloud abstractions, there can be multiple modules with
|
|
addresses that differ only in "system" to reflect provider-specific
|
|
implementations of the abstraction, like
|
|
`registry.opentofu.org/hashicorp/consul/aws` vs.
|
|
`registry.opentofu.org/hashicorp/consul/azurerm`. The system name commonly
|
|
matches the type portion of the address of an official provider, like `aws`
|
|
or `azurerm` in the above examples, but that is not required and so you can
|
|
use whichever system keywords make sense for the organization of your
|
|
particular registry.
|
|
|
|
The `hostname/` portion of a module address (including its slash delimiter)
|
|
is optional, and if omitted defaults to `registry.opentofu.org/`.
|
|
|
|
For example:
|
|
|
|
- `hashicorp/consul/aws` is a shorthand for
|
|
`registry.opentofu.org/hashicorp/consul/aws`, which is a module on the
|
|
public registry for deploying Consul clusters in Amazon Web Services.
|
|
- `example.com/awesomecorp/consul/happycloud` is a hypothetical module published
|
|
on a third-party registry.
|
|
|
|
If you intend to share a module you've developed for use by all OpenTofu
|
|
users, please consider publishing it into the public
|
|
[OpenTofu Registry](https://registry.opentofu.org/) to make your module more
|
|
discoverable. You only need to implement this module registry protocol if you
|
|
wish to publish modules whose addresses include a different hostname that is
|
|
under your control.
|
|
|
|
## Module Versions
|
|
|
|
Each distinct module address has associated with it a set of versions, each
|
|
of which has an associated version number. OpenTofu assumes version numbers
|
|
follow the [Semantic Versioning 2.0](https://semver.org/) conventions, with
|
|
the user-facing behavior of the module serving as the "public API".
|
|
|
|
Each `module` block may select a distinct version of a module, even if multiple
|
|
blocks have the same source address.
|
|
|
|
## Service Discovery
|
|
|
|
The module registry protocol begins with OpenTofu CLI using
|
|
[OpenTofu's remote service discovery protocol](remote-service-discovery.mdx),
|
|
with the hostname in the module address acting as the "User-facing Hostname".
|
|
|
|
The service identifier for the module registry protocol is `modules.v1`.
|
|
Its associated string value is the base URL for the relative URLs defined in
|
|
the sections that follow.
|
|
|
|
For example, the service discovery document for a host that _only_ implements
|
|
the module registry protocol might contain the following:
|
|
|
|
```json
|
|
{
|
|
"modules.v1": "/tofu/modules/v1/"
|
|
}
|
|
```
|
|
|
|
If the given URL is a relative URL then OpenTofu will interpret it as relative
|
|
to the discovery document itself. The specific module registry protocol
|
|
endpoints are defined as URLs relative to the given base URL, and so the
|
|
specified base URL should generally end with a slash to ensure that those
|
|
relative paths will be resolved as expected.
|
|
|
|
The following sections describe the various operations that a module
|
|
registry must implement to be compatible with OpenTofu CLI's module
|
|
installer. The indicated URLs are all relative to the URL resulting from
|
|
service discovery, as described above. We use a hypothetical URL for a provider
|
|
registry, assuming that the caller already performed service discovery on a hypothetical
|
|
`registry.example.io` to learn the base URL.
|
|
|
|
The URLs are shown with the convention that a path portion with a colon `:`
|
|
prefix is a placeholder for a dynamically-selected value, while all other
|
|
path portions are literal. For example, in `:namespace/:type/versions`,
|
|
the first two path portions are placeholders while the third is literally
|
|
the string "versions".
|
|
|
|
## List Available Versions for a Specific Module
|
|
|
|
This is the primary endpoint for resolving module sources, returning the
|
|
available versions for a given fully-qualified module.
|
|
|
|
| Method | Path | Produces |
|
|
| ------ | ----------------------------------- | ------------------ |
|
|
| `GET` | `:namespace/:name/:system/versions` | `application/json` |
|
|
|
|
### Parameters
|
|
|
|
- `namespace` `(string: <required>)` - The user or organization the module is
|
|
owned by. This is required and is specified as part of the URL path.
|
|
|
|
- `name` `(string: <required>)` - The name of the module.
|
|
This is required and is specified as part of the URL path.
|
|
|
|
- `system` `(string: <required>)` - The name of the target system.
|
|
This is required and is specified as part of the URL path.
|
|
|
|
### Sample Request
|
|
|
|
```text
|
|
$ curl 'https://registry.opentofu.org/v1/modules/hashicorp/consul/aws/versions'
|
|
```
|
|
|
|
### Sample Response
|
|
|
|
The `modules` array in the response always includes the requested module as the
|
|
first element.
|
|
|
|
OpenTofu does not use the other elements of this list. However, third-party implementations should always use a single-element list for forward compatibility.
|
|
|
|
Each returned module has an array of available versions, which OpenTofu
|
|
matches against any version constraints given in configuration.
|
|
|
|
```json
|
|
{
|
|
"modules": [
|
|
{
|
|
"versions": [
|
|
{"version": "1.0.0"},
|
|
{"version": "1.1.0"},
|
|
{"version": "2.0.0"}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
Return `404 Not Found` to indicate that no module is available with the
|
|
requested namespace, name, and target system.
|
|
|
|
## Download Source Code for a Specific Module Version
|
|
|
|
This endpoint downloads the specified version of a module for a single target system.
|
|
|
|
| Method | Path | Produces |
|
|
| ------ | -------------------------------------------- | ------------------ |
|
|
| `GET` | `:namespace/:name/:system/:version/download` | `application/json` |
|
|
|
|
### Parameters
|
|
|
|
- `namespace` `(string: <required>)` - The user the module is owned by.
|
|
This is required and is specified as part of the URL path.
|
|
|
|
- `name` `(string: <required>)` - The name of the module.
|
|
This is required and is specified as part of the URL path.
|
|
|
|
- `system` `(string: <required>)` - The name of the target system.
|
|
This is required and is specified as part of the URL path.
|
|
|
|
- `version` `(string: <required>)` - The version of the module.
|
|
This is required and is specified as part of the URL path.
|
|
|
|
### Sample Request
|
|
|
|
```text
|
|
$ curl -i 'https://registry.opentofu.org/v1/modules/foo/bar/baz/0.0.1/download'
|
|
```
|
|
|
|
### Sample Response
|
|
|
|
A successful response contains the location from which the module version's source can be downloaded.
|
|
|
|
It is expected to be found in the JSON encoded body as the value for the key `location`:
|
|
|
|
```text
|
|
HTTP/2 200
|
|
Content-Length: 81
|
|
|
|
{"location": "git::https://github.com/foo/terraform-baz-bar?ref=v0.0.1"}
|
|
```
|
|
|
|
In the absence of a response body, OpenTofu will use the `X-Terraform-Get` header as the module location:
|
|
|
|
```text
|
|
HTTP/2 204 No Content
|
|
Content-Length: 0
|
|
X-Terraform-Get: git::https://github.com/foo/terraform-baz-bar?ref=v0.0.1
|
|
```
|
|
|
|
:::warning
|
|
OpenTofu will prioritize reading the response body content if both, the body and the `X-Terraform-Get` header, are received from the registry server.
|
|
:::
|
|
|
|
The module location value accepts the same values as the `source` argument in a
|
|
`module` block in OpenTofu configuration, as described in [Module Sources](../language/modules/sources.mdx),
|
|
except that it may not recursively refer to another module registry address.
|
|
The value of the module location may instead be a relative URL, indicated by beginning with `/`, `./` or `../`,
|
|
in which case it is resolved relative to the full URL of the download endpoint to
|
|
produce [an HTTP URL module source](../language/modules/sources.mdx#http-urls).
|