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

Terraform get only symlinks first instance of locally sourced module #22499

Open acobaugh opened 5 years ago

acobaugh commented 5 years ago

Terraform Version

Terraform v0.12.6

Terraform Configuration Files

module "cdn" {
  source = "/home/acobaugh/work/eit/terraform-modules/tf-aws-swe-cdn"
  # other config
}

module "developer" {
  source = "/home/acobaugh/work/eit/terraform-modules/tf-aws-swe-cdn"
  # other config
}

Debug Output

https://gist.github.com/acobaugh/656d671c13adfa83a3492ceb0bfe188f

Crash Output

Expected Behavior

terraform get and terraform init should create symlinks for every instance of locally sourced modules so that updating the module source lead to consistent behavior across all module instances, not just the first one.

Actual Behavior

Only the first instance of the module is symlinked. Others are copied.

% ls -l .terraform/modules                                                                                                                                                        (master|✚2…)
total 16
drwx------ 3 acobaugh acobaugh 4096 Aug 17 00:54 acm
lrwxrwxrwx 1 acobaugh acobaugh   56 Aug 17 01:01 cdn -> /home/acobaugh/work/eit/terraform-modules/tf-aws-swe-cdn
drwx------ 3 acobaugh acobaugh 4096 Aug 17 00:54 cdn-user
drwx------ 2 acobaugh acobaugh 4096 Aug 17 01:01 developer
-rw------- 1 acobaugh acobaugh  578 Aug 17 01:01 modules.json

Steps to Reproduce

Create two instances of a module from a local path. Observe that all instances besides the first require a terraform get -update to see changes to that module, whereas the first will "Just Work".

Additional Context

References

teamterraform commented 5 years ago

Hi @acobaugh!

This is an interesting situation where a few different Terraform module installation behaviors are interacting in a strange way.

Per its design, Terraform is supposed to treat an absolute filesystem path like that as if it were a "remote" source, copying the source directory under .terraform/modules so that everything Terraform needs for this configuration is available at a reasonable relative path from the configuration root, but it seems like it is misbehaving here and creating a symlink for the first one. That is likely because of a special case in the underlying remote module fetching library go-getter.

The reason it only does this for the first module is that Terraform also has a behavior where it tries to avoid re-downloading the same module multiple times by instead copying the local directory for each new module coming from the same source. For this absolute local path "downloading" is currently implemented as making a symlink per the above, but because Terraform knows it already "downloaded" that directory it's instead creating a deep copy, flattening out any symlinks along the way.

Per the design of the module installer, the bug here is that there are any symlinks there at all. Instead, even the first of those ought to be a copy, so that the resulting .terraform/modules directory doesn't contain any references to absolute paths that are specific to your current machine.

With all of that said, the usual way to refer to local directories is via relative paths starting with either ./ or ../, in which case Terraform will neither symlink nor copy them. Instead, it'll just refer to them in-place where they are, because they are then considered to belong to the same "package" as the caller. Unless there is an unusual reason why you need to use absolute paths, we'd suggest switching to relative paths between your modules and thus access these modules directly in-place.

dcfsc commented 1 year ago

In my module development, I have two repositories open in two editor windows, one the test configuration, the other the module source. I make changes to the module repo, then flip back to the test.

The source uses the absolute path to reference the module code, for example:

module function {
  source = "/projects/terraform/terraform-module-mystuff"

Normally this works great, as when I modify the files in the module repo, the changes are immediately visible in the test configuration, and I can immediately run plan or apply using the new module changes.

My current project contains 4 instances of the same module, and I noticed that editing the module code did not affect all the test configurations -- they still used the old code. One instance was tied to a symlink, and that one instance tracked the module repository code.

I am surprised to see that the most helpful behavior of Terraform for me in helping to speed my development of module code is actually a defect. I would vote for an option that told Terraform to symlink EVERY local reference, but in a production situation, use whatever optimizations are appropriate.

I could use a relative path, but these test configurations are in different places, and the path would change between them. When this defect gets "fixed", I suppose I will need to do that. I may try it now to fix my 4 instance problem.