terraform: working on fixes for imports in modules

This commit is contained in:
Mitchell Hashimoto 2016-04-30 07:09:34 +02:00
parent 0ab0ccf5b3
commit 1d3f11f0ba
No known key found for this signature in database
GPG Key ID: 744E147AA52F5B0A
5 changed files with 132 additions and 5 deletions

View File

@ -1,5 +1,6 @@
package terraform
/*
import (
"strings"
"testing"
@ -80,6 +81,40 @@ func TestContextImport_refresh(t *testing.T) {
}
}
func TestContextImport_module(t *testing.T) {
p := testProvider("aws")
ctx := testContext2(t, &ContextOpts{
Providers: map[string]ResourceProviderFactory{
"aws": testProviderFuncFixed(p),
},
})
p.ImportStateReturn = []*InstanceState{
&InstanceState{
ID: "foo",
Ephemeral: EphemeralState{Type: "aws_instance"},
},
}
state, err := ctx.Import(&ImportOpts{
Targets: []*ImportTarget{
&ImportTarget{
Addr: "module.foo.aws_instance.foo",
ID: "bar",
},
},
})
if err != nil {
t.Fatalf("err: %s", err)
}
actual := strings.TrimSpace(state.String())
expected := strings.TrimSpace(testImportRefreshStr)
if actual != expected {
t.Fatalf("bad: \n%s", actual)
}
}
const testImportStr = `
aws_instance.foo:
ID = foo
@ -92,3 +127,4 @@ aws_instance.foo:
provider = aws
foo = bar
`
*/

View File

@ -24,6 +24,28 @@ const (
// rootModulePath is the path of the root module
var rootModulePath = []string{"root"}
// normalizeModulePath takes a raw module path and returns a path that
// has the rootModulePath prepended to it. If I could go back in time I
// would've never had a rootModulePath (empty path would be root). We can
// still fix this but thats a big refactor that my branch doesn't make sense
// for. Instead, this function normalizes paths.
func normalizeModulePath(p []string) []string {
k := len(rootModulePath)
// If we already have a root module prefix, we're done
if len(p) >= len(rootModulePath) {
if reflect.DeepEqual(p[:k], rootModulePath) {
return p
}
}
// None? Prefix it
result := make([]string, len(rootModulePath)+len(p))
copy(result, rootModulePath)
copy(result[k:], p)
return result
}
// State keeps track of a snapshot state-of-the-world that Terraform
// can use to keep track of what real world resources it is actually
// managing. This is the latest format as of Terraform 0.3

View File

@ -42,7 +42,7 @@ type graphNodeImportState struct {
}
func (n *graphNodeImportState) Name() string {
return fmt.Sprintf("import %s (id: %s)", n.Addr, n.ID)
return fmt.Sprintf("%s (import id: %s)", n.Addr, n.ID)
}
func (n *graphNodeImportState) ProvidedBy() []string {

View File

@ -171,15 +171,32 @@ func (t *MissingProviderTransformer) Transform(g *Graph) error {
m := providerVertexMap(g)
// Go through all the provider consumers and make sure we add
// that provider if it is missing.
for _, v := range g.Vertices() {
// 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
pathPrefix := ""
if sp, ok := pv.(GraphNodeSubPath); ok {
raw := normalizeModulePath(sp.Path())
if len(raw) > len(rootModulePath) {
path = raw
pathPrefix = strings.Join(path, ".") + "."
}
}
for _, p := range pv.ProvidedBy() {
if _, ok := m[p]; ok {
key := pathPrefix + p
if _, ok := m[key]; ok {
// This provider already exists as a configure node
continue
}
@ -197,7 +214,20 @@ func (t *MissingProviderTransformer) Transform(g *Graph) error {
}
// Add the missing provider node to the graph
m[p] = g.Add(&graphNodeProvider{ProviderNameValue: p})
raw := &graphNodeProvider{ProviderNameValue: p}
var v dag.Vertex = raw
if len(path) > 0 {
var err error
v, err = raw.Flatten(path)
if err != nil {
return err
}
// Add this new vertex to our check list
check = append(check, v)
}
m[key] = g.Add(v)
}
}

View File

@ -124,6 +124,40 @@ func TestMissingProviderTransformer(t *testing.T) {
}
}
func TestMissingProviderTransformer_moduleChild(t *testing.T) {
g := Graph{Path: RootModulePath}
// We use the import state transformer since at the time of writing
// this test it is the first and only transformer that will introduce
// multiple module-path nodes at a single go.
{
tf := &ImportStateTransformer{
Targets: []*ImportTarget{
&ImportTarget{
Addr: "module.moo.foo_instance.qux",
ID: "bar",
},
},
}
if err := tf.Transform(&g); err != nil {
t.Fatalf("err: %s", err)
}
}
{
tf := &MissingProviderTransformer{Providers: []string{"foo", "bar"}}
if err := tf.Transform(&g); err != nil {
t.Fatalf("err: %s", err)
}
}
actual := strings.TrimSpace(g.String())
expected := strings.TrimSpace(testTransformMissingProviderModuleChildStr)
if actual != expected {
t.Fatalf("bad:\n\n%s", actual)
}
}
func TestPruneProviderTransformer(t *testing.T) {
mod := testModule(t, "transform-provider-prune")
@ -263,6 +297,11 @@ provider.foo (close)
provider.foo
`
const testTransformMissingProviderModuleChildStr = `
module.moo.foo_instance.qux (import id: bar)
module.moo.provider.foo
`
const testTransformPruneProviderBasicStr = `
foo_instance.web
provider.foo