github.com/trawler/terraform@v0.10.8-0.20171106022149-4b1c7a1d9b48/terraform/transform_provider.go (about)

     1  package terraform
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"strings"
     7  
     8  	"github.com/hashicorp/go-multierror"
     9  	"github.com/hashicorp/terraform/config/module"
    10  	"github.com/hashicorp/terraform/dag"
    11  )
    12  
    13  // TODO: return the transformers and append them to the list, so we don't lose the log steps
    14  func TransformProviders(providers []string, concrete ConcreteProviderNodeFunc, mod *module.Tree) GraphTransformer {
    15  	return GraphTransformMulti(
    16  		// Add providers from the config
    17  		&ProviderConfigTransformer{
    18  			Module:    mod,
    19  			Providers: providers,
    20  			Concrete:  concrete,
    21  		},
    22  		// Add any remaining missing providers
    23  		&MissingProviderTransformer{
    24  			Providers: providers,
    25  			Concrete:  concrete,
    26  		},
    27  		// Connect the providers
    28  		&ProviderTransformer{},
    29  		// Disable unused providers
    30  		&DisableProviderTransformer{},
    31  		// Connect provider to their parent provider nodes
    32  		&ParentProviderTransformer{},
    33  		// Attach configuration to each provider instance
    34  		&AttachProviderConfigTransformer{
    35  			Module: mod,
    36  		},
    37  	)
    38  }
    39  
    40  // GraphNodeProvider is an interface that nodes that can be a provider
    41  // must implement.
    42  // ProviderName returns the name of the provider this satisfies.
    43  // Name returns the full name of the provider in the config.
    44  type GraphNodeProvider interface {
    45  	ProviderName() string
    46  	Name() string
    47  }
    48  
    49  // GraphNodeCloseProvider is an interface that nodes that can be a close
    50  // provider must implement. The CloseProviderName returned is the name of
    51  // the provider they satisfy.
    52  type GraphNodeCloseProvider interface {
    53  	CloseProviderName() string
    54  }
    55  
    56  // GraphNodeProviderConsumer is an interface that nodes that require
    57  // a provider must implement. ProvidedBy must return the name of the provider
    58  // to use.
    59  type GraphNodeProviderConsumer interface {
    60  	// TODO: make this return s string instead of a []string
    61  	ProvidedBy() []string
    62  	// Set the resolved provider address for this resource.
    63  	SetProvider(string)
    64  }
    65  
    66  // ProviderTransformer is a GraphTransformer that maps resources to
    67  // providers within the graph. This will error if there are any resources
    68  // that don't map to proper resources.
    69  type ProviderTransformer struct{}
    70  
    71  func (t *ProviderTransformer) Transform(g *Graph) error {
    72  	// Go through the other nodes and match them to providers they need
    73  	var err error
    74  	m := providerVertexMap(g)
    75  	for _, v := range g.Vertices() {
    76  		if pv, ok := v.(GraphNodeProviderConsumer); ok {
    77  			p := pv.ProvidedBy()[0]
    78  
    79  			key := providerMapKey(p, pv)
    80  			target := m[key]
    81  
    82  			sp, ok := pv.(GraphNodeSubPath)
    83  			if !ok && target == nil {
    84  				// no target, and no path to walk up
    85  				err = multierror.Append(err, fmt.Errorf(
    86  					"%s: provider %s couldn't be found",
    87  					dag.VertexName(v), p))
    88  				break
    89  			}
    90  
    91  			// if we don't have a provider at this level, walk up the path looking for one
    92  			for i := 1; target == nil; i++ {
    93  				path := normalizeModulePath(sp.Path())
    94  				if len(path) < i {
    95  					break
    96  				}
    97  
    98  				key = ResolveProviderName(p, path[:len(path)-i])
    99  				target = m[key]
   100  				if target != nil {
   101  					break
   102  				}
   103  			}
   104  
   105  			if target == nil {
   106  				err = multierror.Append(err, fmt.Errorf(
   107  					"%s: provider %s couldn't be found",
   108  					dag.VertexName(v), p))
   109  				break
   110  			}
   111  
   112  			pv.SetProvider(key)
   113  			g.Connect(dag.BasicEdge(v, target))
   114  		}
   115  	}
   116  
   117  	return err
   118  }
   119  
   120  // CloseProviderTransformer is a GraphTransformer that adds nodes to the
   121  // graph that will close open provider connections that aren't needed anymore.
   122  // A provider connection is not needed anymore once all depended resources
   123  // in the graph are evaluated.
   124  type CloseProviderTransformer struct{}
   125  
   126  // FIXME: this doesn't close providers if the root provider is disabled
   127  func (t *CloseProviderTransformer) Transform(g *Graph) error {
   128  	pm := providerVertexMap(g)
   129  	cpm := make(map[string]*graphNodeCloseProvider)
   130  	var err error
   131  
   132  	for _, v := range pm {
   133  		p := v.(GraphNodeProvider)
   134  
   135  		// get the close provider of this type if we alread created it
   136  		closer := cpm[p.ProviderName()]
   137  
   138  		if closer == nil {
   139  			// create a closer for this provider type
   140  			closer = &graphNodeCloseProvider{ProviderNameValue: p.ProviderName()}
   141  			g.Add(closer)
   142  			cpm[p.ProviderName()] = closer
   143  		}
   144  
   145  		// Close node depends on the provider itself
   146  		// this is added unconditionally, so it will connect to all instances
   147  		// of the provider. Extra edges will be removed by transitive
   148  		// reduction.
   149  		g.Connect(dag.BasicEdge(closer, p))
   150  
   151  		// connect all the provider's resources to the close node
   152  		for _, s := range g.UpEdges(p).List() {
   153  			if _, ok := s.(GraphNodeProviderConsumer); ok {
   154  				g.Connect(dag.BasicEdge(closer, s))
   155  			}
   156  		}
   157  	}
   158  
   159  	return err
   160  }
   161  
   162  // MissingProviderTransformer is a GraphTransformer that adds nodes for all
   163  // required providers into the graph. Specifically, it creates provider
   164  // configuration nodes for all the providers that we support. These are pruned
   165  // later during an optimization pass.
   166  type MissingProviderTransformer struct {
   167  	// Providers is the list of providers we support.
   168  	Providers []string
   169  
   170  	// Concrete, if set, overrides how the providers are made.
   171  	Concrete ConcreteProviderNodeFunc
   172  }
   173  
   174  func (t *MissingProviderTransformer) Transform(g *Graph) error {
   175  	// Initialize factory
   176  	if t.Concrete == nil {
   177  		t.Concrete = func(a *NodeAbstractProvider) dag.Vertex {
   178  			return a
   179  		}
   180  	}
   181  
   182  	var err error
   183  	m := providerVertexMap(g)
   184  	for _, v := range g.Vertices() {
   185  		pv, ok := v.(GraphNodeProviderConsumer)
   186  		if !ok {
   187  			continue
   188  		}
   189  
   190  		p := pv.ProvidedBy()[0]
   191  		key := ResolveProviderName(p, nil)
   192  		provider := m[key]
   193  
   194  		// we already have it
   195  		if provider != nil {
   196  			continue
   197  		}
   198  
   199  		// create the misisng top-level provider
   200  		provider = t.Concrete(&NodeAbstractProvider{
   201  			NameValue: p,
   202  		}).(dag.Vertex)
   203  
   204  		m[key] = g.Add(provider)
   205  	}
   206  
   207  	return err
   208  }
   209  
   210  // ParentProviderTransformer connects provider nodes to their parents.
   211  //
   212  // This works by finding nodes that are both GraphNodeProviders and
   213  // GraphNodeSubPath. It then connects the providers to their parent
   214  // path. The parent provider is always at the root level.
   215  type ParentProviderTransformer struct{}
   216  
   217  func (t *ParentProviderTransformer) Transform(g *Graph) error {
   218  	pm := providerVertexMap(g)
   219  	for _, v := range g.Vertices() {
   220  		// Only care about providers
   221  		pn, ok := v.(GraphNodeProvider)
   222  		if !ok || pn.ProviderName() == "" {
   223  			continue
   224  		}
   225  
   226  		// Also require a subpath, if there is no subpath then we
   227  		// can't have a parent.
   228  		if pn, ok := v.(GraphNodeSubPath); ok {
   229  			if len(normalizeModulePath(pn.Path())) <= 1 {
   230  				continue
   231  			}
   232  		}
   233  
   234  		// this provider may be disabled, but we can only get it's name from
   235  		// the ProviderName string
   236  		name := ResolveProviderName(strings.SplitN(pn.ProviderName(), " ", 2)[0], nil)
   237  		parent := pm[name]
   238  		if parent != nil {
   239  			g.Connect(dag.BasicEdge(v, parent))
   240  		}
   241  
   242  	}
   243  	return nil
   244  }
   245  
   246  // PruneProviderTransformer is a GraphTransformer that prunes all the
   247  // providers that aren't needed from the graph. A provider is unneeded if
   248  // no resource or module is using that provider.
   249  type PruneProviderTransformer struct{}
   250  
   251  func (t *PruneProviderTransformer) Transform(g *Graph) error {
   252  	for _, v := range g.Vertices() {
   253  		// We only care about the providers
   254  		if pn, ok := v.(GraphNodeProvider); !ok || pn.ProviderName() == "" {
   255  			continue
   256  		}
   257  		// Does anything depend on this? If not, then prune it.
   258  		if s := g.UpEdges(v); s.Len() == 0 {
   259  			if nv, ok := v.(dag.NamedVertex); ok {
   260  				log.Printf("[DEBUG] Pruning provider with no dependencies: %s", nv.Name())
   261  			}
   262  			g.Remove(v)
   263  		}
   264  	}
   265  
   266  	return nil
   267  }
   268  
   269  // providerMapKey is a helper that gives us the key to use for the
   270  // maps returned by things such as providerVertexMap.
   271  func providerMapKey(k string, v dag.Vertex) string {
   272  	// we create a dummy provider to
   273  	var path []string
   274  	if sp, ok := v.(GraphNodeSubPath); ok {
   275  		path = normalizeModulePath(sp.Path())
   276  	}
   277  	return ResolveProviderName(k, path)
   278  }
   279  
   280  func providerVertexMap(g *Graph) map[string]dag.Vertex {
   281  	m := make(map[string]dag.Vertex)
   282  	for _, v := range g.Vertices() {
   283  		if pv, ok := v.(GraphNodeProvider); ok {
   284  			// TODO:  The Name may have meta info, like " (disabled)"
   285  			name := strings.SplitN(pv.Name(), " ", 2)[0]
   286  			m[name] = v
   287  		}
   288  	}
   289  
   290  	return m
   291  }
   292  
   293  func closeProviderVertexMap(g *Graph) map[string]dag.Vertex {
   294  	m := make(map[string]dag.Vertex)
   295  	for _, v := range g.Vertices() {
   296  		if pv, ok := v.(GraphNodeCloseProvider); ok {
   297  			m[pv.CloseProviderName()] = v
   298  		}
   299  	}
   300  
   301  	return m
   302  }
   303  
   304  type graphNodeCloseProvider struct {
   305  	ProviderNameValue string
   306  }
   307  
   308  func (n *graphNodeCloseProvider) Name() string {
   309  	return fmt.Sprintf("provider.%s (close)", n.ProviderNameValue)
   310  }
   311  
   312  // GraphNodeEvalable impl.
   313  func (n *graphNodeCloseProvider) EvalTree() EvalNode {
   314  	return CloseProviderEvalTree(n.ProviderNameValue)
   315  }
   316  
   317  // GraphNodeDependable impl.
   318  func (n *graphNodeCloseProvider) DependableName() []string {
   319  	return []string{n.Name()}
   320  }
   321  
   322  func (n *graphNodeCloseProvider) CloseProviderName() string {
   323  	return n.ProviderNameValue
   324  }
   325  
   326  // GraphNodeDotter impl.
   327  func (n *graphNodeCloseProvider) DotNode(name string, opts *dag.DotOpts) *dag.DotNode {
   328  	if !opts.Verbose {
   329  		return nil
   330  	}
   331  	return &dag.DotNode{
   332  		Name: name,
   333  		Attrs: map[string]string{
   334  			"label": n.Name(),
   335  			"shape": "diamond",
   336  		},
   337  	}
   338  }
   339  
   340  // RemovableIfNotTargeted
   341  func (n *graphNodeCloseProvider) RemoveIfNotTargeted() bool {
   342  	// We need to add this so that this node will be removed if
   343  	// it isn't targeted or a dependency of a target.
   344  	return true
   345  }
   346  
   347  // graphNodeProviderConsumerDummy is a struct that never enters the real
   348  // graph (though it could to no ill effect). It implements
   349  // GraphNodeProviderConsumer and GraphNodeSubpath as a way to force
   350  // certain transformations.
   351  type graphNodeProviderConsumerDummy struct {
   352  	ProviderValue string
   353  	PathValue     []string
   354  }
   355  
   356  func (n *graphNodeProviderConsumerDummy) Path() []string {
   357  	return n.PathValue
   358  }
   359  
   360  func (n *graphNodeProviderConsumerDummy) ProvidedBy() []string {
   361  	return []string{n.ProviderValue}
   362  }
   363  
   364  func (n *graphNodeProviderConsumerDummy) SetProvider(string) {}