2024-02-08 03:48:59 -06:00
|
|
|
// Copyright (c) The OpenTofu Authors
|
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
// Copyright (c) 2023 HashiCorp, Inc.
|
2023-05-02 10:33:06 -05:00
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
|
2023-09-20 07:16:53 -05:00
|
|
|
package tofu
|
2016-09-16 01:20:35 -05:00
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2020-03-06 17:02:20 -06:00
|
|
|
"log"
|
2016-09-16 01:20:35 -05:00
|
|
|
|
2020-09-25 14:10:32 -05:00
|
|
|
"github.com/hashicorp/hcl/v2"
|
2022-06-15 21:03:10 -05:00
|
|
|
"github.com/zclconf/go-cty/cty"
|
|
|
|
|
2023-09-20 06:35:35 -05:00
|
|
|
"github.com/opentofu/opentofu/internal/addrs"
|
|
|
|
"github.com/opentofu/opentofu/internal/configs"
|
|
|
|
"github.com/opentofu/opentofu/internal/dag"
|
|
|
|
"github.com/opentofu/opentofu/internal/lang"
|
|
|
|
"github.com/opentofu/opentofu/internal/lang/marks"
|
|
|
|
"github.com/opentofu/opentofu/internal/plans"
|
|
|
|
"github.com/opentofu/opentofu/internal/states"
|
|
|
|
"github.com/opentofu/opentofu/internal/tfdiags"
|
2016-09-16 01:20:35 -05:00
|
|
|
)
|
|
|
|
|
2020-10-09 16:24:10 -05:00
|
|
|
// nodeExpandOutput is the placeholder for a non-root module output that has
|
|
|
|
// not yet had its module path expanded.
|
2020-05-12 09:44:45 -05:00
|
|
|
type nodeExpandOutput struct {
|
2023-05-22 11:21:30 -05:00
|
|
|
Addr addrs.OutputValue
|
|
|
|
Module addrs.Module
|
|
|
|
Config *configs.Output
|
|
|
|
Destroying bool
|
|
|
|
RefreshOnly bool
|
2022-09-28 12:49:57 -05:00
|
|
|
|
|
|
|
// Planning is set to true when this node is in a graph that was produced
|
|
|
|
// by the plan graph builder, as opposed to the apply graph builder.
|
|
|
|
// This quirk is just because we share the same node type between both
|
|
|
|
// phases but in practice there are a few small differences in the actions
|
|
|
|
// we need to take between plan and apply. See method DynamicExpand for
|
|
|
|
// details.
|
|
|
|
Planning bool
|
2020-02-24 16:42:32 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
var (
|
2020-05-12 09:44:45 -05:00
|
|
|
_ GraphNodeReferenceable = (*nodeExpandOutput)(nil)
|
|
|
|
_ GraphNodeReferencer = (*nodeExpandOutput)(nil)
|
2020-06-06 20:42:01 -05:00
|
|
|
_ GraphNodeReferenceOutside = (*nodeExpandOutput)(nil)
|
2020-05-12 09:44:45 -05:00
|
|
|
_ GraphNodeDynamicExpandable = (*nodeExpandOutput)(nil)
|
2020-05-18 19:59:17 -05:00
|
|
|
_ graphNodeTemporaryValue = (*nodeExpandOutput)(nil)
|
2020-05-21 21:11:58 -05:00
|
|
|
_ graphNodeExpandsInstances = (*nodeExpandOutput)(nil)
|
2020-02-24 16:42:32 -06:00
|
|
|
)
|
|
|
|
|
2020-05-21 21:11:58 -05:00
|
|
|
func (n *nodeExpandOutput) expandsInstances() {}
|
2020-05-18 19:59:17 -05:00
|
|
|
|
2020-05-12 09:44:45 -05:00
|
|
|
func (n *nodeExpandOutput) temporaryValue() bool {
|
2020-10-09 16:24:10 -05:00
|
|
|
// non root outputs are temporary
|
2020-04-02 12:26:53 -05:00
|
|
|
return !n.Module.IsRoot()
|
|
|
|
}
|
|
|
|
|
2020-05-12 09:44:45 -05:00
|
|
|
func (n *nodeExpandOutput) DynamicExpand(ctx EvalContext) (*Graph, error) {
|
2020-02-24 16:42:32 -06:00
|
|
|
expander := ctx.InstanceExpander()
|
2022-04-20 13:45:58 -05:00
|
|
|
changes := ctx.Changes()
|
2020-10-09 16:24:10 -05:00
|
|
|
|
2022-06-15 20:00:20 -05:00
|
|
|
// If this is an output value that participates in custom condition checks
|
|
|
|
// (i.e. it has preconditions or postconditions) then the check state
|
|
|
|
// wants to know the addresses of the checkable objects so that it can
|
|
|
|
// treat them as unknown status if we encounter an error before actually
|
|
|
|
// visiting the checks.
|
2022-09-28 12:49:57 -05:00
|
|
|
//
|
|
|
|
// We must do this only during planning, because the apply phase will start
|
|
|
|
// with all of the same checkable objects that were registered during the
|
|
|
|
// planning phase. Consumers of our JSON plan and state formats expect
|
|
|
|
// that the set of checkable objects will be consistent between the plan
|
|
|
|
// and any state snapshots created during apply, and that only the statuses
|
|
|
|
// of those objects will have changed.
|
2022-06-15 20:00:20 -05:00
|
|
|
var checkableAddrs addrs.Set[addrs.Checkable]
|
2022-09-28 12:49:57 -05:00
|
|
|
if n.Planning {
|
|
|
|
if checkState := ctx.Checks(); checkState.ConfigHasChecks(n.Addr.InModule(n.Module)) {
|
|
|
|
checkableAddrs = addrs.MakeSet[addrs.Checkable]()
|
|
|
|
}
|
2022-06-15 20:00:20 -05:00
|
|
|
}
|
|
|
|
|
2020-10-09 16:24:10 -05:00
|
|
|
var g Graph
|
2020-03-06 17:02:20 -06:00
|
|
|
for _, module := range expander.ExpandModule(n.Module) {
|
2020-10-09 10:09:36 -05:00
|
|
|
absAddr := n.Addr.Absolute(module)
|
2022-06-15 20:00:20 -05:00
|
|
|
if checkableAddrs != nil {
|
|
|
|
checkableAddrs.Add(absAddr)
|
|
|
|
}
|
2020-10-09 10:09:36 -05:00
|
|
|
|
|
|
|
// Find any recorded change for this output
|
|
|
|
var change *plans.OutputChangeSrc
|
2022-06-15 21:03:10 -05:00
|
|
|
var outputChanges []*plans.OutputChangeSrc
|
|
|
|
if module.IsRoot() {
|
|
|
|
outputChanges = changes.GetRootOutputChanges()
|
|
|
|
} else {
|
|
|
|
parent, call := module.Call()
|
|
|
|
outputChanges = changes.GetOutputChanges(parent, call)
|
|
|
|
}
|
|
|
|
for _, c := range outputChanges {
|
2020-10-09 10:09:36 -05:00
|
|
|
if c.Addr.String() == absAddr.String() {
|
|
|
|
change = c
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-18 17:15:17 -05:00
|
|
|
var node dag.Vertex
|
|
|
|
switch {
|
2023-05-22 11:21:30 -05:00
|
|
|
case module.IsRoot() && n.Destroying:
|
2022-10-18 17:15:17 -05:00
|
|
|
node = &NodeDestroyableOutput{
|
2022-11-22 08:11:10 -06:00
|
|
|
Addr: absAddr,
|
|
|
|
Planning: n.Planning,
|
2022-10-18 17:15:17 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
node = &NodeApplyableOutput{
|
|
|
|
Addr: absAddr,
|
|
|
|
Config: n.Config,
|
|
|
|
Change: change,
|
|
|
|
RefreshOnly: n.RefreshOnly,
|
2023-05-22 11:21:30 -05:00
|
|
|
DestroyApply: n.Destroying,
|
2022-11-22 08:11:10 -06:00
|
|
|
Planning: n.Planning,
|
2022-10-18 17:15:17 -05:00
|
|
|
}
|
2020-10-09 10:09:36 -05:00
|
|
|
}
|
2022-10-18 17:15:17 -05:00
|
|
|
|
|
|
|
log.Printf("[TRACE] Expanding output: adding %s as %T", absAddr.String(), node)
|
|
|
|
g.Add(node)
|
2020-10-09 10:09:36 -05:00
|
|
|
}
|
2022-09-27 18:25:04 -05:00
|
|
|
addRootNodeToGraph(&g)
|
2022-06-15 20:00:20 -05:00
|
|
|
|
|
|
|
if checkableAddrs != nil {
|
|
|
|
checkState := ctx.Checks()
|
|
|
|
checkState.ReportCheckableObjects(n.Addr.InModule(n.Module), checkableAddrs)
|
|
|
|
}
|
|
|
|
|
2020-10-09 10:09:36 -05:00
|
|
|
return &g, nil
|
|
|
|
}
|
|
|
|
|
2020-05-12 09:44:45 -05:00
|
|
|
func (n *nodeExpandOutput) Name() string {
|
2020-03-06 17:02:20 -06:00
|
|
|
path := n.Module.String()
|
2020-05-12 09:44:45 -05:00
|
|
|
addr := n.Addr.String() + " (expand)"
|
2020-03-06 17:02:20 -06:00
|
|
|
if path != "" {
|
|
|
|
return path + "." + addr
|
|
|
|
}
|
|
|
|
return addr
|
2020-02-24 16:42:32 -06:00
|
|
|
}
|
|
|
|
|
2020-03-04 20:00:16 -06:00
|
|
|
// GraphNodeModulePath
|
2020-05-12 09:44:45 -05:00
|
|
|
func (n *nodeExpandOutput) ModulePath() addrs.Module {
|
2020-03-04 20:00:16 -06:00
|
|
|
return n.Module
|
|
|
|
}
|
|
|
|
|
2020-02-24 16:42:32 -06:00
|
|
|
// GraphNodeReferenceable
|
2020-05-12 09:44:45 -05:00
|
|
|
func (n *nodeExpandOutput) ReferenceableAddrs() []addrs.Referenceable {
|
2020-02-24 16:42:32 -06:00
|
|
|
// An output in the root module can't be referenced at all.
|
|
|
|
if n.Module.IsRoot() {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// the output is referenced through the module call, and via the
|
|
|
|
// module itself.
|
|
|
|
_, call := n.Module.Call()
|
|
|
|
callOutput := addrs.ModuleCallOutput{
|
2020-03-20 11:18:48 -05:00
|
|
|
Call: call,
|
2020-02-24 16:42:32 -06:00
|
|
|
Name: n.Addr.Name,
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise, we can reference the output via the
|
|
|
|
// module call itself
|
|
|
|
return []addrs.Referenceable{call, callOutput}
|
|
|
|
}
|
|
|
|
|
|
|
|
// GraphNodeReferenceOutside implementation
|
2020-05-12 09:44:45 -05:00
|
|
|
func (n *nodeExpandOutput) ReferenceOutside() (selfPath, referencePath addrs.Module) {
|
2020-02-24 16:42:32 -06:00
|
|
|
// Output values have their expressions resolved in the context of the
|
|
|
|
// module where they are defined.
|
|
|
|
referencePath = n.Module
|
|
|
|
|
|
|
|
// ...but they are referenced in the context of their calling module.
|
|
|
|
selfPath = referencePath.Parent()
|
|
|
|
|
|
|
|
return // uses named return values
|
|
|
|
}
|
|
|
|
|
|
|
|
// GraphNodeReferencer
|
2020-05-12 09:44:45 -05:00
|
|
|
func (n *nodeExpandOutput) References() []*addrs.Reference {
|
2022-10-14 17:08:18 -05:00
|
|
|
// DestroyNodes do not reference anything.
|
2023-05-22 11:21:30 -05:00
|
|
|
if n.Module.IsRoot() && n.Destroying {
|
2022-10-14 17:08:18 -05:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-07-17 17:48:35 -05:00
|
|
|
return referencesForOutput(n.Config)
|
2020-02-24 16:42:32 -06:00
|
|
|
}
|
|
|
|
|
2016-09-16 01:20:35 -05:00
|
|
|
// NodeApplyableOutput represents an output that is "applyable":
|
|
|
|
// it is ready to be applied.
|
|
|
|
type NodeApplyableOutput 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
|
|
|
Addr addrs.AbsOutputValue
|
|
|
|
Config *configs.Output // Config is the output in the config
|
2020-10-09 10:09:36 -05:00
|
|
|
// If this is being evaluated during apply, we may have a change recorded already
|
|
|
|
Change *plans.OutputChangeSrc
|
2022-03-09 15:04:01 -06:00
|
|
|
|
|
|
|
// Refresh-only mode means that any failing output preconditions are
|
|
|
|
// reported as warnings rather than errors
|
|
|
|
RefreshOnly bool
|
2022-10-14 17:08:18 -05:00
|
|
|
|
|
|
|
// DestroyApply indicates that we are applying a destroy plan, and do not
|
|
|
|
// need to account for conditional blocks.
|
|
|
|
DestroyApply bool
|
2022-11-22 08:11:10 -06:00
|
|
|
|
|
|
|
Planning bool
|
2016-09-16 01:20:35 -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
|
|
|
var (
|
2020-03-05 15:13:54 -06:00
|
|
|
_ GraphNodeModuleInstance = (*NodeApplyableOutput)(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 = (*NodeApplyableOutput)(nil)
|
|
|
|
_ GraphNodeReferencer = (*NodeApplyableOutput)(nil)
|
|
|
|
_ GraphNodeReferenceOutside = (*NodeApplyableOutput)(nil)
|
2020-09-08 13:02:45 -05:00
|
|
|
_ GraphNodeExecutable = (*NodeApplyableOutput)(nil)
|
2020-04-02 12:26:53 -05:00
|
|
|
_ graphNodeTemporaryValue = (*NodeApplyableOutput)(nil)
|
2018-05-02 21:55:53 -05:00
|
|
|
_ dag.GraphNodeDotter = (*NodeApplyableOutput)(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-09-16 01:20:35 -05:00
|
|
|
|
2020-04-02 12:26:53 -05:00
|
|
|
func (n *NodeApplyableOutput) temporaryValue() bool {
|
|
|
|
// this must always be evaluated if it is a root module output
|
|
|
|
return !n.Addr.Module.IsRoot()
|
|
|
|
}
|
|
|
|
|
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 *NodeApplyableOutput) Name() string {
|
|
|
|
return n.Addr.String()
|
2016-09-16 01:20:35 -05:00
|
|
|
}
|
|
|
|
|
2020-03-05 15:13:54 -06:00
|
|
|
// GraphNodeModuleInstance
|
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 *NodeApplyableOutput) Path() addrs.ModuleInstance {
|
|
|
|
return n.Addr.Module
|
2016-09-16 01:20:35 -05:00
|
|
|
}
|
|
|
|
|
2020-03-04 20:00:16 -06:00
|
|
|
// GraphNodeModulePath
|
|
|
|
func (n *NodeApplyableOutput) ModulePath() addrs.Module {
|
|
|
|
return n.Addr.Module.Module()
|
|
|
|
}
|
|
|
|
|
2020-02-24 16:42:32 -06:00
|
|
|
func referenceOutsideForOutput(addr addrs.AbsOutputValue) (selfPath, referencePath addrs.Module) {
|
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
|
|
|
// Output values have their expressions resolved in the context of the
|
|
|
|
// module where they are defined.
|
2020-02-24 16:42:32 -06:00
|
|
|
referencePath = addr.Module.Module()
|
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
|
|
|
|
|
|
|
// ...but they are referenced in the context of their calling module.
|
2020-02-24 16:42:32 -06:00
|
|
|
selfPath = addr.Module.Parent().Module()
|
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
|
|
|
|
|
|
|
return // uses named return values
|
|
|
|
}
|
|
|
|
|
|
|
|
// GraphNodeReferenceOutside implementation
|
2020-02-24 16:42:32 -06:00
|
|
|
func (n *NodeApplyableOutput) ReferenceOutside() (selfPath, referencePath addrs.Module) {
|
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
|
|
|
return referenceOutsideForOutput(n.Addr)
|
|
|
|
}
|
|
|
|
|
|
|
|
func referenceableAddrsForOutput(addr addrs.AbsOutputValue) []addrs.Referenceable {
|
|
|
|
// An output in the root module can't be referenced at all.
|
|
|
|
if addr.Module.IsRoot() {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise, we can be referenced via a reference to our output name
|
|
|
|
// on the parent module's call, or via a reference to the entire call.
|
|
|
|
// e.g. module.foo.bar or just module.foo .
|
|
|
|
// Note that our ReferenceOutside method causes these addresses to be
|
|
|
|
// relative to the calling module, not the module where the output
|
|
|
|
// was declared.
|
|
|
|
_, outp := addr.ModuleCallOutput()
|
|
|
|
_, call := addr.Module.CallInstance()
|
|
|
|
|
2020-02-24 16:42:32 -06:00
|
|
|
return []addrs.Referenceable{outp, call}
|
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-09-16 01:20:35 -05:00
|
|
|
// GraphNodeReferenceable
|
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 *NodeApplyableOutput) ReferenceableAddrs() []addrs.Referenceable {
|
|
|
|
return referenceableAddrsForOutput(n.Addr)
|
2016-09-16 01:20:35 -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
|
|
|
func referencesForOutput(c *configs.Output) []*addrs.Reference {
|
2023-01-04 14:12:58 -06:00
|
|
|
var refs []*addrs.Reference
|
|
|
|
|
2023-06-28 02:47:24 -05:00
|
|
|
impRefs, _ := lang.ReferencesInExpr(addrs.ParseRef, c.Expr)
|
|
|
|
expRefs, _ := lang.References(addrs.ParseRef, c.DependsOn)
|
2023-01-04 14:12:58 -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
|
|
|
refs = append(refs, impRefs...)
|
|
|
|
refs = append(refs, expRefs...)
|
2023-01-04 14:12:58 -06:00
|
|
|
|
2020-11-20 17:10:08 -06:00
|
|
|
for _, check := range c.Preconditions {
|
2023-06-28 02:47:24 -05:00
|
|
|
condRefs, _ := lang.ReferencesInExpr(addrs.ParseRef, check.Condition)
|
2023-01-04 14:12:58 -06:00
|
|
|
refs = append(refs, condRefs...)
|
2023-06-28 02:47:24 -05:00
|
|
|
errRefs, _ := lang.ReferencesInExpr(addrs.ParseRef, check.ErrorMessage)
|
2023-01-04 14:12:58 -06:00
|
|
|
refs = append(refs, errRefs...)
|
2020-11-20 17:10:08 -06:00
|
|
|
}
|
2023-01-04 14:12:58 -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
|
|
|
return refs
|
|
|
|
}
|
|
|
|
|
|
|
|
// GraphNodeReferencer
|
|
|
|
func (n *NodeApplyableOutput) References() []*addrs.Reference {
|
2020-07-17 17:48:35 -05:00
|
|
|
return referencesForOutput(n.Config)
|
2016-09-16 01:20:35 -05:00
|
|
|
}
|
|
|
|
|
2020-09-08 13:02:45 -05:00
|
|
|
// GraphNodeExecutable
|
2020-10-28 12:47:04 -05:00
|
|
|
func (n *NodeApplyableOutput) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
|
2020-10-06 16:14:53 -05:00
|
|
|
state := ctx.State()
|
|
|
|
if state == nil {
|
2020-10-28 12:47:04 -05:00
|
|
|
return
|
2020-10-06 16:14:53 -05:00
|
|
|
}
|
2020-09-21 08:36:50 -05:00
|
|
|
|
2020-10-06 16:14:53 -05:00
|
|
|
changes := ctx.Changes() // may be nil, if we're not working on a changeset
|
|
|
|
|
2020-10-09 10:09:36 -05:00
|
|
|
val := cty.UnknownVal(cty.DynamicPseudoType)
|
|
|
|
changeRecorded := n.Change != nil
|
|
|
|
// we we have a change recorded, we don't need to re-evaluate if the value
|
|
|
|
// was known
|
|
|
|
if changeRecorded {
|
2021-05-11 16:55:27 -05:00
|
|
|
change, err := n.Change.Decode()
|
2020-10-09 10:09:36 -05:00
|
|
|
diags = diags.Append(err)
|
2021-05-11 16:55:27 -05:00
|
|
|
if err == nil {
|
|
|
|
val = change.After
|
|
|
|
}
|
2020-10-09 10:09:36 -05:00
|
|
|
}
|
|
|
|
|
2022-10-14 17:08:18 -05:00
|
|
|
// Checks are not evaluated during a destroy. The checks may fail, may not
|
|
|
|
// be valid, or may not have been registered at all.
|
|
|
|
if !n.DestroyApply {
|
|
|
|
checkRuleSeverity := tfdiags.Error
|
|
|
|
if n.RefreshOnly {
|
|
|
|
checkRuleSeverity = tfdiags.Warning
|
|
|
|
}
|
|
|
|
checkDiags := evalCheckRules(
|
|
|
|
addrs.OutputPrecondition,
|
|
|
|
n.Config.Preconditions,
|
|
|
|
ctx, n.Addr, EvalDataForNoInstanceKey,
|
|
|
|
checkRuleSeverity,
|
|
|
|
)
|
|
|
|
diags = diags.Append(checkDiags)
|
|
|
|
if diags.HasErrors() {
|
|
|
|
return diags // failed preconditions prevent further evaluation
|
|
|
|
}
|
2020-11-20 18:03:11 -06:00
|
|
|
}
|
|
|
|
|
2020-10-09 10:09:36 -05:00
|
|
|
// If there was no change recorded, or the recorded change was not wholly
|
|
|
|
// known, then we need to re-evaluate the output
|
|
|
|
if !changeRecorded || !val.IsWhollyKnown() {
|
2024-06-06 05:20:41 -05:00
|
|
|
switch {
|
|
|
|
// If the module is not being overridden, we proceed normally
|
|
|
|
case !n.Config.IsOverridden:
|
|
|
|
// This has to run before we have a state lock, since evaluation also
|
|
|
|
// reads the state
|
|
|
|
var evalDiags tfdiags.Diagnostics
|
|
|
|
val, evalDiags = ctx.EvaluateExpr(n.Config.Expr, cty.DynamicPseudoType, nil)
|
|
|
|
diags = diags.Append(evalDiags)
|
|
|
|
|
|
|
|
// If the module is being overridden and we have a value to use,
|
|
|
|
// we just use it
|
|
|
|
case n.Config.OverrideValue != nil:
|
|
|
|
val = *n.Config.OverrideValue
|
|
|
|
|
|
|
|
// If the module is being overridden, but we don't have any value to use,
|
|
|
|
// we just set it to null
|
|
|
|
default:
|
|
|
|
val = cty.NilVal
|
|
|
|
}
|
2022-03-09 15:04:01 -06:00
|
|
|
|
2020-10-09 10:09:36 -05:00
|
|
|
// We'll handle errors below, after we have loaded the module.
|
|
|
|
// Outputs don't have a separate mode for validation, so validate
|
|
|
|
// depends_on expressions here too
|
|
|
|
diags = diags.Append(validateDependsOn(ctx, n.Config.DependsOn))
|
|
|
|
|
2021-04-20 17:49:54 -05:00
|
|
|
// For root module outputs in particular, an output value must be
|
|
|
|
// statically declared as sensitive in order to dynamically return
|
|
|
|
// a sensitive result, to help avoid accidental exposure in the state
|
|
|
|
// of a sensitive value that the user doesn't want to include there.
|
|
|
|
if n.Addr.Module.IsRoot() {
|
2021-06-25 13:13:57 -05:00
|
|
|
if !n.Config.Sensitive && marks.Contains(val, marks.Sensitive) {
|
2021-04-20 17:49:54 -05:00
|
|
|
diags = diags.Append(&hcl.Diagnostic{
|
|
|
|
Severity: hcl.DiagError,
|
|
|
|
Summary: "Output refers to sensitive values",
|
2023-09-21 07:38:46 -05:00
|
|
|
Detail: `To reduce the risk of accidentally exporting sensitive data that was intended to be only internal, OpenTofu requires that any root module output containing sensitive data be explicitly marked as sensitive, to confirm your intent.
|
2021-04-20 17:49:54 -05:00
|
|
|
|
|
|
|
If you do intend to export this data, annotate the output value as sensitive by adding the following argument:
|
|
|
|
sensitive = true`,
|
|
|
|
Subject: n.Config.DeclRange.Ptr(),
|
|
|
|
})
|
|
|
|
}
|
2020-10-09 10:09:36 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-06 16:14:53 -05:00
|
|
|
// handling the interpolation error
|
|
|
|
if diags.HasErrors() {
|
|
|
|
if flagWarnOutputErrors {
|
|
|
|
log.Printf("[ERROR] Output interpolation %q failed: %s", n.Addr, diags.Err())
|
|
|
|
// if we're continuing, make sure the output is included, and
|
|
|
|
// marked as unknown. If the evaluator was able to find a type
|
|
|
|
// for the value in spite of the error then we'll use it.
|
|
|
|
n.setValue(state, changes, cty.UnknownVal(val.Type()))
|
2020-10-28 12:47:04 -05:00
|
|
|
|
|
|
|
// Keep existing warnings, while converting errors to warnings.
|
|
|
|
// This is not meant to be the normal path, so there no need to
|
|
|
|
// make the errors pretty.
|
|
|
|
var warnings tfdiags.Diagnostics
|
|
|
|
for _, d := range diags {
|
|
|
|
switch d.Severity() {
|
|
|
|
case tfdiags.Warning:
|
|
|
|
warnings = warnings.Append(d)
|
|
|
|
case tfdiags.Error:
|
|
|
|
desc := d.Description()
|
|
|
|
warnings = warnings.Append(tfdiags.SimpleWarning(fmt.Sprintf("%s:%s", desc.Summary, desc.Detail)))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return warnings
|
2020-09-21 08:36:50 -05:00
|
|
|
}
|
2020-10-28 12:47:04 -05:00
|
|
|
return diags
|
2020-10-06 16:14:53 -05:00
|
|
|
}
|
|
|
|
n.setValue(state, changes, val)
|
2020-09-21 08:36:50 -05:00
|
|
|
|
2020-10-06 16:14:53 -05:00
|
|
|
// If we were able to evaluate a new value, we can update that in the
|
|
|
|
// refreshed state as well.
|
|
|
|
if state = ctx.RefreshState(); state != nil && val.IsWhollyKnown() {
|
2022-11-21 10:04:21 -06:00
|
|
|
// we only need to update the state, do not pass in the changes again
|
|
|
|
n.setValue(state, nil, val)
|
2016-09-16 01:20:35 -05:00
|
|
|
}
|
2020-10-06 16:14:53 -05:00
|
|
|
|
2020-10-28 12:47:04 -05:00
|
|
|
return diags
|
2016-09-16 01:20:35 -05:00
|
|
|
}
|
2018-01-29 18:17:31 -06:00
|
|
|
|
2018-05-02 21:55:53 -05:00
|
|
|
// dag.GraphNodeDotter impl.
|
|
|
|
func (n *NodeApplyableOutput) DotNode(name string, opts *dag.DotOpts) *dag.DotNode {
|
|
|
|
return &dag.DotNode{
|
|
|
|
Name: name,
|
|
|
|
Attrs: map[string]string{
|
|
|
|
"label": n.Name(),
|
|
|
|
"shape": "note",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-09 10:09:36 -05:00
|
|
|
// NodeDestroyableOutput represents an output that is "destroyable":
|
2018-01-29 18:17:31 -06:00
|
|
|
// its application will remove the output from the state.
|
|
|
|
type NodeDestroyableOutput struct {
|
2022-11-22 08:11:10 -06:00
|
|
|
Addr addrs.AbsOutputValue
|
|
|
|
Planning bool
|
2018-01-29 18:17:31 -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-09-08 13:02:45 -05:00
|
|
|
_ GraphNodeExecutable = (*NodeDestroyableOutput)(nil)
|
2020-06-24 09:45:58 -05:00
|
|
|
_ dag.GraphNodeDotter = (*NodeDestroyableOutput)(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
|
|
|
)
|
2018-01-29 18:17:31 -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
|
|
|
func (n *NodeDestroyableOutput) Name() string {
|
|
|
|
return fmt.Sprintf("%s (destroy)", n.Addr.String())
|
2018-01-29 18:17:31 -06:00
|
|
|
}
|
|
|
|
|
2020-03-04 20:00:16 -06:00
|
|
|
// GraphNodeModulePath
|
|
|
|
func (n *NodeDestroyableOutput) ModulePath() addrs.Module {
|
2020-03-20 14:19:01 -05:00
|
|
|
return n.Addr.Module.Module()
|
2020-03-04 20:00:16 -06:00
|
|
|
}
|
|
|
|
|
2020-06-24 09:22:10 -05:00
|
|
|
func (n *NodeDestroyableOutput) temporaryValue() bool {
|
|
|
|
// this must always be evaluated if it is a root module output
|
|
|
|
return !n.Addr.Module.IsRoot()
|
|
|
|
}
|
|
|
|
|
2020-09-08 13:02:45 -05:00
|
|
|
// GraphNodeExecutable
|
2020-10-28 12:47:04 -05:00
|
|
|
func (n *NodeDestroyableOutput) Execute(ctx EvalContext, op walkOperation) tfdiags.Diagnostics {
|
2020-09-08 13:02:45 -05:00
|
|
|
state := ctx.State()
|
|
|
|
if state == nil {
|
|
|
|
return nil
|
2018-01-29 18:17:31 -06:00
|
|
|
}
|
2020-10-09 10:09:36 -05:00
|
|
|
|
2020-10-09 17:58:43 -05:00
|
|
|
// if this is a root module, try to get a before value from the state for
|
|
|
|
// the diff
|
2020-10-12 11:10:01 -05:00
|
|
|
sensitiveBefore := false
|
2020-10-09 17:58:43 -05:00
|
|
|
before := cty.NullVal(cty.DynamicPseudoType)
|
|
|
|
mod := state.Module(n.Addr.Module)
|
|
|
|
if n.Addr.Module.IsRoot() && mod != nil {
|
2022-08-03 11:45:13 -05:00
|
|
|
if o, ok := mod.OutputValues[n.Addr.OutputValue.Name]; ok {
|
|
|
|
sensitiveBefore = o.Sensitive
|
|
|
|
before = o.Value
|
|
|
|
} else {
|
|
|
|
// If the output was not in state, a delete change would
|
|
|
|
// be meaningless, so exit early.
|
|
|
|
return nil
|
|
|
|
|
2020-10-09 17:58:43 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-09 10:09:36 -05:00
|
|
|
changes := ctx.Changes()
|
2022-11-22 08:11:10 -06:00
|
|
|
if changes != nil && n.Planning {
|
2020-10-09 10:09:36 -05:00
|
|
|
change := &plans.OutputChange{
|
2020-10-12 11:10:01 -05:00
|
|
|
Addr: n.Addr,
|
|
|
|
Sensitive: sensitiveBefore,
|
2020-10-09 10:09:36 -05:00
|
|
|
Change: plans.Change{
|
|
|
|
Action: plans.Delete,
|
2020-10-09 17:58:43 -05:00
|
|
|
Before: before,
|
2020-10-09 10:09:36 -05:00
|
|
|
After: cty.NullVal(cty.DynamicPseudoType),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
cs, err := change.Encode()
|
|
|
|
if err != nil {
|
|
|
|
// Should never happen, since we just constructed this right above
|
|
|
|
panic(fmt.Sprintf("planned change for %s could not be encoded: %s", n.Addr, err))
|
|
|
|
}
|
2020-10-09 16:24:10 -05:00
|
|
|
log.Printf("[TRACE] NodeDestroyableOutput: Saving %s change for %s in changeset", change.Action, n.Addr)
|
2022-11-22 08:11:10 -06:00
|
|
|
|
2020-10-09 10:09:36 -05:00
|
|
|
changes.RemoveOutputChange(n.Addr) // remove any existing planned change, if present
|
|
|
|
changes.AppendOutputChange(cs) // add the new planned change
|
|
|
|
}
|
|
|
|
|
2020-09-08 13:02:45 -05:00
|
|
|
state.RemoveOutputValue(n.Addr)
|
|
|
|
return nil
|
2018-01-29 18:17:31 -06:00
|
|
|
}
|
2018-05-02 21:55:53 -05:00
|
|
|
|
|
|
|
// dag.GraphNodeDotter impl.
|
|
|
|
func (n *NodeDestroyableOutput) DotNode(name string, opts *dag.DotOpts) *dag.DotNode {
|
|
|
|
return &dag.DotNode{
|
|
|
|
Name: name,
|
|
|
|
Attrs: map[string]string{
|
|
|
|
"label": n.Name(),
|
|
|
|
"shape": "note",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
2020-09-08 13:02:45 -05:00
|
|
|
|
|
|
|
func (n *NodeApplyableOutput) setValue(state *states.SyncState, changes *plans.ChangesSync, val cty.Value) {
|
2022-11-22 08:11:10 -06:00
|
|
|
if changes != nil && n.Planning {
|
2020-10-09 17:58:43 -05:00
|
|
|
// if this is a root module, try to get a before value from the state for
|
|
|
|
// the diff
|
2020-10-12 11:10:01 -05:00
|
|
|
sensitiveBefore := false
|
2020-10-09 17:58:43 -05:00
|
|
|
before := cty.NullVal(cty.DynamicPseudoType)
|
2021-01-14 08:24:47 -06:00
|
|
|
|
|
|
|
// is this output new to our state?
|
|
|
|
newOutput := true
|
|
|
|
|
2020-10-09 17:58:43 -05:00
|
|
|
mod := state.Module(n.Addr.Module)
|
|
|
|
if n.Addr.Module.IsRoot() && mod != nil {
|
|
|
|
for name, o := range mod.OutputValues {
|
|
|
|
if name == n.Addr.OutputValue.Name {
|
|
|
|
before = o.Value
|
2020-10-12 11:10:01 -05:00
|
|
|
sensitiveBefore = o.Sensitive
|
2021-01-14 08:24:47 -06:00
|
|
|
newOutput = false
|
2020-10-09 17:58:43 -05:00
|
|
|
break
|
|
|
|
}
|
2020-09-08 13:02:45 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-20 13:07:39 -05:00
|
|
|
// We will not show the value if either the before or after are marked
|
|
|
|
// as sensitive. We can show the value again once sensitivity is
|
2020-10-12 11:10:01 -05:00
|
|
|
// removed from both the config and the state.
|
|
|
|
sensitiveChange := sensitiveBefore || n.Config.Sensitive
|
|
|
|
|
|
|
|
// strip any marks here just to be sure we don't panic on the True comparison
|
2021-04-20 17:49:54 -05:00
|
|
|
unmarkedVal, _ := val.UnmarkDeep()
|
2020-10-12 11:10:01 -05:00
|
|
|
|
2021-01-14 07:59:31 -06:00
|
|
|
action := plans.Update
|
2020-10-09 17:58:43 -05:00
|
|
|
switch {
|
2021-01-14 07:59:31 -06:00
|
|
|
case val.IsNull() && before.IsNull():
|
|
|
|
// This is separate from the NoOp case below, since we can ignore
|
2021-01-14 08:24:47 -06:00
|
|
|
// sensitivity here when there are only null values.
|
2021-01-14 07:59:31 -06:00
|
|
|
action = plans.NoOp
|
2020-10-12 11:10:01 -05:00
|
|
|
|
2021-01-14 08:24:47 -06:00
|
|
|
case newOutput:
|
|
|
|
// This output was just added to the configuration
|
2020-10-09 17:58:43 -05:00
|
|
|
action = plans.Create
|
2020-10-12 11:10:01 -05:00
|
|
|
|
|
|
|
case val.IsWhollyKnown() &&
|
2021-04-20 17:49:54 -05:00
|
|
|
unmarkedVal.Equals(before).True() &&
|
2020-10-12 11:10:01 -05:00
|
|
|
n.Config.Sensitive == sensitiveBefore:
|
|
|
|
// Sensitivity must also match to be a NoOp.
|
|
|
|
// Theoretically marks may not match here, but sensitivity is the
|
|
|
|
// only one we can act on, and the state will have been loaded
|
|
|
|
// without any marks to consider.
|
2020-10-09 17:58:43 -05:00
|
|
|
action = plans.NoOp
|
|
|
|
}
|
|
|
|
|
|
|
|
change := &plans.OutputChange{
|
|
|
|
Addr: n.Addr,
|
2020-10-12 11:10:01 -05:00
|
|
|
Sensitive: sensitiveChange,
|
2020-10-09 17:58:43 -05:00
|
|
|
Change: plans.Change{
|
|
|
|
Action: action,
|
|
|
|
Before: before,
|
|
|
|
After: val,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2020-09-08 13:02:45 -05:00
|
|
|
cs, err := change.Encode()
|
|
|
|
if err != nil {
|
|
|
|
// Should never happen, since we just constructed this right above
|
|
|
|
panic(fmt.Sprintf("planned change for %s could not be encoded: %s", n.Addr, err))
|
|
|
|
}
|
2020-12-10 08:55:50 -06:00
|
|
|
log.Printf("[TRACE] setValue: Saving %s change for %s in changeset", change.Action, n.Addr)
|
2022-11-22 08:11:10 -06:00
|
|
|
changes.AppendOutputChange(cs) // add the new planned change
|
|
|
|
}
|
|
|
|
|
|
|
|
if changes != nil && !n.Planning {
|
|
|
|
// During apply there is no longer any change to track, so we must
|
|
|
|
// ensure the state is updated and not overridden by a change.
|
|
|
|
changes.RemoveOutputChange(n.Addr)
|
2020-09-08 13:02:45 -05:00
|
|
|
}
|
2020-10-09 17:58:43 -05:00
|
|
|
|
2023-01-26 09:48:49 -06:00
|
|
|
// Null outputs must be saved for modules so that they can still be
|
|
|
|
// evaluated. Null root outputs are removed entirely, which is always fine
|
|
|
|
// because they can't be referenced by anything else in the configuration.
|
|
|
|
if n.Addr.Module.IsRoot() && val.IsNull() {
|
2020-12-10 08:55:50 -06:00
|
|
|
log.Printf("[TRACE] setValue: Removing %s from state (it is now null)", n.Addr)
|
2020-10-09 17:58:43 -05:00
|
|
|
state.RemoveOutputValue(n.Addr)
|
2023-01-26 09:48:49 -06:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Printf("[TRACE] setValue: Saving value for %s in state", n.Addr)
|
2023-03-20 12:27:53 -05:00
|
|
|
|
|
|
|
// non-root outputs need to keep sensitive marks for evaluation, but are
|
|
|
|
// not serialized.
|
|
|
|
if n.Addr.Module.IsRoot() {
|
|
|
|
val, _ = val.UnmarkDeep()
|
|
|
|
val = cty.UnknownAsNull(val)
|
2020-10-09 17:58:43 -05:00
|
|
|
}
|
|
|
|
|
2023-03-20 12:27:53 -05:00
|
|
|
state.SetOutputValue(n.Addr, val, n.Config.Sensitive)
|
2020-09-08 13:02:45 -05:00
|
|
|
}
|