github.com/turtlemonvh/terraform@v0.6.9-0.20151204001754-8e40b6b855e8/terraform/transform_deposed.go (about)

     1  package terraform
     2  
     3  import "fmt"
     4  
     5  // DeposedTransformer is a GraphTransformer that adds deposed resources
     6  // to the graph.
     7  type DeposedTransformer struct {
     8  	// State is the global state. We'll automatically find the correct
     9  	// ModuleState based on the Graph.Path that is being transformed.
    10  	State *State
    11  
    12  	// View, if non-empty, is the ModuleState.View used around the state
    13  	// to find deposed resources.
    14  	View string
    15  }
    16  
    17  func (t *DeposedTransformer) Transform(g *Graph) error {
    18  	state := t.State.ModuleByPath(g.Path)
    19  	if state == nil {
    20  		// If there is no state for our module there can't be any deposed
    21  		// resources, since they live in the state.
    22  		return nil
    23  	}
    24  
    25  	// If we have a view, apply it now
    26  	if t.View != "" {
    27  		state = state.View(t.View)
    28  	}
    29  
    30  	// Go through all the resources in our state to look for deposed resources
    31  	for k, rs := range state.Resources {
    32  		// If we have no deposed resources, then move on
    33  		if len(rs.Deposed) == 0 {
    34  			continue
    35  		}
    36  		deposed := rs.Deposed
    37  
    38  		for i, _ := range deposed {
    39  			g.Add(&graphNodeDeposedResource{
    40  				Index:        i,
    41  				ResourceName: k,
    42  				ResourceType: rs.Type,
    43  				Provider:     rs.Provider,
    44  			})
    45  		}
    46  	}
    47  
    48  	return nil
    49  }
    50  
    51  // graphNodeDeposedResource is the graph vertex representing a deposed resource.
    52  type graphNodeDeposedResource struct {
    53  	Index        int
    54  	ResourceName string
    55  	ResourceType string
    56  	Provider     string
    57  }
    58  
    59  func (n *graphNodeDeposedResource) Name() string {
    60  	return fmt.Sprintf("%s (deposed #%d)", n.ResourceName, n.Index)
    61  }
    62  
    63  func (n *graphNodeDeposedResource) ProvidedBy() []string {
    64  	return []string{resourceProvider(n.ResourceName, n.Provider)}
    65  }
    66  
    67  // GraphNodeEvalable impl.
    68  func (n *graphNodeDeposedResource) EvalTree() EvalNode {
    69  	var provider ResourceProvider
    70  	var state *InstanceState
    71  
    72  	seq := &EvalSequence{Nodes: make([]EvalNode, 0, 5)}
    73  
    74  	// Build instance info
    75  	info := &InstanceInfo{Id: n.ResourceName, Type: n.ResourceType}
    76  	seq.Nodes = append(seq.Nodes, &EvalInstanceInfo{Info: info})
    77  
    78  	// Refresh the resource
    79  	seq.Nodes = append(seq.Nodes, &EvalOpFilter{
    80  		Ops: []walkOperation{walkRefresh},
    81  		Node: &EvalSequence{
    82  			Nodes: []EvalNode{
    83  				&EvalGetProvider{
    84  					Name:   n.ProvidedBy()[0],
    85  					Output: &provider,
    86  				},
    87  				&EvalReadStateDeposed{
    88  					Name:   n.ResourceName,
    89  					Output: &state,
    90  					Index:  n.Index,
    91  				},
    92  				&EvalRefresh{
    93  					Info:     info,
    94  					Provider: &provider,
    95  					State:    &state,
    96  					Output:   &state,
    97  				},
    98  				&EvalWriteStateDeposed{
    99  					Name:         n.ResourceName,
   100  					ResourceType: n.ResourceType,
   101  					Provider:     n.Provider,
   102  					State:        &state,
   103  					Index:        n.Index,
   104  				},
   105  			},
   106  		},
   107  	})
   108  
   109  	// Apply
   110  	var diff *InstanceDiff
   111  	var err error
   112  	seq.Nodes = append(seq.Nodes, &EvalOpFilter{
   113  		Ops: []walkOperation{walkApply, walkDestroy},
   114  		Node: &EvalSequence{
   115  			Nodes: []EvalNode{
   116  				&EvalGetProvider{
   117  					Name:   n.ProvidedBy()[0],
   118  					Output: &provider,
   119  				},
   120  				&EvalReadStateDeposed{
   121  					Name:   n.ResourceName,
   122  					Output: &state,
   123  					Index:  n.Index,
   124  				},
   125  				&EvalDiffDestroy{
   126  					Info:   info,
   127  					State:  &state,
   128  					Output: &diff,
   129  				},
   130  				&EvalApply{
   131  					Info:     info,
   132  					State:    &state,
   133  					Diff:     &diff,
   134  					Provider: &provider,
   135  					Output:   &state,
   136  					Error:    &err,
   137  				},
   138  				// Always write the resource back to the state deposed... if it
   139  				// was successfully destroyed it will be pruned. If it was not, it will
   140  				// be caught on the next run.
   141  				&EvalWriteStateDeposed{
   142  					Name:         n.ResourceName,
   143  					ResourceType: n.ResourceType,
   144  					Provider:     n.Provider,
   145  					State:        &state,
   146  					Index:        n.Index,
   147  				},
   148  				&EvalReturnError{
   149  					Error: &err,
   150  				},
   151  				&EvalUpdateStateHook{},
   152  			},
   153  		},
   154  	})
   155  
   156  	return seq
   157  }