I was not able to see another ticket mentioning this, so here I go:
I would like to pass-though/copy/declare all output variables of a sub module as output variables of my own module. This is normally not a problem when the sub module got two or three outputs, but it is a hassle when there are lot of them. Let me illustrate this by using a imaginary module.
# the prolific module
module "plenty" {
source = "./output/plenty/of"
}
# the boilerplate
output "out1" {
value = "${module.plenty.out1}"
}
output "out2" {
value = "${module.plenty.out2}"
}
output "out3" {
value = "${module.plenty.out3}"
}
output "out4" {
value = "${module.plenty.out1}"
}
output "out5" {
value = "${module.plenty.out2}"
}
output "out6" {
value = "${module.plenty.out3}"
}
# and so on... you get the idea...
output "outN" {
value = "${module.plenty.outN}"
}
AFAIK outputs are stored in a map. If this is the case then I would like to be able to export the keys of any arbitrary map as separated output elements.
We could use a new keyword like export.
In order to add some flexibility we should be also be able to specify some selectors which could allow a regex/globbing syntax and with a default for all such as [ "*" ] or [ ".+" ]
# the prolific module again
module "plenty" {
source = "./output/plenty/of"
}
export "many" {
source = "${module.plenty.outputs}" # accept a map
selectors = [".+"] # this could be the the default setup
delimiter = "_" # same here, or just an empty string.
}
if we set the input variables to some sane default values we could then just write
export "many" {
source = "${module.plenty.outputs}"
}
This will produce a set of outputs in the format export_name + delimter + individual_module_output_name like:
many_out2
many_out3
many_out4
many_out5
many_out6
...
...
...
many_outN
# the same the prolific module
module "plenty" {
source = "./output/plenty/of"
}
# select just some keys
outputs "many" {
source = "${module.plenty}"
selectors = ["out1", "out75", ".+text(10|11)-suffix"]
}
variable "mymap" {
type = "map"
default = {
key1 = "val1"
key2 = "val2"
key3 = "val3"
key4 = "val4"
}
}
export "many" {
source = "${var.mymap}"
}
Opinions? Ideas?
Just noting my immediate thoughts: I'd be open to a special automatic variable on modules that always includes all the outputs.
A more or less related issue I keep forgetting: Assuming that the here proposed strategy gets implemented, then using a map for reducing the amount of code is not really viable due to the fact that variables cannot use interpolations, not event for defining a key within a map.
I just tried to export all my outputs into a single map. This is my code:
variable "init" {
type = "map"
default = {
account_id = "${module.init.account_id}"
opsworks_service_role_arn = "${module.init.opsworks_service_role_arn}"
opsworks_instance_profile_arn = "${module.init.opsworks_instance_profile_arn}"
hosted_zone_id = "${module.init.hosted_zone_id}"
cloudwatch_alarm_mail_arn = "${module.init.cloudwatch_alarm_mail_arn}"
cloudwatch_alarm_pagerduty_arn = "${module.init.cloudwatch_alarm_pagerduty_arn}"
role_switch_link_devops = "${module.init.role_switch_link_devops}"
role_switch_link_qa = "${module.init.role_switch_link_qa}"
}
}
output "init" {
value = "${var.init}"
}
This yielded the known error Variable 'init': cannot contain interpolations.
So, basically the proposal in this ticket, if implemented as described, would be only a half solution. It would only help exporting the module output variables, but not really more than that.
Something similar would be intersting on the cli like so: terraform inspect
terraform inspect root.modue.submodule.outputs.output_variable
Something around this should also be expected to work:
terraform inspect root.modue.*.outputs.output_variable
and could probably result, for enhanced usefulness:
{
"submodule1" : "output_variable_1_value",
"submodule2" : "output_variable_2_value",
}
Why not simply add a flag inside a resource that declares create_output = true and it takes the resource name and declares it as an output, which is equivalent to manually declaring an output?
Real case scenario:
I have a module which creates lots of subnets on AWS and I need to access each subnet's ID, therefore I need to declare an output for each subnet, quite a hassle.
So basically my idea is:
// subnet module
resource "aws_subnet" "subnet-d81e1aac-6" {
vpc_id = "${var.vpc_production_id}"
cidr_block = "192.168.6.0/23"
availability_zone = "${var.aws_region}a"
map_public_ip_on_launch = false
create_output = true <--- Note this
tags {
"Name" = "6"
}
}
This will automatically create an output that can be reached via ${module.vpc.subnet-d81e1aac-6.id}
This would be a fantastic feature to add. Right now our vpc instantiations have tons of boilerplate just to expose the vpc module outputs. If we change the vpc module and add or subtract any outputs, each of the dependent projects must be individually updated... this is clearly not a maintainable design pattern.
I recognize this feature likely has a large change to logic in core. Is this something Hashicorp has roadmapped for internal dev or is this something Hashicorp would accept a PR to add into current state?
seems like this ticket and https://github.com/hashicorp/terraform/issues/9067 are closely coupled in scope/implementation
Hi all! Sorry for the long silence here.
As part of the configuration language improvements we're working on for the next major release, it should be possible to return an entire module or resource as an object via an output:
# Not yet implemented, and details may change before release
module "plenty" {
source = "./output/plenty/of"
}
output "plenty" {
value = module.plenty
}
...or:
# Not yet implemented, and details may change before release
resource "aws_vpc" "example" {
# ...
}
module "other" {
source = "./other"
vpc = aws_vpc.example
}
As @cpoole noted, this is what is being discussed over in #9067. I'd previously left a comment saying it wasn't clear yet whether this would make the initial release. It's still not 100% certain, since there are some wrinkles to work out in the implementation (changes lots of Terraform's internal assumptions), but we _do_ intend to make that work and it's just a matter of the effort required to get there.
While _this_ issue isn't describing exactly that idea, I think for the time being the capability to treat modules and resources as objects will be our proposed solution to the underlying need here, and so I'm going to close this one just to consolidate the discussion over in #9067. Once the change I described above is released and we've gathered some real-world experiences with it we can see if additional features are warranted to fill any remaining capability gaps.
Since this issue was originally opened, we've also added the concept of Local Values, which allow a name to be assigned to a local value within a module that can then be used elsewhere, and which (unlike variable defaults) can contain arbitrary expressions.
Thanks for sharing this use case and feature proposal, @martin-flaregames!
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 all! Sorry for the long silence here.
As part of the configuration language improvements we're working on for the next major release, it should be possible to return an entire module or resource as an object via an output:
...or:
As @cpoole noted, this is what is being discussed over in #9067. I'd previously left a comment saying it wasn't clear yet whether this would make the initial release. It's still not 100% certain, since there are some wrinkles to work out in the implementation (changes lots of Terraform's internal assumptions), but we _do_ intend to make that work and it's just a matter of the effort required to get there.
While _this_ issue isn't describing exactly that idea, I think for the time being the capability to treat modules and resources as objects will be our proposed solution to the underlying need here, and so I'm going to close this one just to consolidate the discussion over in #9067. Once the change I described above is released and we've gathered some real-world experiences with it we can see if additional features are warranted to fill any remaining capability gaps.
Since this issue was originally opened, we've also added the concept of Local Values, which allow a name to be assigned to a local value within a module that can then be used elsewhere, and which (unlike variable defaults) can contain arbitrary expressions.
Thanks for sharing this use case and feature proposal, @martin-flaregames!