summaryrefslogtreecommitdiff
path: root/vendor/github.com/hashicorp/terraform/terraform/transform_provider.go
diff options
context:
space:
mode:
authorFlavio Castelli <fcastelli@suse.com>2017-05-03 11:37:08 +0200
committerAlvaro <alvaro.saurin@gmail.com>2017-05-03 11:40:31 +0200
commitee12004ab93e54f326896e9909ba9e6a2bd11e89 (patch)
tree1ea30d204b04425ebd1dadaf8cc991d572c7f0fb /vendor/github.com/hashicorp/terraform/terraform/transform_provider.go
parenta286dc5494691c2b04c48ef6695ed0c902912c0f (diff)
downloadterraform-provider-libvirt-ee12004ab93e54f326896e9909ba9e6a2bd11e89.tar
terraform-provider-libvirt-ee12004ab93e54f326896e9909ba9e6a2bd11e89.tar.gz
Vendor dependencies with vndr
This fixes issue #123
Diffstat (limited to 'vendor/github.com/hashicorp/terraform/terraform/transform_provider.go')
-rw-r--r--vendor/github.com/hashicorp/terraform/terraform/transform_provider.go380
1 files changed, 380 insertions, 0 deletions
diff --git a/vendor/github.com/hashicorp/terraform/terraform/transform_provider.go b/vendor/github.com/hashicorp/terraform/terraform/transform_provider.go
new file mode 100644
index 00000000..b9695d52
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/terraform/transform_provider.go
@@ -0,0 +1,380 @@
+package terraform
+
+import (
+ "fmt"
+ "log"
+ "strings"
+
+ "github.com/hashicorp/go-multierror"
+ "github.com/hashicorp/terraform/dag"
+)
+
+// GraphNodeProvider is an interface that nodes that can be a provider
+// must implement. The ProviderName returned is the name of the provider
+// they satisfy.
+type GraphNodeProvider interface {
+ ProviderName() string
+}
+
+// GraphNodeCloseProvider is an interface that nodes that can be a close
+// provider must implement. The CloseProviderName returned is the name of
+// the provider they satisfy.
+type GraphNodeCloseProvider interface {
+ CloseProviderName() string
+}
+
+// GraphNodeProviderConsumer is an interface that nodes that require
+// a provider must implement. ProvidedBy must return the name of the provider
+// to use.
+type GraphNodeProviderConsumer interface {
+ ProvidedBy() []string
+}
+
+// ProviderTransformer is a GraphTransformer that maps resources to
+// providers within the graph. This will error if there are any resources
+// that don't map to proper resources.
+type ProviderTransformer struct{}
+
+func (t *ProviderTransformer) Transform(g *Graph) error {
+ // Go through the other nodes and match them to providers they need
+ var err error
+ m := providerVertexMap(g)
+ for _, v := range g.Vertices() {
+ if pv, ok := v.(GraphNodeProviderConsumer); ok {
+ for _, p := range pv.ProvidedBy() {
+ target := m[providerMapKey(p, pv)]
+ if target == nil {
+ println(fmt.Sprintf("%#v\n\n%#v", m, providerMapKey(p, pv)))
+ err = multierror.Append(err, fmt.Errorf(
+ "%s: provider %s couldn't be found",
+ dag.VertexName(v), p))
+ continue
+ }
+
+ g.Connect(dag.BasicEdge(v, target))
+ }
+ }
+ }
+
+ return err
+}
+
+// CloseProviderTransformer is a GraphTransformer that adds nodes to the
+// graph that will close open provider connections that aren't needed anymore.
+// A provider connection is not needed anymore once all depended resources
+// in the graph are evaluated.
+type CloseProviderTransformer struct{}
+
+func (t *CloseProviderTransformer) Transform(g *Graph) error {
+ pm := providerVertexMap(g)
+ cpm := closeProviderVertexMap(g)
+ var err error
+ for _, v := range g.Vertices() {
+ if pv, ok := v.(GraphNodeProviderConsumer); ok {
+ for _, p := range pv.ProvidedBy() {
+ key := p
+ source := cpm[key]
+
+ if source == nil {
+ // Create a new graphNodeCloseProvider and add it to the graph
+ source = &graphNodeCloseProvider{ProviderNameValue: p}
+ g.Add(source)
+
+ // Close node needs to depend on provider
+ provider, ok := pm[key]
+ if !ok {
+ err = multierror.Append(err, fmt.Errorf(
+ "%s: provider %s couldn't be found for closing",
+ dag.VertexName(v), p))
+ continue
+ }
+ g.Connect(dag.BasicEdge(source, provider))
+
+ // Make sure we also add the new graphNodeCloseProvider to the map
+ // so we don't create and add any duplicate graphNodeCloseProviders.
+ cpm[key] = source
+ }
+
+ // Close node depends on all nodes provided by the provider
+ g.Connect(dag.BasicEdge(source, v))
+ }
+ }
+ }
+
+ return err
+}
+
+// MissingProviderTransformer is a GraphTransformer that adds nodes
+// for missing providers into the graph. Specifically, it creates provider
+// configuration nodes for all the providers that we support. These are
+// pruned later during an optimization pass.
+type MissingProviderTransformer struct {
+ // Providers is the list of providers we support.
+ Providers []string
+
+ // AllowAny will not check that a provider is supported before adding
+ // it to the graph.
+ AllowAny bool
+
+ // Concrete, if set, overrides how the providers are made.
+ Concrete ConcreteProviderNodeFunc
+}
+
+func (t *MissingProviderTransformer) Transform(g *Graph) error {
+ // Initialize factory
+ if t.Concrete == nil {
+ t.Concrete = func(a *NodeAbstractProvider) dag.Vertex {
+ return a
+ }
+ }
+
+ // Create a set of our supported providers
+ supported := make(map[string]struct{}, len(t.Providers))
+ for _, v := range t.Providers {
+ supported[v] = struct{}{}
+ }
+
+ // Get the map of providers we already have in our graph
+ m := providerVertexMap(g)
+
+ // Go through all the provider consumers and make sure we add
+ // that provider if it is missing. We use a for loop here instead
+ // of "range" since we'll modify check as we go to add more to check.
+ check := g.Vertices()
+ for i := 0; i < len(check); i++ {
+ v := check[i]
+
+ pv, ok := v.(GraphNodeProviderConsumer)
+ if !ok {
+ continue
+ }
+
+ // If this node has a subpath, then we use that as a prefix
+ // into our map to check for an existing provider.
+ var path []string
+ if sp, ok := pv.(GraphNodeSubPath); ok {
+ raw := normalizeModulePath(sp.Path())
+ if len(raw) > len(rootModulePath) {
+ path = raw
+ }
+ }
+
+ for _, p := range pv.ProvidedBy() {
+ key := providerMapKey(p, pv)
+ if _, ok := m[key]; ok {
+ // This provider already exists as a configure node
+ continue
+ }
+
+ // If the provider has an alias in it, we just want the type
+ ptype := p
+ if idx := strings.IndexRune(p, '.'); idx != -1 {
+ ptype = p[:idx]
+ }
+
+ if !t.AllowAny {
+ if _, ok := supported[ptype]; !ok {
+ // If we don't support the provider type, skip it.
+ // Validation later will catch this as an error.
+ continue
+ }
+ }
+
+ // Add the missing provider node to the graph
+ v := t.Concrete(&NodeAbstractProvider{
+ NameValue: p,
+ PathValue: path,
+ }).(dag.Vertex)
+ if len(path) > 0 {
+ // We'll need the parent provider as well, so let's
+ // add a dummy node to check to make sure that we add
+ // that parent provider.
+ check = append(check, &graphNodeProviderConsumerDummy{
+ ProviderValue: p,
+ PathValue: path[:len(path)-1],
+ })
+ }
+
+ m[key] = g.Add(v)
+ }
+ }
+
+ return nil
+}
+
+// ParentProviderTransformer connects provider nodes to their parents.
+//
+// This works by finding nodes that are both GraphNodeProviders and
+// GraphNodeSubPath. It then connects the providers to their parent
+// path.
+type ParentProviderTransformer struct{}
+
+func (t *ParentProviderTransformer) Transform(g *Graph) error {
+ // Make a mapping of path to dag.Vertex, where path is: "path.name"
+ m := make(map[string]dag.Vertex)
+
+ // Also create a map that maps a provider to its parent
+ parentMap := make(map[dag.Vertex]string)
+ for _, raw := range g.Vertices() {
+ // If it is the flat version, then make it the non-flat version.
+ // We eventually want to get rid of the flat version entirely so
+ // this is a stop-gap while it still exists.
+ var v dag.Vertex = raw
+
+ // Only care about providers
+ pn, ok := v.(GraphNodeProvider)
+ if !ok || pn.ProviderName() == "" {
+ continue
+ }
+
+ // Also require a subpath, if there is no subpath then we
+ // just totally ignore it. The expectation of this transform is
+ // that it is used with a graph builder that is already flattened.
+ var path []string
+ if pn, ok := raw.(GraphNodeSubPath); ok {
+ path = pn.Path()
+ }
+ path = normalizeModulePath(path)
+
+ // Build the key with path.name i.e. "child.subchild.aws"
+ key := fmt.Sprintf("%s.%s", strings.Join(path, "."), pn.ProviderName())
+ m[key] = raw
+
+ // Determine the parent if we're non-root. This is length 1 since
+ // the 0 index should be "root" since we normalize above.
+ if len(path) > 1 {
+ path = path[:len(path)-1]
+ key := fmt.Sprintf("%s.%s", strings.Join(path, "."), pn.ProviderName())
+ parentMap[raw] = key
+ }
+ }
+
+ // Connect!
+ for v, key := range parentMap {
+ if parent, ok := m[key]; ok {
+ g.Connect(dag.BasicEdge(v, parent))
+ }
+ }
+
+ return nil
+}
+
+// PruneProviderTransformer is a GraphTransformer that prunes all the
+// providers that aren't needed from the graph. A provider is unneeded if
+// no resource or module is using that provider.
+type PruneProviderTransformer struct{}
+
+func (t *PruneProviderTransformer) Transform(g *Graph) error {
+ for _, v := range g.Vertices() {
+ // We only care about the providers
+ if pn, ok := v.(GraphNodeProvider); !ok || pn.ProviderName() == "" {
+ continue
+ }
+ // Does anything depend on this? If not, then prune it.
+ if s := g.UpEdges(v); s.Len() == 0 {
+ if nv, ok := v.(dag.NamedVertex); ok {
+ log.Printf("[DEBUG] Pruning provider with no dependencies: %s", nv.Name())
+ }
+ g.Remove(v)
+ }
+ }
+
+ return nil
+}
+
+// providerMapKey is a helper that gives us the key to use for the
+// maps returned by things such as providerVertexMap.
+func providerMapKey(k string, v dag.Vertex) string {
+ pathPrefix := ""
+ if sp, ok := v.(GraphNodeSubPath); ok {
+ raw := normalizeModulePath(sp.Path())
+ if len(raw) > len(rootModulePath) {
+ pathPrefix = modulePrefixStr(raw) + "."
+ }
+ }
+
+ return pathPrefix + k
+}
+
+func providerVertexMap(g *Graph) map[string]dag.Vertex {
+ m := make(map[string]dag.Vertex)
+ for _, v := range g.Vertices() {
+ if pv, ok := v.(GraphNodeProvider); ok {
+ key := providerMapKey(pv.ProviderName(), v)
+ m[key] = v
+ }
+ }
+
+ return m
+}
+
+func closeProviderVertexMap(g *Graph) map[string]dag.Vertex {
+ m := make(map[string]dag.Vertex)
+ for _, v := range g.Vertices() {
+ if pv, ok := v.(GraphNodeCloseProvider); ok {
+ m[pv.CloseProviderName()] = v
+ }
+ }
+
+ return m
+}
+
+type graphNodeCloseProvider struct {
+ ProviderNameValue string
+}
+
+func (n *graphNodeCloseProvider) Name() string {
+ return fmt.Sprintf("provider.%s (close)", n.ProviderNameValue)
+}
+
+// GraphNodeEvalable impl.
+func (n *graphNodeCloseProvider) EvalTree() EvalNode {
+ return CloseProviderEvalTree(n.ProviderNameValue)
+}
+
+// GraphNodeDependable impl.
+func (n *graphNodeCloseProvider) DependableName() []string {
+ return []string{n.Name()}
+}
+
+func (n *graphNodeCloseProvider) CloseProviderName() string {
+ return n.ProviderNameValue
+}
+
+// GraphNodeDotter impl.
+func (n *graphNodeCloseProvider) DotNode(name string, opts *dag.DotOpts) *dag.DotNode {
+ if !opts.Verbose {
+ return nil
+ }
+ return &dag.DotNode{
+ Name: name,
+ Attrs: map[string]string{
+ "label": n.Name(),
+ "shape": "diamond",
+ },
+ }
+}
+
+// RemovableIfNotTargeted
+func (n *graphNodeCloseProvider) RemoveIfNotTargeted() bool {
+ // We need to add this so that this node will be removed if
+ // it isn't targeted or a dependency of a target.
+ return true
+}
+
+// graphNodeProviderConsumerDummy is a struct that never enters the real
+// graph (though it could to no ill effect). It implements
+// GraphNodeProviderConsumer and GraphNodeSubpath as a way to force
+// certain transformations.
+type graphNodeProviderConsumerDummy struct {
+ ProviderValue string
+ PathValue []string
+}
+
+func (n *graphNodeProviderConsumerDummy) Path() []string {
+ return n.PathValue
+}
+
+func (n *graphNodeProviderConsumerDummy) ProvidedBy() []string {
+ return []string{n.ProviderValue}
+}