opentofu/terraform/node_module_removed.go
2020-03-11 14:52:15 -04:00

98 lines
2.9 KiB
Go

package terraform
import (
"fmt"
"github.com/hashicorp/terraform/addrs"
)
// NodeModuleRemoved represents a module that is no longer in the
// config.
type NodeModuleRemoved struct {
Addr addrs.ModuleInstance
}
var (
_ GraphNodeModuleInstance = (*NodeModuleRemoved)(nil)
_ RemovableIfNotTargeted = (*NodeModuleRemoved)(nil)
_ GraphNodeEvalable = (*NodeModuleRemoved)(nil)
_ GraphNodeReferencer = (*NodeModuleRemoved)(nil)
_ GraphNodeReferenceOutside = (*NodeModuleRemoved)(nil)
)
func (n *NodeModuleRemoved) Name() string {
return fmt.Sprintf("%s (removed)", n.Addr.String())
}
// GraphNodeModuleInstance
func (n *NodeModuleRemoved) Path() addrs.ModuleInstance {
return n.Addr
}
// GraphNodeModulePath implementation
func (n *NodeModuleRemoved) ModulePath() addrs.Module {
// This node represents the module call within a module,
// so return the CallerAddr as the path, as the module
// call may expand into multiple child instances
return n.Addr.Module()
}
// GraphNodeEvalable
func (n *NodeModuleRemoved) EvalTree() EvalNode {
return &EvalOpFilter{
Ops: []walkOperation{walkRefresh, walkApply, walkDestroy},
Node: &EvalCheckModuleRemoved{
Addr: n.Addr,
},
}
}
func (n *NodeModuleRemoved) ReferenceOutside() (selfPath, referencePath addrs.Module) {
// Our "References" implementation indicates that this node depends on
// the call to the module it represents, which implicitly depends on
// everything inside the module. That reference must therefore be
// interpreted in terms of our parent module.
return n.Addr.Module(), n.Addr.Parent().Module()
}
func (n *NodeModuleRemoved) References() []*addrs.Reference {
// We depend on the call to the module we represent, because that
// implicitly then depends on everything inside that module.
// Our ReferenceOutside implementation causes this to be interpreted
// within the parent module.
_, call := n.Addr.CallInstance()
return []*addrs.Reference{
{
Subject: call,
// No source range here, because there's nothing reasonable for
// us to return.
},
}
}
// RemovableIfNotTargeted
func (n *NodeModuleRemoved) RemoveIfNotTargeted() bool {
// We need to add this so that this node will be removed if
// it isn't targeted or a dependency of a target.
return true
}
// EvalCheckModuleRemoved is an EvalNode implementation that verifies that
// a module has been removed from the state as expected.
type EvalCheckModuleRemoved struct {
Addr addrs.ModuleInstance
}
func (n *EvalCheckModuleRemoved) Eval(ctx EvalContext) (interface{}, error) {
mod := ctx.State().Module(n.Addr)
if mod != nil {
// If we get here then that indicates a bug either in the states
// module or in an earlier step of the graph walk, since we should've
// pruned out the module when the last resource was removed from it.
return nil, fmt.Errorf("leftover module %s in state that should have been removed; this is a bug in Terraform and should be reported", n.Addr)
}
return nil, nil
}