This module enables parsing, comparison and canonical representation of
Terraform Registry provider addresses
(such as registry.terraform.io/grafana/grafana
or hashicorp/aws
)
and module addresses (such as hashicorp/subnets/cidr
).
Provider addresses can be found in
terraform show -json <FILE>
(full_name
)terraform version -json
(provider_selections
)terraform providers schema -json
(keys ofprovider_schemas
)- within
required_providers
block in Terraform configuration (*.tf
) - Terraform CLI configuration file
- Plugin reattach configurations
Module addresses can be found within source
argument
of module
block in Terraform configuration (*.tf
)
and parts of the address (namespace and name) in the Registry API.
The module assumes compatibility with Terraform v0.12 and later, which have the mentioned JSON output produced by corresponding CLI flags.
We recommend carefully reading the ambigouous provider addresses
section below which may impact versions 0.12
and 0.13
.
Other libraries which may help with consuming most of the above Terraform outputs in automation:
pAddr, err := ParseProviderSource("hashicorp/aws")
if err != nil {
// deal with error
}
// pAddr == Provider{
// Type: "aws",
// Namespace: "hashicorp",
// Hostname: DefaultProviderRegistryHost,
// }
mAddr, err := ParseModuleSource("hashicorp/consul/aws//modules/consul-cluster")
if err != nil {
// deal with error
}
// mAddr == Module{
// Package: ModulePackage{
// Host: DefaultProviderRegistryHost,
// Namespace: "hashicorp",
// Name: "consul",
// TargetSystem: "aws",
// },
// Subdir: "modules/consul-cluster",
// },
Modules can also be sourced from other sources
and these other sources (outside of Terraform Registry)
have different address formats, such as ./local
or
github.com/hashicorp/example
.
This library does not recognize such other address formats and it will return error upon parsing these.
Qualified addresses with namespace (such as hashicorp/aws
)
are used exclusively in all recent versions (0.14+
) of Terraform.
If you only work with Terraform v0.14.0+
configuration/output, you may
safely ignore the rest of this section and related part of the API.
There are a few types of ambiguous addresses you may comes accross:
- Terraform
v0.12
uses "namespace-less address", such asaws
. - Terraform
v0.13
may use-
as a placeholder for the unknown namespace, resulting in address such as-/aws
. - Terraform
v0.14+
configuration still allows ambiguous providers throughprovider "<NAME>" {}
block without corresponding entry insiderequired_providers
, but these providers are always resolved ashashicorp/<NAME>
and all JSON outputs only use that resolved address.
Both ambiguous address formats are accepted by ParseProviderSource()
pAddr, err := ParseProviderSource("aws")
if err != nil {
// deal with error
}
// pAddr == Provider{
// Type: "aws",
// Namespace: UnknownProviderNamespace, // "?"
// Hostname: DefaultProviderRegistryHost, // "registry.terraform.io"
// }
pAddr.HasKnownNamespace() // == false
pAddr.IsLegacy() // == false
pAddr, err := ParseProviderSource("-/aws")
if err != nil {
// deal with error
}
// pAddr == Provider{
// Type: "aws",
// Namespace: LegacyProviderNamespace, // "-"
// Hostname: DefaultProviderRegistryHost, // "registry.terraform.io"
// }
pAddr.HasKnownNamespace() // == true
pAddr.IsLegacy() // == true
However NewProvider()
will panic if you pass an empty namespace
or any placeholder indicating unknown namespace.
NewProvider(DefaultProviderRegistryHost, "", "aws") // panic
NewProvider(DefaultProviderRegistryHost, "-", "aws") // panic
NewProvider(DefaultProviderRegistryHost, "?", "aws") // panic
If you come across an ambiguous address, you should resolve it to a fully qualified one and use that one instead.
The Registry API provides the safest way of resolving an ambiguous address.
# grafana (redirected to its own namespace)
$ curl -s https://registry.terraform.io/v1/providers/-/grafana/versions | jq '(.id, .moved_to)'
"terraform-providers/grafana"
"grafana/grafana"
# aws (provider without redirection)
$ curl -s https://registry.terraform.io/v1/providers/-/aws/versions | jq '(.id, .moved_to)'
"hashicorp/aws"
null
When you cache results, ensure you have invalidation mechanism in place as target (migrated) namespace may change.
Like any other legacy address terraform
is also ambiguous. Such address may
(most unlikely) represent a custom-built provider called terraform
,
or the now archived hashicorp/terraform
provider in the registry,
or (most likely) the terraform
provider built into 0.11+, which is
represented via a dedicated FQN of terraform.io/builtin/terraform
in 0.13+.
You may be able to differentiate between these different providers if you know the version of Terraform.
Alternatively you may just treat the address as the builtin provider, i.e. assume all of its logic including schema is contained within Terraform Core.
In such case you should construct the address in the following way
pAddr := NewProvider(BuiltInProviderHost, BuiltInProviderNamespace, "terraform")