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(),
110 steps = append(steps, &TargetsTransformer{
111 ParsedTargets: n.Targets,
114 // Always end with the root being added
115 steps = append(steps, &RootTransformer{})
118 b := &BasicGraphBuilder{
120 Name: "NodeResourceDestroy",
122 return b.Build(ctx.Path())
126 func (n *NodeDestroyResource) EvalTree() EvalNode {
127 // stateId is the ID to put into the state
128 stateId := n.Addr.stateId()
130 // Build the instance info. More of this will be populated during eval
131 info := &InstanceInfo{
134 uniqueExtra: "destroy",
137 // Build the resource for eval
139 resource := &Resource{
142 CountIndex: addr.Index,
144 if resource.CountIndex < 0 {
145 resource.CountIndex = 0
149 rs := n.ResourceState
151 rs = &ResourceState{}
154 var diffApply *InstanceDiff
155 var provider ResourceProvider
156 var state *InstanceState
158 return &EvalOpFilter{
159 Ops: []walkOperation{walkApply, walkDestroy},
162 // Get the saved diff for apply
168 // Filter the diff so we only get the destroy
175 // If we're not destroying, then compare diffs
177 If: func(ctx EvalContext) (bool, error) {
178 if diffApply != nil && diffApply.GetDestroy() {
182 return true, EvalEarlyExitError{}
187 // Load the instance info so we have the module path set
188 &EvalInstanceInfo{Info: info},
191 Name: n.ProvidedBy()[0],
202 // Call pre-apply hook
209 // Run destroy provisioners if not tainted
211 If: func(ctx EvalContext) (bool, error) {
212 if state != nil && state.Tainted {
219 Then: &EvalApplyProvisioners{
223 InterpResource: resource,
225 When: config.ProvisionerWhenDestroy,
229 // If we have a provisioning error, then we just call
230 // the post-apply hook now.
232 If: func(ctx EvalContext) (bool, error) {
233 return err != nil, nil
236 Then: &EvalApplyPost{
243 // Make sure we handle data sources properly.
245 If: func(ctx EvalContext) (bool, error) {
247 return false, fmt.Errorf("nil address")
250 if n.Addr.Mode == config.DataResourceMode {
257 Then: &EvalReadDataApply{
274 ResourceType: n.Addr.Type,
275 Provider: rs.Provider,
276 Dependencies: rs.Dependencies,
284 &EvalUpdateStateHook{},