Terraform v0.11.3
# main.tf
# The root provider
provider aws {
region = "eu-west-1"
}
provider aws {
region = "ap-southeast-2"
alias = "sydney"
}
provider aws {
region = "us-west-2"
alias = "portland"
}
resource aws_ssm_parameter "root" {
name = "root"
type = "String"
value = "derp"
}
resource aws_ssm_parameter "portland" {
provider = "aws.portland"
name = "portland"
type = "String"
value = "derp"
}
resource aws_ssm_parameter "sydney" {
provider = "aws.sydney"
name = "sydney"
type = "String"
value = "derp"
}
output root_arn {
value = "${aws_ssm_parameter.root.arn}"
}
output portland_arn {
value = "${aws_ssm_parameter.portland.arn}"
}
output sydney_arn {
value = "${aws_ssm_parameter.sydney.arn}"
}
module "a" {
source = "./modules/a"
providers = {
aws = "aws"
aws.portland = "aws.portland"
aws.sydney = "aws.sydney"
}
}
output a_root_arn {
value = "${module.a.root_arn}"
}
output a_portland_arn {
value = "${module.a.portland_arn}"
}
output a_sydney_arn {
value = "${module.a.sydney_arn}"
}
output b_root_arn {
value = "${module.a.b_root_arn}"
}
output b_portland_arn {
value = "${module.a.b_portland_arn}"
}
output b_sydney_arn {
value = "${module.a.b_sydney_arn}"
}
# modules/a/main.tf
resource aws_ssm_parameter "root" {
name = "a.root"
type = "String"
value = "derp"
}
resource aws_ssm_parameter "portland" {
provider = "aws.portland"
name = "a.portland"
type = "String"
value = "derp"
}
resource aws_ssm_parameter "sydney" {
provider = "aws.sydney"
name = "a.sydney"
type = "String"
value = "derp"
}
output root_arn {
value = "${aws_ssm_parameter.root.arn}"
}
output portland_arn {
value = "${aws_ssm_parameter.portland.arn}"
}
output sydney_arn {
value = "${aws_ssm_parameter.sydney.arn}"
}
module "b" {
source = "../b"
providers = {
aws = "aws"
aws.portland = "aws.portland"
aws.sydney = "aws.sydney"
}
}
output b_root_arn {
value = "${module.b.root_arn}"
}
output b_portland_arn {
value = "${module.b.portland_arn}"
}
output b_sydney_arn {
value = "${module.b.sydney_arn}"
}
# modules/b/main.tf
resource aws_ssm_parameter "root" {
name = "b.root"
type = "String"
value = "derp"
}
resource aws_ssm_parameter "portland" {
provider = "aws.portland"
name = "b.portland"
type = "String"
value = "derp"
}
resource aws_ssm_parameter "sydney" {
provider = "aws.sydney"
name = "b.sydney"
type = "String"
value = "derp"
}
output root_arn {
value = "${aws_ssm_parameter.root.arn}"
}
output portland_arn {
value = "${aws_ssm_parameter.portland.arn}"
}
output sydney_arn {
value = "${aws_ssm_parameter.sydney.arn}"
}
N/A
N/A
Providers are explicitly passed from root module to module A to module B and we can therefore create resources in module B
2018/02/21 15:26:46 [ERROR] 3 problems:
- module "b": cannot pass non-existent provider "aws"
- module "b": cannot pass non-existent provider "aws.portland"
- module "b": cannot pass non-existent provider "aws.sydney"
terraform init
There are other issues on the grandchild topic, but I believe they all related to implicit inheritance so I opened this one on explicit inheritance.
Hi @sjauld,
Sorry that this is still a bit confusing. Once we get the new configuration framework in place We're going to revisit the structure of the providers a bit more.
In the documentation for modules within providers, we mention that a configuration must have what we refer to as "proxy configuration blocks" for the providers it wants to receive. In order to make this system a bit more flexible and work with existing modules, I added the ability to allow passing a provider into a module with no corresponding block for that provider (#16619). However in order for the receiving module to pass on the provider again, it will still require a block in the configuration to reference.
What the "a" module needs is empty configuration blocks for the 3 providers, like so:
provider "aws" {
}
provider "aws" {
alias = "sydney"
}
provider "aws" {
alias = "portland"
}
Since the module is already using the providers by name, there's no additional coupling caused by requiring the empty "proxy" configuration blocks. This still can cause issues when modules want to set version constraints, which is what we're going to cover in #16835.
Ah, thanks @jbardin!
I'm going to lock this issue because it has been closed for _30 days_ โณ. This helps our maintainers find and focus on the active issues.
If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.
Most helpful comment
Hi @sjauld,
Sorry that this is still a bit confusing. Once we get the new configuration framework in place We're going to revisit the structure of the providers a bit more.
In the documentation for modules within providers, we mention that a configuration must have what we refer to as "proxy configuration blocks" for the providers it wants to receive. In order to make this system a bit more flexible and work with existing modules, I added the ability to allow passing a provider into a module with no corresponding block for that provider (#16619). However in order for the receiving module to pass on the provider again, it will still require a block in the configuration to reference.
What the "a" module needs is empty configuration blocks for the 3 providers, like so:
Since the module is already using the providers by name, there's no additional coupling caused by requiring the empty "proxy" configuration blocks. This still can cause issues when modules want to set version constraints, which is what we're going to cover in #16835.