github.com/tarrant/terraform@v0.3.8-0.20150402012457-f68c9eee638e/terraform/transform_tainted.go (about)

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