-
Notifications
You must be signed in to change notification settings - Fork 903
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
Allow variables to be marked as deprecated to communicate variable removal to module consumers #1005
Comments
Just noticed there's a 5 year old feature request for this in terraform: hashicorp/terraform#18381 |
Hi @reegnz this is a cool idea, I like it. However, I believe this would make module code incompatible with Terraform, which some module authors probably would have an issue with. We are currently working towards a stable OpenTofu release, I think this proposal could be revisited after that release is out. I added a label to that effect. |
I think it's a neat idea and would be useful, but share the same concern as @janosdebugs. We need to figure out how to handle that compatibility going forward. I wonder if a comment annotation would be a reasonable workaround, though it would definitely be a bit of a hack. |
That issues title and comments specifically reference output values not variables. I think separate issues for these things is good since we know how to implement this for variables but still don't know how to handle outputs. Let variables be implemented then circle back to outputs when someone figures out a plan. |
Maybe a good way to implement this would be to detect a deprecated line in the variable "this_is_my_variable" {
type = string
description = "This is a variable for the old way of configuring things. Deprecated: This variable will be removed on 2024-12-31. Use that_is_my_variable instead."
} The rule could be that the deprecation notice must always be at the end of the description and must have the format of:
OpenTofu could then extract this text and display it as a warning to the user. This would work for both variables and outputs and could be implemented in one go. @reegnz what do you think? |
I think parsing descriptions is bound to be flaky. I'd maybe suggest a custom "deprecation" provider, to maintain compatibility with Hashicorp Terraform. |
@lorengordon how would that work? |
Just the way providers work. Write a resource with the behavior and workflow you want. Something like, take the deprecated variable value and an deprecation message as an input, generate an error with the deprecation message if the variable value is not null. Or take inspiration from variable validation, and take a |
@lorengordon this wouldn't work in on outputs, and it also wouldn't work if the user passed in the default value of a variable explicitly. Both of these would trip up someone if the variable/output in question went away. |
This issue is about variable deprecation, not outputs. That would be different anyway. Would probably want the warning to occur when a user accesses the deprecated output. That's going to require changes to terraform core, no matter what. But the provider idea certainly would work if the user passed in the default value explicitly. The module author would be responsible for determining what happens in that scenario. There are options. The resource could also simply take another input for the default value, and decide how to handle the scenario when the value passed in matches the default. Or the |
Now that the stable release has been out for some time we are happy to accept contributions on this issue. We feel it is valid. In my personal opinion, I feel it may be best to ensure that we as a community agree on the approach before development starts though. We should also be careful to make sure that we narrow down the scope to only |
Hey, I would like to take up this issue. |
Hey @sanskruti-shahu thank you for volunteering, I've assigned you. Before you begin coding, please read this section of the contribution guide. |
Other than the above, I propose that we use a more "special string" than just "Deprecated: ". E.g.
To display the warnings, I think you can just return them as part of the diags struct (as a warning) during the planning phase and they will be propagated up and displayed. I don't think there needs to be any special apply-time handling of this. |
Perhaps @deprecated{message} or some other enclosing mark? |
I agree with @cube2222 , I will go through the codebase once and will let you know about changes I'll be making before implementing them. |
I actually really like this idea, and if an update to the HCL parser would enable first-class support for features-by-comment, this could open some new doors. (I've used the HCL parser, but never for trying to read comments, so I don't recall if it's possible at-present.) The current reality is that we live in a mixed ecosystem where people/orgs/companies will be spending the next few years transitioning tools (assuming they plan to come over to OpenTofu). If anyone remembers Mark Pilgrim (Dive into Mark, assassinated his digital presence in 2010), he wrote a really great maxim:
The ability to opt-in and enable new features that are not broadly compatible is interesting. # @deprecated: This variable will be removed on 2024-12-31. Use that_is_my_variable instead.
variable "this_is_my_variable" {
type = string
description = "This is a variable for the old way of configuring things."
} I think that a well-defined syntax for this would be in order.
And if we look at the pattern used by conventional commits, we can do a little more.
I would caution, however, that we take the time to learn from the W3C's mistakes with I would hope that with a spec, we could get community + tooling support (across HashiCorp, the OTF, and others) for adding features via comments that could eventually make their way into the core HCL parser(s), like browser engines have. Something like a I would love to be able to say — for tools like terraform {
# @opentofu(required_version): ~> 1.6.0
required_version = ">= 0.13, < 2.0"
required_providers {
# https://github.com/hashicorp/terraform-provider-aws/releases/latest
aws = {
source = "hashicorp/aws"
version = ">= 4.0, < 6.0"
}
}
}
(CSS had it easy because browsers simply ignored things it didn't understand. The HCL parser throws errors/panics.) |
Hey @skyzyx, I got your point but I think reading comment for deprecation message would be quite complex than directly checking out variable's description. |
Alright, we've discussed this internally, and have a hard time deciding between the two approaches:
The comment approach would most likely require us to for the HCL repo, which isn't something we want to do right now. Thus, we've decided to submit this to the steering committee for decision. This might take a week or two to resolve, until the steering committee will meet. |
So until then the next best thing is to try and build the deprecation warnings into a plugin for tflint: https://github.com/terraform-linters/tflint/blob/master/docs/user-guide/plugins.md |
Hey folks, we have discussed this with the core team and believe that this should only be done once #1328 is done. |
I hope if we come up with a design, it also works for deprecating locals. |
@sftim can you elaborate on deprecating locals? The main goal behind this issue is to communicate to consumers of a module that the inputs (and probably outputs) have changed are will not be supported in a future version. |
Deprecation could look, for example, like this: -locals {
- foo = data.foo_bar.json_value
-
- foo_json = jsonencode(data.foo.value)
-}
+#[deprecated]
+locals {
+ # use local.foo_json instead
+ # the values are NOT equivalent, see JIRA-42
+ foo = data.foo_bar.json_value
+}
+locals {
+ foo_json = jsonencode(data.foo.value)
+} Having two different deprecation mechanisms would be annoying to coders and to people explaining it all. |
This could work, I think: variable "this_is_my_variable" {
lifecycle {
deprecated = true
}
type = string
description = "This is a variable for the old way of configuring things."
} |
@sftim I want to understand why you want to deprecate locals? The main goal of this issue is to communicate to consumers of a module that the inputs have changes? I'm also a fan of keeping the description the same and adding an additional "deprecation" field as discussed above. |
When we design how to deprecate module inputs, we should consider how we'll mark other things duplicated (eg: provider-managed functions, locals, outputs, entire modules, inner modules). For example, in Python you can mark any internal method as deprecated and gradually update your code. You can even lint on adding new uses of deprecated things. |
Going back to your python example, that's still a "function call" interface. Are you looking for something that can hint to IDEs that a particular local in a module should eventually removed? Why wouldn't a comment suffice there? The biggest value IMO of deprecated is at the module interface. Saying "This Input" or "This Output" won't be supported much longer provides clear messaging between distinct teams and organizations (module writers and maintainers vs consumers). Given that locals are module-internal, I don't see the need for any of that information to be provided to consumers of the module. Any modern editor can easily and will happy identify and point out To make it more concrete, I would not want tofu warning me that a module I use has internal stuff that's deprecated. That would just be confusing to me. I would only want to know that I need to update my calling code when I use a module directly. This does bring up a scenario on the original issue that we have yet to consider: Would you only want deprecated warnings from the root module -> first level child modules? Does it ever make sense to warn about child -> child module deprecation? |
Imagine you are working on a module and use a deprecated detail of it. You get a warning. Making the warning machine readable and unambiguous is useful, even if IDEs can draw inferences. The thing to watch out for is ending up with more than one way to mark things deprecated. If we're happy that won't happen, all is well. |
I agree it would be best to have a consistent deprecation mechanism across the terraform language. Languages like Java allow you to deprecate fields, methods, classes, interfaces etc the same way with annotations, and the compiler reports on deprecated code being used. If we think holistically module user facing and module developer facing ways of deprecation should not be bifurcated. I still think initially the consumer-side should be worked on, unless the change is trivial enough to do it across the board at the same time. Nowadays I think this should be solved outside the tool as a linting solution, via comments. Changing the language makes sense once it's proven this can be linted. Anyway, maybe someone could contribute something to tflint for this purpose. |
Hey @sftim thank you for your input. We discussed your suggestion with the core team and due to how the HCL language works, a generalized deprecation mechanism is difficult to implement. It is also not what this issue is about, so we would like to ask you to open a separate issue if you would like to see a generalized mechanism. |
I'll try to clarify; I don't want to request a general mechanism in this issue. I do want the design to leave room for future work. |
@sftim this is a topic that would likely require an RFC with technical details. HCL is a very restrictive language and the codebase is extremely complex and "designing for the future" isn't a concept that is easily applied here. |
I might have a good idea that maintains compatibility with Hashi, so module authors are not discouraged, but is also not too hacky. Since the most recent versions allow for files with deprecation "my_var" {
type = "variable"
message = "This variable is deprecated!"
}
deprecation "my_output" {
type = "output"
message = "The output called my_output is going away soon!"
} If you only define these blocks in a file with the |
One interesting detail to consider here is exactly what in the calling module ought to trigger the deprecation warning. The easiest case to call is directly assigning a non-null value to an optional input variable: module "example" {
source = "./example"
deprecated_thing = "foo"
} A less obvious case is when the expression being assigned produces a null value, which is how we represent the idea of making a dynamic decision about whether an input variable is being set: module "example" {
source = "./example"
deprecated_thing = var.use_deprecated_thing ? "foo" : null
} Should the mere presence of a definition of Making an exception for I'd also note that when providers implement deprecation they do that "server-side" in the plugin protocol (where OpenTofu Core is acting as the client) and the plugin protocol does not allow a provider to distinguish between an omitted argument and an argument explicitly set to I think an RFC related to this feature request ought to take a position on this question and discuss both the advantages and disadvantages of that position. @cam72cam's earlier thought about only generating warnings for the first level of module calls might be an interesting way to compromise here, since I think the most likely reason for writing a conditional assignment like I showed above is that someone is maintaining an intermediate module that bridges between two other modules where they want to give their users the option of continuing to use the deprecated feature without imposing a deprecation warning on calls that set If we did that then I assume we'd want to make sure that the deprecation warnings appear when using |
deprecation "my_var" {
type = "variable"
message = "This variable is deprecated!"
condition = var.my_var != null
} ? |
Hey there! Feel free to leave your thoughts on the RFC for the deprecation of module variables and outputs: #2180 |
OpenTofu Version
Use Cases
Over the lifecycle of an opentofu module, one might need to remove variables from a module.
It would be great to have a mechanism to notify users that they are using a deprecated variable that is scheduled for a future removal.
Attempted Solutions
Proposal
Introduce a new field into the variable declaration that is used to define a deprecation message:
Whenever a user is using a deprecated variable of the module, they will get a warning message on
tofu validate
,tofu plan
andtofu apply
invocations as long as the variable is still being passed to the module.The deprecation message is freeform text, so it could contain a URL to migration instructions too.
References
Other languages support communicating deprecation to software component users.
@Deprecated
annotation and even had@deprecated
javadoc comments in Java 1.1, 26 years ago.The text was updated successfully, but these errors were encountered: