github.com/gavinw2006/hashicorp-terraform@v0.11.12-beta1/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  	// The provider used by the resourced which were deposed
    17  	ResolvedProvider string
    18  }
    19  
    20  func (t *DeposedTransformer) Transform(g *Graph) error {
    21  	state := t.State.ModuleByPath(g.Path)
    22  	if state == nil {
    23  		// If there is no state for our module there can't be any deposed
    24  		// resources, since they live in the state.
    25  		return nil
    26  	}
    27  
    28  	// If we have a view, apply it now
    29  	if t.View != "" {
    30  		state = state.View(t.View)
    31  	}
    32  
    33  	// Go through all the resources in our state to look for deposed resources
    34  	for k, rs := range state.Resources {
    35  		// If we have no deposed resources, then move on
    36  		if len(rs.Deposed) == 0 {
    37  			continue
    38  		}
    39  
    40  		deposed := rs.Deposed
    41  
    42  		for i, _ := range deposed {
    43  			g.Add(&graphNodeDeposedResource{
    44  				Index:            i,
    45  				ResourceName:     k,
    46  				ResourceType:     rs.Type,
    47  				ProviderName:     rs.Provider,
    48  				ResolvedProvider: t.ResolvedProvider,
    49  			})
    50  		}
    51  	}
    52  
    53  	return nil
    54  }
    55  
    56  // graphNodeDeposedResource is the graph vertex representing a deposed resource.
    57  type graphNodeDeposedResource struct {
    58  	Index            int
    59  	ResourceName     string
    60  	ResourceType     string
    61  	ProviderName     string
    62  	ResolvedProvider string
    63  }
    64  
    65  func (n *graphNodeDeposedResource) Name() string {
    66  	return fmt.Sprintf("%s (deposed #%d)", n.ResourceName, n.Index)
    67  }
    68  
    69  func (n *graphNodeDeposedResource) ProvidedBy() string {
    70  	return resourceProvider(n.ResourceName, n.ProviderName)
    71  }
    72  
    73  func (n *graphNodeDeposedResource) SetProvider(p string) {
    74  	n.ResolvedProvider = p
    75  }
    76  
    77  // GraphNodeEvalable impl.
    78  func (n *graphNodeDeposedResource) EvalTree() EvalNode {
    79  	var provider ResourceProvider
    80  	var state *InstanceState
    81  
    82  	seq := &EvalSequence{Nodes: make([]EvalNode, 0, 5)}
    83  
    84  	// Build instance info
    85  	info := &InstanceInfo{Id: n.Name(), Type: n.ResourceType}
    86  	seq.Nodes = append(seq.Nodes, &EvalInstanceInfo{Info: info})
    87  
    88  	// Refresh the resource
    89  	seq.Nodes = append(seq.Nodes, &EvalOpFilter{
    90  		Ops: []walkOperation{walkRefresh},
    91  		Node: &EvalSequence{
    92  			Nodes: []EvalNode{
    93  				&EvalGetProvider{
    94  					Name:   n.ResolvedProvider,
    95  					Output: &provider,
    96  				},
    97  				&EvalReadStateDeposed{
    98  					Name:   n.ResourceName,
    99  					Output: &state,
   100  					Index:  n.Index,
   101  				},
   102  				&EvalRefresh{
   103  					Info:     info,
   104  					Provider: &provider,
   105  					State:    &state,
   106  					Output:   &state,
   107  				},
   108  				&EvalWriteStateDeposed{
   109  					Name:         n.ResourceName,
   110  					ResourceType: n.ResourceType,
   111  					Provider:     n.ResolvedProvider,
   112  					State:        &state,
   113  					Index:        n.Index,
   114  				},
   115  			},
   116  		},
   117  	})
   118  
   119  	// Apply
   120  	var diff *InstanceDiff
   121  	var err error
   122  	seq.Nodes = append(seq.Nodes, &EvalOpFilter{
   123  		Ops: []walkOperation{walkApply, walkDestroy},
   124  		Node: &EvalSequence{
   125  			Nodes: []EvalNode{
   126  				&EvalGetProvider{
   127  					Name:   n.ResolvedProvider,
   128  					Output: &provider,
   129  				},
   130  				&EvalReadStateDeposed{
   131  					Name:   n.ResourceName,
   132  					Output: &state,
   133  					Index:  n.Index,
   134  				},
   135  				&EvalDiffDestroy{
   136  					Info:   info,
   137  					State:  &state,
   138  					Output: &diff,
   139  				},
   140  				// Call pre-apply hook
   141  				&EvalApplyPre{
   142  					Info:  info,
   143  					State: &state,
   144  					Diff:  &diff,
   145  				},
   146  				&EvalApply{
   147  					Info:     info,
   148  					State:    &state,
   149  					Diff:     &diff,
   150  					Provider: &provider,
   151  					Output:   &state,
   152  					Error:    &err,
   153  				},
   154  				// Always write the resource back to the state deposed... if it
   155  				// was successfully destroyed it will be pruned. If it was not, it will
   156  				// be caught on the next run.
   157  				&EvalWriteStateDeposed{
   158  					Name:         n.ResourceName,
   159  					ResourceType: n.ResourceType,
   160  					Provider:     n.ResolvedProvider,
   161  					State:        &state,
   162  					Index:        n.Index,
   163  				},
   164  				&EvalApplyPost{
   165  					Info:  info,
   166  					State: &state,
   167  					Error: &err,
   168  				},
   169  				&EvalReturnError{
   170  					Error: &err,
   171  				},
   172  				&EvalUpdateStateHook{},
   173  			},
   174  		},
   175  	})
   176  
   177  	return seq
   178  }