6 "github.com/hashicorp/terraform/config"
9 // NodeDestroyResource represents a resource that is to be destroyed.
10 type NodeDestroyResource struct {
14 func (n *NodeDestroyResource) Name() string {
15 return n.NodeAbstractResource.Name() + " (destroy)"
19 func (n *NodeDestroyResource) DestroyAddr() *ResourceAddress {
23 // GraphNodeDestroyerCBD
24 func (n *NodeDestroyResource) CreateBeforeDestroy() bool {
25 // If we have no config, we just assume no
30 return n.Config.Lifecycle.CreateBeforeDestroy
33 // GraphNodeDestroyerCBD
34 func (n *NodeDestroyResource) ModifyCreateBeforeDestroy(v bool) error {
35 // If we have no config, do nothing since it won't affect the
36 // create step anyways.
42 n.Config.Lifecycle.CreateBeforeDestroy = true
47 // GraphNodeReferenceable, overriding NodeAbstractResource
48 func (n *NodeDestroyResource) ReferenceableName() []string {
49 // We modify our referenceable name to have the suffix of ".destroy"
50 // since depending on the creation side doesn't necessarilly mean
51 // depending on destruction.
54 // If we're CBD, we also append "-cbd". This is because CBD will setup
55 // its own edges (in CBDEdgeTransformer). Depending on the "destroy"
56 // side generally doesn't mean depending on CBD as well. See GH-11349
57 if n.CreateBeforeDestroy() {
61 result := n.NodeAbstractResource.ReferenceableName()
62 for i, v := range result {
63 result[i] = v + suffix
69 // GraphNodeReferencer, overriding NodeAbstractResource
70 func (n *NodeDestroyResource) References() []string {
71 // If we have a config, then we need to include destroy-time dependencies
72 if c := n.Config; c != nil {
74 for _, p := range c.Provisioners {
75 // We include conn info and config for destroy time provisioners
76 // as dependencies that we have.
77 if p.When == config.ProvisionerWhenDestroy {
78 result = append(result, ReferencesFromConfig(p.ConnInfo)...)
79 result = append(result, ReferencesFromConfig(p.RawConfig)...)
89 // GraphNodeDynamicExpandable
90 func (n *NodeDestroyResource) DynamicExpand(ctx EvalContext) (*Graph, error) {
91 // If we have no config we do nothing
96 state, lock := ctx.State()
100 // Start creating the steps
101 steps := make([]GraphTransformer, 0, 5)
103 // We want deposed resources in the state to be destroyed
104 steps = append(steps, &DeposedTransformer{
106 View: n.Addr.stateId(),
107 ResolvedProvider: n.ResolvedProvider,
111 steps = append(steps, &TargetsTransformer{
112 ParsedTargets: n.Targets,
115 // Always end with the root being added
116 steps = append(steps, &RootTransformer{})
119 b := &BasicGraphBuilder{
121 Name: "NodeResourceDestroy",
123 return b.Build(ctx.Path())
127 func (n *NodeDestroyResource) EvalTree() EvalNode {
128 // stateId is the ID to put into the state
129 stateId := n.Addr.stateId()
131 // Build the instance info. More of this will be populated during eval
132 info := &InstanceInfo{
135 uniqueExtra: "destroy",
138 // Build the resource for eval
140 resource := &Resource{
143 CountIndex: addr.Index,
145 if resource.CountIndex < 0 {
146 resource.CountIndex = 0
150 rs := n.ResourceState
153 Provider: n.ResolvedProvider,
157 var diffApply *InstanceDiff
158 var provider ResourceProvider
159 var state *InstanceState
161 return &EvalOpFilter{
162 Ops: []walkOperation{walkApply, walkDestroy},
165 // Get the saved diff for apply
171 // Filter the diff so we only get the destroy
178 // If we're not destroying, then compare diffs
180 If: func(ctx EvalContext) (bool, error) {
181 if diffApply != nil && diffApply.GetDestroy() {
185 return true, EvalEarlyExitError{}
190 // Load the instance info so we have the module path set
191 &EvalInstanceInfo{Info: info},
194 Name: n.ResolvedProvider,
205 // Call pre-apply hook
212 // Run destroy provisioners if not tainted
214 If: func(ctx EvalContext) (bool, error) {
215 if state != nil && state.Tainted {
222 Then: &EvalApplyProvisioners{
226 InterpResource: resource,
228 When: config.ProvisionerWhenDestroy,
232 // If we have a provisioning error, then we just call
233 // the post-apply hook now.
235 If: func(ctx EvalContext) (bool, error) {
236 return err != nil, nil
239 Then: &EvalApplyPost{
246 // Make sure we handle data sources properly.
248 If: func(ctx EvalContext) (bool, error) {
250 return false, fmt.Errorf("nil address")
253 if n.Addr.Mode == config.DataResourceMode {
260 Then: &EvalReadDataApply{
277 ResourceType: n.Addr.Type,
278 Provider: n.ResolvedProvider,
279 Dependencies: rs.Dependencies,
287 &EvalUpdateStateHook{},