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.31k stars 9.49k forks source link

Fast-changing terraform modules - tracking module git commit? #4234

Closed james-masson closed 1 month ago

james-masson commented 8 years ago

Consider this terraform workflow:

A team of people are updating a centralised terraform module repo - making frequent improvements.

Another team of people are consumers of these modules, deploying infrastructure sets using these modules. These environments are long-lived. The consumers have no write access to the module codebase.

  1. Consumer team member 1 deploys an environment, from HEAD/master of the modules, commits the tfstate back to a team repository.
  2. Time passes - lots of commits are made to the modules upstream
  3. Consumer team member 2 has to destroy the previously created environment.
  4. Consumer team member 2 does a terraform get, gets the latest HEAD/master modules code
  5. terraform apply/plan/destroy will not function, because of the significant difference in module code.

There isn't a function in terraform to link the module version ( git commit? branch? ) used to the state file generated, so the previous TF state / TF code match is guesswork. Committing the .terraform local module checkout directory to git is discouraged - https://www.terraform.io/docs/commands/get.html

Right now, you're probably thinking about the module source directive... - https://www.terraform.io/docs/modules/sources.html

module "consul" {
    source = "git::https://hashicorp.com/module.git?ref=master"
}

This would allow the consumers to pin the particular environment deployed to a particular upstream module commit. Because consumers have no write access to modules, to create branches / tags, only git commit references could be used here.

This has the side effect of making the module use a bit of a snowflake, if used natively with Terraform.

module "blah" {
    source = "git::ssh://git@bitbucket.org/foo/bar//baz?ref=4a2d42"

    var1 = "${var.var1}"
    var2 = "${var.var2}"
    var3 = "${var.var3}"

    var4 = "${var.var4}"
    var5 = "${var.var5}"

    var6 = "${var.var6}"
    var7 = "${var.var7}"
    var8 = "${var.var8}"
    var9 = "${var.var9}"
    ....
    var20 = "${var.var20}"
}

This module use code would be 99% the same across deployed environments, but only the git ref would change. Unlike the module input variables, this cannot be templated - https://github.com/hashicorp/terraform/issues/1439 - Hence it would have to be committed separately for each environment, and is likely to accidentally diverge.

Another possibility is another level of intermediate modules, but this leads us to have to pass in many more parameters than should ideally be necessary - https://github.com/hashicorp/terraform/issues/4015

This has lead us to develop our own templating system for creating the terraform code/variables that consumes the modules.

We've also added this hack into our modules, to store the module git version inside the tfstate - so we can manually reconstruct the module version / state match.

# This is used to store the current git state/commit
# in the tfstate file, for future reference
resource "template_file" "gitversion" {
    template = "${file("${path.module}/.git/logs/HEAD")}"
}

What we're after is a feel of what Hashicorp's current best practice is, and also any other tips & tricks people are using to manage codebases like ours.

Any thoughts?

As an example of an improvement - having the last used module version information stored natively in tfstate eg.

    "modules": [
        {
            "path": [
                "root"
            ],
            "outputs": {},
            "resources": {}
        },
        {
            "path": [
                "root",
                "mgt"
            ],
            "version": "b48817faee9f34790ad73f12f46fd8b76a98ab5e"

and restored properly with terraform get - would be very helpful.

apparentlymart commented 8 years ago

Coincidentally I had just the same thought a few hours ago and was pleasantly surprised to find it already written up in detail when I got here. Thanks!

My specific issue (which is a subset of what you described, I think) is that if you want to destroy an infrastructure it's necessary to use a very similar config than was used to create it. We have a bunch of similar infrastructures built from the same config (using variables and multiple remote states) and today I was cleaning up a number of them in bulk. Some of them were pretty stale due to not being kept up-to-date with the latest config changes, and so it took me quite some time to locate the appropriate config commits to use to successfully destroy each of them, so that the right provider configurations would be present to allow the refresh/plan/destroy.

Recording the git commit id in the state would've saved me here, since I would know exactly which commit to wind back to.

There is, as always, the issue of how to represent a dirty git tree where changes haven't yet been committed, but I could accept a "dirty tree" flag that tells me that I might actually need to use the following commit, if the changes were commited only after the change was applied -- which happens often in development environments.

Edit: actually on second reading it looks like you are primarily concerned with non-root modules. So I guess my comment above is a request for it to work at the root as well. :grinning:

sl1pm4t commented 8 years ago

We are facing a very similar problem with our use case. Fortunately in our case, the team writing to Git repo are aware of the downstream consumers problem and have been creating tags. We have another tool that generates the module stubs, and populates the module source ref field with the latest tag.

ozbillwang commented 7 years ago

So any updates for this issue, can we have a lock file , similar as ansible galaxy's requirements.yml, that easily lock to commit/version/tag when source the module in terraform?

CalebMacdonaldBlack commented 6 years ago

I would like to see this aswell

ooglek commented 6 years ago

👍 +1 Dependency resolution is a giant pain, and what works today should work 6-12 months from now, short of a provider deprecating APIs. The module that successfully deployed the infrastructure should be the same version, same code, as when you have to update or apply it 6 months from now.

We already commit our vendor dependencies with our Golang projects because of the inability to lock dependencies at a version (you can but it is a pain and if the upstream dev deletes the code, you're hosed unless you have a local copy).

Until this exists, and heck even if it does exist, including the .terraform directories in your repo seems like the safest way to ensure your config today works tomorrow, despite admonishment not to. The docs should probably change to reflect this subtlety that some may not consider.

eedwards-sk commented 5 years ago

This is still desired in TF 0.12+

I want to be able to know what git commits terraform checked out. I have terraform monorepos with modules in them getting used in CI. The commits are regularly changing between each run. I don't know what commit terraform is going to use until it runs, and even then, I don't know what commit it uses.

I can target specific commit sha's for e.g. production environments, but it makes promotion much more manual (and since we still can't dynamically set the commit sha for module source either).

Let me dump an output or similar with the module commits :)

sfc-gh-tbacon commented 4 years ago

Any updates on this front? I'm trying to figure out the best way to expose the version of the module source used to configure some infrastructure, and this seems like the most straightforward.

danieldreier commented 4 years ago

@sfc-gh-tbacon no updates - our current priority is wrapping up 0.13 work and finding/fixing bugs in the new functionality we're introducing, and no work related to this enhancement request is going into 0.13.0.

Mr-Saikiran commented 1 month ago

if anyone looking at this thread ### This feature is working now

crw commented 1 month ago

Closing as duplicate of https://github.com/hashicorp/terraform/issues/31301

Despite this issue being older, the more current discussion and thinking on this topic is in the above-referenced issue. Module pinning is not yet implemented, and that seems to be the extant feature request being specified in this issue. Thanks!

github-actions[bot] commented 6 days ago

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.