terraform: modules are put into the graph
This commit is contained in:
parent
6f7c3caab3
commit
1d106d3fa4
|
@ -50,6 +50,12 @@ type GraphOpts struct {
|
|||
// graph. This node is just a placemarker and has no associated functionality.
|
||||
const GraphRootNode = "root"
|
||||
|
||||
// GraphNodeModule is a node type in the graph that represents a module
|
||||
// that will be created/managed.
|
||||
type GraphNodeModule struct {
|
||||
Config *config.Module
|
||||
}
|
||||
|
||||
// GraphNodeResource is a node type in the graph that represents a resource
|
||||
// that will be created or managed. Unlike the GraphNodeResourceMeta node,
|
||||
// this represents a _single_, _resource_ to be managed, not a set of resources
|
||||
|
@ -108,6 +114,9 @@ func Graph(opts *GraphOpts) (*depgraph.Graph, error) {
|
|||
// and not "orphans" (that are in the state, but not in the config).
|
||||
graphAddConfigResources(g, opts.Config, opts.State)
|
||||
|
||||
// Add the modules that are in the configuration.
|
||||
graphAddConfigModules(g, opts)
|
||||
|
||||
// Add explicit dependsOn dependencies to the graph
|
||||
graphAddExplicitDeps(g)
|
||||
|
||||
|
@ -220,6 +229,33 @@ func graphInitState(s *State, g *depgraph.Graph) {
|
|||
}
|
||||
}
|
||||
|
||||
// graphAddConfigModules adds the modules from a configuration structure
|
||||
// into the graph, expanding each to their own sub-graph.
|
||||
func graphAddConfigModules(g *depgraph.Graph, opts *GraphOpts) {
|
||||
c := opts.Config
|
||||
|
||||
// Just short-circuit the whole thing if we don't have modules
|
||||
if len(c.Modules) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// Build the list of nouns to add to the graph
|
||||
nounsList := make([]*depgraph.Noun, 0, len(c.Modules))
|
||||
for _, m := range c.Modules {
|
||||
name := fmt.Sprintf("module.%s", m.Name)
|
||||
n := &depgraph.Noun{
|
||||
Name: name,
|
||||
Meta: &GraphNodeModule{
|
||||
Config: m,
|
||||
},
|
||||
}
|
||||
|
||||
nounsList = append(nounsList, n)
|
||||
}
|
||||
|
||||
g.Nouns = append(g.Nouns, nounsList...)
|
||||
}
|
||||
|
||||
// configGraph turns a configuration structure into a dependency graph.
|
||||
func graphAddConfigResources(
|
||||
g *depgraph.Graph, c *config.Config, s *State) {
|
||||
|
@ -752,18 +788,21 @@ func graphAddRoot(g *depgraph.Graph) {
|
|||
// based on variable values.
|
||||
func graphAddVariableDeps(g *depgraph.Graph) {
|
||||
for _, n := range g.Nouns {
|
||||
var vars map[string]config.InterpolatedVariable
|
||||
switch m := n.Meta.(type) {
|
||||
case *GraphNodeModule:
|
||||
vars := m.Config.RawConfig.Variables
|
||||
nounAddVariableDeps(g, n, vars, false)
|
||||
|
||||
case *GraphNodeResource:
|
||||
if m.Config != nil {
|
||||
// Handle the resource variables
|
||||
vars = m.Config.RawConfig.Variables
|
||||
vars := m.Config.RawConfig.Variables
|
||||
nounAddVariableDeps(g, n, vars, false)
|
||||
}
|
||||
|
||||
// Handle the variables of the resource provisioners
|
||||
for _, p := range m.Resource.Provisioners {
|
||||
vars = p.RawConfig.Variables
|
||||
vars := p.RawConfig.Variables
|
||||
nounAddVariableDeps(g, n, vars, true)
|
||||
|
||||
vars = p.ConnInfo.Variables
|
||||
|
@ -771,10 +810,11 @@ func graphAddVariableDeps(g *depgraph.Graph) {
|
|||
}
|
||||
|
||||
case *GraphNodeResourceProvider:
|
||||
vars = m.Config.RawConfig.Variables
|
||||
vars := m.Config.RawConfig.Variables
|
||||
nounAddVariableDeps(g, n, vars, false)
|
||||
|
||||
default:
|
||||
// Other node types don't have dependencies or we don't support it
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
@ -854,15 +894,20 @@ func nounAddVariableDeps(
|
|||
n *depgraph.Noun,
|
||||
vars map[string]config.InterpolatedVariable,
|
||||
removeSelf bool) {
|
||||
for _, v := range vars {
|
||||
// Only resource variables impose dependencies
|
||||
rv, ok := v.(*config.ResourceVariable)
|
||||
if !ok {
|
||||
continue
|
||||
for _, rawV := range vars {
|
||||
var name string
|
||||
var target *depgraph.Noun
|
||||
|
||||
switch v := rawV.(type) {
|
||||
case *config.ModuleVariable:
|
||||
name = fmt.Sprintf("module.%s", v.Name)
|
||||
target = g.Noun(name)
|
||||
case *config.ResourceVariable:
|
||||
name = v.ResourceId()
|
||||
target = g.Noun(v.ResourceId())
|
||||
default:
|
||||
}
|
||||
|
||||
// Find the target
|
||||
target := g.Noun(rv.ResourceId())
|
||||
if target == nil {
|
||||
continue
|
||||
}
|
||||
|
@ -875,7 +920,7 @@ func nounAddVariableDeps(
|
|||
|
||||
// Build the dependency
|
||||
dep := &depgraph.Dependency{
|
||||
Name: rv.ResourceId(),
|
||||
Name: name,
|
||||
Source: n,
|
||||
Target: target,
|
||||
}
|
||||
|
|
|
@ -81,6 +81,21 @@ func TestGraph_dependsOnCount(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestGraph_modules(t *testing.T) {
|
||||
config := testConfig(t, "graph-modules")
|
||||
|
||||
g, err := Graph(&GraphOpts{Config: config})
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
actual := strings.TrimSpace(g.String())
|
||||
expected := strings.TrimSpace(testTerraformGraphModulesStr)
|
||||
if actual != expected {
|
||||
t.Fatalf("bad:\n\n%s", actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGraph_state(t *testing.T) {
|
||||
config := testConfig(t, "graph-basic")
|
||||
state := &State{
|
||||
|
@ -767,6 +782,23 @@ root
|
|||
root -> aws_load_balancer.weblb
|
||||
`
|
||||
|
||||
const testTerraformGraphModulesStr = `
|
||||
root: root
|
||||
aws_instance.web
|
||||
aws_instance.web -> aws_security_group.firewall
|
||||
aws_instance.web -> module.consul
|
||||
aws_instance.web -> provider.aws
|
||||
aws_security_group.firewall
|
||||
aws_security_group.firewall -> provider.aws
|
||||
module.consul
|
||||
module.consul -> aws_security_group.firewall
|
||||
provider.aws
|
||||
root
|
||||
root -> aws_instance.web
|
||||
root -> aws_security_group.firewall
|
||||
root -> module.consul
|
||||
`
|
||||
|
||||
const testTerraformGraphStateStr = `
|
||||
root: root
|
||||
aws_instance.old
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
module "consul" {
|
||||
foo = "${aws_security_group.firewall.foo}"
|
||||
}
|
||||
|
||||
provider "aws" {}
|
||||
|
||||
resource "aws_security_group" "firewall" {}
|
||||
|
||||
resource "aws_instance" "web" {
|
||||
security_groups = [
|
||||
"foo",
|
||||
"${aws_security_group.firewall.foo}",
|
||||
"${module.consul.security_group}"
|
||||
]
|
||||
}
|
Loading…
Reference in New Issue