-
-
Notifications
You must be signed in to change notification settings - Fork 1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RFC: transform blocks for handling terragrunt limitations #1809
Conversation
deployment: | ||
|
||
```hcl | ||
transform { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would this be an attribute of the terraform
block, since it would be specifically related to the source
argument?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I kind of like it being a separate block, given that the terraform
block is more about how terragrunt calls terraform, and transforming the code is a different operation. In that regard, it is more similar to generate
than terraform
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, and that makes me wonder what kind of terragrunt config/feature might it be to support multiple terraform blocks...
type = list(string) | ||
} | ||
output "my_password_hashed" { | ||
sensitive = true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How would collisions be handled? E.g. say sensitive = true
already existed for this output in the source module but the user specifically wanted to override it with sensitive = false
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In my mind, this was more like a shallow merge operation, where each block shallow merges up, with the "default" being what's in the terraform code. Updated to clarify this: f2d8e44
|
||
- Scan all `.tf` files in the directory. | ||
- For each file found, parse using the `hclwrite` parser. | ||
- Walk the AST, looking for `variable` or `output` blocks that match the `transform` sub blocks. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Theoretically, this could also rewrite resource
and data
blocks? 🤯
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes in theory, although I think that would be fairly complex. I think at that point, forking the underlying module is a better approach.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for putting together the RFC. A few thoughts:
- Does this RFC encourage anti-patterns? For example, it seems like not specifying the
type
on an input variable, especially when the type is not astring
, is borderline a bug. I understand it works in Terraform, but it feels like a leftover from the early days, when there weren't explicit types, and like something we'd want to discourage, rather than support via a first-class feature. Similarly, what is the use case for not puttingsensitive
on output variables that contain sensitive data, even in a shared module? Perhaps there is some legitimate reason for doing that, but it's not obvious to me what that is, and I don't know if adding a first-class feature to work around that is a good direction. Update: thinking about this more, is this just to avoid having to putsensitive = true
all over the place, and instead allowing Terraform to track sensitive values internally, and you only need the explicit label if that output is in a root module and therefore, could be written to a log file? - Thinking more through the points above, is the primary goal to make it possible to use legacy modules (i.e., those that are out of date with the latest Terraform functionality) or those that a user might not have access to change?
- Could overwriting the source code result in the changes accidentally getting written back to version control? In particular, IIRC, if you had a
source
URL pointing to a local file path, we (or more accurately, go-getter) used to use a symlink, so if we modify the code in.terragrunt-cache
, it will actually modify it in the original source folder. Not sure if that still happens. - Does this create maintenance headaches? E.g., Let's say you add
transform
blocks for a few variables, and then at some point, the maintainer of the module changes those variables: e.g., they addtype
to some of them, rename others, etc. Will it be obvious what's going on with these transform blocks? Is this debuggable?
Yes, this is my understanding. I think the issue is that it's hard to see this in shared modules, and thus know when you have to mark outputs as sensitive or not, since terraform doesn't really give you tools to do this (e.g.,
I'm not sure this RFC by itself would encourage anti-patterns. Ultimately, many module developers would much rather focus on supporting the core terraform use case rather than additionally Terragrunt, and these issues are arguably only a problem if you use Terragrunt to deploy those modules (since it turns the shared module where these aren't issues, into a root module where they are). I also think this is a maintenance headache if you have direct access to the module itself. It seems much easier to maintain to have this logic directly in the module, than in terragrunt.hcl. So it really is an escape hatch for cases where you can't modify the module. That said, you do bring up a good point that these should really only be used for modules on the public registry, because otherwise it is desirable to mark
I was primarily thinking about the latter. More specifically, about modules on the public registry (which relates to the point above about restricting to
Ah yes that is true... Another reason to do the
This is a good point. In terms of debuggability, I think we can add a feature to
Given the above, what are your thoughts on restricting this to |
Please no! We have a use case where we fork every module so we "own" it, but that's just so we can trust the source and the tags we've already inspected (managing supply chain risk)! We prefer not to modify the forks because that is a maintenance headache, and instead inspect upstream changes and update the forks as needed. Being able to modify the source on the fly when needed would be handy! |
Ah that makes sense @lorengordon . Hmm I'll have to think through what mechanisms we can put in place in terragrunt to support both concerns. Off the top of my head, a compromise is to make it a soft restriction that is overrideable with config/cli arg. Something that basically indicates "I know what I am doing" to terragrunt. E.g., maybe by default it is restricted to I know this can be annoying to you, but at least it makes it explicit that terragrunt doesn't encourage usage of the |
That would be fine. We certainly have no problem managing config. But I would suggest documenting it and putting a warning in the doc. Default value could be |
If my understanding is correct, some submodules cannot be used as terragrunt root modules, but all modules that work as terragrunt root modules could be used as submodules in a terraform root module. Would it then make sense to make it so that terragrunt does not download the A bit more in depth... Currently, if I use module Would things break if instead, terragrunt created a module "terragrunt_root" {
source = "terraform-aws-modules/foo/aws"
inputs = "resolved from terragrunt pre-processing"
}
output "foo_output_1" { ...generated for each output in the foo module... } There would need to be some path mapping done for local modules, but my (probably naive) understanding is that this would make the terragrunt/terraform compatibility stronger, as all modules could be supported this way, and things like module registry source URLs in terragrunt would work because terraform (with whatever version the user had downloaded) would be responsible for resolving the reference. As far as the |
@dmattia Yes that is the end extrapolation of this feature, but the concern is that that is a major backward incompatibility. It triggers a major migration where every terragrunt project will need to reallocate everything in state to be nested under the This change would also makes things like OTOH, something like transform blocks would be backward compatible, while still solving the problem for the short term. |
@yorinasub17 Thank you for that explanation! I think some of these may have solutions (like Overall I like this proposal, and think it's great that it's all backwards compatible. I do have one question though: Where would the line be drawn between using |
The line would be whether you need to add blocks to the existing module or modify blocks. Some blocks in terraform support combining (e.g., the In essence, the |
…in why we should support it
Co-authored-by: Zack Proser <zackproser@gmail.com>
Closing as stale |
This a proposed design for addressing #1808. I wanted to write this down before it hits brain rot and I forget about it.
Easy reading link.
Note that I think this feature does indeed belong in Terragrunt. As the discussion in #1774 revealed, the vast majority of modules in the registry do not support Terragrunt, nor do the module maintainers want to (it goes without saying that that is perfectly ok).
However, this does not mean that the modules in the registry are NOT service modules. Use cases of the module by users may show that there are modules in the registry that actually can be deployed directly as a service module, despite not being labeled as such, but have the
variable
andoutput
limitations that terragrunt currently doesn't support. For those modules, it is fairly painful for users to have to wrap and repeat all the variables and outputs of the underlying module.The feature proposed in this RFC should help support this, and I believe we can implement this with relatively little effort.
cc @lorengordon since you indicated being curious about how we could address this problem.