diff options
Diffstat (limited to 'vendor/github.com/hashicorp/terraform/terraform/node_resource_destroy.go')
-rw-r--r-- | vendor/github.com/hashicorp/terraform/terraform/node_resource_destroy.go | 288 |
1 files changed, 288 insertions, 0 deletions
diff --git a/vendor/github.com/hashicorp/terraform/terraform/node_resource_destroy.go b/vendor/github.com/hashicorp/terraform/terraform/node_resource_destroy.go new file mode 100644 index 00000000..c2efd2c3 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform/terraform/node_resource_destroy.go @@ -0,0 +1,288 @@ +package terraform + +import ( + "fmt" + + "github.com/hashicorp/terraform/config" +) + +// NodeDestroyResource represents a resource that is to be destroyed. +type NodeDestroyResource struct { + *NodeAbstractResource +} + +func (n *NodeDestroyResource) Name() string { + return n.NodeAbstractResource.Name() + " (destroy)" +} + +// GraphNodeDestroyer +func (n *NodeDestroyResource) DestroyAddr() *ResourceAddress { + return n.Addr +} + +// GraphNodeDestroyerCBD +func (n *NodeDestroyResource) CreateBeforeDestroy() bool { + // If we have no config, we just assume no + if n.Config == nil { + return false + } + + return n.Config.Lifecycle.CreateBeforeDestroy +} + +// GraphNodeDestroyerCBD +func (n *NodeDestroyResource) ModifyCreateBeforeDestroy(v bool) error { + // If we have no config, do nothing since it won't affect the + // create step anyways. + if n.Config == nil { + return nil + } + + // Set CBD to true + n.Config.Lifecycle.CreateBeforeDestroy = true + + return nil +} + +// GraphNodeReferenceable, overriding NodeAbstractResource +func (n *NodeDestroyResource) ReferenceableName() []string { + // We modify our referenceable name to have the suffix of ".destroy" + // since depending on the creation side doesn't necessarilly mean + // depending on destruction. + suffix := ".destroy" + + // If we're CBD, we also append "-cbd". This is because CBD will setup + // its own edges (in CBDEdgeTransformer). Depending on the "destroy" + // side generally doesn't mean depending on CBD as well. See GH-11349 + if n.CreateBeforeDestroy() { + suffix += "-cbd" + } + + result := n.NodeAbstractResource.ReferenceableName() + for i, v := range result { + result[i] = v + suffix + } + + return result +} + +// GraphNodeReferencer, overriding NodeAbstractResource +func (n *NodeDestroyResource) References() []string { + // If we have a config, then we need to include destroy-time dependencies + if c := n.Config; c != nil { + var result []string + for _, p := range c.Provisioners { + // We include conn info and config for destroy time provisioners + // as dependencies that we have. + if p.When == config.ProvisionerWhenDestroy { + result = append(result, ReferencesFromConfig(p.ConnInfo)...) + result = append(result, ReferencesFromConfig(p.RawConfig)...) + } + } + + return result + } + + return nil +} + +// GraphNodeDynamicExpandable +func (n *NodeDestroyResource) DynamicExpand(ctx EvalContext) (*Graph, error) { + // If we have no config we do nothing + if n.Addr == nil { + return nil, nil + } + + state, lock := ctx.State() + lock.RLock() + defer lock.RUnlock() + + // Start creating the steps + steps := make([]GraphTransformer, 0, 5) + + // We want deposed resources in the state to be destroyed + steps = append(steps, &DeposedTransformer{ + State: state, + View: n.Addr.stateId(), + }) + + // Target + steps = append(steps, &TargetsTransformer{ + ParsedTargets: n.Targets, + }) + + // Always end with the root being added + steps = append(steps, &RootTransformer{}) + + // Build the graph + b := &BasicGraphBuilder{ + Steps: steps, + Name: "NodeResourceDestroy", + } + return b.Build(ctx.Path()) +} + +// GraphNodeEvalable +func (n *NodeDestroyResource) EvalTree() EvalNode { + // stateId is the ID to put into the state + stateId := n.Addr.stateId() + + // Build the instance info. More of this will be populated during eval + info := &InstanceInfo{ + Id: stateId, + Type: n.Addr.Type, + uniqueExtra: "destroy", + } + + // Build the resource for eval + addr := n.Addr + resource := &Resource{ + Name: addr.Name, + Type: addr.Type, + CountIndex: addr.Index, + } + if resource.CountIndex < 0 { + resource.CountIndex = 0 + } + + // Get our state + rs := n.ResourceState + if rs == nil { + rs = &ResourceState{} + } + + var diffApply *InstanceDiff + var provider ResourceProvider + var state *InstanceState + var err error + return &EvalOpFilter{ + Ops: []walkOperation{walkApply, walkDestroy}, + Node: &EvalSequence{ + Nodes: []EvalNode{ + // Get the saved diff for apply + &EvalReadDiff{ + Name: stateId, + Diff: &diffApply, + }, + + // Filter the diff so we only get the destroy + &EvalFilterDiff{ + Diff: &diffApply, + Output: &diffApply, + Destroy: true, + }, + + // If we're not destroying, then compare diffs + &EvalIf{ + If: func(ctx EvalContext) (bool, error) { + if diffApply != nil && diffApply.GetDestroy() { + return true, nil + } + + return true, EvalEarlyExitError{} + }, + Then: EvalNoop{}, + }, + + // Load the instance info so we have the module path set + &EvalInstanceInfo{Info: info}, + + &EvalGetProvider{ + Name: n.ProvidedBy()[0], + Output: &provider, + }, + &EvalReadState{ + Name: stateId, + Output: &state, + }, + &EvalRequireState{ + State: &state, + }, + + // Call pre-apply hook + &EvalApplyPre{ + Info: info, + State: &state, + Diff: &diffApply, + }, + + // Run destroy provisioners if not tainted + &EvalIf{ + If: func(ctx EvalContext) (bool, error) { + if state != nil && state.Tainted { + return false, nil + } + + return true, nil + }, + + Then: &EvalApplyProvisioners{ + Info: info, + State: &state, + Resource: n.Config, + InterpResource: resource, + Error: &err, + When: config.ProvisionerWhenDestroy, + }, + }, + + // If we have a provisioning error, then we just call + // the post-apply hook now. + &EvalIf{ + If: func(ctx EvalContext) (bool, error) { + return err != nil, nil + }, + + Then: &EvalApplyPost{ + Info: info, + State: &state, + Error: &err, + }, + }, + + // Make sure we handle data sources properly. + &EvalIf{ + If: func(ctx EvalContext) (bool, error) { + if n.Addr == nil { + return false, fmt.Errorf("nil address") + } + + if n.Addr.Mode == config.DataResourceMode { + return true, nil + } + + return false, nil + }, + + Then: &EvalReadDataApply{ + Info: info, + Diff: &diffApply, + Provider: &provider, + Output: &state, + }, + Else: &EvalApply{ + Info: info, + State: &state, + Diff: &diffApply, + Provider: &provider, + Output: &state, + Error: &err, + }, + }, + &EvalWriteState{ + Name: stateId, + ResourceType: n.Addr.Type, + Provider: rs.Provider, + Dependencies: rs.Dependencies, + State: &state, + }, + &EvalApplyPost{ + Info: info, + State: &state, + Error: &err, + }, + &EvalUpdateStateHook{}, + }, + }, + } +} |