2016-11-06 12:07:17 -06:00
|
|
|
package terraform
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2020-12-04 08:16:26 -06:00
|
|
|
"log"
|
2021-03-26 08:40:33 -05:00
|
|
|
"sort"
|
2016-11-06 12:07:17 -06:00
|
|
|
|
2021-05-17 14:33:17 -05:00
|
|
|
"github.com/hashicorp/terraform/internal/plans"
|
2021-05-17 14:43:35 -05:00
|
|
|
"github.com/hashicorp/terraform/internal/states"
|
2021-05-17 12:11:06 -05:00
|
|
|
"github.com/hashicorp/terraform/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
|
|
|
|
2021-05-17 14:00:50 -05:00
|
|
|
"github.com/hashicorp/terraform/internal/addrs"
|
2016-11-06 12:07:17 -06:00
|
|
|
)
|
|
|
|
|
|
|
|
// NodePlannableResourceInstance represents a _single_ resource
|
|
|
|
// instance that is plannable. This means this represents a single
|
|
|
|
// count index, for example.
|
|
|
|
type NodePlannableResourceInstance struct {
|
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
|
|
|
*NodeAbstractResourceInstance
|
2018-09-21 19:08:52 -05:00
|
|
|
ForceCreateBeforeDestroy bool
|
2021-04-05 19:05:57 -05:00
|
|
|
|
|
|
|
// skipRefresh indicates that we should skip refreshing individual instances
|
|
|
|
skipRefresh bool
|
|
|
|
|
|
|
|
// skipPlanChanges indicates we should skip trying to plan change actions
|
|
|
|
// for any instances.
|
|
|
|
skipPlanChanges bool
|
2021-04-06 19:37:38 -05:00
|
|
|
|
|
|
|
// forceReplace are resource instance addresses where the user wants to
|
|
|
|
// force generating a replace action. This set isn't pre-filtered, so
|
|
|
|
// it might contain addresses that have nothing to do with the resource
|
|
|
|
// that this node represents, which the node itself must therefore ignore.
|
|
|
|
forceReplace []addrs.AbsResourceInstance
|
2016-11-06 12:07:17 -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 = (*NodePlannableResourceInstance)(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 = (*NodePlannableResourceInstance)(nil)
|
|
|
|
_ GraphNodeReferencer = (*NodePlannableResourceInstance)(nil)
|
2020-03-15 10:32:06 -05:00
|
|
|
_ GraphNodeConfigResource = (*NodePlannableResourceInstance)(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 = (*NodePlannableResourceInstance)(nil)
|
|
|
|
_ GraphNodeAttachResourceConfig = (*NodePlannableResourceInstance)(nil)
|
|
|
|
_ GraphNodeAttachResourceState = (*NodePlannableResourceInstance)(nil)
|
2020-09-29 13:31:20 -05:00
|
|
|
_ GraphNodeExecutable = (*NodePlannableResourceInstance)(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
|
|
|
)
|
|
|
|
|
2016-11-06 12:07:17 -06:00
|
|
|
// GraphNodeEvalable
|
2020-10-28 12:47:04 -05:00
|
|
|
func (n *NodePlannableResourceInstance) 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-06 12:07:17 -06:00
|
|
|
|
|
|
|
// Eval info is different depending on what kind of resource this is
|
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
|
|
|
switch addr.Resource.Resource.Mode {
|
|
|
|
case addrs.ManagedResourceMode:
|
2020-10-22 09:15:22 -05:00
|
|
|
return n.managedResourceExecute(ctx)
|
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
|
|
|
case addrs.DataResourceMode:
|
2020-09-29 13:31:20 -05:00
|
|
|
return n.dataResourceExecute(ctx)
|
2016-11-06 12:07:17 -06:00
|
|
|
default:
|
|
|
|
panic(fmt.Errorf("unsupported resource mode %s", n.Config.Mode))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-28 12:47:04 -05:00
|
|
|
func (n *NodePlannableResourceInstance) dataResourceExecute(ctx EvalContext) (diags tfdiags.Diagnostics) {
|
2018-06-22 18:54:27 -05:00
|
|
|
config := n.Config
|
2020-09-29 13:31:20 -05:00
|
|
|
addr := n.ResourceInstanceAddr()
|
|
|
|
|
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
|
|
|
var change *plans.ResourceInstanceChange
|
2020-05-04 20:53:43 -05:00
|
|
|
|
2020-12-10 08:55:50 -06:00
|
|
|
_, providerSchema, err := getProvider(ctx, n.ResolvedProvider)
|
2020-10-28 12:47:04 -05:00
|
|
|
diags = diags.Append(err)
|
|
|
|
if diags.HasErrors() {
|
|
|
|
return diags
|
2020-09-29 13:31:20 -05:00
|
|
|
}
|
|
|
|
|
2021-04-28 12:43:45 -05:00
|
|
|
state, readDiags := n.readResourceInstanceState(ctx, addr)
|
|
|
|
diags = diags.Append(readDiags)
|
2020-10-28 12:47:04 -05:00
|
|
|
if diags.HasErrors() {
|
|
|
|
return diags
|
2020-09-29 13:31:20 -05:00
|
|
|
}
|
|
|
|
|
2021-05-04 20:14:43 -05:00
|
|
|
// We'll save a snapshot of what we just read from the state into the
|
|
|
|
// prevRunState which will capture the result read in the previous
|
|
|
|
// run, possibly tweaked by any upgrade steps that
|
|
|
|
// readResourceInstanceState might've made.
|
|
|
|
// However, note that we don't have any explicit mechanism for upgrading
|
|
|
|
// data resource results as we do for managed resources, and so the
|
|
|
|
// prevRunState might not conform to the current schema if the
|
|
|
|
// previous run was with a different provider version.
|
|
|
|
diags = diags.Append(n.writeResourceInstanceState(ctx, state, prevRunState))
|
|
|
|
if diags.HasErrors() {
|
|
|
|
return diags
|
|
|
|
}
|
|
|
|
|
2020-12-08 09:52:39 -06:00
|
|
|
diags = diags.Append(validateSelfRef(addr.Resource, config.Config, providerSchema))
|
2020-10-28 11:32:49 -05:00
|
|
|
if diags.HasErrors() {
|
2020-10-28 12:47:04 -05:00
|
|
|
return diags
|
2020-09-29 13:31:20 -05:00
|
|
|
}
|
|
|
|
|
2020-12-08 09:43:04 -06:00
|
|
|
change, state, planDiags := n.planDataSource(ctx, state)
|
|
|
|
diags = diags.Append(planDiags)
|
2020-10-28 10:57:45 -05:00
|
|
|
if diags.HasErrors() {
|
2020-10-28 12:47:04 -05:00
|
|
|
return diags
|
2020-09-29 13:31:20 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// write the data source into both the refresh state and the
|
|
|
|
// working state
|
2021-03-26 08:40:33 -05:00
|
|
|
diags = diags.Append(n.writeResourceInstanceState(ctx, state, refreshState))
|
2020-10-28 11:23:03 -05:00
|
|
|
if diags.HasErrors() {
|
2020-10-28 12:47:04 -05:00
|
|
|
return diags
|
2020-09-29 13:31:20 -05:00
|
|
|
}
|
2021-03-26 08:40:33 -05:00
|
|
|
diags = diags.Append(n.writeResourceInstanceState(ctx, state, workingState))
|
2020-10-28 11:23:03 -05:00
|
|
|
if diags.HasErrors() {
|
2020-10-28 12:47:04 -05:00
|
|
|
return diags
|
2020-09-29 13:31:20 -05:00
|
|
|
}
|
|
|
|
|
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(n.writeChange(ctx, change, ""))
|
2020-10-28 12:47:04 -05:00
|
|
|
return diags
|
2016-11-06 12:07:17 -06:00
|
|
|
}
|
|
|
|
|
2020-10-28 12:47:04 -05:00
|
|
|
func (n *NodePlannableResourceInstance) managedResourceExecute(ctx EvalContext) (diags tfdiags.Diagnostics) {
|
2018-06-22 18:54:27 -05:00
|
|
|
config := n.Config
|
2020-09-29 13:31:20 -05:00
|
|
|
addr := n.ResourceInstanceAddr()
|
|
|
|
|
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
|
|
|
var change *plans.ResourceInstanceChange
|
2021-04-05 19:05:57 -05:00
|
|
|
var instanceRefreshState *states.ResourceInstanceObject
|
2016-11-06 12:07:17 -06:00
|
|
|
|
2020-12-10 08:55:50 -06:00
|
|
|
_, providerSchema, err := getProvider(ctx, n.ResolvedProvider)
|
2020-10-28 12:47:04 -05:00
|
|
|
diags = diags.Append(err)
|
|
|
|
if diags.HasErrors() {
|
|
|
|
return diags
|
2020-09-29 13:31:20 -05:00
|
|
|
}
|
|
|
|
|
2020-12-08 09:52:39 -06:00
|
|
|
diags = diags.Append(validateSelfRef(addr.Resource, config.Config, providerSchema))
|
2020-10-28 11:32:49 -05:00
|
|
|
if diags.HasErrors() {
|
2020-10-28 12:47:04 -05:00
|
|
|
return diags
|
2020-09-29 13:31:20 -05:00
|
|
|
}
|
|
|
|
|
2021-04-28 12:43:45 -05:00
|
|
|
instanceRefreshState, readDiags := n.readResourceInstanceState(ctx, addr)
|
|
|
|
diags = diags.Append(readDiags)
|
2020-10-28 12:47:04 -05:00
|
|
|
if diags.HasErrors() {
|
|
|
|
return diags
|
2020-10-01 15:04:35 -05:00
|
|
|
}
|
2020-12-04 08:16:26 -06:00
|
|
|
|
2021-05-04 20:14:43 -05:00
|
|
|
// We'll save a snapshot of what we just read from the state into the
|
|
|
|
// prevRunState before we do anything else, since this will capture the
|
|
|
|
// result of any schema upgrading that readResourceInstanceState just did,
|
|
|
|
// but not include any out-of-band changes we might detect in in the
|
|
|
|
// refresh step below.
|
|
|
|
diags = diags.Append(n.writeResourceInstanceState(ctx, instanceRefreshState, prevRunState))
|
|
|
|
if diags.HasErrors() {
|
|
|
|
return diags
|
|
|
|
}
|
|
|
|
// Also the refreshState, because that should still reflect schema upgrades
|
|
|
|
// even if it doesn't reflect upstream changes.
|
|
|
|
diags = diags.Append(n.writeResourceInstanceState(ctx, instanceRefreshState, refreshState))
|
|
|
|
if diags.HasErrors() {
|
|
|
|
return diags
|
|
|
|
}
|
|
|
|
|
2020-12-04 08:16:26 -06:00
|
|
|
// In 0.13 we could be refreshing a resource with no config.
|
|
|
|
// We should be operating on managed resource, but check here to be certain
|
|
|
|
if n.Config == nil || n.Config.Managed == nil {
|
|
|
|
log.Printf("[WARN] managedResourceExecute: no Managed config value found in instance state for %q", n.Addr)
|
|
|
|
} else {
|
|
|
|
if instanceRefreshState != nil {
|
|
|
|
instanceRefreshState.CreateBeforeDestroy = n.Config.Managed.CreateBeforeDestroy || n.ForceCreateBeforeDestroy
|
|
|
|
}
|
2020-10-01 15:04:35 -05:00
|
|
|
}
|
|
|
|
|
2020-09-29 13:31:20 -05:00
|
|
|
// Refresh, maybe
|
2020-10-22 09:15:22 -05:00
|
|
|
if !n.skipRefresh {
|
2021-05-12 17:18:25 -05:00
|
|
|
s, refreshDiags := n.refresh(ctx, states.NotDeposed, instanceRefreshState)
|
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-09-29 13:31:20 -05:00
|
|
|
}
|
2021-03-26 08:40:33 -05:00
|
|
|
|
2021-01-21 11:46:37 -06:00
|
|
|
instanceRefreshState = s
|
2020-09-29 13:31:20 -05:00
|
|
|
|
2021-03-26 08:40:33 -05:00
|
|
|
if instanceRefreshState != nil {
|
|
|
|
// When refreshing we start by merging the stored dependencies and
|
|
|
|
// the configured dependencies. The configured dependencies will be
|
|
|
|
// stored to state once the changes are applied. If the plan
|
|
|
|
// results in no changes, we will re-write these dependencies
|
|
|
|
// below.
|
|
|
|
instanceRefreshState.Dependencies = mergeDeps(n.Dependencies, instanceRefreshState.Dependencies)
|
|
|
|
}
|
|
|
|
|
|
|
|
diags = diags.Append(n.writeResourceInstanceState(ctx, instanceRefreshState, refreshState))
|
2020-10-28 11:23:03 -05:00
|
|
|
if diags.HasErrors() {
|
2020-10-28 12:47:04 -05:00
|
|
|
return diags
|
2020-09-29 13:31:20 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-05 19:05:57 -05:00
|
|
|
// Plan the instance, unless we're in the refresh-only mode
|
|
|
|
if !n.skipPlanChanges {
|
2021-04-06 19:37:38 -05:00
|
|
|
change, instancePlanState, planDiags := n.plan(
|
|
|
|
ctx, change, instanceRefreshState, n.ForceCreateBeforeDestroy, n.forceReplace,
|
|
|
|
)
|
2021-04-05 19:05:57 -05:00
|
|
|
diags = diags.Append(planDiags)
|
|
|
|
if diags.HasErrors() {
|
|
|
|
return diags
|
|
|
|
}
|
2020-09-29 13:31:20 -05:00
|
|
|
|
2021-04-05 19:05:57 -05:00
|
|
|
diags = diags.Append(n.checkPreventDestroy(change))
|
|
|
|
if diags.HasErrors() {
|
|
|
|
return diags
|
|
|
|
}
|
2020-09-29 13:31:20 -05:00
|
|
|
|
2021-04-05 19:05:57 -05:00
|
|
|
diags = diags.Append(n.writeResourceInstanceState(ctx, instancePlanState, workingState))
|
2021-03-26 08:40:33 -05:00
|
|
|
if diags.HasErrors() {
|
|
|
|
return diags
|
|
|
|
}
|
2021-04-05 19:05:57 -05:00
|
|
|
|
|
|
|
// If this plan resulted in a NoOp, then apply won't have a chance to make
|
|
|
|
// any changes to the stored dependencies. Since this is a NoOp we know
|
|
|
|
// that the stored dependencies will have no effect during apply, and we can
|
|
|
|
// write them out now.
|
|
|
|
if change.Action == plans.NoOp && !depsEqual(instanceRefreshState.Dependencies, n.Dependencies) {
|
|
|
|
// the refresh state will be the final state for this resource, so
|
|
|
|
// finalize the dependencies here if they need to be updated.
|
|
|
|
instanceRefreshState.Dependencies = n.Dependencies
|
|
|
|
diags = diags.Append(n.writeResourceInstanceState(ctx, instanceRefreshState, refreshState))
|
|
|
|
if diags.HasErrors() {
|
|
|
|
return diags
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
diags = diags.Append(n.writeChange(ctx, change, ""))
|
2021-05-07 17:50:11 -05:00
|
|
|
} else {
|
|
|
|
// Even if we don't plan changes, we do still need to at least update
|
|
|
|
// the working state to reflect the refresh result. If not, then e.g.
|
|
|
|
// any output values refering to this will not react to the drift.
|
|
|
|
// (Even if we didn't actually refresh above, this will still save
|
|
|
|
// the result of any schema upgrading we did in readResourceInstanceState.)
|
|
|
|
diags = diags.Append(n.writeResourceInstanceState(ctx, instanceRefreshState, workingState))
|
|
|
|
if diags.HasErrors() {
|
|
|
|
return diags
|
|
|
|
}
|
2021-03-26 08:40:33 -05:00
|
|
|
}
|
|
|
|
|
2020-10-28 12:47:04 -05:00
|
|
|
return diags
|
2016-11-06 12:07:17 -06:00
|
|
|
}
|
2021-03-26 08:40:33 -05:00
|
|
|
|
|
|
|
// mergeDeps returns the union of 2 sets of dependencies
|
|
|
|
func mergeDeps(a, b []addrs.ConfigResource) []addrs.ConfigResource {
|
|
|
|
switch {
|
|
|
|
case len(a) == 0:
|
|
|
|
return b
|
|
|
|
case len(b) == 0:
|
|
|
|
return a
|
|
|
|
}
|
|
|
|
|
|
|
|
set := make(map[string]addrs.ConfigResource)
|
|
|
|
|
|
|
|
for _, dep := range a {
|
|
|
|
set[dep.String()] = dep
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, dep := range b {
|
|
|
|
set[dep.String()] = dep
|
|
|
|
}
|
|
|
|
|
|
|
|
newDeps := make([]addrs.ConfigResource, 0, len(set))
|
|
|
|
for _, dep := range set {
|
|
|
|
newDeps = append(newDeps, dep)
|
|
|
|
}
|
|
|
|
|
|
|
|
return newDeps
|
|
|
|
}
|
|
|
|
|
|
|
|
func depsEqual(a, b []addrs.ConfigResource) bool {
|
|
|
|
if len(a) != len(b) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
less := func(s []addrs.ConfigResource) func(i, j int) bool {
|
|
|
|
return func(i, j int) bool {
|
|
|
|
return s[i].String() < s[j].String()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sort.Slice(a, less(a))
|
|
|
|
sort.Slice(b, less(b))
|
|
|
|
|
|
|
|
for i := range a {
|
|
|
|
if !a[i].Equal(b[i]) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|