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