terraform: orphans should properly depend on modules

This commit is contained in:
Mitchell Hashimoto 2014-09-26 10:03:10 -07:00
parent 4782e31e9d
commit 2ac6c127bc
2 changed files with 109 additions and 37 deletions

View File

@ -236,6 +236,9 @@ func Graph(opts *GraphOpts) (*depgraph.Graph, error) {
} }
} }
// Add the orphan dependencies
graphAddOrphanDeps(g, modState)
// Add the provider dependencies // Add the provider dependencies
graphAddResourceProviderDeps(g) graphAddResourceProviderDeps(g)
@ -771,6 +774,56 @@ func graphAddModuleOrphans(
return nil return nil
} }
// graphAddOrphanDeps adds the dependencies to the orphans based on their
// explicit Dependencies state.
func graphAddOrphanDeps(g *depgraph.Graph, mod *ModuleState) {
for _, n := range g.Nouns {
rn, ok := n.Meta.(*GraphNodeResource)
if !ok {
continue
}
if rn.Resource.Flags&FlagOrphan == 0 {
continue
}
// If we have no dependencies, then just continue
rs := mod.Resources[n.Name]
if len(rs.Dependencies) == 0 {
continue
}
for _, n2 := range g.Nouns {
// Don't ever depend on ourselves
if n2.Meta == n.Meta {
continue
}
var compareName string
switch rn2 := n2.Meta.(type) {
case *GraphNodeModule:
compareName = n2.Name
case *GraphNodeResource:
compareName = rn2.Resource.Id
}
if compareName == "" {
continue
}
for _, depName := range rs.Dependencies {
if compareName != depName {
continue
}
dep := &depgraph.Dependency{
Name: depName,
Source: n,
Target: n2,
}
n.Deps = append(n.Deps, dep)
}
}
}
}
// graphAddOrphans adds the orphans to the graph. // graphAddOrphans adds the orphans to the graph.
func graphAddOrphans(g *depgraph.Graph, c *config.Config, mod *ModuleState) { func graphAddOrphans(g *depgraph.Graph, c *config.Config, mod *ModuleState) {
meta := g.Meta.(*GraphMeta) meta := g.Meta.(*GraphMeta)
@ -802,43 +855,6 @@ func graphAddOrphans(g *depgraph.Graph, c *config.Config, mod *ModuleState) {
// Add the nouns to the graph // Add the nouns to the graph
g.Nouns = append(g.Nouns, nlist...) g.Nouns = append(g.Nouns, nlist...)
// Handle the orphan dependencies after adding them
// to the graph because there may be depedencies between the
// orphans that otherwise cannot be handled
for _, n := range nlist {
rn := n.Meta.(*GraphNodeResource)
// If we have no dependencies, then just continue
rs := mod.Resources[n.Name]
if len(rs.Dependencies) == 0 {
continue
}
for _, n2 := range g.Nouns {
rn2, ok := n2.Meta.(*GraphNodeResource)
if !ok {
continue
}
// Don't ever depend on ourselves
if rn2 == rn {
continue
}
for _, depName := range rs.Dependencies {
if rn2.Resource.Id != depName {
continue
}
dep := &depgraph.Dependency{
Name: depName,
Source: n,
Target: n2,
}
n.Deps = append(n.Deps, dep)
}
}
}
} }
// graphAddParentProviderConfigs goes through and adds/merges provider // graphAddParentProviderConfigs goes through and adds/merges provider

View File

@ -824,6 +824,40 @@ func TestGraph_orphan_dependencies(t *testing.T) {
} }
} }
func TestGraph_orphanDependenciesModules(t *testing.T) {
m := testModule(t, "graph-modules")
state := &State{
Modules: []*ModuleState{
&ModuleState{
Path: rootModulePath,
Resources: map[string]*ResourceState{
"aws_instance.foo": &ResourceState{
Type: "aws_instance",
Primary: &InstanceState{
ID: "foo",
},
Dependencies: []string{
"module.consul",
},
},
},
},
},
}
g, err := Graph(&GraphOpts{Module: m, State: state})
if err != nil {
t.Fatalf("err: %s", err)
}
actual := strings.TrimSpace(g.String())
expected := strings.TrimSpace(testTerraformGraphOrphanModuleDepsStr)
if actual != expected {
t.Fatalf("bad:\n\nactual:\n%s\n\nexpected:\n%s", actual, expected)
}
}
const testTerraformGraphStr = ` const testTerraformGraphStr = `
root: root root: root
aws_instance.web aws_instance.web
@ -1094,3 +1128,25 @@ root
root -> aws_load_balancer.old root -> aws_load_balancer.old
root -> aws_load_balancer.weblb root -> aws_load_balancer.weblb
` `
const testTerraformGraphOrphanModuleDepsStr = `
root: root
aws_instance.foo
aws_instance.foo -> module.consul
aws_instance.foo -> provider.aws
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
module.consul -> provider.aws
provider.aws
root
root -> aws_instance.foo
root -> aws_instance.web
root -> aws_security_group.firewall
root -> module.consul
`