github.com/tkak/terraform@v0.5.4-0.20150712180941-7f738dc27225/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) Flatten(p []string) (dag.Vertex, error) {
   180  	return &graphNodeOrphanResourceFlat{
   181  		graphNodeOrphanResource: n,
   182  		PathValue:               p,
   183  	}, nil
   184  }
   185  
   186  func (n *graphNodeOrphanResource) Name() string {
   187  	return fmt.Sprintf("%s (orphan)", n.ResourceName)
   188  }
   189  
   190  func (n *graphNodeOrphanResource) ProvidedBy() []string {
   191  	return []string{resourceProvider(n.ResourceName, n.Provider)}
   192  }
   193  
   194  // GraphNodeEvalable impl.
   195  func (n *graphNodeOrphanResource) EvalTree() EvalNode {
   196  	var provider ResourceProvider
   197  	var state *InstanceState
   198  
   199  	seq := &EvalSequence{Nodes: make([]EvalNode, 0, 5)}
   200  
   201  	// Build instance info
   202  	info := &InstanceInfo{Id: n.ResourceName, Type: n.ResourceType}
   203  	seq.Nodes = append(seq.Nodes, &EvalInstanceInfo{Info: info})
   204  
   205  	// Refresh the resource
   206  	seq.Nodes = append(seq.Nodes, &EvalOpFilter{
   207  		Ops: []walkOperation{walkRefresh},
   208  		Node: &EvalSequence{
   209  			Nodes: []EvalNode{
   210  				&EvalGetProvider{
   211  					Name:   n.ProvidedBy()[0],
   212  					Output: &provider,
   213  				},
   214  				&EvalReadState{
   215  					Name:   n.ResourceName,
   216  					Output: &state,
   217  				},
   218  				&EvalRefresh{
   219  					Info:     info,
   220  					Provider: &provider,
   221  					State:    &state,
   222  					Output:   &state,
   223  				},
   224  				&EvalWriteState{
   225  					Name:         n.ResourceName,
   226  					ResourceType: n.ResourceType,
   227  					Provider:     n.Provider,
   228  					Dependencies: n.DependentOn(),
   229  					State:        &state,
   230  				},
   231  			},
   232  		},
   233  	})
   234  
   235  	// Diff the resource
   236  	var diff *InstanceDiff
   237  	seq.Nodes = append(seq.Nodes, &EvalOpFilter{
   238  		Ops: []walkOperation{walkPlan, walkPlanDestroy},
   239  		Node: &EvalSequence{
   240  			Nodes: []EvalNode{
   241  				&EvalReadState{
   242  					Name:   n.ResourceName,
   243  					Output: &state,
   244  				},
   245  				&EvalDiffDestroy{
   246  					Info:   info,
   247  					State:  &state,
   248  					Output: &diff,
   249  				},
   250  				&EvalWriteDiff{
   251  					Name: n.ResourceName,
   252  					Diff: &diff,
   253  				},
   254  			},
   255  		},
   256  	})
   257  
   258  	// Apply
   259  	var err error
   260  	seq.Nodes = append(seq.Nodes, &EvalOpFilter{
   261  		Ops: []walkOperation{walkApply},
   262  		Node: &EvalSequence{
   263  			Nodes: []EvalNode{
   264  				&EvalReadDiff{
   265  					Name: n.ResourceName,
   266  					Diff: &diff,
   267  				},
   268  				&EvalGetProvider{
   269  					Name:   n.ProvidedBy()[0],
   270  					Output: &provider,
   271  				},
   272  				&EvalReadState{
   273  					Name:   n.ResourceName,
   274  					Output: &state,
   275  				},
   276  				&EvalApply{
   277  					Info:     info,
   278  					State:    &state,
   279  					Diff:     &diff,
   280  					Provider: &provider,
   281  					Output:   &state,
   282  					Error:    &err,
   283  				},
   284  				&EvalWriteState{
   285  					Name:         n.ResourceName,
   286  					ResourceType: n.ResourceType,
   287  					Provider:     n.Provider,
   288  					Dependencies: n.DependentOn(),
   289  					State:        &state,
   290  				},
   291  				&EvalApplyPost{
   292  					Info:  info,
   293  					State: &state,
   294  					Error: &err,
   295  				},
   296  				&EvalUpdateStateHook{},
   297  			},
   298  		},
   299  	})
   300  
   301  	return seq
   302  }
   303  
   304  func (n *graphNodeOrphanResource) dependableName() string {
   305  	return n.ResourceName
   306  }
   307  
   308  // GraphNodeDestroyable impl.
   309  func (n *graphNodeOrphanResource) DestroyNode(mode GraphNodeDestroyMode) GraphNodeDestroy {
   310  	if mode != DestroyPrimary {
   311  		return nil
   312  	}
   313  
   314  	return n
   315  }
   316  
   317  // GraphNodeDestroy impl.
   318  func (n *graphNodeOrphanResource) CreateBeforeDestroy() bool {
   319  	return false
   320  }
   321  
   322  func (n *graphNodeOrphanResource) CreateNode() dag.Vertex {
   323  	return n
   324  }
   325  
   326  // Same as graphNodeOrphanResource, but for flattening
   327  type graphNodeOrphanResourceFlat struct {
   328  	*graphNodeOrphanResource
   329  
   330  	PathValue []string
   331  }
   332  
   333  func (n *graphNodeOrphanResourceFlat) Name() string {
   334  	return fmt.Sprintf(
   335  		"%s.%s", modulePrefixStr(n.PathValue), n.graphNodeOrphanResource.Name())
   336  }
   337  
   338  func (n *graphNodeOrphanResourceFlat) Path() []string {
   339  	return n.PathValue
   340  }
   341  
   342  // GraphNodeDestroyable impl.
   343  func (n *graphNodeOrphanResourceFlat) DestroyNode(mode GraphNodeDestroyMode) GraphNodeDestroy {
   344  	if mode != DestroyPrimary {
   345  		return nil
   346  	}
   347  
   348  	return n
   349  }
   350  
   351  // GraphNodeDestroy impl.
   352  func (n *graphNodeOrphanResourceFlat) CreateBeforeDestroy() bool {
   353  	return false
   354  }
   355  
   356  func (n *graphNodeOrphanResourceFlat) CreateNode() dag.Vertex {
   357  	return n
   358  }