github.com/muratcelep/terraform@v1.1.0-beta2-not-internal-4/not-internal/terraform/node_resource_destroy.go (about) 1 package terraform 2 3 import ( 4 "fmt" 5 "log" 6 7 "github.com/muratcelep/terraform/not-internal/plans" 8 "github.com/muratcelep/terraform/not-internal/tfdiags" 9 10 "github.com/muratcelep/terraform/not-internal/addrs" 11 "github.com/muratcelep/terraform/not-internal/configs" 12 "github.com/muratcelep/terraform/not-internal/states" 13 ) 14 15 // NodeDestroyResourceInstance represents a resource instance that is to be 16 // destroyed. 17 type NodeDestroyResourceInstance struct { 18 *NodeAbstractResourceInstance 19 20 // If DeposedKey is set to anything other than states.NotDeposed then 21 // this node destroys a deposed object of the associated instance 22 // rather than its current object. 23 DeposedKey states.DeposedKey 24 } 25 26 var ( 27 _ GraphNodeModuleInstance = (*NodeDestroyResourceInstance)(nil) 28 _ GraphNodeConfigResource = (*NodeDestroyResourceInstance)(nil) 29 _ GraphNodeResourceInstance = (*NodeDestroyResourceInstance)(nil) 30 _ GraphNodeDestroyer = (*NodeDestroyResourceInstance)(nil) 31 _ GraphNodeDestroyerCBD = (*NodeDestroyResourceInstance)(nil) 32 _ GraphNodeReferenceable = (*NodeDestroyResourceInstance)(nil) 33 _ GraphNodeReferencer = (*NodeDestroyResourceInstance)(nil) 34 _ GraphNodeExecutable = (*NodeDestroyResourceInstance)(nil) 35 _ GraphNodeProviderConsumer = (*NodeDestroyResourceInstance)(nil) 36 _ GraphNodeProvisionerConsumer = (*NodeDestroyResourceInstance)(nil) 37 ) 38 39 func (n *NodeDestroyResourceInstance) Name() string { 40 if n.DeposedKey != states.NotDeposed { 41 return fmt.Sprintf("%s (destroy deposed %s)", n.ResourceInstanceAddr(), n.DeposedKey) 42 } 43 return n.ResourceInstanceAddr().String() + " (destroy)" 44 } 45 46 func (n *NodeDestroyResourceInstance) ProvidedBy() (addr addrs.ProviderConfig, exact bool) { 47 if n.Addr.Resource.Resource.Mode == addrs.DataResourceMode { 48 // indicate that this node does not require a configured provider 49 return nil, true 50 } 51 return n.NodeAbstractResourceInstance.ProvidedBy() 52 } 53 54 // GraphNodeDestroyer 55 func (n *NodeDestroyResourceInstance) DestroyAddr() *addrs.AbsResourceInstance { 56 addr := n.ResourceInstanceAddr() 57 return &addr 58 } 59 60 // GraphNodeDestroyerCBD 61 func (n *NodeDestroyResourceInstance) CreateBeforeDestroy() bool { 62 // State takes precedence during destroy. 63 // If the resource was removed, there is no config to check. 64 // If CBD was forced from descendent, it should be saved in the state 65 // already. 66 if s := n.instanceState; s != nil { 67 if s.Current != nil { 68 return s.Current.CreateBeforeDestroy 69 } 70 } 71 72 if n.Config != nil && n.Config.Managed != nil { 73 return n.Config.Managed.CreateBeforeDestroy 74 } 75 76 return false 77 } 78 79 // GraphNodeDestroyerCBD 80 func (n *NodeDestroyResourceInstance) ModifyCreateBeforeDestroy(v bool) error { 81 return nil 82 } 83 84 // GraphNodeReferenceable, overriding NodeAbstractResource 85 func (n *NodeDestroyResourceInstance) ReferenceableAddrs() []addrs.Referenceable { 86 normalAddrs := n.NodeAbstractResourceInstance.ReferenceableAddrs() 87 destroyAddrs := make([]addrs.Referenceable, len(normalAddrs)) 88 89 phaseType := addrs.ResourceInstancePhaseDestroy 90 if n.CreateBeforeDestroy() { 91 phaseType = addrs.ResourceInstancePhaseDestroyCBD 92 } 93 94 for i, normalAddr := range normalAddrs { 95 switch ta := normalAddr.(type) { 96 case addrs.Resource: 97 destroyAddrs[i] = ta.Phase(phaseType) 98 case addrs.ResourceInstance: 99 destroyAddrs[i] = ta.Phase(phaseType) 100 default: 101 destroyAddrs[i] = normalAddr 102 } 103 } 104 105 return destroyAddrs 106 } 107 108 // GraphNodeReferencer, overriding NodeAbstractResource 109 func (n *NodeDestroyResourceInstance) References() []*addrs.Reference { 110 // If we have a config, then we need to include destroy-time dependencies 111 if c := n.Config; c != nil && c.Managed != nil { 112 var result []*addrs.Reference 113 114 // We include conn info and config for destroy time provisioners 115 // as dependencies that we have. 116 for _, p := range c.Managed.Provisioners { 117 schema := n.ProvisionerSchemas[p.Type] 118 119 if p.When == configs.ProvisionerWhenDestroy { 120 if p.Connection != nil { 121 result = append(result, ReferencesFromConfig(p.Connection.Config, connectionBlockSupersetSchema)...) 122 } 123 result = append(result, ReferencesFromConfig(p.Config, schema)...) 124 } 125 } 126 127 return result 128 } 129 130 return nil 131 } 132 133 // GraphNodeExecutable 134 func (n *NodeDestroyResourceInstance) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) { 135 addr := n.ResourceInstanceAddr() 136 137 // Eval info is different depending on what kind of resource this is 138 switch addr.Resource.Resource.Mode { 139 case addrs.ManagedResourceMode: 140 return n.managedResourceExecute(ctx) 141 case addrs.DataResourceMode: 142 return n.dataResourceExecute(ctx) 143 default: 144 panic(fmt.Errorf("unsupported resource mode %s", n.Config.Mode)) 145 } 146 } 147 148 func (n *NodeDestroyResourceInstance) managedResourceExecute(ctx EvalContext) (diags tfdiags.Diagnostics) { 149 addr := n.ResourceInstanceAddr() 150 151 // Get our state 152 is := n.instanceState 153 if is == nil { 154 log.Printf("[WARN] NodeDestroyResourceInstance for %s with no state", addr) 155 } 156 157 // These vars are updated through pointers at various stages below. 158 var changeApply *plans.ResourceInstanceChange 159 var state *states.ResourceInstanceObject 160 161 _, providerSchema, err := getProvider(ctx, n.ResolvedProvider) 162 diags = diags.Append(err) 163 if diags.HasErrors() { 164 return diags 165 } 166 167 changeApply, err = n.readDiff(ctx, providerSchema) 168 diags = diags.Append(err) 169 if changeApply == nil || diags.HasErrors() { 170 return diags 171 } 172 173 changeApply = reducePlan(addr.Resource, changeApply, true) 174 // reducePlan may have simplified our planned change 175 // into a NoOp if it does not require destroying. 176 if changeApply == nil || changeApply.Action == plans.NoOp { 177 return diags 178 } 179 180 state, readDiags := n.readResourceInstanceState(ctx, addr) 181 diags = diags.Append(readDiags) 182 if diags.HasErrors() { 183 return diags 184 } 185 186 // Exit early if the state object is null after reading the state 187 if state == nil || state.Value.IsNull() { 188 return diags 189 } 190 191 diags = diags.Append(n.preApplyHook(ctx, changeApply)) 192 if diags.HasErrors() { 193 return diags 194 } 195 196 // Run destroy provisioners if not tainted 197 if state.Status != states.ObjectTainted { 198 applyProvisionersDiags := n.evalApplyProvisioners(ctx, state, false, configs.ProvisionerWhenDestroy) 199 diags = diags.Append(applyProvisionersDiags) 200 // keep the diags separate from the main set until we handle the cleanup 201 202 if diags.HasErrors() { 203 // If we have a provisioning error, then we just call 204 // the post-apply hook now. 205 diags = diags.Append(n.postApplyHook(ctx, state, diags.Err())) 206 return diags 207 } 208 } 209 210 // Managed resources need to be destroyed, while data sources 211 // are only removed from state. 212 // we pass a nil configuration to apply because we are destroying 213 s, d := n.apply(ctx, state, changeApply, nil, false) 214 state, diags = s, diags.Append(d) 215 // we don't return immediately here on error, so that the state can be 216 // finalized 217 218 err = n.writeResourceInstanceState(ctx, state, workingState) 219 if err != nil { 220 return diags.Append(err) 221 } 222 223 // create the err value for postApplyHook 224 diags = diags.Append(n.postApplyHook(ctx, state, diags.Err())) 225 diags = diags.Append(updateStateHook(ctx)) 226 return diags 227 } 228 229 func (n *NodeDestroyResourceInstance) dataResourceExecute(ctx EvalContext) (diags tfdiags.Diagnostics) { 230 log.Printf("[TRACE] NodeDestroyResourceInstance: removing state object for %s", n.Addr) 231 ctx.State().SetResourceInstanceCurrent(n.Addr, nil, n.ResolvedProvider) 232 return diags.Append(updateStateHook(ctx)) 233 }