mirror of
https://github.com/opentffoundation/opentf.git
synced 2025-12-19 17:59:05 -05:00
docs for provider for_each in modules and resources (#2696)
Signed-off-by: Diogenes Fernandes <diofeher@gmail.com>
This commit is contained in:
committed by
GitHub
parent
18b2cb2100
commit
cb73ae4299
@@ -187,11 +187,11 @@ configuration: only the expression in brackets (`each.key` in the above example)
|
||||
can vary between the instances of the module.
|
||||
|
||||
:::warning
|
||||
**The `for_each` expression for a resource must not exactly match the
|
||||
**The `for_each` expression for a module must *be different from* the
|
||||
`for_each` expression for its associated provider configuration.**
|
||||
|
||||
OpenTofu uses a provider instance to plan and apply _all_ actions related
|
||||
to a resource instance, including destroying a resource instance that
|
||||
to a module instance, including destroying a module instance that
|
||||
has been removed from the configuration.
|
||||
|
||||
Therefore a provider instance passed into a child module that will declare
|
||||
|
||||
@@ -316,7 +316,7 @@ same provider configuration block, but can they each be bound to a different
|
||||
instance.
|
||||
|
||||
:::warning
|
||||
**The `for_each` expression for a resource must not exactly match the
|
||||
**The `for_each` expression for a resource must *be different* from the
|
||||
`for_each` expression for its associated provider configuration.**
|
||||
|
||||
OpenTofu uses a provider instance to plan and apply _all_ actions related
|
||||
@@ -339,6 +339,124 @@ action. You can then remove the element altogether on the next round, once
|
||||
all of the associated resource instances have been destroyed.
|
||||
:::
|
||||
|
||||
### Deleting a provider instance
|
||||
|
||||
One main limitation of the provider instances feature is that removing a provider instance requires extra rounds of planning and applying. The following example illustrates this issue and how to avoid it.
|
||||
|
||||
As explained above, a resource should always use a `for_each` expression that is a subset of the provider configuration's `for_each`. In the following configuration, both the provider and the resource use the same `for_each` value:
|
||||
|
||||
```
|
||||
variable "aws_active_regions" {
|
||||
type = set(string)
|
||||
default = ["us-east-1", "sa-east-1"]
|
||||
}
|
||||
|
||||
provider "aws" {
|
||||
alias = "by_region"
|
||||
for_each = var.aws_active_regions
|
||||
region = each.key
|
||||
}
|
||||
|
||||
resource "aws_cloudwatch_log_group" "lambda_cloudfront" {
|
||||
name = "/aws/lambda/${each.key}.lambda"
|
||||
provider = aws.by_region[each.key]
|
||||
for_each = var.aws_active_regions
|
||||
}
|
||||
```
|
||||
|
||||
This configuration will produce the following warning:
|
||||
|
||||
```
|
||||
╷
|
||||
│ Warning: Provider configuration for_each matches resource
|
||||
│
|
||||
│ on main.tf line 24, in resource "aws_cloudwatch_log_group" "lambda_cloudfront":
|
||||
│ 24: for_each = var.aws_regions
|
||||
│
|
||||
│ This provider configuration uses the same for_each expression as a
|
||||
│ resource, which means that subsequent removal of elements from this
|
||||
│ collection would cause a planning error.
|
||||
│
|
||||
│ OpenTofu relies on a provider instance to destroy resource instances
|
||||
│ that are associated with it, and so the provider instance must
|
||||
│ outlive all of its resource instances by at least one plan/apply
|
||||
│ round. For removal of instances to succeed in future you must
|
||||
│ structure the configuration so that the provider block's for_each
|
||||
│ expression can produce a superset of the instances of the resources
|
||||
│ associated with the provider configuration. Refer to the OpenTofu
|
||||
│ documentation for specific suggestions.
|
||||
│
|
||||
│ To destroy this object before removing the provider configuration,
|
||||
│ consider first performing a targeted destroy:
|
||||
│ tofu apply -destroy -target=aws_cloudwatch_log_group.lambda_cloudfront
|
||||
╵
|
||||
```
|
||||
|
||||
This approach is error-prone because you must run `apply -destroy -target` for all resources associated with the provider instance before you can remove the provider instance itself. If you try to remove the provider instance by deleting the key from `aws_active_regions` before destroying the resources, OpenTofu will prevent you:
|
||||
|
||||
```
|
||||
╷
|
||||
│ Error: Provider instance not present
|
||||
│
|
||||
│ To work with aws_cloudwatch_log_group.lambda_cloudfront["sa-east-1"]
|
||||
│ its original provider instance at
|
||||
│ provider["registry.opentofu.org/hashicorp/aws"].by_region["sa-east-1"]
|
||||
│ is required, but it has been removed. This occurs when an element is
|
||||
│ removed from the provider configuration's for_each collection while
|
||||
│ objects created by that the associated provider instance still exist
|
||||
│ in the state. Re-add the for_each element to destroy
|
||||
│ aws_cloudwatch_log_group.lambda_cloudfront["sa-east-1"], after which
|
||||
│ you can remove the provider configuration again.
|
||||
│
|
||||
│ This is commonly caused by using the same for_each collection both
|
||||
│ for a resource (or its containing module) and its associated provider
|
||||
│ configuration. To successfully remove an instance of a resource it
|
||||
│ must be possible to remove the corresponding element from the
|
||||
│ resource's for_each collection while retaining the corresponding
|
||||
│ element in the provider's for_each collection.
|
||||
╵
|
||||
```
|
||||
|
||||
An alternative approach is to use a different subset for the resource's `for_each` expression:
|
||||
|
||||
```hcl
|
||||
variable "aws_active_regions" {
|
||||
type = set(string)
|
||||
default = ["us-east-1", "sa-east-1"]
|
||||
}
|
||||
|
||||
variable "aws_disabled_regions" {
|
||||
description = "A list of regions that should be disabled and all resources removed."
|
||||
type = set(string)
|
||||
default = []
|
||||
}
|
||||
|
||||
// Superset of the provider configuration
|
||||
provider "aws" {
|
||||
alias = "by_region"
|
||||
for_each = var.aws_active_regions
|
||||
region = each.key
|
||||
}
|
||||
|
||||
// Resource using a subset of the provider's configuration
|
||||
resource "aws_cloudwatch_log_group" "lambda_cloudfront" {
|
||||
name = "/aws/lambda/${each.key}.lambda"
|
||||
provider = aws.by_region[each.key]
|
||||
for_each = setsubtract(var.aws_active_regions, var.aws_disabled_regions)
|
||||
}
|
||||
```
|
||||
|
||||
If you need to remove a provider instance (for example, for a specific AWS region), add that region to `aws_disabled_regions`:
|
||||
```
|
||||
variable "aws_disabled_regions" {
|
||||
description = "A list of regions that should be disabled and all resources removed."
|
||||
type = set(string)
|
||||
default = ["us-east-1"]
|
||||
}
|
||||
```
|
||||
|
||||
With this approach, running `tofu plan` and `tofu apply` is sufficient to disable the provider instance and remove all associated resources.
|
||||
|
||||
### Passing provider configurations between modules
|
||||
|
||||
Each module has its own separate namespace of provider configurations, but
|
||||
|
||||
Reference in New Issue
Block a user