Skip to content
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

state pull command doesn't have a -config flag #17378

Open
alexturek opened this issue Feb 18, 2018 · 8 comments
Open

state pull command doesn't have a -config flag #17378

alexturek opened this issue Feb 18, 2018 · 8 comments

Comments

@alexturek
Copy link

Terraform Version

Terraform v0.11.2
+ provider.datadog v1.0.3
+ provider.local v1.1.0

Terraform Configuration Files

terraform {
  backend "s3" {
    bucket  = "my-bucket-name"
    profile = "default"
    dynamodb_table = "TerraformLocks"
  }
}

Debug Output

aturek@aturek~mbpro ~/ops> TF_LOG=trace terraform state pull config
2018/02/17 21:37:04 [INFO] Terraform version: 0.11.2  a6008b8a48a749c7c167453b9cf55ffd572b9a5d
2018/02/17 21:37:04 [INFO] Go runtime version: go1.9.1
2018/02/17 21:37:04 [INFO] CLI args: []string{"/Users/aturek/ops/.tools/terraform", "state", "pull", "config"}
2018/02/17 21:37:04 [DEBUG] Attempting to open CLI config file: /Users/aturek/.terraformrc
2018/02/17 21:37:04 [DEBUG] File doesn't exist, but doesn't need to. Ignoring.
2018/02/17 21:37:04 [INFO] CLI command args: []string{"state", "pull", "config"}
2018/02/17 21:37:04 [DEBUG] command: loading backend config file: /Users/aturek/ops
2018/02/17 21:37:04 [INFO] command: backend config not found, returning nil: /Users/aturek/ops
2018/02/17 21:37:04 [INFO] command: no config, returning nil
2018/02/17 21:37:04 [TRACE] Preserving existing state lineage "826a0f5d-1ce4-45ea-857c-9c731692c282"
2018/02/17 21:37:04 [TRACE] Preserving existing state lineage "826a0f5d-1ce4-45ea-857c-9c731692c282"
2018/02/17 21:37:04 [DEBUG] plugin: waiting for all plugin processes to complete...
Backend reinitialization required. Please run "terraform init".
Reason: Unsetting the previously set backend "s3"

The "backend" is the interface that Terraform uses to store state,
perform operations, etc. If this message is showing up, it means that the
Terraform configuration you're using is using a custom configuration for
the Terraform backend.

Changes to backend configurations require reinitialization. This allows
Terraform to setup the new configuration, copy existing state, etc. This is
only done during "terraform init". Please run that command now then try again.

If the change reason above is incorrect, please verify your configuration
hasn't changed and try again. At this point, no changes to your existing
configuration or state have been made.

Failed to load backend: Initialization required. Please see the error message above.

Expected Behavior

I would hope (although this isn't documented) that terraform state pull would accept some sort of argument to tell it where to look for .tf files, and output my state from S3.

Actual Behavior

Terraform sees the disconnect between the seemingly unconfigured backend, and my .terraform/terraform.tfstate which says I have an S3 backend, and asks for an init.

Steps to Reproduce

  1. Create a folder structure like this
project/
project/config/main.tf (containing an S3 backend)
  1. terraform init config (should work if the S3 bucket/configuration is set up correctly)
  2. terraform state pull (should fail with above error)

References

@jbardin
Copy link
Member

jbardin commented Feb 19, 2018

Hi @alexturek,

It's a known issue that some of the commands that take positional arguments don't also take the legacy config path as an argument. Because Terraform is configured relative to the working directory, it's usually recommended to run it from the root of the config. Running Terraform on disparate configurations from the same directory can cause a number of confusing issues with state and providers.

We are planning on cleaning up the cli UI in an upcoming release to address these issues.

@walterdolce
Copy link
Contributor

With regards to #20382 (comment) and to:

[...] it's usually recommended to run it from the root of the config. Running Terraform on disparate configurations from the same directory can cause a number of confusing issues with state and providers. [...]

I see, but I disagree. The above assumes Terraform is the only tool to be used within a project. But a project may not be a Terraform project per-se. It could be made of different supporting tools.

What if you are using Ansible and Terraform in the same project? What if you even add InSpec in the picture?

Would you keep your project files as follows?

controls/     # This belongs to InSpec
host_vars/    # This belongs to Ansible
libraries/    # This belongs to InSpec
modules/      # This belongs to Terraform
roles/        # This belongs to Ansible
src/          # A python app? PHP app? Doesn't matter
ansible.cfg   # This belongs to Ansible
Gemfile       # App dependencies, if this is a Ruby app?
inspec.yml    # This belongs to InSpec
main.tf       # This belongs to Terraform
playbook.yml  # This belongs to Ansible
vpc.tf        # This belongs to Terraform

The above is a mess.

I would rather keep files as follows instead (YMMV):

src/             # A python app? PHP app? Doesn't matter
tools/
    ansible/
        host_vars/   # This belongs to Ansible
        roles/       # This belongs to Ansible
        playbook.yml # This belongs to Ansible
    inspec/
        controls/    # This belongs to InSpec
        libraries/   # This belongs to InSpec
        inspec.yml   # This belongs to InSpec
    terraform/
        modules/     # This belongs to Terraform
        main.tf      # This belongs to Terraform
        vpc.tf       # This belongs to Terraform
ansible.cfg          # This belongs to Ansible
Gemfile              # App dependencies, if this is a Ruby app?

The above looks much more cleaner to me. Note how the root folder only contains base config stuff.

I think this is a valid use case for being able to:

terraform plan tools/terraform/
terraform apply tools/terraform/

..from the root of the project.

Then you can do things like:

ansible-playbook tools/ansible/playbook.yml

And then:

inspec exec tools/inspec

...without having to [remember to] cd all over the place.

With regards to the following, specifically:

Running Terraform on disparate configurations from the same directory can cause a number of confusing issues with state and providers.

I am not sure. But I would expect providers or modules would stick to what is the "terraform base directory", which in the case above is tools/terraform/ (or [DIR] as already provided).
If that's not the case, then perhaps someone hasn't done the home works? :P

I hope this gives enough information (that hopefully make sense) to build a case for not deprecating the [DIR] parameter but, on the contrary, to implement it for all commands.

PS: One thing I would probably not do or like to have is to have Terraform remember the "configuration directory" as stated in #15934. I am in favour of having to be explicit when it comes to running Terraform commands in general.

@deeco
Copy link

deeco commented Aug 13, 2019

I have this exact issue in azure devops pipeline, state file is stored in backend and when look to read it examines the root under .terraform folder after an init is ran

@teamterraform
Copy link
Contributor

The recommended way to run Terraform in the directory structure given above is:

cd tools/terraform
terraform apply

Each working directory can only be initialized for one configuration at a time, so while these legacy compatibility arguments for setting the subdirectory can work as long as there's only one Terraform root module in your project, you'd run into problems if there were ever more than one because terraform init terraform-1 would initialize the root directory for the terraform-1 config, and then terraform init terraform-2 would think you're asking it to reinitialize with a different backend configuration and will prompt you to migrate the state.


The change we're considering for the future is to make it so that only terraform init accepts a config directory argument, and then every other command uses whatever directory was given to terraform init. That way it forces consistency in which directories are used in multiple commands and avoids the risk of accidentally selecting the wrong directories when running multiple commands. In that case, terraform init terraform-1 would cause any subsequent terraform apply to automatically work with terraform-1 as the root directory.

We do not plan to add configuration directory override arguments to any more commands, because real-world experience has shown that it is very error-prone to use Terraform in that way right now and easy to take bad actions that you didn't intend.

@uritau
Copy link

uritau commented Oct 10, 2019

Thanks for your attention on this issue @jbardin .
Just to add some extra use cases:

In order to reduce the number of duplicated code and to simplify the the different environments maintenance, we are following this approach:

app1/
    manifests/
        backend.tf     # S3 Backend configuration (with no defined key)
        modules.tf     # Calls to modules (they are in another repos)
        locals.tf     
        output.tf     
        variables.tf
    environment1/
        bakend-environment1.tfvars     # Only The S3 backend key configuration
        environment1.tfvars                  # "Environment customization" of the variables
    environment2/
        bakend-environment2.tfvars     # Only The S3 backend key configuration
        environment2.tfvars                  # "Environment customization" of the variables

How we use this:

# Enter in the environment folder
cd app1/staging

# Init tfstate
terraform init -backend-config=backend.tfvars ../manifests

# Apply configuration
terraform apply -var-file=staging.tfvars ../manifests/

With this approach we are able to reduce the inconsistency between environments, and we avoid the problems of launching more than 1 environment from the same folder. But we are facing the issues with terraform state and terraform output.

As far as we understand the docu this is a "good practice" (or at least not a "bad practice"),because we are facing the same issues like @alexturek and other posters we started to doubt it.
So, if using terraform init outside the main folder it's a bad practice, two questions:

  • Is there a place where we can open a PR to update the documentation?
  • Do you have some references/guidance on how to not repeat the code between environments?

Thanks again for your help and your efforts!!

@jonathangreen
Copy link

Just want to chime in to +1 @uritau comments here. We independently came up with almost the exact same directory structure. The works well for us in most cases, but causes issues with state commands.

If this sort of file layout will not be supported by terraform in the future it would be nice to have some guidance about another way to achieve the same goal of not repeating code between environments.

@mikesimons
Copy link

We have a very similar structure & use case to @jonathangreen & @uritau as it's the only way we've found to avoid divergence between environments; one copy of the code parameterized per env.

I think the suggestion in #17378 (comment) would work nicely for this setup though since terraform commands would always be executed from the "env" folders which contain the .terraform directories anyway.

@jonathangreen
Copy link

Is there any update or open issue for making terraform init accept a config directory argument? I was hoping to see that as a change in 0.13, but it doesn't seem like it made the cut. I tried searching the issue queue, but this is the only issue I found.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants