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.
|
// graph. This node is just a placemarker and has no associated functionality.
|
||||||
const GraphRootNode = "root"
|
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
|
// GraphNodeResource is a node type in the graph that represents a resource
|
||||||
// that will be created or managed. Unlike the GraphNodeResourceMeta node,
|
// that will be created or managed. Unlike the GraphNodeResourceMeta node,
|
||||||
// this represents a _single_, _resource_ to be managed, not a set of resources
|
// 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).
|
// and not "orphans" (that are in the state, but not in the config).
|
||||||
graphAddConfigResources(g, opts.Config, opts.State)
|
graphAddConfigResources(g, opts.Config, opts.State)
|
||||||
|
|
||||||
|
// Add the modules that are in the configuration.
|
||||||
|
graphAddConfigModules(g, opts)
|
||||||
|
|
||||||
// Add explicit dependsOn dependencies to the graph
|
// Add explicit dependsOn dependencies to the graph
|
||||||
graphAddExplicitDeps(g)
|
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.
|
// configGraph turns a configuration structure into a dependency graph.
|
||||||
func graphAddConfigResources(
|
func graphAddConfigResources(
|
||||||
g *depgraph.Graph, c *config.Config, s *State) {
|
g *depgraph.Graph, c *config.Config, s *State) {
|
||||||
|
@ -752,18 +788,21 @@ func graphAddRoot(g *depgraph.Graph) {
|
||||||
// based on variable values.
|
// based on variable values.
|
||||||
func graphAddVariableDeps(g *depgraph.Graph) {
|
func graphAddVariableDeps(g *depgraph.Graph) {
|
||||||
for _, n := range g.Nouns {
|
for _, n := range g.Nouns {
|
||||||
var vars map[string]config.InterpolatedVariable
|
|
||||||
switch m := n.Meta.(type) {
|
switch m := n.Meta.(type) {
|
||||||
|
case *GraphNodeModule:
|
||||||
|
vars := m.Config.RawConfig.Variables
|
||||||
|
nounAddVariableDeps(g, n, vars, false)
|
||||||
|
|
||||||
case *GraphNodeResource:
|
case *GraphNodeResource:
|
||||||
if m.Config != nil {
|
if m.Config != nil {
|
||||||
// Handle the resource variables
|
// Handle the resource variables
|
||||||
vars = m.Config.RawConfig.Variables
|
vars := m.Config.RawConfig.Variables
|
||||||
nounAddVariableDeps(g, n, vars, false)
|
nounAddVariableDeps(g, n, vars, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle the variables of the resource provisioners
|
// Handle the variables of the resource provisioners
|
||||||
for _, p := range m.Resource.Provisioners {
|
for _, p := range m.Resource.Provisioners {
|
||||||
vars = p.RawConfig.Variables
|
vars := p.RawConfig.Variables
|
||||||
nounAddVariableDeps(g, n, vars, true)
|
nounAddVariableDeps(g, n, vars, true)
|
||||||
|
|
||||||
vars = p.ConnInfo.Variables
|
vars = p.ConnInfo.Variables
|
||||||
|
@ -771,10 +810,11 @@ func graphAddVariableDeps(g *depgraph.Graph) {
|
||||||
}
|
}
|
||||||
|
|
||||||
case *GraphNodeResourceProvider:
|
case *GraphNodeResourceProvider:
|
||||||
vars = m.Config.RawConfig.Variables
|
vars := m.Config.RawConfig.Variables
|
||||||
nounAddVariableDeps(g, n, vars, false)
|
nounAddVariableDeps(g, n, vars, false)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
// Other node types don't have dependencies or we don't support it
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -854,15 +894,20 @@ func nounAddVariableDeps(
|
||||||
n *depgraph.Noun,
|
n *depgraph.Noun,
|
||||||
vars map[string]config.InterpolatedVariable,
|
vars map[string]config.InterpolatedVariable,
|
||||||
removeSelf bool) {
|
removeSelf bool) {
|
||||||
for _, v := range vars {
|
for _, rawV := range vars {
|
||||||
// Only resource variables impose dependencies
|
var name string
|
||||||
rv, ok := v.(*config.ResourceVariable)
|
var target *depgraph.Noun
|
||||||
if !ok {
|
|
||||||
continue
|
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 {
|
if target == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -875,7 +920,7 @@ func nounAddVariableDeps(
|
||||||
|
|
||||||
// Build the dependency
|
// Build the dependency
|
||||||
dep := &depgraph.Dependency{
|
dep := &depgraph.Dependency{
|
||||||
Name: rv.ResourceId(),
|
Name: name,
|
||||||
Source: n,
|
Source: n,
|
||||||
Target: target,
|
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) {
|
func TestGraph_state(t *testing.T) {
|
||||||
config := testConfig(t, "graph-basic")
|
config := testConfig(t, "graph-basic")
|
||||||
state := &State{
|
state := &State{
|
||||||
|
@ -767,6 +782,23 @@ root
|
||||||
root -> aws_load_balancer.weblb
|
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 = `
|
const testTerraformGraphStateStr = `
|
||||||
root: root
|
root: root
|
||||||
aws_instance.old
|
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