Skip to content

hashicorp/terraform-registry-address

terraform-registry-address

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

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.

Compatibility

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.

Related Libraries

Other libraries which may help with consuming most of the above Terraform outputs in automation:

Usage

Provider

pAddr, err := ParseProviderSource("hashicorp/aws")
if err != nil {
	// deal with error
}

// pAddr == Provider{
//   Type:      "aws",
//   Namespace: "hashicorp",
//   Hostname:  DefaultProviderRegistryHost,
// }

Module

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",
// },

Other Module Address Formats

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.

Ambiguous Provider Addresses

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 as aws.
  • 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 through provider "<NAME>" {} block without corresponding entry inside required_providers, but these providers are always resolved as hashicorp/<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.

Resolving Ambiguous Address

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.

terraform provider

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")