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

Failed to install providers for proxied external providers, e.g. cloudflare #26448

Closed
ChristophShyper opened this issue Oct 1, 2020 · 17 comments · Fixed by #27739
Closed

Failed to install providers for proxied external providers, e.g. cloudflare #26448

ChristophShyper opened this issue Oct 1, 2020 · 17 comments · Fixed by #27739
Labels
bug documentation explained a Terraform Core team member has described the root cause of this issue in code v0.13 Issues (primarily bugs) reported against v0.13 releases

Comments

@ChristophShyper
Copy link

ChristophShyper commented Oct 1, 2020

Terraform Version

0.13.3

Terraform Configuration Files

./main.tf:

terraform {
  backend "local" {}

  required_version = "0.13.3"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 3"
    }

    cloudflare = {
      source  = "cloudflare/cloudflare"
      version = "~> 2"
    }

    external = {
      source  = "hashicorp/external"
      version = "~> 1.2"
    }
  }
}

provider "aws" {
  region = "eu-west-1"
}

provider "cloudflare" {}

provider "external" {}

module "submodule" {
  source = "./submodule"

  providers = {
    aws                     = aws
    cloudflare              = cloudflare
    external                = external
  }

  (...)
}

(...)

./submodule/main.tf:

terraform {
  backend "local" {}

  required_version = "0.13.3"
}

provider "aws" {
}

provider "cloudflare" {
}

provider "external" {
}

(...)

Debug Output

Crash Output

$> terraform init; terraform validate;

Initializing modules...

Initializing the backend...

Initializing provider plugins...
- Using previously-installed hashicorp/external v1.2.0
- Using previously-installed hashicorp/null v2.1.2
- Using previously-installed hashicorp/template v2.1.2
- Using previously-installed hashicorp/aws v3.8.0
- Using previously-installed cloudflare/cloudflare v2.11.0
- Finding latest version of hashicorp/cloudflare...

Error: Failed to install providers

Could not find required providers, but found possible alternatives:

  hashicorp/cloudflare -> cloudflare/cloudflare

If these suggestions look correct, upgrade your configuration with the
following commands:
    terraform 0.13upgrade submodule


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/hashicorp/cloudflare" to
obtain schema: unknown provider "registry.terraform.io/hashicorp/cloudflare"

Expected Behavior

Proxied external providers (not the ones from hashicorp/... should work the same as the hashicrop's ones) should be passed properly and just work.

Actual Behavior

It fails the validation, because provider is not passed properly to submodules.

Steps to Reproduce

  1. terraform init
  2. terraform validate

Additional Context

If I add required_providers just for cloudflare it starts to work.
./submodule/main.tf:

terraform {
  backend "local" {}

  required_version = "0.13.3"

    required_providers {
      cloudflare = {
        source  = "cloudflare/cloudflare"
        version = "~> 2"
      }
    }
}

provider "aws" {
}

provider "cloudflare" {
}

provider "external" {
}

(...)

References

@ChristophShyper ChristophShyper added bug new new issue not yet triaged labels Oct 1, 2020
@apparentlymart
Copy link
Contributor

Hi @ChristophShyper!

It seems like you've already found the solution to this problem, which is to declare in your submodule that the local name cloudflare refers to cloudflare/cloudflare. That is also what the terraform 0.13upgrade submodule command that terraform init suggested would've done for you automatically in order to fix it.

From what you've said here it seems like you now have a working configuration, so I'm not sure what else remains to be done with this issue. Did you run into some other problem after you added that missing dependency declaration?

@apparentlymart apparentlymart added the waiting-response An issue/pull request is waiting for a response from the community label Oct 2, 2020
@ChristophShyper
Copy link
Author

So it's expected behaviour that only some providers can be proxied? Shouldn't that be mentioned in the documentation?

@nlloyd-invitae
Copy link

nlloyd-invitae commented Nov 9, 2020

Initializing provider plugins...
- terraform.io/builtin/terraform is built in to Terraform
- Finding hashicorp/null versions matching "2.1.2"...
- Finding hashicorp/template versions matching "2.1.2"...
- Finding hashicorp/vault versions matching "2.7.0"...
- Finding latest version of hashicorp/healthchecksio...
- Finding kristofferahl/healthchecksio versions matching "1.6.3"...
- Finding hashicorp/aws versions matching "2.61.0"...
- Finding hashicorp/local versions matching "1.3.0"...
- Installing hashicorp/null v2.1.2...
- Installed hashicorp/null v2.1.2 (signed by HashiCorp)
- Installing hashicorp/template v2.1.2...
- Installed hashicorp/template v2.1.2 (signed by HashiCorp)
- Installing hashicorp/vault v2.7.0...
- Installed hashicorp/vault v2.7.0 (signed by HashiCorp)
- Installing kristofferahl/healthchecksio v1.6.3...
- Installed kristofferahl/healthchecksio v1.6.3 (self-signed, key ID 8F12D887C063E3E4)
- Installing hashicorp/aws v2.61.0...
- Installed hashicorp/aws v2.61.0 (signed by HashiCorp)
- Installing hashicorp/local v1.3.0...
- Installed hashicorp/local v1.3.0 (signed by HashiCorp)

Partner and community providers are signed by their developers.
If you'd like to know more about provider signing, you can read about it here:
https://www.terraform.io/docs/plugins/signing.html

Error: Failed to install provider

Error while installing hashicorp/healthchecksio: provider registry
registry.terraform.io does not have a provider named
registry.terraform.io/hashicorp/healthchecksio

I am running into the same issue and I tried the same solution but was unable to resolve it.
In this case the healthchecksio provider is downloaded and installed BUT terraform still attempts to find and download the non-existent hashicorp/healthchecksio provider.

Terraform version: 0.13.5

@ghost ghost removed waiting-response An issue/pull request is waiting for a response from the community labels Nov 9, 2020
@pselle
Copy link
Contributor

pselle commented Nov 9, 2020

@nlloyd-invitae I believe you have a different issue here, the original author's issue is about a submodule that needed to be upgraded to 0.13, which they then did manually outside of the upgrade tool.

Your issue sounds like you're talking about a local provider not being correctly identified -- it could be you also need to run the 0.13upgrade command on a submodule, but your issue could also be entirely different, since there's not additional information.

Could you open a separate issue if you're still having trouble, filling out the issue template with more information?

@ChristophShyper
Copy link
Author

@pselle my original issue isn't resolved. Proxied providers work only for Hashicorp's ones. I only found a workaround.

Issue reported by @nlloyd-invitae looks almost exactly the same as mine. Terraform can find version of the provider, but cannot install it for whatever reason.

@nlloyd-invitae
Copy link

Also the workaround that is working for @ChristophShyper is not working for me unfortunately.
Note the following excerpt from my posted output:

- Finding latest version of hashicorp/healthchecksio...
- Finding kristofferahl/healthchecksio versions matching "1.6.3"...

Based on the configuration the first line should not be happening at all.

@pselle
Copy link
Contributor

pselle commented Nov 9, 2020

@ChristophShyper as to documentation, perhaps https://www.terraform.io/docs/configuration/provider-requirements.html#names-and-addresses is what you're looking for on clarification on what addresses are? Specifically the note under https://www.terraform.io/docs/configuration/provider-requirements.html#source-addresses where hashicorp/ will be an implied source?

@ChristophShyper
Copy link
Author

@pselle I know it. It says hashicorp is a default namespace, but it doesn't say it's the only one and cannot be overwritten. According to the whole documentation proxied providers should work also for external ones. Not only for the main ones. If you decide to move AWS provider from your registry, as you did with Cloudflare, whole internet will collapse...

@pselle
Copy link
Contributor

pselle commented Nov 9, 2020

Perhaps a point of confusion here is that you're passing provider configuration through the proxy providers block in the module call -- this is not equivalent to wholesale passing a provider. The providers argument to a module call only passes provider configuration. It does not define the fully-qualified provider name, which is always controlled by the called module (./submodule). This means that if the called module uses a non-HashiCorp provider (something outside the default namespace), it must specify this by using a required_providers block in that module.

@ChristophShyper
Copy link
Author

Ok, this makes sense now. Can such information be added to documentation then? Because it's confusing why it works only sometimes.

@nlloyd-invitae
Copy link

I found my mistake, the provider block was being defined in the parent module not the submodule, however the resources themselves were only being defined/used in the submodule. Moving the required_providers block and provider block into the submodule addressed the issue.

@pselle
Copy link
Contributor

pselle commented Nov 10, 2020

@ChristophShyper I'll mark this issue as a documentation update, because it catches people pretty often.

@pselle pselle added documentation explained a Terraform Core team member has described the root cause of this issue in code and removed new new issue not yet triaged labels Nov 10, 2020
@raffraffraff
Copy link

Thank you @pselle and @nlloyd-invitae for making it clear that provider "inheritance" for non-HashiCorp modules is broken.

if the called module uses a non-HashiCorp provider (something outside the default namespace), it must specify this by using a required_providers block in that module.

I found my mistake, the provider block was being defined in the parent module not the submodule, however the resources themselves were only being defined/used in the submodule.

Questions

  1. Is there a plan to "fix" this? Or was the pre 0.13 simplicity itself considered "broken"
  2. If you're compiling a provider from source, is there any documentation for configuring it?

@apparentlymart apparentlymart added the v0.13 Issues (primarily bugs) reported against v0.13 releases label Dec 2, 2020
@Weilbyte
Copy link

Weilbyte commented Dec 8, 2020

Why is this not in the documentation?

@tguvdamm
Copy link
Contributor

How does one solve the issue of @nlloyd-invitae for modules on the registry?
I have a published module that uses the cloudflare provider, with appropriate required_resources blocks defining the cloudflare provider requirement. The calling module defines cloudflare but Terraform tries to pull hashicorp/cloudflare since it does not see that the cloudflare provider is for the called module (with provider cloudflare/cloudflare).

You shouldn't have to redefine required_providers for the modules you call I think?

@apparentlymart
Copy link
Contributor

apparentlymart commented Jan 5, 2021

Each module that refers to a provider must separately define a dependency for it, in its own required_providers block. Provider requirements are a per-module idea, not a whole-configuration idea.

Using the most recent comment for an example, if you are publishing a shared module that uses the cloudflare/cloudflare provider then that module should include a declaration like the following to say that the module uses that provider and which minimum version of the provider it needs:

terraform {
  required_providers {
    cloudflare = {
      source  = "cloudflare/cloudflare"
      version = ">= 2.14.0"
    }
  }
}

The above declaration tells Terraform that when declarations in the rest of the module refer to "cloudflare" that means cloudflare/cloudflare version 2.14.0 or later. The fact that the module uses cloudflare/cloudflare is a property of that module which is true regardless of which configuration it is embedded in, so you need to declare it in the module itself.

As we've seen earlier in the discussion, this is something separate from providing a configuration for that provider. The module we're discussing will presumably also contain at least one resource whose type belongs to the cloudflare/cloudflare provider, such as this example:

resource "cloudflare_zone" "example" {
  zone = "example.com"
}

This is a situation where Terraform has some implied behavior to keep things concise but where as a result it might be hard to follow what's going on. The implied behavior is that Terraform sees the cloudflare_ prefix on that resource type and therefore behaves as if you'd written a provider argument in the block, like this:

resource "cloudflare_zone" "example" {
  provider = cloudflare

  zone = "example.com"
}

The cloudflare here is a reference to the cloudflare in the required_providers block, and so Terraform can see that this resource is associated with the default (unaliased) configuration for the cloudflare/cloudflare provider.


The remaining missing piece then is to write out the default (unaliased) configuration for the cloudflare/cloudflare provider. Provider configurations typically live in the root module and are inherited by child modules, so we'd therefore write the provider block to configure this provider in the root module. That means that the root module will also be referring to the cloudflare/cloudflare provider and so the root module also depends on that provider and must declare that to be true:

terraform {
  required_providers {
    cloudflare = {
      source  = "cloudflare/cloudflare"
      version = ">= 2.0.0"
    }
  }
}

provider "cloudflare" {
  account_id = "abc123"
}

Again, the required_providers block tells Terraform "when I say cloudflare in this module I mean the cloudflare/cloudflare provider". Therefore when Terraform encounters the provider "cloudflare" block below it knows that it's intended to create a configuration for the cloudflare/cloudflare provider, because that's what the cloudflare alias maps to in the required_providers block. The root module also requires only an earlier version of the provider, because its dependency is only on what is supported inside the provider "cloudflare" block; the root module doesn't make use of any specific resources, so it needs no compatibility constraints related to those.

Declaring such a provider therefore satisfies the needs of that child module, due to the automatic inheritance behavior for default provider configurations. However, we can also write it out explicitly to see what's really going on:

module "example" {
  source = "../shared-module-example"

  providers = {
    cloudflare = cloudflare
  }
}

The providers argument in the above says "whenever the child module looks for a default provider configuration for cloudflare/cloudflare, use the default configuration defined in this module (the calling module)".

Such a provider argument feels redundant in the common case where there's only one configuration for each provider, but Terraform has the more explicit syntax to allow for more complex situations where a module might require multiple additional (aliased) provider configurations. In that case, it's useful to write out the providers argument explicitly so it's clear which configurations are being passed into each slot in the child module.


All of what I've said above is covered by text somewhere in the documentation, but I can see that the current organization of the documentation makes it hard to absorb all of this information together and understand the full system. I'm not sure yet how better to organize it, but the work to figure that out is what this issue already represents.

I expect a big contributor to the lack of clarity here is the existing design of aliased provider configurations and proxy provider configurations, which isn't actually a new thing in v0.13 -- it was added back in v0.11 -- but it's got enough confusing and implied behavior to make it hard to follow what exactly it's doing, which then has the knock-on effect of making it harder to understand how it interacts with provider requirements. A new design for passing around provider configurations isn't in scope for this issue but it's an item on the list for longer-term design work.

In the meantime, I hope the above example helps to connect the parts together to understand the overall model.

@ghost
Copy link

ghost commented Mar 14, 2021

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 Mar 14, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug documentation explained a Terraform Core team member has described the root cause of this issue in code v0.13 Issues (primarily bugs) reported against v0.13 releases
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants