github.com/turtlemonvh/terraform@v0.6.9-0.20151204001754-8e40b6b855e8/terraform/transform_orphan.go (about)

     1  package terraform
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     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  	Targets []ResourceAddress
    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  	// Build up all our state representatives
    45  	resourceRep := make(map[string]struct{})
    46  	for _, v := range g.Vertices() {
    47  		if sr, ok := v.(GraphNodeStateRepresentative); ok {
    48  			for _, k := range sr.StateId() {
    49  				resourceRep[k] = struct{}{}
    50  			}
    51  		}
    52  	}
    53  
    54  	var config *config.Config
    55  	if t.Module != nil {
    56  		if module := t.Module.Child(g.Path[1:]); module != nil {
    57  			config = module.Config()
    58  		}
    59  	}
    60  
    61  	var resourceVertexes []dag.Vertex
    62  	if state := t.State.ModuleByPath(g.Path); state != nil {
    63  		// If we have state, then we can have orphan resources
    64  
    65  		// If we have a view, get the view
    66  		if t.View != "" {
    67  			state = state.View(t.View)
    68  		}
    69  
    70  		resourceOrphans := state.Orphans(config)
    71  		if len(t.Targets) > 0 {
    72  			var targetedOrphans []string
    73  			for _, o := range resourceOrphans {
    74  				targeted := false
    75  				for _, t := range t.Targets {
    76  					prefix := fmt.Sprintf("%s.%s.%d", t.Type, t.Name, t.Index)
    77  					if strings.HasPrefix(o, prefix) {
    78  						targeted = true
    79  					}
    80  				}
    81  				if targeted {
    82  					targetedOrphans = append(targetedOrphans, o)
    83  				}
    84  			}
    85  			resourceOrphans = targetedOrphans
    86  		}
    87  
    88  		resourceVertexes = make([]dag.Vertex, len(resourceOrphans))
    89  		for i, k := range resourceOrphans {
    90  			// If this orphan is represented by some other node somehow,
    91  			// then ignore it.
    92  			if _, ok := resourceRep[k]; ok {
    93  				continue
    94  			}
    95  
    96  			rs := state.Resources[k]
    97  
    98  			resourceVertexes[i] = g.Add(&graphNodeOrphanResource{
    99  				ResourceName: k,
   100  				ResourceType: rs.Type,
   101  				Provider:     rs.Provider,
   102  				dependentOn:  rs.Dependencies,
   103  			})
   104  		}
   105  	}
   106  
   107  	// Go over each module orphan and add it to the graph. We store the
   108  	// vertexes and states outside so that we can connect dependencies later.
   109  	moduleOrphans := t.State.ModuleOrphans(g.Path, config)
   110  	moduleVertexes := make([]dag.Vertex, len(moduleOrphans))
   111  	for i, path := range moduleOrphans {
   112  		var deps []string
   113  		if s := t.State.ModuleByPath(path); s != nil {
   114  			deps = s.Dependencies
   115  		}
   116  
   117  		moduleVertexes[i] = g.Add(&graphNodeOrphanModule{
   118  			Path:        path,
   119  			dependentOn: deps,
   120  		})
   121  	}
   122  
   123  	// Now do the dependencies. We do this _after_ adding all the orphan
   124  	// nodes above because there are cases in which the orphans themselves
   125  	// depend on other orphans.
   126  
   127  	// Resource dependencies
   128  	for _, v := range resourceVertexes {
   129  		g.ConnectDependent(v)
   130  	}
   131  
   132  	// Module dependencies
   133  	for _, v := range moduleVertexes {
   134  		g.ConnectDependent(v)
   135  	}
   136  
   137  	return nil
   138  }
   139  
   140  // graphNodeOrphanModule is the graph vertex representing an orphan resource..
   141  type graphNodeOrphanModule struct {
   142  	Path []string
   143  
   144  	dependentOn []string
   145  }
   146  
   147  func (n *graphNodeOrphanModule) DependableName() []string {
   148  	return []string{n.dependableName()}
   149  }
   150  
   151  func (n *graphNodeOrphanModule) DependentOn() []string {
   152  	return n.dependentOn
   153  }
   154  
   155  func (n *graphNodeOrphanModule) Name() string {
   156  	return fmt.Sprintf("%s (orphan)", n.dependableName())
   157  }
   158  
   159  func (n *graphNodeOrphanModule) dependableName() string {
   160  	return fmt.Sprintf("module.%s", n.Path[len(n.Path)-1])
   161  }
   162  
   163  // GraphNodeExpandable
   164  func (n *graphNodeOrphanModule) Expand(b GraphBuilder) (GraphNodeSubgraph, error) {
   165  	g, err := b.Build(n.Path)
   166  	if err != nil {
   167  		return nil, err
   168  	}
   169  
   170  	return &GraphNodeBasicSubgraph{
   171  		NameValue: n.Name(),
   172  		Graph:     g,
   173  	}, nil
   174  }
   175  
   176  // graphNodeOrphanResource is the graph vertex representing an orphan resource..
   177  type graphNodeOrphanResource struct {
   178  	ResourceName string
   179  	ResourceType string
   180  	Provider     string
   181  
   182  	dependentOn []string
   183  }
   184  
   185  func (n *graphNodeOrphanResource) ResourceAddress() *ResourceAddress {
   186  	return n.ResourceAddress()
   187  }
   188  
   189  func (n *graphNodeOrphanResource) DependableName() []string {
   190  	return []string{n.dependableName()}
   191  }
   192  
   193  func (n *graphNodeOrphanResource) DependentOn() []string {
   194  	return n.dependentOn
   195  }
   196  
   197  func (n *graphNodeOrphanResource) Flatten(p []string) (dag.Vertex, error) {
   198  	return &graphNodeOrphanResourceFlat{
   199  		graphNodeOrphanResource: n,
   200  		PathValue:               p,
   201  	}, nil
   202  }
   203  
   204  func (n *graphNodeOrphanResource) Name() string {
   205  	return fmt.Sprintf("%s (orphan)", n.ResourceName)
   206  }
   207  
   208  func (n *graphNodeOrphanResource) ProvidedBy() []string {
   209  	return []string{resourceProvider(n.ResourceName, n.Provider)}
   210  }
   211  
   212  // GraphNodeEvalable impl.
   213  func (n *graphNodeOrphanResource) EvalTree() EvalNode {
   214  	var provider ResourceProvider
   215  	var state *InstanceState
   216  
   217  	seq := &EvalSequence{Nodes: make([]EvalNode, 0, 5)}
   218  
   219  	// Build instance info
   220  	info := &InstanceInfo{Id: n.ResourceName, Type: n.ResourceType}
   221  	seq.Nodes = append(seq.Nodes, &EvalInstanceInfo{Info: info})
   222  
   223  	// Refresh the resource
   224  	seq.Nodes = append(seq.Nodes, &EvalOpFilter{
   225  		Ops: []walkOperation{walkRefresh},
   226  		Node: &EvalSequence{
   227  			Nodes: []EvalNode{
   228  				&EvalGetProvider{
   229  					Name:   n.ProvidedBy()[0],
   230  					Output: &provider,
   231  				},
   232  				&EvalReadState{
   233  					Name:   n.ResourceName,
   234  					Output: &state,
   235  				},
   236  				&EvalRefresh{
   237  					Info:     info,
   238  					Provider: &provider,
   239  					State:    &state,
   240  					Output:   &state,
   241  				},
   242  				&EvalWriteState{
   243  					Name:         n.ResourceName,
   244  					ResourceType: n.ResourceType,
   245  					Provider:     n.Provider,
   246  					Dependencies: n.DependentOn(),
   247  					State:        &state,
   248  				},
   249  			},
   250  		},
   251  	})
   252  
   253  	// Diff the resource
   254  	var diff *InstanceDiff
   255  	seq.Nodes = append(seq.Nodes, &EvalOpFilter{
   256  		Ops: []walkOperation{walkPlan, walkPlanDestroy},
   257  		Node: &EvalSequence{
   258  			Nodes: []EvalNode{
   259  				&EvalReadState{
   260  					Name:   n.ResourceName,
   261  					Output: &state,
   262  				},
   263  				&EvalDiffDestroy{
   264  					Info:   info,
   265  					State:  &state,
   266  					Output: &diff,
   267  				},
   268  				&EvalWriteDiff{
   269  					Name: n.ResourceName,
   270  					Diff: &diff,
   271  				},
   272  			},
   273  		},
   274  	})
   275  
   276  	// Apply
   277  	var err error
   278  	seq.Nodes = append(seq.Nodes, &EvalOpFilter{
   279  		Ops: []walkOperation{walkApply, walkDestroy},
   280  		Node: &EvalSequence{
   281  			Nodes: []EvalNode{
   282  				&EvalReadDiff{
   283  					Name: n.ResourceName,
   284  					Diff: &diff,
   285  				},
   286  				&EvalGetProvider{
   287  					Name:   n.ProvidedBy()[0],
   288  					Output: &provider,
   289  				},
   290  				&EvalReadState{
   291  					Name:   n.ResourceName,
   292  					Output: &state,
   293  				},
   294  				&EvalApply{
   295  					Info:     info,
   296  					State:    &state,
   297  					Diff:     &diff,
   298  					Provider: &provider,
   299  					Output:   &state,
   300  					Error:    &err,
   301  				},
   302  				&EvalWriteState{
   303  					Name:         n.ResourceName,
   304  					ResourceType: n.ResourceType,
   305  					Provider:     n.Provider,
   306  					Dependencies: n.DependentOn(),
   307  					State:        &state,
   308  				},
   309  				&EvalApplyPost{
   310  					Info:  info,
   311  					State: &state,
   312  					Error: &err,
   313  				},
   314  				&EvalUpdateStateHook{},
   315  			},
   316  		},
   317  	})
   318  
   319  	return seq
   320  }
   321  
   322  func (n *graphNodeOrphanResource) dependableName() string {
   323  	return n.ResourceName
   324  }
   325  
   326  // GraphNodeDestroyable impl.
   327  func (n *graphNodeOrphanResource) DestroyNode(mode GraphNodeDestroyMode) GraphNodeDestroy {
   328  	if mode != DestroyPrimary {
   329  		return nil
   330  	}
   331  
   332  	return n
   333  }
   334  
   335  // GraphNodeDestroy impl.
   336  func (n *graphNodeOrphanResource) CreateBeforeDestroy() bool {
   337  	return false
   338  }
   339  
   340  func (n *graphNodeOrphanResource) CreateNode() dag.Vertex {
   341  	return n
   342  }
   343  
   344  // Same as graphNodeOrphanResource, but for flattening
   345  type graphNodeOrphanResourceFlat struct {
   346  	*graphNodeOrphanResource
   347  
   348  	PathValue []string
   349  }
   350  
   351  func (n *graphNodeOrphanResourceFlat) Name() string {
   352  	return fmt.Sprintf(
   353  		"%s.%s", modulePrefixStr(n.PathValue), n.graphNodeOrphanResource.Name())
   354  }
   355  
   356  func (n *graphNodeOrphanResourceFlat) Path() []string {
   357  	return n.PathValue
   358  }
   359  
   360  // GraphNodeDestroyable impl.
   361  func (n *graphNodeOrphanResourceFlat) DestroyNode(mode GraphNodeDestroyMode) GraphNodeDestroy {
   362  	if mode != DestroyPrimary {
   363  		return nil
   364  	}
   365  
   366  	return n
   367  }
   368  
   369  // GraphNodeDestroy impl.
   370  func (n *graphNodeOrphanResourceFlat) CreateBeforeDestroy() bool {
   371  	return false
   372  }
   373  
   374  func (n *graphNodeOrphanResourceFlat) CreateNode() dag.Vertex {
   375  	return n
   376  }
   377  
   378  func (n *graphNodeOrphanResourceFlat) ProvidedBy() []string {
   379  	return modulePrefixList(
   380  		n.graphNodeOrphanResource.ProvidedBy(),
   381  		modulePrefixStr(n.PathValue))
   382  }