Terraform v0.12.9
+ provider.aws v2.28.1
sample module
provider "aws" {
alias = "us-east-1"
region = "us-east-1"
}
resource "aws_cloudwatch_log_group" "main" {
provider = "aws.us-east-1"
name = "testme"
}
calling the module
module "test" {
source = "./module/"
providers = {
aws.us-east-1 = aws.us-east-1
}
}
provider "aws" {
version = "~> 2.28.0"
region = "us-west-2"
}
provider "aws" {
alias = "us-east-1"
region = "us-east-1"
version = "~> 2.28.0"
}
Deleting the module should destroy the resources contained in that module.
I get an error about provider configuration not present
Error: Provider configuration not present
To work with module.test.aws_cloudwatch_log_group.main its original provider
configuration at module.test.provider.aws.us-east-1 is required, but it has
been removed. This occurs when a provider configuration is removed while
objects created by that provider still exist in the state. Re-add the provider
configuration to destroy module.test.aws_cloudwatch_log_group.main, after
which you can remove the provider configuration again.
terraform initterraform apply to create the resourceterraform applyIf I remove the region definition in the sample module, I'm able to add and remove the module just fine. It only becomes an issue when I include the region attribute in the provider defined in the module.
I couldn't find any related issues that talked about the issue removing the module, but there are a couple around how in 0.12 you need to specific a explicit provider in the module along with passing it in.
Hi @dynamike! Sorry for this unfortunate behavior.
It seems that you've run into the issue described in the documentation section Providers Within Modules: if you put a provider configuration inside a child module then removing that module will fail any time there are resources present using that provider in the module, because by removing the module you've also removed the provider configuration Terraform would need in order to destroy those objects.
It's for that reason that the documentation recommends using provider blocks _only_ in the root module, and passing them down to child modules using the providers argument inside the module block as you showed in your example.
To get out of the jam you've found yourself in here, the easiest answer is to do a two-step process here to destroy the resource instances in the module first, while the module "test" block is still present, and _then_ remove the module "test" block:
module.test, thus making inert.terraform apply with those changes to make sure all of the dependencies on module.test are dropped.terraform destroy -target=module.test and be sure to review the plan to make sure it's only destroying objects belonging to module.test.module "test" block and run terraform apply again. This should show no changes, confirming that the module removal was successful.To prevent this problem from arising again in the future, you can remove the region argument from your provider "aws" block in your child module, which will then turn it into a "proxy configuration block" as defined in Passing Providers Explicitly:
provider "aws" {
# Module expects aws.us-east-1 to be passed in via the "providers" argument
alias = "us-east-1"
}
A provider block with only an alias and no other settings is interpreted by Terraform as a placeholder to be filled by explicit provider passing; the above is a statement that this module expects to receive a provider aws.us-east-1 from its caller, rather than configuring it explicitly.
The behavior described here is working as designed, but the current design includes a compatibility allowance for configurations written for Terraform 0.10 which was intended to give a window to rework configurations to the new model added in Terraform 0.11 that is not subject to this gotcha.
Given that Terraform 0.10 is now two major versions old, it's time for us to consider dropping this backward-compatibility allowance in order to remove this trap. In order to resolve this issue, we should consider whether the next major release could drop support for non-proxy providers in child modules altogether, and if so add a deprecation warning in the current release series to prepare for that.
If removal of that feature altogether is too extreme, we should consider ways that we can adjust the current behavior so that the implications of this usage pattern are explicit when running Terraform, rather than just hidden in the documentation.
FYI, I was unable to solve this using a providers parameter to the module. Must the original module be created with this parameter already in place? If so, there鈥檚 not much of a way to migrate the config.
As a follow up on my previous comment - I was able to confirm I am unable to remove a module using the providers parameter even when creating the module initially with the providers parameter present.
A provider block with only an alias and no other settings is interpreted by Terraform as a placeholder to be filled by explicit provider passing; the above is a statement that this module expects to receive a provider aws.us-east-1 from its caller, rather than configuring it explicitly.
Having now been playing with this configuration aspect for the last few hours, yes, this is true, but it is both valid and invalid code!
provider "aws" {
alias = "local"
}
provider "aws {
alias = "remote"
}
I created the above configuration in the main.tf of my module, as per the documentation and various other guides, but every attempt to run it through terraform validate during the pre-commit hook failed:
Error: Missing required argument
on main.tf line 1, in provider "aws":
1: provider "aws" {
The argument "region" is required, but no definition was found.
Error: Missing required argument
on main.tf line 5, in provider "aws":
1: provider "aws" {
The argument "region" is required, but no definition was found.
In the end, I added the region explicitly:
provider "aws" {
alias = "local"
region = "eu-west-2"
}
provider "aws {
alias = "remote"
region = "eu-west-2"
}
That successfully passed the validation, but when the configuration was deployed via the module all the resources were configured in the wrong account! I slowly worked my way back and after removing the region arguments and forcefully committing the provider{} proxy blocks properly, as outlined above, by bypassing validation, the pipeline ran fine. (Once, of course, I went through all the extra steps of removing the module-created resources before destroying the module configuration and re-creating it all, as suggested above too.)
Therefore I think this particular issue may need to pivot. The documentation on the site is correct, but it seems that the terraform validation is giving out some bad advice and unintentionally forcing the creation of dedicated providers within the module rather than preparing for the proxying of providers via the provider{} block within the module{} configuration.
The provider{} proxy blocks are valid code and are accepted by Terraform at run time, but terraform validate reports them as invalid code.
Thanks @teamterraform for your answer, but this error is crawling over hundreds of modules in my Terraform too. It is so ambiguous and non-sensical to be playing around with providers in root and child modules. Are no immediate fixes for this in the future?
Hello, any updates?
I was able to use the below as a workaround without destroying the resource instances in the module(s)
I was then able to comment out the module block, run a terraform plan, and did not receive "Error: Provider configuration not present".
Most helpful comment
Hi @dynamike! Sorry for this unfortunate behavior.
It seems that you've run into the issue described in the documentation section Providers Within Modules: if you put a
providerconfiguration inside a child module then removing that module will fail any time there are resources present using that provider in the module, because by removing the module you've also removed the provider configuration Terraform would need in order to destroy those objects.It's for that reason that the documentation recommends using
providerblocks _only_ in the root module, and passing them down to child modules using theprovidersargument inside themoduleblock as you showed in your example.To get out of the jam you've found yourself in here, the easiest answer is to do a two-step process here to destroy the resource instances in the module first, while the
module "test"block is still present, and _then_ remove themodule "test"block:module.test, thus making inert.terraform applywith those changes to make sure all of the dependencies onmodule.testare dropped.terraform destroy -target=module.testand be sure to review the plan to make sure it's only destroying objects belonging tomodule.test.module "test"block and runterraform applyagain. This should show no changes, confirming that the module removal was successful.To prevent this problem from arising again in the future, you can remove the
regionargument from yourprovider "aws"block in your child module, which will then turn it into a "proxy configuration block" as defined in Passing Providers Explicitly:A provider block with only an alias and no other settings is interpreted by Terraform as a placeholder to be filled by explicit provider passing; the above is a statement that this module expects to receive a provider
aws.us-east-1from its caller, rather than configuring it explicitly.The behavior described here is working as designed, but the current design includes a compatibility allowance for configurations written for Terraform 0.10 which was intended to give a window to rework configurations to the new model added in Terraform 0.11 that is not subject to this gotcha.
Given that Terraform 0.10 is now two major versions old, it's time for us to consider dropping this backward-compatibility allowance in order to remove this trap. In order to resolve this issue, we should consider whether the next major release could drop support for non-proxy providers in child modules altogether, and if so add a deprecation warning in the current release series to prepare for that.
If removal of that feature altogether is too extreme, we should consider ways that we can adjust the current behavior so that the implications of this usage pattern are explicit when running Terraform, rather than just hidden in the documentation.