hashicorp / terraform

Terraform enables you to safely and predictably create, change, and improve infrastructure. It is a source-available tool that codifies APIs into declarative configuration files that can be shared amongst team members, treated as code, edited, reviewed, and versioned.
https://www.terraform.io/
Other
42.34k stars 9.49k forks source link

Support concurrent installation of multiple versions of terraform CLI. #27713

Open bcsgh opened 3 years ago

bcsgh commented 3 years ago

(Yes, I know you can do this already, but it's error prone and not easy to work with.)

Use-cases

Multiple different sets of unconnected resources are managed using multiple different configurations by multiple different users and systems of automation. Upgrading the version of TF being used is not possible to do atomically across this whole ecosystem. Furthermore, at least some version steps happen automatically and irreversibly the first time a newer TF binary is used to act on a given configuration. Prevent that (and the resulting error when any non-upgraded installation then tries to look at it) necessitates a specific version pin in the configurations, which then requires that every user of that config have only that version installed, and that every configuration they use agree on the same version. ... Yuck.

Handling this would be made significantly simpler if the correct version of TF was automatically run.

Proposal

Provide a binary/wrapper/script that can inspect a TF config, check which version of terraform it is using and then lookup and invoke that version from the locally installed versions.

With this, the upgrade path would be:

skyzyx commented 3 years ago

This tool helps with these exact issues: https://tfswitch.warrensbox.com

bcsgh commented 3 years ago

@skyzyx that looks like a nice tool for a somewhat related problem. However it seems to be focusing on a problem that is somewhat different in a few relevant ways.

  1. To quote that page "from the dropdown"... that seems to be targeted at an interactive environment which is not true for about half of the described use case. Tools that target an interactive use case generally behave poorly in non-interactive use cases.
  2. If I'm guessing correctly, that tool is "globally" altering the version of terraform in use, where as I'm wanting something that will pick a version on a per invocation level: assume multiple process will be invoking terraform concurrency and will need to invoke different versions. There may be ways around that, but they would probably require extra steps which can be forgotten, omitted or bungled. Ideally, a solution would impose no constrains on the TF configuration or execution environment beyond what the desired version of terraform it self does.
  3. That tool seems to generaly assumes the user already knows what version needs to be used, the bulk of the complexity around what I'm asking for is how to figuring that out. What I'm asking for is a general solution that would inspect any and all relevant required_version as well as the local or remote tfstate and identify which available version will not alter the tfstate in non-backwards compatible ways. If having to know what version to use was acceptable, then installing multiple terrafrom binaries as terrafrom.$VER would cover my use case. The docs do say that it can figure out required_version in at least some cases, but that is only part of the problem. Furthermore, unless the information is coming from terraform it self or some other tool developed in concert with it, there will inevitably be fidelity issues in selecting an acceptable version.

Practically, unless the solution is part of terraform it self, it's likely to come up short or outright fail on one or more of those points.

Also: this seems like a problem that the terraform product should provide a solution for.

apparentlymart commented 3 years ago

Thanks for sharing this use-case, @bcsgh.

While we're talking about existing solutions, I will also point out tfenv, which supports putting a .terraform-version file in your project directory to specify which version you intend to use with it.

I've not used tfswitch before myself, but from referring to its documentation it seems like it has a similar capability with a .tfswitchrc file.


While working on the dependency pinning problem in a recent release period I did start some research on this but ultimately concluded that it seems weird for Terraform CLI itself to be responsible for choosing which version of itself to run, because by the time Terraform CLI is running it's already, in a sense, "too late". However, I did consider making terraform init detect a .terraform-version file that seems to conflict with the current Terraform version and emit a warning, as a compromise to help folks who aren't using something like tfenv to recognize when they've selected the wrong version, while letting tfenv (or similar) make that automatic when installed.

I ended up not proceeding with that mainly because I ran out of research time and decided to focus only on provider dependency pinning for the first round, although now I see that tfswitch exists and has its own .tfswitchrc file and so if Terraform CLI were to start being aware of .terraform-version it would in a sense be "playing favorites". With that said though, I think one potential way to start here would be to try to define a standard way to signal that a particular working directory is locked to a particular Terraform version, and then in the interim existing tools like tfenv and tfswitch could make use of that standard, with Terraform CLI itself potentially paying attention to it later if we can find a reasonable technical and UX design for it to do so.

bcsgh commented 3 years ago

Thanks for the commentary and background. I suspect this is one of those cases where most of the complexity is in correctly defining the problem, and very little in actually implementing it.

The "tool picking the correct version of it self" problem would be avoided if the solution is a separate tool that is just invoked the same way. If there was a standard pattern for installing multiple version of terraform (e.g. put them all in the same directory named terrafrom.$FULL_VERSION) then it would be possible to make a tool (which would be put in the same directory and user could choose to name terraform) that is build using the same version inspection logic that the different version of terraform uses and that just identifies and exec the right version.

As noted in a prior comment, there is nothing hard about that other than correctly identifying the version to run. (And doing that quickly.) Having both tools maintained by the same people would help avoid Hyrum's law kind of problems which would simplify and stabilize things a lot.

apparentlymart commented 3 years ago

Hi @bcsgh! Thanks for those extra clarifications about your intent here.

I think what this ultimately comes down to is that there's only a limited amount of time we can practically spend working on fixes and improvements for Terraform, and so naturally we tend to prioritize spending time on problems not solved yet rather than problems that already have reasonable solutions, even if those reasonable solutions were built by others. We're grateful that folks in the community have spent the time building tools like tfenv and tfswitch, because they solve a real problem (which you identified well in this issue) and do so in a way that is mostly independent of what Terraform CLI itself does once run.

The divergence between .terraform-version and .tfswitchrc feels unfortunate to me here and so, as I was saying before, perhaps a practical short-term step here would be to encourage converging on a particular convention that Terraform CLI can therefore also have some straightforward awareness of. I'd love to hear from the tfenv and tfswitch maintainers about whether there are any practical concerns with that convergence, such as if tfenv and tfswitch are implementing slightly different behaviors that therefore benefit from their inputs being separated like this.

As you say, perhaps one day the Terraform team will also maintain a tool like this, but I want to be candid that it's unlikely that we'd prioritize such a thing in the short term simply due to the opportunity cost of doing so. My commentary here is aiming to find a compromise somewhere between these two extremes of doing nothing at all or creating an "official" single solution, so that we can try to make the existing answers work as well together with Terraform CLI as possible.

bcsgh commented 3 years ago

That you think this is something worth having, in some form, and are willing to leave this FR open as a placeholder for that desire is good enough for me. As to your priorities, they are yours to set. The only thing I can ask is that you continue to allow community interests to have some influence on the them.

Thanks.

stumyp commented 3 years ago

I second that, but from a bit different angle:

Currently terraform system packages (deb/rpm/etc) are coming with latest version on and multiple versions can not coexist.

What I would suggest is to have separate packages for teraform-0.12, terraform-0.13 terraform-0.14 etc, providing virtual package terraform and using update-alternatives command to manage where the /usr/bin/terraform points to.