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.78k stars 9.56k forks source link

Unexpected behavior when creating cache for local modules (symlink to + copies of module) #23031

Open agrzegorczyk-leonsoftware opened 5 years ago

agrzegorczyk-leonsoftware commented 5 years ago

Terraform Version

Terraform v0.12.10

Terraform Configuration Files

/home/devops
├── infrastructure
│   └── main.tf
└── modules
    └── test
        └── empty.tf
# infrastructure/main.tf:
module "a" {
  source = "/home/devops/modules/test"
}

module "b" {
  source = "/home/devops/modules/test"
}

module "c" {
  source = "/home/devops/modules/test"
}

https://leon-downloads.s3-eu-west-1.amazonaws.com/devops/github/012modules.tar.gz

Debug Output

terraform init ``` 2019/10/08 17:59:39 [INFO] Terraform version: 0.12.10 2019/10/08 17:59:39 [INFO] Go runtime version: go1.12.9 2019/10/08 17:59:39 [INFO] CLI args: []string{"/usr/local/bin/terraform", "init"} 2019/10/08 17:59:39 [DEBUG] Attempting to open CLI config file: /home/geck/.terraformrc 2019/10/08 17:59:39 [DEBUG] File doesn't exist, but doesn't need to. Ignoring. 2019/10/08 17:59:39 [INFO] CLI command args: []string{"init"} Initializing modules... 2019/10/08 17:59:39 [TRACE] ModuleInstaller: installing child modules for . into .terraform/modules 2019/10/08 17:59:39 [DEBUG] Module installer: begin a 2019/10/08 17:59:39 [TRACE] ModuleInstaller: a is not yet installed 2019/10/08 17:59:39 [TRACE] ModuleInstaller: cleaning directory .terraform/modules/a prior to install of a 2019/10/08 17:59:39 [TRACE] ModuleInstaller: a address "/home/devops/modules/test" will be handled by go-getter 2019/10/08 17:59:39 [DEBUG] will download "/home/devops/modules/test" to .terraform/modules/a Downloading /home/devops/modules/test for a... 2019/10/08 17:59:39 [TRACE] go-getter detectors rewrote "/home/devops/modules/test" to "file:///home/devops/modules/test" 2019/10/08 17:59:39 [TRACE] fetching "file:///home/devops/modules/test" to ".terraform/modules/a" 2019/10/08 17:59:39 [TRACE] ModuleInstaller: a "/home/devops/modules/test" was downloaded to .terraform/modules/a 2019/10/08 17:59:39 [DEBUG] Module installer: a installed at .terraform/modules/a - a in .terraform/modules/a 2019/10/08 17:59:39 [DEBUG] Module installer: begin b 2019/10/08 17:59:39 [TRACE] ModuleInstaller: b is not yet installed 2019/10/08 17:59:39 [TRACE] ModuleInstaller: cleaning directory .terraform/modules/b prior to install of b 2019/10/08 17:59:39 [TRACE] ModuleInstaller: b address "/home/devops/modules/test" will be handled by go-getter Downloading /home/devops/modules/test for b... 2019/10/08 17:59:39 [DEBUG] will download "/home/devops/modules/test" to .terraform/modules/b 2019/10/08 17:59:39 [TRACE] go-getter detectors rewrote "/home/devops/modules/test" to "file:///home/devops/modules/test" 2019/10/08 17:59:39 [TRACE] copying previous install .terraform/modules/a to .terraform/modules/b 2019/10/08 17:59:39 [TRACE] ModuleInstaller: b "/home/devops/modules/test" was downloaded to .terraform/modules/b 2019/10/08 17:59:39 [DEBUG] Module installer: b installed at .terraform/modules/b - b in .terraform/modules/b 2019/10/08 17:59:39 [DEBUG] Module installer: begin c 2019/10/08 17:59:39 [TRACE] ModuleInstaller: c is not yet installed 2019/10/08 17:59:39 [TRACE] ModuleInstaller: cleaning directory .terraform/modules/c prior to install of c 2019/10/08 17:59:39 [TRACE] ModuleInstaller: c address "/home/devops/modules/test" will be handled by go-getter Downloading /home/devops/modules/test for c... 2019/10/08 17:59:39 [DEBUG] will download "/home/devops/modules/test" to .terraform/modules/c 2019/10/08 17:59:39 [TRACE] go-getter detectors rewrote "/home/devops/modules/test" to "file:///home/devops/modules/test" 2019/10/08 17:59:39 [TRACE] copying previous install .terraform/modules/a to .terraform/modules/c 2019/10/08 17:59:39 [TRACE] ModuleInstaller: c "/home/devops/modules/test" was downloaded to .terraform/modules/c - c in .terraform/modules/c Initializing the backend... 2019/10/08 17:59:39 [DEBUG] Module installer: c installed at .terraform/modules/c 2019/10/08 17:59:39 [TRACE] modsdir: writing modules manifest to .terraform/modules/modules.json 2019/10/08 17:59:39 [TRACE] Meta.Backend: no config given or present on disk, so returning nil config 2019/10/08 17:59:39 [TRACE] Meta.Backend: backend has not previously been initialized in this working directory 2019/10/08 17:59:39 [DEBUG] New state was assigned lineage "149e705b-17e1-d737-3932-325c45c81f32" 2019/10/08 17:59:39 [TRACE] Meta.Backend: using default local state only (no backend configuration, and no existing initialized backend) 2019/10/08 17:59:39 [TRACE] Meta.Backend: instantiated backend of type 2019/10/08 17:59:39 [DEBUG] checking for provider in "." 2019/10/08 17:59:39 [DEBUG] checking for provider in "/usr/local/bin" 2019/10/08 17:59:39 [DEBUG] checking for provisioner in "." 2019/10/08 17:59:39 [DEBUG] checking for provisioner in "/usr/local/bin" 2019/10/08 17:59:39 [INFO] Failed to read plugin lock file .terraform/plugins/linux_amd64/lock.json: open .terraform/plugins/linux_amd64/lock.json: no such file or directory 2019/10/08 17:59:39 [TRACE] Meta.Backend: backend does not support operations, so wrapping it in a local backend 2019/10/08 17:59:39 [TRACE] backend/local: state manager for workspace "default" will: - read initial snapshot from terraform.tfstate - write new snapshots to terraform.tfstate - create any backup at terraform.tfstate.backup 2019/10/08 17:59:39 [TRACE] statemgr.Filesystem: reading initial snapshot from terraform.tfstate 2019/10/08 17:59:39 [TRACE] statemgr.Filesystem: snapshot file has nil snapshot, but that's okay 2019/10/08 17:59:39 [TRACE] statemgr.Filesystem: read nil snapshot 2019/10/08 17:59:39 [DEBUG] checking for provider in "." 2019/10/08 17:59:39 [DEBUG] checking for provider in "/usr/local/bin" ```

Crash Output

N/A

Expected Behavior

All of referenced modules symlinked (preferably) or copied to local .terraform/modules cache.

Actual Behavior

Terraform during initialization creates one symlink to source of a module and additional 2 copies of it. Exact numer on copies depends of quantity of the module instances Happens when module source is absolute path to local directory (outside the main terraform working dir).

/home/devops
├── infrastructure
│   ├── .terraform
│   │   └── modules
│   │       ├── a -> /home/devops/modules/test # symlink
│   │       ├── b # copy
│   │       │   └── empty.tf
│   │       ├── c # copy
│   │       │   └── empty.tf
│   │       └── modules.json
│   └── main.tf
└── modules
    └── test
        └── main.tf

Steps to Reproduce

terraform init

Additional Context

References

landintrees commented 4 years ago

This has caught us out a few times by exhibiting quite confusing behaviour when a change is made in a module source that is then not pulled into calling modules greater than 1.

For instance, after adding a new variable "cosmosdb_resource_group" to a module definition, the first caller works fine (because it is symlinked), but the 2nd and 3rd error (because they are copies):

Error: Unsupported argument on main.tf line 116, in module "module_2": 116: cosmosdb_resource_group = local.cosmosdb_resource_group

hayorov commented 4 years ago

Due to closed https://github.com/hashicorp/terraform/issues/11435 I'd like to slightly offtopic and share a small pre-terraform routine utility that optimize init (modules download) for git modules https://github.com/hayorov/terraform-init-booster