github.com/tarrant/terraform@v0.3.8-0.20150402012457-f68c9eee638e/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  			})
    44  		}
    45  	}
    46  
    47  	return nil
    48  }
    49  
    50  // graphNodeDeposedResource is the graph vertex representing a deposed resource.
    51  type graphNodeDeposedResource struct {
    52  	Index        int
    53  	ResourceName string
    54  	ResourceType string
    55  }
    56  
    57  func (n *graphNodeDeposedResource) Name() string {
    58  	return fmt.Sprintf("%s (deposed #%d)", n.ResourceName, n.Index)
    59  }
    60  
    61  func (n *graphNodeDeposedResource) ProvidedBy() []string {
    62  	return []string{resourceProvider(n.ResourceName)}
    63  }
    64  
    65  // GraphNodeEvalable impl.
    66  func (n *graphNodeDeposedResource) EvalTree() EvalNode {
    67  	var provider ResourceProvider
    68  	var state *InstanceState
    69  
    70  	seq := &EvalSequence{Nodes: make([]EvalNode, 0, 5)}
    71  
    72  	// Build instance info
    73  	info := &InstanceInfo{Id: n.ResourceName, Type: n.ResourceType}
    74  	seq.Nodes = append(seq.Nodes, &EvalInstanceInfo{Info: info})
    75  
    76  	// Refresh the resource
    77  	seq.Nodes = append(seq.Nodes, &EvalOpFilter{
    78  		Ops: []walkOperation{walkRefresh},
    79  		Node: &EvalSequence{
    80  			Nodes: []EvalNode{
    81  				&EvalGetProvider{
    82  					Name:   n.ProvidedBy()[0],
    83  					Output: &provider,
    84  				},
    85  				&EvalReadStateDeposed{
    86  					Name:   n.ResourceName,
    87  					Output: &state,
    88  					Index:  n.Index,
    89  				},
    90  				&EvalRefresh{
    91  					Info:     info,
    92  					Provider: &provider,
    93  					State:    &state,
    94  					Output:   &state,
    95  				},
    96  				&EvalWriteStateDeposed{
    97  					Name:         n.ResourceName,
    98  					ResourceType: n.ResourceType,
    99  					State:        &state,
   100  					Index:        n.Index,
   101  				},
   102  			},
   103  		},
   104  	})
   105  
   106  	// Apply
   107  	var diff *InstanceDiff
   108  	var err error
   109  	seq.Nodes = append(seq.Nodes, &EvalOpFilter{
   110  		Ops: []walkOperation{walkApply},
   111  		Node: &EvalSequence{
   112  			Nodes: []EvalNode{
   113  				&EvalGetProvider{
   114  					Name:   n.ProvidedBy()[0],
   115  					Output: &provider,
   116  				},
   117  				&EvalReadStateDeposed{
   118  					Name:   n.ResourceName,
   119  					Output: &state,
   120  					Index:  n.Index,
   121  				},
   122  				&EvalDiffDestroy{
   123  					Info:   info,
   124  					State:  &state,
   125  					Output: &diff,
   126  				},
   127  				&EvalApply{
   128  					Info:     info,
   129  					State:    &state,
   130  					Diff:     &diff,
   131  					Provider: &provider,
   132  					Output:   &state,
   133  					Error:    &err,
   134  				},
   135  				// Always write the resource back to the state deposed... if it
   136  				// was successfully destroyed it will be pruned. If it was not, it will
   137  				// be caught on the next run.
   138  				&EvalWriteStateDeposed{
   139  					Name:         n.ResourceName,
   140  					ResourceType: n.ResourceType,
   141  					State:        &state,
   142  					Index:        n.Index,
   143  				},
   144  				&EvalReturnError{
   145  					Error: &err,
   146  				},
   147  				&EvalUpdateStateHook{},
   148  			},
   149  		},
   150  	})
   151  
   152  	return seq
   153  }