github.com/erriapo/terraform@v0.6.12-0.20160203182612-0340ea72354f/terraform/transform_orphan.go (about)

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