terraform: add destroy nodes, destroys kind of work
This commit is contained in:
parent
2e8a419fd8
commit
9e8cd48cda
|
@ -54,6 +54,9 @@ func (b *ApplyGraphBuilder) Steps() []GraphTransformer {
|
||||||
State: b.State,
|
State: b.State,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Attach the state
|
||||||
|
&AttachStateTransformer{State: b.State},
|
||||||
|
|
||||||
// Create all the providers
|
// Create all the providers
|
||||||
&MissingProviderTransformer{Providers: b.Providers, Factory: providerFactory},
|
&MissingProviderTransformer{Providers: b.Providers, Factory: providerFactory},
|
||||||
&ProviderTransformer{},
|
&ProviderTransformer{},
|
||||||
|
|
|
@ -86,6 +86,16 @@ func (n *NodeApplyableResource) ProvisionedBy() []string {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GraphNodeAttachResourceState
|
||||||
|
func (n *NodeApplyableResource) ResourceAddr() *ResourceAddress {
|
||||||
|
return n.Addr
|
||||||
|
}
|
||||||
|
|
||||||
|
// GraphNodeAttachResourceState
|
||||||
|
func (n *NodeApplyableResource) AttachResourceState(s *ResourceState) {
|
||||||
|
n.ResourceState = s
|
||||||
|
}
|
||||||
|
|
||||||
// GraphNodeEvalable
|
// GraphNodeEvalable
|
||||||
func (n *NodeApplyableResource) EvalTree() EvalNode {
|
func (n *NodeApplyableResource) EvalTree() EvalNode {
|
||||||
// stateId is the ID to put into the state
|
// stateId is the ID to put into the state
|
||||||
|
|
|
@ -2,42 +2,27 @@ package terraform
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/config"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// NodeDestroyResource represents a resource that is to be destroyed.
|
// NodeDestroyResource represents a resource that is to be destroyed.
|
||||||
type NodeApplyableResource struct {
|
type NodeDestroyResource struct {
|
||||||
Addr *ResourceAddress // Addr is the address for this resource
|
Addr *ResourceAddress // Addr is the address for this resource
|
||||||
|
ResourceState *ResourceState // State is the resource state for this resource
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *NodeApplyableResource) Name() string {
|
func (n *NodeDestroyResource) Name() string {
|
||||||
return n.Addr.String()
|
return n.Addr.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
// GraphNodeSubPath
|
// GraphNodeSubPath
|
||||||
func (n *NodeApplyableResource) Path() []string {
|
func (n *NodeDestroyResource) Path() []string {
|
||||||
return n.Addr.Path
|
return n.Addr.Path
|
||||||
}
|
}
|
||||||
|
|
||||||
// GraphNodeReferenceable
|
|
||||||
func (n *NodeApplyableResource) ReferenceableName() []string {
|
|
||||||
if n.Config == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return []string{n.Config.Id()}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GraphNodeProviderConsumer
|
// GraphNodeProviderConsumer
|
||||||
func (n *NodeApplyableResource) ProvidedBy() []string {
|
func (n *NodeDestroyResource) ProvidedBy() []string {
|
||||||
// If we have a config we prefer that above all else
|
|
||||||
if n.Config != nil {
|
|
||||||
return []string{resourceProvider(n.Config.Type, n.Config.Provider)}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we have state, then we will use the provider from there
|
// If we have state, then we will use the provider from there
|
||||||
if n.ResourceState != nil {
|
if n.ResourceState != nil && n.ResourceState.Provider != "" {
|
||||||
return []string{n.ResourceState.Provider}
|
return []string{n.ResourceState.Provider}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,7 +30,124 @@ func (n *NodeApplyableResource) ProvidedBy() []string {
|
||||||
return []string{resourceProvider(n.Addr.Type, "")}
|
return []string{resourceProvider(n.Addr.Type, "")}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GraphNodeEvalable
|
// GraphNodeAttachResourceState
|
||||||
func (n *NodeApplyableResource) EvalTree() EvalNode {
|
func (n *NodeDestroyResource) ResourceAddr() *ResourceAddress {
|
||||||
return nil
|
return n.Addr
|
||||||
|
}
|
||||||
|
|
||||||
|
// GraphNodeAttachResourceState
|
||||||
|
func (n *NodeDestroyResource) AttachResourceState(s *ResourceState) {
|
||||||
|
n.ResourceState = s
|
||||||
|
}
|
||||||
|
|
||||||
|
// GraphNodeEvalable
|
||||||
|
func (n *NodeDestroyResource) EvalTree() EvalNode {
|
||||||
|
// stateId is the ID to put into the state
|
||||||
|
stateId := n.Addr.stateId()
|
||||||
|
if n.Addr.Index > -1 {
|
||||||
|
stateId = fmt.Sprintf("%s.%d", stateId, n.Addr.Index)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build the instance info. More of this will be populated during eval
|
||||||
|
info := &InstanceInfo{
|
||||||
|
Id: stateId,
|
||||||
|
Type: n.Addr.Type,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get our state
|
||||||
|
rs := n.ResourceState
|
||||||
|
if rs == nil {
|
||||||
|
rs = &ResourceState{}
|
||||||
|
}
|
||||||
|
rs.Provider = n.ProvidedBy()[0]
|
||||||
|
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
// Make sure we handle data sources properly.
|
||||||
|
&EvalIf{
|
||||||
|
If: func(ctx EvalContext) (bool, error) {
|
||||||
|
/* TODO: data source
|
||||||
|
if n.Resource.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,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
package terraform
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/dag"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GraphNodeAttachResourceState is an interface that can be implemented
|
||||||
|
// to request that a ResourceState is attached to the node.
|
||||||
|
type GraphNodeAttachResourceState interface {
|
||||||
|
// The address to the resource for the state
|
||||||
|
ResourceAddr() *ResourceAddress
|
||||||
|
|
||||||
|
// Sets the state
|
||||||
|
AttachResourceState(*ResourceState)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AttachStateTransformer goes through the graph and attaches
|
||||||
|
// state to nodes that implement the interfaces above.
|
||||||
|
type AttachStateTransformer struct {
|
||||||
|
State *State // State is the root state
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *AttachStateTransformer) Transform(g *Graph) error {
|
||||||
|
// If no state, then nothing to do
|
||||||
|
if t.State == nil {
|
||||||
|
log.Printf("[DEBUG] Not attaching any state: state is nil")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
filter := &StateFilter{State: t.State}
|
||||||
|
for _, v := range g.Vertices() {
|
||||||
|
// Only care about nodes requesting we're adding state
|
||||||
|
an, ok := v.(GraphNodeAttachResourceState)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
addr := an.ResourceAddr()
|
||||||
|
|
||||||
|
// Get the module state
|
||||||
|
results, err := filter.Filter(addr.String())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attach the first resource state we get
|
||||||
|
found := false
|
||||||
|
for _, result := range results {
|
||||||
|
if rs, ok := result.Value.(*ResourceState); ok {
|
||||||
|
log.Printf(
|
||||||
|
"[DEBUG] Attaching resource state to %q: %s",
|
||||||
|
dag.VertexName(v), rs)
|
||||||
|
an.AttachResourceState(rs)
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !found {
|
||||||
|
log.Printf(
|
||||||
|
"[DEBUG] Resource state not foudn for %q: %s",
|
||||||
|
dag.VertexName(v), addr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -41,16 +41,6 @@ func (t *DiffTransformer) Transform(g *Graph) error {
|
||||||
for name, inst := range m.Resources {
|
for name, inst := range m.Resources {
|
||||||
log.Printf("[TRACE] DiffTransformer: Resource %q: %#v", name, inst)
|
log.Printf("[TRACE] DiffTransformer: Resource %q: %#v", name, inst)
|
||||||
|
|
||||||
// TODO: destroy
|
|
||||||
if inst.Destroy {
|
|
||||||
}
|
|
||||||
|
|
||||||
// If this diff has no attribute changes, then we have
|
|
||||||
// nothing to do and therefore won't add it to the graph.
|
|
||||||
if len(inst.Attributes) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// We have changes! This is a create or update operation.
|
// We have changes! This is a create or update operation.
|
||||||
// First grab the address so we have a unique way to
|
// First grab the address so we have a unique way to
|
||||||
// reference this resource.
|
// reference this resource.
|
||||||
|
@ -64,10 +54,18 @@ func (t *DiffTransformer) Transform(g *Graph) error {
|
||||||
// the address. Remove "root" from it.
|
// the address. Remove "root" from it.
|
||||||
addr.Path = m.Path[1:]
|
addr.Path = m.Path[1:]
|
||||||
|
|
||||||
// Add the resource to the graph
|
// If we're destroying, add the destroy node
|
||||||
nodes = append(nodes, &NodeApplyableResource{
|
if inst.Destroy {
|
||||||
Addr: addr,
|
g.Add(&NodeDestroyResource{Addr: addr})
|
||||||
})
|
}
|
||||||
|
|
||||||
|
// If we have changes, then add the applyable version
|
||||||
|
if len(inst.Attributes) > 0 {
|
||||||
|
// Add the resource to the graph
|
||||||
|
nodes = append(nodes, &NodeApplyableResource{
|
||||||
|
Addr: addr,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,28 +95,6 @@ func (t *DiffTransformer) Transform(g *Graph) error {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Grab the state at this path
|
|
||||||
if ms := t.State.ModuleByPath(normalizeModulePath(n.Addr.Path)); ms != nil {
|
|
||||||
for name, rs := range ms.Resources {
|
|
||||||
// Parse the name for comparison
|
|
||||||
addr, err := parseResourceAddressInternal(name)
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf(
|
|
||||||
"Error parsing internal name, this is a bug: %q", name))
|
|
||||||
}
|
|
||||||
addr.Path = n.Addr.Path
|
|
||||||
|
|
||||||
// If this is not the same resource, then continue
|
|
||||||
if !addr.Equals(n.Addr) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Same resource!
|
|
||||||
n.ResourceState = rs
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add all the nodes to the graph
|
// Add all the nodes to the graph
|
||||||
|
|
Loading…
Reference in New Issue