hashicorp / terraform

Terraform enables you to safely and predictably create, change, and improve infrastructure. It is a source-available tool that codifies APIs into declarative configuration files that can be shared amongst team members, treated as code, edited, reviewed, and versioned.
https://www.terraform.io
Other
43.13k stars 9.58k forks source link

Moved block to support merging mutiple resources using for_each together #35500

Open biggles007 opened 4 months ago

biggles007 commented 4 months ago

Terraform Version

1.8.5

Use Cases

Currently it's not possible to consolidate resources into the same resource name. Where two separate resources exist, both with using for_each with unique key values, as Terraform states the target resource exists in state. There are often times when the key values are unknown so specific moved blocks can't be statically assigned.

Attempted Solutions

Attempted using moved {} blocks against the resources without key values but got the following message from Terraform

Terraform tried to adjust resource instance addresses in the prior state based on change information recorded in the configuration, but some adjustments did not succeed due to existing objects already at the intended addresses

Proposal

The following code (obviously not valid resource arguments) would allow the want_to_consolidate resource to be moved into the example resource as Terraform would ensure that all keys were unique.

resource "azurerm_resource_group" "example"
  for_each = toset(["name1"])
}

resource "azurerm_resource_group" "want_to_consolidate"
  for_each = toset(["name2"])
}

moved {
  from = azurerm_resource_group.want_to_consolidate
  to = azurerm_resource_group.example
}

References

No response

apparentlymart commented 4 months ago

Thanks for suggesting this, @biggles007!

Currently all of the supported moved operations are changes that can in principle be reversed with the same number of declarations: if you move azurerm_resource_group.a to azurerm_resource_group.b (taking all of its instances) then you can later move back from azurerm_resource_group.b to azurerm_resource_group.a and take all of the instances back.

Merging the instances of multiple resources together into a single resource would be "lossy" in that Terraform would lose track of which instance keys came from which resource, and so if you wanted to reverse it you'd need to replace your single moved block with multiple blocks to move each instance separately.

I don't think that's a deal-breaker but I think it does suggest that this behavior might warrant an explicit opt-in, such as an additional argument in the moved block which gives Terraform permission to take individual instances of the object in from, rather than always trying to move it whole.

Aside from that I think everything else about this seems consistent with the rules for moved. In particular, in the situation where both azurerm_resource_group.want_to_consolidate and azurerm_resource_group.example have an instance with the same key, Terraform would propose to delete the instance from azurerm_resource_group.want_to_consolidate and emit a warning explaining that there was no free slot for it to move into.


In a real example the resource "azurerm_resource_group" "example" block would presumably need to be deleted in order for this configuration to be valid, because it's not valid for the object mentioned in from to still be present in the configuration at the same time as its moved block, and so bringing all of the above together I expect it would appear something like this:

resource "azurerm_resource_group" "example"
  for_each = toset(["name1", "name2"])
}

moved {
  from = azurerm_resource_group.want_to_consolidate
  to   = azurerm_resource_group.example

  merge_instances = true
}

Note that:

crw commented 4 months ago

Thanks for this feature request! If you are viewing this issue and would like to indicate your interest, please use the 👍 reaction on the issue description to upvote this issue. We also welcome additional use case descriptions. Thanks again!