terraform: new provider graph node for flattened world

This commit is contained in:
Mitchell Hashimoto 2016-09-14 23:58:16 -07:00
parent b2ef4e9ac0
commit 79a742c1ae
No known key found for this signature in database
GPG Key ID: 744E147AA52F5B0A
4 changed files with 165 additions and 13 deletions

View File

@ -38,6 +38,14 @@ func (b *ApplyGraphBuilder) Build(path []string) (*Graph, error) {
// See GraphBuilder
func (b *ApplyGraphBuilder) Steps() []GraphTransformer {
// Custom factory for creating providers.
providerFactory := func(name string, path []string) GraphNodeProvider {
return &NodeApplyableProvider{
NameValue: name,
PathValue: path,
}
}
steps := []GraphTransformer{
// Creates all the nodes represented in the diff.
&DiffTransformer{
@ -47,10 +55,13 @@ func (b *ApplyGraphBuilder) Steps() []GraphTransformer {
},
// Create all the providers
&MissingProviderTransformer{Providers: b.Providers},
&MissingProviderTransformer{Providers: b.Providers, Factory: providerFactory},
&ProviderTransformer{},
&ParentProviderTransformer{},
// Attach the configurations
&AttachConfigTransformer{Module: b.Module},
// Single root
&RootTransformer{},
}

View File

@ -0,0 +1,55 @@
package terraform
import (
"fmt"
"github.com/hashicorp/terraform/config"
)
// NodeApplyableProvider represents a provider during an apply.
//
// NOTE: There is a lot of logic here that will be shared with non-Apply.
// The plan is to abstract that eventually into an embedded abstract struct.
type NodeApplyableProvider struct {
NameValue string
PathValue []string
Config *config.ProviderConfig
}
func (n *NodeApplyableProvider) Name() string {
result := fmt.Sprintf("provider.%s", n.NameValue)
if len(n.PathValue) > 1 {
result = fmt.Sprintf("%s.%s", modulePrefixStr(n.PathValue), result)
}
return result
}
// GraphNodeSubPath
func (n *NodeApplyableProvider) Path() []string {
return n.PathValue
}
// GraphNodeProvider
func (n *NodeApplyableProvider) ProviderName() string {
return n.NameValue
}
// GraphNodeProvider
func (n *NodeApplyableProvider) ProviderConfig() *config.RawConfig {
if n.Config == nil {
return nil
}
return n.Config.RawConfig
}
// GraphNodeAttachProvider
func (n *NodeApplyableProvider) AttachProvider(c *config.ProviderConfig) {
n.Config = c
}
// GraphNodeEvalable
func (n *NodeApplyableProvider) EvalTree() EvalNode {
return ProviderEvalTree(n.NameValue, nil)
}

View File

@ -0,0 +1,74 @@
package terraform
import (
"log"
"github.com/hashicorp/terraform/config"
"github.com/hashicorp/terraform/config/module"
)
// GraphNodeAttachProvider is an interface that must be implemented by nodes
// that want provider configurations attached.
type GraphNodeAttachProvider interface {
// Must be implemented to determine the path for the configuration
GraphNodeSubPath
// ProviderName with no module prefix. Example: "aws".
ProviderName() string
// Sets the configuration
AttachProvider(*config.ProviderConfig)
}
// AttachConfigTransformer goes through the graph and attaches configuration
// structures to nodes that implement the interfaces above.
//
// The attached configuration structures are directly from the configuration.
// If they're going to be modified, a copy should be made.
type AttachConfigTransformer struct {
Module *module.Tree // Module is the root module for the config
}
func (t *AttachConfigTransformer) Transform(g *Graph) error {
if err := t.attachProviders(g); err != nil {
return err
}
return nil
}
func (t *AttachConfigTransformer) attachProviders(g *Graph) error {
// Go through and find GraphNodeAttachProvider
for _, v := range g.Vertices() {
// Only care about GraphNodeAttachProvider implementations
apn, ok := v.(GraphNodeAttachProvider)
if !ok {
continue
}
// TODO: aliases?
// Determine what we're looking for
path := normalizeModulePath(apn.Path())
path = path[1:]
name := apn.ProviderName()
log.Printf("[TRACE] Attach provider request: %#v %s", path, name)
// Get the configuration.
tree := t.Module.Child(path)
if tree == nil {
continue
}
// Go through the provider configs to find the matching config
for _, p := range tree.Config().ProviderConfigs {
if p.Name == name {
log.Printf("[TRACE] Attaching provider config: %#v", p)
apn.AttachProvider(p)
break
}
}
}
return nil
}

View File

@ -163,9 +163,19 @@ func (t *CloseProviderTransformer) Transform(g *Graph) error {
type MissingProviderTransformer struct {
// Providers is the list of providers we support.
Providers []string
// Factory, if set, overrides how the providers are made.
Factory func(name string, path []string) GraphNodeProvider
}
func (t *MissingProviderTransformer) Transform(g *Graph) error {
// Initialize factory
if t.Factory == nil {
t.Factory = func(name string, path []string) GraphNodeProvider {
return &graphNodeProvider{ProviderNameValue: name}
}
}
// Create a set of our supported providers
supported := make(map[string]struct{}, len(t.Providers))
for _, v := range t.Providers {
@ -217,17 +227,14 @@ func (t *MissingProviderTransformer) Transform(g *Graph) error {
}
// Add the missing provider node to the graph
raw := &graphNodeProvider{
ProviderNameValue: p,
PathValue: path,
}
var v dag.Vertex = raw
v := t.Factory(p, path).(dag.Vertex)
if len(path) > 0 {
var err error
v, err = raw.Flatten(path)
if err != nil {
return err
if fn, ok := v.(GraphNodeFlattenable); ok {
var err error
v, err = fn.Flatten(path)
if err != nil {
return err
}
}
// We'll need the parent provider as well, so let's
@ -347,7 +354,12 @@ 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 {
m[pv.ProviderName()] = v
key := pv.ProviderName()
if _, ok := v.(*NodeApplyableProvider); ok {
key = providerMapKey(pv.ProviderName(), v)
}
m[key] = v
}
}
@ -512,7 +524,6 @@ func (n *graphNodeCloseProvider) DotNode(name string, opts *GraphDotOpts) *dot.N
type graphNodeProvider struct {
ProviderNameValue string
PathValue []string
}
func (n *graphNodeProvider) Name() string {
@ -529,6 +540,7 @@ func (n *graphNodeProvider) DependableName() []string {
return []string{n.Name()}
}
// GraphNodeProvider
func (n *graphNodeProvider) ProviderName() string {
return n.ProviderNameValue
}