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

"Unknown provider" when upgrading to 0.13 with a non-default state file name #25920

Closed
kmoe opened this issue Aug 19, 2020 · 6 comments
Closed
Assignees
Labels
confirmed a Terraform Core team member has reproduced this issue documentation explained a Terraform Core team member has described the root cause of this issue in code

Comments

@kmoe
Copy link
Member

kmoe commented Aug 19, 2020

Terraform 0.13 commands cannot be run on a state file created under Terraform 0.12 with a non-default name, because the provider FQNs are not migrated.

Terraform Version

terraform012: 0.12.29
terraform013: 189f9fa (0.13.1-dev)

Terraform Configuration Files

resource null_resource "foo" {
}

Steps to Reproduce

  1. terraform012 init
  2. terraform012 apply -state=foo
  3. terraform013 init
  4. terraform013 apply -state=foo

Expected Behavior

All commands should be successful.

Without -state=foo, i.e. using the default state file name, this works.

Actual Behavior

Init is successful, but final apply is not:

❤ @up ➜  tfbug  $GOPATH/bin/terraform apply -state=foo

Error: Could not load plugin


Plugin reinitialization required. Please run "terraform init".

Plugins are external binaries that Terraform uses to access and manipulate
resources. The configuration provided requires plugins which can't be located,
don't satisfy the version constraints, or are otherwise incompatible.

Terraform automatically discovers provider requirements from your
configuration, including providers used in child modules. To see the
requirements and constraints, run "terraform providers".

Failed to instantiate provider "registry.terraform.io/-/null" to obtain
schema: unknown provider "registry.terraform.io/-/null"

All other commands involving the state file, such as terraform show foo, also fail.

State file

After performing all four steps, the state file is:

❤ @up ➜  tfbug  cat foo
{
  "version": 4,
  "terraform_version": "0.12.29",
  "serial": 1,
  "lineage": "f88b2c1c-b8ee-ab86-f4b5-0bd49bda07fd",
  "outputs": {},
  "resources": [
    {
      "mode": "managed",
      "type": "null_resource",
      "name": "foo",
      "provider": "provider.null",
      "instances": [
        {
          "schema_version": 0,
          "attributes": {
            "id": "5921273781850838351",
            "triggers": null
          },
          "private": "bnVsbA=="
        }
      ]
    }
  ]
}

This is despite the correct provider being present in the .terraform directory as detected from config.

@kmoe kmoe added bug new new issue not yet triaged labels Aug 19, 2020
@mildwonkey mildwonkey added the confirmed a Terraform Core team member has reproduced this issue label Aug 19, 2020
@mildwonkey mildwonkey self-assigned this Aug 19, 2020
@mildwonkey
Copy link
Contributor

I'm still working out the precise details, but this relates to the fact that terraform init does not support the -state=foo option. To be honest, we would like to deprecate that option in the future, as its inconsistency frequently causes issues much like this one.

I'm not sure if this workaround is useful for your situation, but if you want to use an alternative state path without having to use -state=foo (and without ending up in this situation), you can configure the local backend instead:

terraform {
  backend "local" {
    path = "foo"
  }
}

The difference between using the flag vs. using the backend is that terraform stores the backend configuration in a pseudo-statefile, and terraform init parses that to find (among other things) the correct state path:

cat .terraform/terraform.tfstate
{
    "version": 3,
    "serial": 1,
    "lineage": "b20c55c3-040e-25a2-057c-b0affd9dca1a",
    "backend": {
        "type": "local",
        "config": {
            "path": "foo",
            "workspace_dir": null
        },
        "hash": 2173512942
    },
    "modules": [
        {
            "path": [
                "root"
            ],
            "outputs": {},
            "resources": {},
            "depends_on": []
        }
    ]
}

@mildwonkey mildwonkey added documentation explained a Terraform Core team member has described the root cause of this issue in code and removed bug new new issue not yet triaged labels Aug 19, 2020
@mildwonkey
Copy link
Contributor

After some more digging, and an internal discussion about the workaround, I am going to re-label this as a documentation issue, since we aren't going to add the -state= flag to init.
It's not documented as such, but the -state= flag is not designed for constant use: it's a convenience flag for one-off use cases. If a user needs an alternate state file for every run - something that init is aware of - they will need to use the local backend.

Perhaps we could start by just adding some words to the docs describing these options as "legacy" and not well supported, and also call out the backend option for folks who are using this to declare an alternate state file path for all runs.

@mildwonkey
Copy link
Contributor

It's not much, but I just added some words to the apply docs to call out the fact that using the -state flag does not persist that setting, and so other commands (like init) may behave in unexpected ways.

@voidmain
Copy link

voidmain commented Sep 16, 2020

Hi @mildwonkey. I'm having a similar issue but my issue is that I cannot run terraform destroy using version 0.13.2 when the tfstate file is from version 0.12.x. I get this error and I'm not able to determine how to tell Terraform to initialize the working directly such that it can install the correct plugins.

UPDATE: Here's my output from the destroy command:

Error: Could not load plugin


Plugin reinitialization required. Please run "terraform init".

Plugins are external binaries that Terraform uses to access and manipulate
resources. The configuration provided requires plugins which can't be located,
don't satisfy the version constraints, or are otherwise incompatible.

Terraform automatically discovers provider requirements from your
configuration, including providers used in child modules. To see the
requirements and constraints, run "terraform providers".

3 problems:

- Failed to instantiate provider "registry.terraform.io/-/aws" to obtain
schema: unknown provider "registry.terraform.io/-/aws"
- Failed to instantiate provider "registry.terraform.io/-/null" to obtain
schema: unknown provider "registry.terraform.io/-/null"
- Failed to instantiate provider "registry.terraform.io/-/statuscake" to
obtain schema: unknown provider "registry.terraform.io/-/statuscake"

Any insight you can provide would be awesome!

@voidmain
Copy link

voidmain commented Sep 18, 2020

Just thought I would leave an update. I figured out how to make this work. Our TF state files were stored in a database and then we have a process to query them, write them to disk and then fork-exec Terraform using those files. To fix this, I added some code that would search and replace all of the 0.12 provider definitions with the 0.13 definitions. I also updated the Terraform scripts to include these providers using the new fully qualified naming system along with the correct versions we needed.

Once I cleared out the broken versions.tf files and re-ran terraform init, everything is working nicely!

Here's my Java code to do the search and replace:

String tfState = deployment.tfState.replace("provider.null", "provider[\\\"registry.terraform.io/hashicorp/null\\\"]")
                                   .replace("provider.aws", "provider[\\\"registry.terraform.io/hashicorp/aws\\\"]")
                                   .replace("provider.statuscake", "provider[\\\"registry.terraform.io/terraform-providers/statuscake\\\"]");

And here's my update to the main.tf files:

//
// Terraform config
//
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 3.1"
    }
    null = {
      source  = "hashicorp/null"
      version = "~> 2.1"
    }
    statuscake = {
      source  = "terraform-providers/statuscake"
      version = "~> 1.0"
    }
  }
  required_version = "~> 0.13.2"
}

@ghost
Copy link

ghost commented Oct 10, 2020

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.

@ghost ghost locked as resolved and limited conversation to collaborators Oct 10, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
confirmed a Terraform Core team member has reproduced this issue documentation explained a Terraform Core team member has described the root cause of this issue in code
Projects
None yet
Development

No branches or pull requests

3 participants