github.com/markdia/terraform@v0.5.1-0.20150508012022-f1ae920aa970/terraform/transform_orphan.go (about)

     1  package terraform
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  
     7  	"github.com/hashicorp/terraform/config"
     8  	"github.com/hashicorp/terraform/config/module"
     9  	"github.com/hashicorp/terraform/dag"
    10  )
    11  
    12  // GraphNodeStateRepresentative is an interface that can be implemented by
    13  // a node to say that it is representing a resource in the state.
    14  type GraphNodeStateRepresentative interface {
    15  	StateId() []string
    16  }
    17  
    18  // OrphanTransformer is a GraphTransformer that adds orphans to the
    19  // graph. This transformer adds both resource and module orphans.
    20  type OrphanTransformer struct {
    21  	// State is the global state. We require the global state to
    22  	// properly find module orphans at our path.
    23  	State *State
    24  
    25  	// Module is the root module. We'll look up the proper configuration
    26  	// using the graph path.
    27  	Module *module.Tree
    28  
    29  	// Targets are user-specified resources to target. We need to be aware of
    30  	// these so we don't improperly identify orphans when they've just been
    31  	// filtered out of the graph via targeting.
    32  	Targeting bool
    33  
    34  	// View, if non-nil will set a view on the module state.
    35  	View string
    36  }
    37  
    38  func (t *OrphanTransformer) Transform(g *Graph) error {
    39  	if t.State == nil {
    40  		// If the entire state is nil, there can't be any orphans
    41  		return nil
    42  	}
    43  
    44  	if t.Targeting {
    45  		log.Printf("Skipping orphan transformer because we have targets.")
    46  		// If we are in a run where we are targeting nodes, we won't process
    47  		// orphans for this run.
    48  		return nil
    49  	}
    50  
    51  	// Build up all our state representatives
    52  	resourceRep := make(map[string]struct{})
    53  	for _, v := range g.Vertices() {
    54  		if sr, ok := v.(GraphNodeStateRepresentative); ok {
    55  			for _, k := range sr.StateId() {
    56  				resourceRep[k] = struct{}{}
    57  			}
    58  		}
    59  	}
    60  
    61  	var config *config.Config
    62  	if t.Module != nil {
    63  		if module := t.Module.Child(g.Path[1:]); module != nil {
    64  			config = module.Config()
    65  		}
    66  	}
    67  
    68  	var resourceVertexes []dag.Vertex
    69  	if state := t.State.ModuleByPath(g.Path); state != nil {
    70  		// If we have state, then we can have orphan resources
    71  
    72  		// If we have a view, get the view
    73  		if t.View != "" {
    74  			state = state.View(t.View)
    75  		}
    76  
    77  		// Go over each resource orphan and add it to the graph.
    78  		resourceOrphans := state.Orphans(config)
    79  		resourceVertexes = make([]dag.Vertex, len(resourceOrphans))
    80  		for i, k := range resourceOrphans {
    81  			// If this orphan is represented by some other node somehow,
    82  			// then ignore it.
    83  			if _, ok := resourceRep[k]; ok {
    84  				continue
    85  			}
    86  
    87  			rs := state.Resources[k]
    88  
    89  			resourceVertexes[i] = g.Add(&graphNodeOrphanResource{
    90  				ResourceName: k,
    91  				ResourceType: rs.Type,
    92  				Provider:     rs.Provider,
    93  				dependentOn:  rs.Dependencies,
    94  			})
    95  		}
    96  	}
    97  
    98  	// Go over each module orphan and add it to the graph. We store the
    99  	// vertexes and states outside so that we can connect dependencies later.
   100  	moduleOrphans := t.State.ModuleOrphans(g.Path, config)
   101  	moduleVertexes := make([]dag.Vertex, len(moduleOrphans))
   102  	for i, path := range moduleOrphans {
   103  		moduleVertexes[i] = g.Add(&graphNodeOrphanModule{
   104  			Path:        path,
   105  			dependentOn: t.State.ModuleByPath(path).Dependencies,
   106  		})
   107  	}
   108  
   109  	// Now do the dependencies. We do this _after_ adding all the orphan
   110  	// nodes above because there are cases in which the orphans themselves
   111  	// depend on other orphans.
   112  
   113  	// Resource dependencies
   114  	for _, v := range resourceVertexes {
   115  		g.ConnectDependent(v)
   116  	}
   117  
   118  	// Module dependencies
   119  	for _, v := range moduleVertexes {
   120  		g.ConnectDependent(v)
   121  	}
   122  
   123  	return nil
   124  }
   125  
   126  // graphNodeOrphanModule is the graph vertex representing an orphan resource..
   127  type graphNodeOrphanModule struct {
   128  	Path []string
   129  
   130  	dependentOn []string
   131  }
   132  
   133  func (n *graphNodeOrphanModule) DependableName() []string {
   134  	return []string{n.dependableName()}
   135  }
   136  
   137  func (n *graphNodeOrphanModule) DependentOn() []string {
   138  	return n.dependentOn
   139  }
   140  
   141  func (n *graphNodeOrphanModule) Name() string {
   142  	return fmt.Sprintf("%s (orphan)", n.dependableName())
   143  }
   144  
   145  func (n *graphNodeOrphanModule) dependableName() string {
   146  	return fmt.Sprintf("module.%s", n.Path[len(n.Path)-1])
   147  }
   148  
   149  // GraphNodeExpandable
   150  func (n *graphNodeOrphanModule) Expand(b GraphBuilder) (GraphNodeSubgraph, error) {
   151  	g, err := b.Build(n.Path)
   152  	if err != nil {
   153  		return nil, err
   154  	}
   155  
   156  	return &GraphNodeBasicSubgraph{
   157  		NameValue: n.Name(),
   158  		Graph:     g,
   159  	}, nil
   160  }
   161  
   162  // graphNodeOrphanResource is the graph vertex representing an orphan resource..
   163  type graphNodeOrphanResource struct {
   164  	ResourceName string
   165  	ResourceType string
   166  	Provider     string
   167  
   168  	dependentOn []string
   169  }
   170  
   171  func (n *graphNodeOrphanResource) DependableName() []string {
   172  	return []string{n.dependableName()}
   173  }
   174  
   175  func (n *graphNodeOrphanResource) DependentOn() []string {
   176  	return n.dependentOn
   177  }
   178  
   179  func (n *graphNodeOrphanResource) Name() string {
   180  	return fmt.Sprintf("%s (orphan)", n.ResourceName)
   181  }
   182  
   183  func (n *graphNodeOrphanResource) ProvidedBy() []string {
   184  	return []string{resourceProvider(n.ResourceName, n.Provider)}
   185  }
   186  
   187  // GraphNodeEvalable impl.
   188  func (n *graphNodeOrphanResource) EvalTree() EvalNode {
   189  	var provider ResourceProvider
   190  	var state *InstanceState
   191  
   192  	seq := &EvalSequence{Nodes: make([]EvalNode, 0, 5)}
   193  
   194  	// Build instance info
   195  	info := &InstanceInfo{Id: n.ResourceName, Type: n.ResourceType}
   196  	seq.Nodes = append(seq.Nodes, &EvalInstanceInfo{Info: info})
   197  
   198  	// Refresh the resource
   199  	seq.Nodes = append(seq.Nodes, &EvalOpFilter{
   200  		Ops: []walkOperation{walkRefresh},
   201  		Node: &EvalSequence{
   202  			Nodes: []EvalNode{
   203  				&EvalGetProvider{
   204  					Name:   n.ProvidedBy()[0],
   205  					Output: &provider,
   206  				},
   207  				&EvalReadState{
   208  					Name:   n.ResourceName,
   209  					Output: &state,
   210  				},
   211  				&EvalRefresh{
   212  					Info:     info,
   213  					Provider: &provider,
   214  					State:    &state,
   215  					Output:   &state,
   216  				},
   217  				&EvalWriteState{
   218  					Name:         n.ResourceName,
   219  					ResourceType: n.ResourceType,
   220  					Provider:     n.Provider,
   221  					Dependencies: n.DependentOn(),
   222  					State:        &state,
   223  				},
   224  			},
   225  		},
   226  	})
   227  
   228  	// Diff the resource
   229  	var diff *InstanceDiff
   230  	seq.Nodes = append(seq.Nodes, &EvalOpFilter{
   231  		Ops: []walkOperation{walkPlan, walkPlanDestroy},
   232  		Node: &EvalSequence{
   233  			Nodes: []EvalNode{
   234  				&EvalReadState{
   235  					Name:   n.ResourceName,
   236  					Output: &state,
   237  				},
   238  				&EvalDiffDestroy{
   239  					Info:   info,
   240  					State:  &state,
   241  					Output: &diff,
   242  				},
   243  				&EvalWriteDiff{
   244  					Name: n.ResourceName,
   245  					Diff: &diff,
   246  				},
   247  			},
   248  		},
   249  	})
   250  
   251  	// Apply
   252  	seq.Nodes = append(seq.Nodes, &EvalOpFilter{
   253  		Ops: []walkOperation{walkApply},
   254  		Node: &EvalSequence{
   255  			Nodes: []EvalNode{
   256  				&EvalReadDiff{
   257  					Name: n.ResourceName,
   258  					Diff: &diff,
   259  				},
   260  				&EvalGetProvider{
   261  					Name:   n.ProvidedBy()[0],
   262  					Output: &provider,
   263  				},
   264  				&EvalReadState{
   265  					Name:   n.ResourceName,
   266  					Output: &state,
   267  				},
   268  				&EvalApply{
   269  					Info:     info,
   270  					State:    &state,
   271  					Diff:     &diff,
   272  					Provider: &provider,
   273  					Output:   &state,
   274  				},
   275  				&EvalWriteState{
   276  					Name:         n.ResourceName,
   277  					ResourceType: n.ResourceType,
   278  					Provider:     n.Provider,
   279  					Dependencies: n.DependentOn(),
   280  					State:        &state,
   281  				},
   282  				&EvalUpdateStateHook{},
   283  			},
   284  		},
   285  	})
   286  
   287  	return seq
   288  }
   289  
   290  func (n *graphNodeOrphanResource) dependableName() string {
   291  	return n.ResourceName
   292  }