Open brandon-fryslie opened 2 years ago
Thanks for the enhancement request!
Hi @brandon-fryslie! Thanks for sharing this.
It's an interesting coincidence that just yesterday I was thinking about this very possibility. Today we typically advise using the type conversion functions like toset
to influence the return type of an output value, but although that broadly works it does have a number of drawbacks:
type
argument does for input variables.type
describes the overall intended type and thus allows Terraform to automatically convert the given value all at once, without the need for fiddly annotations in all of the leaves of the expression.The reason I was thinking about that this week is that we're currently considering some extensions to the type constraints model and the custom validation features, part of which is intended to advance the existing optional attributes experiment. Some of our design sketches so far call for introducing a new argument alongside variable type
so that we can add some new features that wouldn't fit cleanly into the existing constraint model, and so I think we ought to wait until that design effort is a little more baked before doing anything specific here -- if we do decide to introduce a new argument that supersedes type
then I imagine we'd want to use that new design for output
too, so that the two will remain symmetrical.
That design work is still early so I can't promise anything specific here yet, but I'm grateful for you raising this because it helps me to see that my thoughts about the limitations of the current approach are valid, since you've encountered at least one of these problems yourself.
Thank you! I'm glad to know this fits in with Terraform's design ethos and goals. I'm a fan of strong typing and catching bugs statically (and the focus on that is one of the reasons I love Terraform over other tools).
serve as explicit documentation for users of the module as to what type they should expect to receive
no separate statement about the author's intention in order to validate the value against, which makes it easy to accidentally change the return type of an output value and not know about it until it breaks a consuming module
These are the two main factors that caused me to open the ticket. If someone else modifies a module to change the type
field on an output
, that will service as a strong signal they need to also consider that they are breaking downstream consumers. I also think the symmetry with variable
will be nice.
I'm really excited for the work on optional
and can't wait until that makes it out of experimental. I'm in no rush for this feature because there are workarounds, but it would generally be appreciated by users. Thanks again, have a good day.
Hi all, we recently released the Terraform v1.3 alpha, which includes the ability to mark object type attributes as optional and set default values.
I'm following up with issues that have provided feedback on the previous experiment, and wanted to invite you all to try the alpha and provide any feedback on this updated design. You can learn more/add comments here. Thank you so much in advance, and hope you like the feature!
although optional
is nice, it's not enough. There are still use cases where we want to control types. e.g. infamous conditionals.
│ Error: Error in function call
│
│ on .terraform/modules/namespace_centrals/loadbalancer.tf line 38, in module "network_loadbalancer":
│ 38: local_alb_arn = coalesce(var.alb_use_existing.lb_arn, module.application_loadbalancer[0].arn)
│ ├────────────────
│ │ while calling coalesce(vals...)
│ │ module.application_loadbalancer[0].arn is null
│ │ var.alb_use_existing.lb_arn is "arn:aws:elasticloadbalancing:eu-west-************************"
│
│ Call to function "coalesce" failed: all arguments must have the same type.
where module.application_loadbalancer[0].arn
supposed to be optional(string), but terraform sees it as either string or null and union is not possible (at least I don't understand how).
code for the output:
output "arn" {
value = length(aws_lb.network) != 0 ? aws_lb.network.*.arn : null
}
it was just aws_lb.network.*.arn
before, but then tf saw either empty tuple or string, which is even more confusing
Hi @makarov-roman,
In that example your output value would be inferred as having a tuple type because the one of the results is from a splat expression. Therefore this error seems correct because you are coalescing a string and a tuple.
If your intention was for the output value to be just a single string -- presumably then, your resource has a count
that is either zero or one -- then I think this would be a good situation to use the one
function:
output "arn" {
value = one(aws_lb.network.*.arn)
}
This would then cause the output value to be of type string
.
Of course, if Terraform had allowed you to set type = string
on the output value then you could have an a more specific error message here, saying that the output value's result was a tuple instead of a string, so I think specifying the type of an output value is still valuable; I just shared the above in the hope of giving you something that works in the meantime.
We have designed the language for Terraform Stacks to use explicit types on output values as a way to trial this in a less risky context than the current Terraform language. If that design proves successful (Stacks is currently in a private preview phase) then I expect to bring a similar design and implementation to the traditional Terraform language too.
Current Terraform Version
Use-cases
It would be useful to define the expected
type
of anoutput
(the same way we can forvariable
). That would allow Terraform to throw an error if the output value does not conform to the specified type.For example, I have a child module (
config_module
) that provides some information about the environment that the current root module is being run in. I want to add an output calledis_prod
. This value should always be a boolean. However right now there is no way to enforce this withinconfig_module
itself, and we will only see an error when a consuming module attempts to use the value inappropriately.Attempted Solutions
Currently you cannot set a
type
on anoutput
. I'm sure I could hack together some sort of type checking module but that would defeat the purpose.Proposal
I don't believe this would interfere with or impact any other existing Terraform features, beyond enabling more strict type checking at module boundaries. Output type checking could take place whenever is most convenient for the implementation, such as when running an
apply
or for aplan
when all output values are known.References