1package terraform
2
3import (
4	"fmt"
5
6	"github.com/hashicorp/terraform-plugin-sdk/internal/addrs"
7)
8
9// NodeModuleRemoved represents a module that is no longer in the
10// config.
11type NodeModuleRemoved struct {
12	Addr addrs.ModuleInstance
13}
14
15var (
16	_ GraphNodeSubPath          = (*NodeModuleRemoved)(nil)
17	_ GraphNodeEvalable         = (*NodeModuleRemoved)(nil)
18	_ GraphNodeReferencer       = (*NodeModuleRemoved)(nil)
19	_ GraphNodeReferenceOutside = (*NodeModuleRemoved)(nil)
20)
21
22func (n *NodeModuleRemoved) Name() string {
23	return fmt.Sprintf("%s (removed)", n.Addr.String())
24}
25
26// GraphNodeSubPath
27func (n *NodeModuleRemoved) Path() addrs.ModuleInstance {
28	return n.Addr
29}
30
31// GraphNodeEvalable
32func (n *NodeModuleRemoved) EvalTree() EvalNode {
33	return &EvalOpFilter{
34		Ops: []walkOperation{walkRefresh, walkApply, walkDestroy},
35		Node: &EvalCheckModuleRemoved{
36			Addr: n.Addr,
37		},
38	}
39}
40
41func (n *NodeModuleRemoved) ReferenceOutside() (selfPath, referencePath addrs.ModuleInstance) {
42	// Our "References" implementation indicates that this node depends on
43	// the call to the module it represents, which implicitly depends on
44	// everything inside the module. That reference must therefore be
45	// interpreted in terms of our parent module.
46	return n.Addr, n.Addr.Parent()
47}
48
49func (n *NodeModuleRemoved) References() []*addrs.Reference {
50	// We depend on the call to the module we represent, because that
51	// implicitly then depends on everything inside that module.
52	// Our ReferenceOutside implementation causes this to be interpreted
53	// within the parent module.
54
55	_, call := n.Addr.CallInstance()
56	return []*addrs.Reference{
57		{
58			Subject: call,
59
60			// No source range here, because there's nothing reasonable for
61			// us to return.
62		},
63	}
64}
65
66// EvalCheckModuleRemoved is an EvalNode implementation that verifies that
67// a module has been removed from the state as expected.
68type EvalCheckModuleRemoved struct {
69	Addr addrs.ModuleInstance
70}
71
72func (n *EvalCheckModuleRemoved) Eval(ctx EvalContext) (interface{}, error) {
73	mod := ctx.State().Module(n.Addr)
74	if mod != nil {
75		// If we get here then that indicates a bug either in the states
76		// module or in an earlier step of the graph walk, since we should've
77		// pruned out the module when the last resource was removed from it.
78		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)
79	}
80	return nil, nil
81}
82