github.com/jsoriano/terraform@v0.6.7-0.20151026070445-8b70867fdd95/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  		var deps []string
   104  		if s := t.State.ModuleByPath(path); s != nil {
   105  			deps = s.Dependencies
   106  		}
   107  
   108  		moduleVertexes[i] = g.Add(&graphNodeOrphanModule{
   109  			Path:        path,
   110  			dependentOn: deps,
   111  		})
   112  	}
   113  
   114  	// Now do the dependencies. We do this _after_ adding all the orphan
   115  	// nodes above because there are cases in which the orphans themselves
   116  	// depend on other orphans.
   117  
   118  	// Resource dependencies
   119  	for _, v := range resourceVertexes {
   120  		g.ConnectDependent(v)
   121  	}
   122  
   123  	// Module dependencies
   124  	for _, v := range moduleVertexes {
   125  		g.ConnectDependent(v)
   126  	}
   127  
   128  	return nil
   129  }
   130  
   131  // graphNodeOrphanModule is the graph vertex representing an orphan resource..
   132  type graphNodeOrphanModule struct {
   133  	Path []string
   134  
   135  	dependentOn []string
   136  }
   137  
   138  func (n *graphNodeOrphanModule) DependableName() []string {
   139  	return []string{n.dependableName()}
   140  }
   141  
   142  func (n *graphNodeOrphanModule) DependentOn() []string {
   143  	return n.dependentOn
   144  }
   145  
   146  func (n *graphNodeOrphanModule) Name() string {
   147  	return fmt.Sprintf("%s (orphan)", n.dependableName())
   148  }
   149  
   150  func (n *graphNodeOrphanModule) dependableName() string {
   151  	return fmt.Sprintf("module.%s", n.Path[len(n.Path)-1])
   152  }
   153  
   154  // GraphNodeExpandable
   155  func (n *graphNodeOrphanModule) Expand(b GraphBuilder) (GraphNodeSubgraph, error) {
   156  	g, err := b.Build(n.Path)
   157  	if err != nil {
   158  		return nil, err
   159  	}
   160  
   161  	return &GraphNodeBasicSubgraph{
   162  		NameValue: n.Name(),
   163  		Graph:     g,
   164  	}, nil
   165  }
   166  
   167  // graphNodeOrphanResource is the graph vertex representing an orphan resource..
   168  type graphNodeOrphanResource struct {
   169  	ResourceName string
   170  	ResourceType string
   171  	Provider     string
   172  
   173  	dependentOn []string
   174  }
   175  
   176  func (n *graphNodeOrphanResource) DependableName() []string {
   177  	return []string{n.dependableName()}
   178  }
   179  
   180  func (n *graphNodeOrphanResource) DependentOn() []string {
   181  	return n.dependentOn
   182  }
   183  
   184  func (n *graphNodeOrphanResource) Flatten(p []string) (dag.Vertex, error) {
   185  	return &graphNodeOrphanResourceFlat{
   186  		graphNodeOrphanResource: n,
   187  		PathValue:               p,
   188  	}, nil
   189  }
   190  
   191  func (n *graphNodeOrphanResource) Name() string {
   192  	return fmt.Sprintf("%s (orphan)", n.ResourceName)
   193  }
   194  
   195  func (n *graphNodeOrphanResource) ProvidedBy() []string {
   196  	return []string{resourceProvider(n.ResourceName, n.Provider)}
   197  }
   198  
   199  // GraphNodeEvalable impl.
   200  func (n *graphNodeOrphanResource) EvalTree() EvalNode {
   201  	var provider ResourceProvider
   202  	var state *InstanceState
   203  
   204  	seq := &EvalSequence{Nodes: make([]EvalNode, 0, 5)}
   205  
   206  	// Build instance info
   207  	info := &InstanceInfo{Id: n.ResourceName, Type: n.ResourceType}
   208  	seq.Nodes = append(seq.Nodes, &EvalInstanceInfo{Info: info})
   209  
   210  	// Refresh the resource
   211  	seq.Nodes = append(seq.Nodes, &EvalOpFilter{
   212  		Ops: []walkOperation{walkRefresh},
   213  		Node: &EvalSequence{
   214  			Nodes: []EvalNode{
   215  				&EvalGetProvider{
   216  					Name:   n.ProvidedBy()[0],
   217  					Output: &provider,
   218  				},
   219  				&EvalReadState{
   220  					Name:   n.ResourceName,
   221  					Output: &state,
   222  				},
   223  				&EvalRefresh{
   224  					Info:     info,
   225  					Provider: &provider,
   226  					State:    &state,
   227  					Output:   &state,
   228  				},
   229  				&EvalWriteState{
   230  					Name:         n.ResourceName,
   231  					ResourceType: n.ResourceType,
   232  					Provider:     n.Provider,
   233  					Dependencies: n.DependentOn(),
   234  					State:        &state,
   235  				},
   236  			},
   237  		},
   238  	})
   239  
   240  	// Diff the resource
   241  	var diff *InstanceDiff
   242  	seq.Nodes = append(seq.Nodes, &EvalOpFilter{
   243  		Ops: []walkOperation{walkPlan, walkPlanDestroy},
   244  		Node: &EvalSequence{
   245  			Nodes: []EvalNode{
   246  				&EvalReadState{
   247  					Name:   n.ResourceName,
   248  					Output: &state,
   249  				},
   250  				&EvalDiffDestroy{
   251  					Info:   info,
   252  					State:  &state,
   253  					Output: &diff,
   254  				},
   255  				&EvalWriteDiff{
   256  					Name: n.ResourceName,
   257  					Diff: &diff,
   258  				},
   259  			},
   260  		},
   261  	})
   262  
   263  	// Apply
   264  	var err error
   265  	seq.Nodes = append(seq.Nodes, &EvalOpFilter{
   266  		Ops: []walkOperation{walkApply, walkDestroy},
   267  		Node: &EvalSequence{
   268  			Nodes: []EvalNode{
   269  				&EvalReadDiff{
   270  					Name: n.ResourceName,
   271  					Diff: &diff,
   272  				},
   273  				&EvalGetProvider{
   274  					Name:   n.ProvidedBy()[0],
   275  					Output: &provider,
   276  				},
   277  				&EvalReadState{
   278  					Name:   n.ResourceName,
   279  					Output: &state,
   280  				},
   281  				&EvalApply{
   282  					Info:     info,
   283  					State:    &state,
   284  					Diff:     &diff,
   285  					Provider: &provider,
   286  					Output:   &state,
   287  					Error:    &err,
   288  				},
   289  				&EvalWriteState{
   290  					Name:         n.ResourceName,
   291  					ResourceType: n.ResourceType,
   292  					Provider:     n.Provider,
   293  					Dependencies: n.DependentOn(),
   294  					State:        &state,
   295  				},
   296  				&EvalApplyPost{
   297  					Info:  info,
   298  					State: &state,
   299  					Error: &err,
   300  				},
   301  				&EvalUpdateStateHook{},
   302  			},
   303  		},
   304  	})
   305  
   306  	return seq
   307  }
   308  
   309  func (n *graphNodeOrphanResource) dependableName() string {
   310  	return n.ResourceName
   311  }
   312  
   313  // GraphNodeDestroyable impl.
   314  func (n *graphNodeOrphanResource) DestroyNode(mode GraphNodeDestroyMode) GraphNodeDestroy {
   315  	if mode != DestroyPrimary {
   316  		return nil
   317  	}
   318  
   319  	return n
   320  }
   321  
   322  // GraphNodeDestroy impl.
   323  func (n *graphNodeOrphanResource) CreateBeforeDestroy() bool {
   324  	return false
   325  }
   326  
   327  func (n *graphNodeOrphanResource) CreateNode() dag.Vertex {
   328  	return n
   329  }
   330  
   331  // Same as graphNodeOrphanResource, but for flattening
   332  type graphNodeOrphanResourceFlat struct {
   333  	*graphNodeOrphanResource
   334  
   335  	PathValue []string
   336  }
   337  
   338  func (n *graphNodeOrphanResourceFlat) Name() string {
   339  	return fmt.Sprintf(
   340  		"%s.%s", modulePrefixStr(n.PathValue), n.graphNodeOrphanResource.Name())
   341  }
   342  
   343  func (n *graphNodeOrphanResourceFlat) Path() []string {
   344  	return n.PathValue
   345  }
   346  
   347  // GraphNodeDestroyable impl.
   348  func (n *graphNodeOrphanResourceFlat) DestroyNode(mode GraphNodeDestroyMode) GraphNodeDestroy {
   349  	if mode != DestroyPrimary {
   350  		return nil
   351  	}
   352  
   353  	return n
   354  }
   355  
   356  // GraphNodeDestroy impl.
   357  func (n *graphNodeOrphanResourceFlat) CreateBeforeDestroy() bool {
   358  	return false
   359  }
   360  
   361  func (n *graphNodeOrphanResourceFlat) CreateNode() dag.Vertex {
   362  	return n
   363  }
   364  
   365  func (n *graphNodeOrphanResourceFlat) ProvidedBy() []string {
   366  	return modulePrefixList(
   367  		n.graphNodeOrphanResource.ProvidedBy(),
   368  		modulePrefixStr(n.PathValue))
   369  }