2023-05-02 10:33:06 -05:00
|
|
|
// Copyright (c) HashiCorp, Inc.
|
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
|
2023-09-20 07:16:53 -05:00
|
|
|
package tofu
|
2016-11-07 10:57:27 -06:00
|
|
|
|
terraform: Ugly huge change to weave in new State and Plan types
Due to how often the state and plan types are referenced throughout
Terraform, there isn't a great way to switch them out gradually. As a
consequence, this huge commit gets us from the old world to a _compilable_
new world, but still has a large number of known test failures due to
key functionality being stubbed out.
The stubs here are for anything that interacts with providers, since we
now need to do the follow-up work to similarly replace the old
terraform.ResourceProvider interface with its replacement in the new
"providers" package. That work, along with work to fix the remaining
failing tests, will follow in subsequent commits.
The aim here was to replace all references to terraform.State and its
downstream types with states.State, terraform.Plan with plans.Plan,
state.State with statemgr.State, and switch to the new implementations of
the state and plan file formats. However, due to the number of times those
types are used, this also ended up affecting numerous other parts of core
such as terraform.Hook, the backend.Backend interface, and most of the CLI
commands.
Just as with 5861dbf3fc49b19587a31816eb06f511ab861bb4 before, I apologize
in advance to the person who inevitably just found this huge commit while
spelunking through the commit history.
2018-08-14 16:24:45 -05:00
|
|
|
import (
|
2020-10-22 09:15:22 -05:00
|
|
|
"fmt"
|
|
|
|
"log"
|
|
|
|
|
2023-09-20 06:35:35 -05:00
|
|
|
"github.com/opentofu/opentofu/internal/addrs"
|
|
|
|
"github.com/opentofu/opentofu/internal/plans"
|
|
|
|
"github.com/opentofu/opentofu/internal/states"
|
|
|
|
"github.com/opentofu/opentofu/internal/tfdiags"
|
terraform: Ugly huge change to weave in new State and Plan types
Due to how often the state and plan types are referenced throughout
Terraform, there isn't a great way to switch them out gradually. As a
consequence, this huge commit gets us from the old world to a _compilable_
new world, but still has a large number of known test failures due to
key functionality being stubbed out.
The stubs here are for anything that interacts with providers, since we
now need to do the follow-up work to similarly replace the old
terraform.ResourceProvider interface with its replacement in the new
"providers" package. That work, along with work to fix the remaining
failing tests, will follow in subsequent commits.
The aim here was to replace all references to terraform.State and its
downstream types with states.State, terraform.Plan with plans.Plan,
state.State with statemgr.State, and switch to the new implementations of
the state and plan file formats. However, due to the number of times those
types are used, this also ended up affecting numerous other parts of core
such as terraform.Hook, the backend.Backend interface, and most of the CLI
commands.
Just as with 5861dbf3fc49b19587a31816eb06f511ab861bb4 before, I apologize
in advance to the person who inevitably just found this huge commit while
spelunking through the commit history.
2018-08-14 16:24:45 -05:00
|
|
|
)
|
|
|
|
|
terraform: ugly huge change to weave in new HCL2-oriented types
Due to how deeply the configuration types go into Terraform Core, there
isn't a great way to switch out to HCL2 gradually. As a consequence, this
huge commit gets us from the old state to a _compilable_ new state, but
does not yet attempt to fix any tests and has a number of known missing
parts and bugs. We will continue to iterate on this in forthcoming
commits, heading back towards passing tests and making Terraform
fully-functional again.
The three main goals here are:
- Use the configuration models from the "configs" package instead of the
older models in the "config" package, which is now deprecated and
preserved only to help us write our migration tool.
- Do expression inspection and evaluation using the functionality of the
new "lang" package, instead of the Interpolator type and related
functionality in the main "terraform" package.
- Represent addresses of various objects using types in the addrs package,
rather than hand-constructed strings. This is not critical to support
the above, but was a big help during the implementation of these other
points since it made it much more explicit what kind of address is
expected in each context.
Since our new packages are built to accommodate some future planned
features that are not yet implemented (e.g. the "for_each" argument on
resources, "count"/"for_each" on modules), and since there's still a fair
amount of functionality still using old-style APIs, there is a moderate
amount of shimming here to connect new assumptions with old, hopefully in
a way that makes it easier to find and eliminate these shims later.
I apologize in advance to the person who inevitably just found this huge
commit while spelunking through the commit history.
2018-04-30 12:33:53 -05:00
|
|
|
// NodePlannableResourceInstanceOrphan represents a resource that is "applyable":
|
2016-11-07 10:57:27 -06:00
|
|
|
// it is ready to be applied and is represented by a diff.
|
terraform: ugly huge change to weave in new HCL2-oriented types
Due to how deeply the configuration types go into Terraform Core, there
isn't a great way to switch out to HCL2 gradually. As a consequence, this
huge commit gets us from the old state to a _compilable_ new state, but
does not yet attempt to fix any tests and has a number of known missing
parts and bugs. We will continue to iterate on this in forthcoming
commits, heading back towards passing tests and making Terraform
fully-functional again.
The three main goals here are:
- Use the configuration models from the "configs" package instead of the
older models in the "config" package, which is now deprecated and
preserved only to help us write our migration tool.
- Do expression inspection and evaluation using the functionality of the
new "lang" package, instead of the Interpolator type and related
functionality in the main "terraform" package.
- Represent addresses of various objects using types in the addrs package,
rather than hand-constructed strings. This is not critical to support
the above, but was a big help during the implementation of these other
points since it made it much more explicit what kind of address is
expected in each context.
Since our new packages are built to accommodate some future planned
features that are not yet implemented (e.g. the "for_each" argument on
resources, "count"/"for_each" on modules), and since there's still a fair
amount of functionality still using old-style APIs, there is a moderate
amount of shimming here to connect new assumptions with old, hopefully in
a way that makes it easier to find and eliminate these shims later.
I apologize in advance to the person who inevitably just found this huge
commit while spelunking through the commit history.
2018-04-30 12:33:53 -05:00
|
|
|
type NodePlannableResourceInstanceOrphan struct {
|
|
|
|
*NodeAbstractResourceInstance
|
2020-10-22 08:13:02 -05:00
|
|
|
|
2021-04-05 19:05:57 -05:00
|
|
|
// skipRefresh indicates that we should skip refreshing individual instances
|
2020-10-22 08:13:02 -05:00
|
|
|
skipRefresh bool
|
2021-04-05 19:05:57 -05:00
|
|
|
|
|
|
|
// skipPlanChanges indicates we should skip trying to plan change actions
|
|
|
|
// for any instances.
|
|
|
|
skipPlanChanges bool
|
2016-11-07 10:57:27 -06:00
|
|
|
}
|
|
|
|
|
terraform: ugly huge change to weave in new HCL2-oriented types
Due to how deeply the configuration types go into Terraform Core, there
isn't a great way to switch out to HCL2 gradually. As a consequence, this
huge commit gets us from the old state to a _compilable_ new state, but
does not yet attempt to fix any tests and has a number of known missing
parts and bugs. We will continue to iterate on this in forthcoming
commits, heading back towards passing tests and making Terraform
fully-functional again.
The three main goals here are:
- Use the configuration models from the "configs" package instead of the
older models in the "config" package, which is now deprecated and
preserved only to help us write our migration tool.
- Do expression inspection and evaluation using the functionality of the
new "lang" package, instead of the Interpolator type and related
functionality in the main "terraform" package.
- Represent addresses of various objects using types in the addrs package,
rather than hand-constructed strings. This is not critical to support
the above, but was a big help during the implementation of these other
points since it made it much more explicit what kind of address is
expected in each context.
Since our new packages are built to accommodate some future planned
features that are not yet implemented (e.g. the "for_each" argument on
resources, "count"/"for_each" on modules), and since there's still a fair
amount of functionality still using old-style APIs, there is a moderate
amount of shimming here to connect new assumptions with old, hopefully in
a way that makes it easier to find and eliminate these shims later.
I apologize in advance to the person who inevitably just found this huge
commit while spelunking through the commit history.
2018-04-30 12:33:53 -05:00
|
|
|
var (
|
2020-03-05 15:13:54 -06:00
|
|
|
_ GraphNodeModuleInstance = (*NodePlannableResourceInstanceOrphan)(nil)
|
terraform: ugly huge change to weave in new HCL2-oriented types
Due to how deeply the configuration types go into Terraform Core, there
isn't a great way to switch out to HCL2 gradually. As a consequence, this
huge commit gets us from the old state to a _compilable_ new state, but
does not yet attempt to fix any tests and has a number of known missing
parts and bugs. We will continue to iterate on this in forthcoming
commits, heading back towards passing tests and making Terraform
fully-functional again.
The three main goals here are:
- Use the configuration models from the "configs" package instead of the
older models in the "config" package, which is now deprecated and
preserved only to help us write our migration tool.
- Do expression inspection and evaluation using the functionality of the
new "lang" package, instead of the Interpolator type and related
functionality in the main "terraform" package.
- Represent addresses of various objects using types in the addrs package,
rather than hand-constructed strings. This is not critical to support
the above, but was a big help during the implementation of these other
points since it made it much more explicit what kind of address is
expected in each context.
Since our new packages are built to accommodate some future planned
features that are not yet implemented (e.g. the "for_each" argument on
resources, "count"/"for_each" on modules), and since there's still a fair
amount of functionality still using old-style APIs, there is a moderate
amount of shimming here to connect new assumptions with old, hopefully in
a way that makes it easier to find and eliminate these shims later.
I apologize in advance to the person who inevitably just found this huge
commit while spelunking through the commit history.
2018-04-30 12:33:53 -05:00
|
|
|
_ GraphNodeReferenceable = (*NodePlannableResourceInstanceOrphan)(nil)
|
|
|
|
_ GraphNodeReferencer = (*NodePlannableResourceInstanceOrphan)(nil)
|
2020-03-15 10:32:06 -05:00
|
|
|
_ GraphNodeConfigResource = (*NodePlannableResourceInstanceOrphan)(nil)
|
terraform: ugly huge change to weave in new HCL2-oriented types
Due to how deeply the configuration types go into Terraform Core, there
isn't a great way to switch out to HCL2 gradually. As a consequence, this
huge commit gets us from the old state to a _compilable_ new state, but
does not yet attempt to fix any tests and has a number of known missing
parts and bugs. We will continue to iterate on this in forthcoming
commits, heading back towards passing tests and making Terraform
fully-functional again.
The three main goals here are:
- Use the configuration models from the "configs" package instead of the
older models in the "config" package, which is now deprecated and
preserved only to help us write our migration tool.
- Do expression inspection and evaluation using the functionality of the
new "lang" package, instead of the Interpolator type and related
functionality in the main "terraform" package.
- Represent addresses of various objects using types in the addrs package,
rather than hand-constructed strings. This is not critical to support
the above, but was a big help during the implementation of these other
points since it made it much more explicit what kind of address is
expected in each context.
Since our new packages are built to accommodate some future planned
features that are not yet implemented (e.g. the "for_each" argument on
resources, "count"/"for_each" on modules), and since there's still a fair
amount of functionality still using old-style APIs, there is a moderate
amount of shimming here to connect new assumptions with old, hopefully in
a way that makes it easier to find and eliminate these shims later.
I apologize in advance to the person who inevitably just found this huge
commit while spelunking through the commit history.
2018-04-30 12:33:53 -05:00
|
|
|
_ GraphNodeResourceInstance = (*NodePlannableResourceInstanceOrphan)(nil)
|
|
|
|
_ GraphNodeAttachResourceConfig = (*NodePlannableResourceInstanceOrphan)(nil)
|
|
|
|
_ GraphNodeAttachResourceState = (*NodePlannableResourceInstanceOrphan)(nil)
|
2020-09-25 10:18:14 -05:00
|
|
|
_ GraphNodeExecutable = (*NodePlannableResourceInstanceOrphan)(nil)
|
2020-12-16 13:10:51 -06:00
|
|
|
_ GraphNodeProviderConsumer = (*NodePlannableResourceInstanceOrphan)(nil)
|
terraform: ugly huge change to weave in new HCL2-oriented types
Due to how deeply the configuration types go into Terraform Core, there
isn't a great way to switch out to HCL2 gradually. As a consequence, this
huge commit gets us from the old state to a _compilable_ new state, but
does not yet attempt to fix any tests and has a number of known missing
parts and bugs. We will continue to iterate on this in forthcoming
commits, heading back towards passing tests and making Terraform
fully-functional again.
The three main goals here are:
- Use the configuration models from the "configs" package instead of the
older models in the "config" package, which is now deprecated and
preserved only to help us write our migration tool.
- Do expression inspection and evaluation using the functionality of the
new "lang" package, instead of the Interpolator type and related
functionality in the main "terraform" package.
- Represent addresses of various objects using types in the addrs package,
rather than hand-constructed strings. This is not critical to support
the above, but was a big help during the implementation of these other
points since it made it much more explicit what kind of address is
expected in each context.
Since our new packages are built to accommodate some future planned
features that are not yet implemented (e.g. the "for_each" argument on
resources, "count"/"for_each" on modules), and since there's still a fair
amount of functionality still using old-style APIs, there is a moderate
amount of shimming here to connect new assumptions with old, hopefully in
a way that makes it easier to find and eliminate these shims later.
I apologize in advance to the person who inevitably just found this huge
commit while spelunking through the commit history.
2018-04-30 12:33:53 -05:00
|
|
|
)
|
|
|
|
|
|
|
|
func (n *NodePlannableResourceInstanceOrphan) Name() string {
|
|
|
|
return n.ResourceInstanceAddr().String() + " (orphan)"
|
2016-11-07 10:57:27 -06:00
|
|
|
}
|
|
|
|
|
2020-09-25 10:18:14 -05:00
|
|
|
// GraphNodeExecutable
|
2020-10-28 12:47:04 -05:00
|
|
|
func (n *NodePlannableResourceInstanceOrphan) Execute(ctx EvalContext, op walkOperation) tfdiags.Diagnostics {
|
terraform: ugly huge change to weave in new HCL2-oriented types
Due to how deeply the configuration types go into Terraform Core, there
isn't a great way to switch out to HCL2 gradually. As a consequence, this
huge commit gets us from the old state to a _compilable_ new state, but
does not yet attempt to fix any tests and has a number of known missing
parts and bugs. We will continue to iterate on this in forthcoming
commits, heading back towards passing tests and making Terraform
fully-functional again.
The three main goals here are:
- Use the configuration models from the "configs" package instead of the
older models in the "config" package, which is now deprecated and
preserved only to help us write our migration tool.
- Do expression inspection and evaluation using the functionality of the
new "lang" package, instead of the Interpolator type and related
functionality in the main "terraform" package.
- Represent addresses of various objects using types in the addrs package,
rather than hand-constructed strings. This is not critical to support
the above, but was a big help during the implementation of these other
points since it made it much more explicit what kind of address is
expected in each context.
Since our new packages are built to accommodate some future planned
features that are not yet implemented (e.g. the "for_each" argument on
resources, "count"/"for_each" on modules), and since there's still a fair
amount of functionality still using old-style APIs, there is a moderate
amount of shimming here to connect new assumptions with old, hopefully in
a way that makes it easier to find and eliminate these shims later.
I apologize in advance to the person who inevitably just found this huge
commit while spelunking through the commit history.
2018-04-30 12:33:53 -05:00
|
|
|
addr := n.ResourceInstanceAddr()
|
2016-11-07 10:57:27 -06:00
|
|
|
|
2020-10-22 09:15:22 -05:00
|
|
|
// Eval info is different depending on what kind of resource this is
|
|
|
|
switch addr.Resource.Resource.Mode {
|
|
|
|
case addrs.ManagedResourceMode:
|
|
|
|
return n.managedResourceExecute(ctx)
|
|
|
|
case addrs.DataResourceMode:
|
|
|
|
return n.dataResourceExecute(ctx)
|
|
|
|
default:
|
|
|
|
panic(fmt.Errorf("unsupported resource mode %s", n.Config.Mode))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-16 13:10:51 -06:00
|
|
|
func (n *NodePlannableResourceInstanceOrphan) ProvidedBy() (addr addrs.ProviderConfig, exact bool) {
|
|
|
|
if n.Addr.Resource.Resource.Mode == addrs.DataResourceMode {
|
|
|
|
// indicate that this node does not require a configured provider
|
|
|
|
return nil, true
|
|
|
|
}
|
|
|
|
return n.NodeAbstractResourceInstance.ProvidedBy()
|
|
|
|
}
|
|
|
|
|
2020-10-28 12:47:04 -05:00
|
|
|
func (n *NodePlannableResourceInstanceOrphan) dataResourceExecute(ctx EvalContext) tfdiags.Diagnostics {
|
2020-10-22 09:15:22 -05:00
|
|
|
// A data source that is no longer in the config is removed from the state
|
|
|
|
log.Printf("[TRACE] NodePlannableResourceInstanceOrphan: removing state object for %s", n.Addr)
|
2021-01-28 15:35:21 -06:00
|
|
|
|
|
|
|
// we need to update both the refresh state to refresh the current data
|
|
|
|
// source, and the working state for plan-time evaluations.
|
|
|
|
refreshState := ctx.RefreshState()
|
|
|
|
refreshState.SetResourceInstanceCurrent(n.Addr, nil, n.ResolvedProvider)
|
|
|
|
|
|
|
|
workingState := ctx.State()
|
|
|
|
workingState.SetResourceInstanceCurrent(n.Addr, nil, n.ResolvedProvider)
|
2020-10-22 09:15:22 -05:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-10-28 12:47:04 -05:00
|
|
|
func (n *NodePlannableResourceInstanceOrphan) managedResourceExecute(ctx EvalContext) (diags tfdiags.Diagnostics) {
|
2020-10-22 09:15:22 -05:00
|
|
|
addr := n.ResourceInstanceAddr()
|
|
|
|
|
2021-04-05 19:05:57 -05:00
|
|
|
oldState, readDiags := n.readResourceInstanceState(ctx, addr)
|
2021-04-28 12:43:45 -05:00
|
|
|
diags = diags.Append(readDiags)
|
2020-10-28 12:47:04 -05:00
|
|
|
if diags.HasErrors() {
|
|
|
|
return diags
|
2020-09-25 10:18:14 -05:00
|
|
|
}
|
|
|
|
|
2021-05-04 20:14:43 -05:00
|
|
|
// Note any upgrades that readResourceInstanceState might've done in the
|
|
|
|
// prevRunState, so that it'll conform to current schema.
|
|
|
|
diags = diags.Append(n.writeResourceInstanceState(ctx, oldState, prevRunState))
|
|
|
|
if diags.HasErrors() {
|
|
|
|
return diags
|
|
|
|
}
|
|
|
|
// Also the refreshState, because that should still reflect schema upgrades
|
|
|
|
// even if not refreshing.
|
|
|
|
diags = diags.Append(n.writeResourceInstanceState(ctx, oldState, refreshState))
|
|
|
|
if diags.HasErrors() {
|
|
|
|
return diags
|
|
|
|
}
|
|
|
|
|
2020-10-22 08:13:02 -05:00
|
|
|
if !n.skipRefresh {
|
|
|
|
// Refresh this instance even though it is going to be destroyed, in
|
|
|
|
// order to catch missing resources. If this is a normal plan,
|
|
|
|
// providers expect a Read request to remove missing resources from the
|
|
|
|
// plan before apply, and may not handle a missing resource during
|
2023-09-26 12:09:27 -05:00
|
|
|
// Delete correctly. If this is a simple refresh, OpenTofu is
|
2020-10-22 08:13:02 -05:00
|
|
|
// expected to remove the missing resource from the state entirely
|
2021-05-12 17:18:25 -05:00
|
|
|
refreshedState, refreshDiags := n.refresh(ctx, states.NotDeposed, oldState)
|
Eval() Refactor: Plan Edition (#27177)
* terraforn: refactor EvalRefresh
EvalRefresh.Eval(ctx) is now Refresh(evalRefreshReqest, ctx). While none
of the inner logic of the function has changed, it now returns a
states.ResourceInstanceObject instead of updating a pointer. This is a
human-centric change, meant to make the logic flow (in the calling
functions) easier to follow.
* terraform: refactor EvalReadDataPlan and Apply
This is a very minor refactor that removes the (currently) redundant
types EvalReadDataPlan and EvalReadDataApply in favor of using
EvalReadData with a Plan and Apply functions.
This is in effect an aesthetic change; since there is no longer an
Eval() abstraction we can rename functions to make their functionality
as obvious as possible.
* terraform: refactor EvalCheckPlannedChange
EvalCheckPlannedChange was only used by NodeApplyableResourceInstance
and has been refactored into a method on that type called
checkPlannedChange.
* terraform: refactor EvalDiff.Eval
EvalDiff.Eval is now a method on NodeResourceAbstracted called Plan
which takes as a parameter an EvalPlanRequest. Instead of updating
pointers it returns a new plan and state.
I removed as many redundant fields from the original EvalDiff struct as
possible.
* terraform: refactor EvalReduceDiff
EvalReduceDiff is now reducePlan, a regular function (without a method)
that returns a value.
* terraform: refactor EvalDiffDestroy
EvalDiffDestroy.Eval is now NodeAbstractResourceInstance.PlanDestroy
which takes ctx, state and optional DeposedKey and returns a change.
I've removed the state return value since it was only ever returning a
nil state.
* terraform: refactor EvalWriteDiff
EvalWriteDiff.Eval is now NodeAbstractResourceInstance.WriteChange.
* rename files to something more logical
* terrafrom: refresh refactor, continued!
I had originally made Refresh a stand-alone function since it was
(obnoxiously) called from a graphNodeImportStateSub, but after some
(greatly appreciated) prompting in the PR I instead made it a method on
the NodeAbstractResourceInstance, in keeping with the other refactored
eval nodes, and then built a NodeAbstractResourceInstance inside import.
Since I did that I could also remove my duplicated 'writeState' code
inside graphNodeImportStateSub and use n.writeResourceInstanceState, so
double thanks!
* unexport eval methods
* re-refactor Plan, it made more sense on NodeAbstractResourceInstance. Sorry
* Remove uninformative `Eval`s from EvalReadData, consolidate to a single
file, and rename file to match function names.
* manual rebase
2020-12-08 07:50:30 -06:00
|
|
|
diags = diags.Append(refreshDiags)
|
2020-10-28 11:03:00 -05:00
|
|
|
if diags.HasErrors() {
|
2020-10-28 12:47:04 -05:00
|
|
|
return diags
|
2020-10-22 08:13:02 -05:00
|
|
|
}
|
|
|
|
|
2021-04-05 19:05:57 -05:00
|
|
|
diags = diags.Append(n.writeResourceInstanceState(ctx, refreshedState, refreshState))
|
2020-10-28 11:23:03 -05:00
|
|
|
if diags.HasErrors() {
|
2020-10-28 12:47:04 -05:00
|
|
|
return diags
|
2020-10-22 08:13:02 -05:00
|
|
|
}
|
2021-05-06 13:35:05 -05:00
|
|
|
|
|
|
|
// If we refreshed then our subsequent planning should be in terms of
|
|
|
|
// the new object, not the original object.
|
|
|
|
oldState = refreshedState
|
2020-10-22 08:13:02 -05:00
|
|
|
}
|
|
|
|
|
2022-11-18 07:48:15 -06:00
|
|
|
// If we're skipping planning, all we need to do is write the state. If the
|
|
|
|
// refresh indicates the instance no longer exists, there is also nothing
|
|
|
|
// to plan because there is no longer any state and it doesn't exist in the
|
|
|
|
// config.
|
2023-02-09 12:53:11 -06:00
|
|
|
if n.skipPlanChanges || oldState == nil || oldState.Value.IsNull() {
|
2022-11-18 07:48:15 -06:00
|
|
|
return diags.Append(n.writeResourceInstanceState(ctx, oldState, workingState))
|
|
|
|
}
|
2020-09-25 10:18:14 -05:00
|
|
|
|
2022-11-18 07:48:15 -06:00
|
|
|
var change *plans.ResourceInstanceChange
|
|
|
|
change, destroyPlanDiags := n.planDestroy(ctx, oldState, "")
|
|
|
|
diags = diags.Append(destroyPlanDiags)
|
|
|
|
if diags.HasErrors() {
|
|
|
|
return diags
|
|
|
|
}
|
terraform: Ugly huge change to weave in new State and Plan types
Due to how often the state and plan types are referenced throughout
Terraform, there isn't a great way to switch them out gradually. As a
consequence, this huge commit gets us from the old world to a _compilable_
new world, but still has a large number of known test failures due to
key functionality being stubbed out.
The stubs here are for anything that interacts with providers, since we
now need to do the follow-up work to similarly replace the old
terraform.ResourceProvider interface with its replacement in the new
"providers" package. That work, along with work to fix the remaining
failing tests, will follow in subsequent commits.
The aim here was to replace all references to terraform.State and its
downstream types with states.State, terraform.Plan with plans.Plan,
state.State with statemgr.State, and switch to the new implementations of
the state and plan file formats. However, due to the number of times those
types are used, this also ended up affecting numerous other parts of core
such as terraform.Hook, the backend.Backend interface, and most of the CLI
commands.
Just as with 5861dbf3fc49b19587a31816eb06f511ab861bb4 before, I apologize
in advance to the person who inevitably just found this huge commit while
spelunking through the commit history.
2018-08-14 16:24:45 -05:00
|
|
|
|
2022-11-18 07:48:15 -06:00
|
|
|
diags = diags.Append(n.checkPreventDestroy(change))
|
|
|
|
if diags.HasErrors() {
|
|
|
|
return diags
|
|
|
|
}
|
2021-09-22 19:58:41 -05:00
|
|
|
|
2022-11-18 07:48:15 -06:00
|
|
|
// We might be able to offer an approximate reason for why we are
|
|
|
|
// planning to delete this object. (This is best-effort; we might
|
|
|
|
// sometimes not have a reason.)
|
|
|
|
change.ActionReason = n.deleteActionReason(ctx)
|
2021-04-05 19:05:57 -05:00
|
|
|
|
2022-11-18 07:48:15 -06:00
|
|
|
diags = diags.Append(n.writeChange(ctx, change, ""))
|
|
|
|
if diags.HasErrors() {
|
|
|
|
return diags
|
2020-09-25 10:18:14 -05:00
|
|
|
}
|
2020-09-25 11:37:23 -05:00
|
|
|
|
2022-11-18 07:48:15 -06:00
|
|
|
return diags.Append(n.writeResourceInstanceState(ctx, nil, workingState))
|
2016-11-07 10:57:27 -06:00
|
|
|
}
|
2021-09-22 19:58:41 -05:00
|
|
|
|
|
|
|
func (n *NodePlannableResourceInstanceOrphan) deleteActionReason(ctx EvalContext) plans.ResourceInstanceChangeActionReason {
|
|
|
|
cfg := n.Config
|
|
|
|
if cfg == nil {
|
2022-08-30 12:01:29 -05:00
|
|
|
if !n.Addr.Equal(n.prevRunAddr(ctx)) {
|
|
|
|
// This means the resource was moved - see also
|
|
|
|
// ResourceInstanceChange.Moved() which calculates
|
|
|
|
// this the same way.
|
|
|
|
return plans.ResourceInstanceDeleteBecauseNoMoveTarget
|
|
|
|
}
|
|
|
|
|
2021-09-22 19:58:41 -05:00
|
|
|
return plans.ResourceInstanceDeleteBecauseNoResourceConfig
|
|
|
|
}
|
|
|
|
|
instances: Non-existing module instance has no resource instances
Previously we were treating it as a programming error to ask for the
instances of a resource inside an instance of a module that is declared
but whose declaration doesn't include the given instance key.
However, that's actually a valid situation which can arise if, for
example, the user has changed the repetition/expansion mode for an
existing module call and so now all of the resource instances addresses it
previously contained are "orphaned".
To represent that, we'll instead say that an invalid instance key of a
declared module behaves as if it contains no resource instances at all,
regardless of the configurations of any resources nested inside. This
then gives the result needed to successfully detect all of the former
resource instances as "orphaned" and plan to destroy them.
However, this then introduces a new case for
NodePlannableResourceInstanceOrphan.deleteActionReason to deal with: the
resource configuration still exists (because configuration isn't aware of
individual module/resource instances) but the module instance does not.
This actually allows us to resolve, at least partially, a previous missing
piece of explaining to the user why the resource instances are planned
for deletion in that case, finally allowing us to be explicit to the user
that it's because of the module instance being removed, which
internally we call plans.ResourceInstanceDeleteBecauseNoModule.
Co-authored-by: Alisdair McDiarmid <alisdair@users.noreply.github.com>
2021-12-08 14:40:32 -06:00
|
|
|
// If this is a resource instance inside a module instance that's no
|
|
|
|
// longer declared then we will have a config (because config isn't
|
|
|
|
// instance-specific) but the expander will know that our resource
|
|
|
|
// address's module path refers to an undeclared module instance.
|
|
|
|
if expander := ctx.InstanceExpander(); expander != nil { // (sometimes nil in MockEvalContext in tests)
|
|
|
|
validModuleAddr := expander.GetDeepestExistingModuleInstance(n.Addr.Module)
|
|
|
|
if len(validModuleAddr) != len(n.Addr.Module) {
|
|
|
|
// If we get here then at least one step in the resource's module
|
|
|
|
// path is to a module instance that doesn't exist at all, and
|
|
|
|
// so a missing module instance is the delete reason regardless
|
|
|
|
// of whether there might _also_ be a change to the resource
|
|
|
|
// configuration inside the module. (Conceptually the configurations
|
|
|
|
// inside the non-existing module instance don't exist at all,
|
|
|
|
// but they end up existing just as an artifact of the
|
|
|
|
// implementation detail that we detect module instance orphans
|
|
|
|
// only dynamically.)
|
|
|
|
return plans.ResourceInstanceDeleteBecauseNoModule
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-22 19:58:41 -05:00
|
|
|
switch n.Addr.Resource.Key.(type) {
|
|
|
|
case nil: // no instance key at all
|
|
|
|
if cfg.Count != nil || cfg.ForEach != nil {
|
|
|
|
return plans.ResourceInstanceDeleteBecauseWrongRepetition
|
|
|
|
}
|
|
|
|
case addrs.IntKey:
|
|
|
|
if cfg.Count == nil {
|
|
|
|
// This resource isn't using "count" at all, then
|
|
|
|
return plans.ResourceInstanceDeleteBecauseWrongRepetition
|
|
|
|
}
|
|
|
|
|
|
|
|
expander := ctx.InstanceExpander()
|
|
|
|
if expander == nil {
|
|
|
|
break // only for tests that produce an incomplete MockEvalContext
|
|
|
|
}
|
|
|
|
insts := expander.ExpandResource(n.Addr.ContainingResource())
|
|
|
|
|
|
|
|
declared := false
|
|
|
|
for _, inst := range insts {
|
|
|
|
if n.Addr.Equal(inst) {
|
|
|
|
declared = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !declared {
|
|
|
|
// This instance key is outside of the configured range
|
|
|
|
return plans.ResourceInstanceDeleteBecauseCountIndex
|
|
|
|
}
|
|
|
|
case addrs.StringKey:
|
|
|
|
if cfg.ForEach == nil {
|
|
|
|
// This resource isn't using "for_each" at all, then
|
|
|
|
return plans.ResourceInstanceDeleteBecauseWrongRepetition
|
|
|
|
}
|
|
|
|
|
|
|
|
expander := ctx.InstanceExpander()
|
|
|
|
if expander == nil {
|
|
|
|
break // only for tests that produce an incomplete MockEvalContext
|
|
|
|
}
|
|
|
|
insts := expander.ExpandResource(n.Addr.ContainingResource())
|
|
|
|
|
|
|
|
declared := false
|
|
|
|
for _, inst := range insts {
|
|
|
|
if n.Addr.Equal(inst) {
|
|
|
|
declared = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !declared {
|
|
|
|
// This instance key is outside of the configured range
|
|
|
|
return plans.ResourceInstanceDeleteBecauseEachKey
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we get here then the instance key type matches the configured
|
|
|
|
// repetition mode, and so we need to consider whether the key itself
|
|
|
|
// is within the range of the repetition construct.
|
|
|
|
if expander := ctx.InstanceExpander(); expander != nil { // (sometimes nil in MockEvalContext in tests)
|
|
|
|
// First we'll check whether our containing module instance still
|
|
|
|
// exists, so we can talk about that differently in the reason.
|
|
|
|
declared := false
|
|
|
|
for _, inst := range expander.ExpandModule(n.Addr.Module.Module()) {
|
|
|
|
if n.Addr.Module.Equal(inst) {
|
|
|
|
declared = true
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !declared {
|
|
|
|
return plans.ResourceInstanceDeleteBecauseNoModule
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now we've proven that we're in a still-existing module instance,
|
|
|
|
// we'll see if our instance key matches something actually declared.
|
|
|
|
declared = false
|
|
|
|
for _, inst := range expander.ExpandResource(n.Addr.ContainingResource()) {
|
|
|
|
if n.Addr.Equal(inst) {
|
|
|
|
declared = true
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !declared {
|
|
|
|
// Because we already checked that the key _type_ was correct
|
|
|
|
// above, we can assume that any mismatch here is a range error,
|
|
|
|
// and thus we just need to decide which of the two range
|
|
|
|
// errors we're going to return.
|
|
|
|
switch n.Addr.Resource.Key.(type) {
|
|
|
|
case addrs.IntKey:
|
|
|
|
return plans.ResourceInstanceDeleteBecauseCountIndex
|
|
|
|
case addrs.StringKey:
|
|
|
|
return plans.ResourceInstanceDeleteBecauseEachKey
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we didn't find any specific reason to report, we'll report "no reason"
|
|
|
|
// as a fallback, which means the UI should just state it'll be deleted
|
|
|
|
// without any explicit reasoning.
|
|
|
|
return plans.ResourceInstanceChangeNoReason
|
|
|
|
}
|