core: Restore CountBoundaryTransformer to apply, add/adjust tests

Moving the transformer wholesale looks like it broke some tests, with
some actually doing legit work in normalizing singular resources from a
foo.0 notation to just foo.

Adjusted the TestPlanGraphBuilder to account for the extra
meta.count-boundary nodes in the graph output now, as well as added
another context test that tests this case. It appears the issue happens
during validate, as this is where the state can be altered to a broken
state if things are not properly transformed in the plan graph.
This commit is contained in:
Chris Marchesi 2017-04-19 22:23:52 -07:00
parent 2802d319d2
commit d41b806789
6 changed files with 174 additions and 9 deletions

View File

@ -100,11 +100,11 @@ resource "test_resource" "foo" {
}) })
} }
// Test that a grandchild data source that is based off of count works, ie: // TestDataSource_dataSourceCountGrandChild tests that a grandchild data source
// dependency chain foo -> bar -> baz. This was failing because // that is based off of count works, ie: dependency chain foo -> bar -> baz.
// CountBoundaryTransformer is being run during apply instead of plan, which // This was failing because CountBoundaryTransformer is being run during apply
// meant that it wasn't firing after data sources were potentially changing // instead of plan, which meant that it wasn't firing after data sources were
// state and causing diff/interpolation issues. // potentially changing state and causing diff/interpolation issues.
// //
// This happens after the initial apply, after state is saved. // This happens after the initial apply, after state is saved.
func TestDataSource_dataSourceCountGrandChild(t *testing.T) { func TestDataSource_dataSourceCountGrandChild(t *testing.T) {

View File

@ -3146,3 +3146,145 @@ func TestContext2Plan_ignoreChangesWithFlatmaps(t *testing.T) {
t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected) t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected)
} }
} }
// TestContext2Plan_resourceNestedCount ensures resource sets that depend on
// the count of another resource set (ie: count of a data source that depends
// on another data source's instance count - data.x.foo.*.id) get properly
// normalized to the indexes they should be. This case comes up when there is
// an existing state (after an initial apply).
func TestContext2Plan_resourceNestedCount(t *testing.T) {
m := testModule(t, "nested-resource-count-plan")
p := testProvider("aws")
p.DiffFn = testDiffFn
p.RefreshFn = func(i *InstanceInfo, is *InstanceState) (*InstanceState, error) {
return is, nil
}
s := &State{
Modules: []*ModuleState{
&ModuleState{
Path: rootModulePath,
Resources: map[string]*ResourceState{
"aws_instance.foo.0": &ResourceState{
Type: "aws_instance",
Primary: &InstanceState{
ID: "foo0",
Attributes: map[string]string{
"id": "foo0",
},
},
},
"aws_instance.foo.1": &ResourceState{
Type: "aws_instance",
Primary: &InstanceState{
ID: "foo1",
Attributes: map[string]string{
"id": "foo1",
},
},
},
"aws_instance.bar.0": &ResourceState{
Type: "aws_instance",
Dependencies: []string{"aws_instance.foo.*"},
Primary: &InstanceState{
ID: "bar0",
Attributes: map[string]string{
"id": "bar0",
},
},
},
"aws_instance.bar.1": &ResourceState{
Type: "aws_instance",
Dependencies: []string{"aws_instance.foo.*"},
Primary: &InstanceState{
ID: "bar1",
Attributes: map[string]string{
"id": "bar1",
},
},
},
"aws_instance.baz.0": &ResourceState{
Type: "aws_instance",
Dependencies: []string{"aws_instance.bar.*"},
Primary: &InstanceState{
ID: "baz0",
Attributes: map[string]string{
"id": "baz0",
},
},
},
"aws_instance.baz.1": &ResourceState{
Type: "aws_instance",
Dependencies: []string{"aws_instance.bar.*"},
Primary: &InstanceState{
ID: "baz1",
Attributes: map[string]string{
"id": "baz1",
},
},
},
},
},
},
}
ctx := testContext2(t, &ContextOpts{
Module: m,
Providers: map[string]ResourceProviderFactory{
"aws": testProviderFuncFixed(p),
},
State: s,
})
_, e := ctx.Validate()
if len(e) > 0 {
for _, err := range e {
t.Errorf("bad: %s", err)
}
}
_, err := ctx.Refresh()
if err != nil {
t.Fatalf("refresh err: %s", err)
}
plan, err := ctx.Plan()
if err != nil {
t.Fatalf("plan err: %s", err)
}
actual := strings.TrimSpace(plan.String())
expected := strings.TrimSpace(`
DIFF:
STATE:
aws_instance.bar.0:
ID = bar0
Dependencies:
aws_instance.foo.*
aws_instance.bar.1:
ID = bar1
Dependencies:
aws_instance.foo.*
aws_instance.baz.0:
ID = baz0
Dependencies:
aws_instance.bar.*
aws_instance.baz.1:
ID = baz1
Dependencies:
aws_instance.bar.*
aws_instance.foo.0:
ID = foo0
aws_instance.foo.1:
ID = foo1
`)
if actual != expected {
t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected)
}
}

View File

@ -117,6 +117,9 @@ func (b *ApplyGraphBuilder) Steps() []GraphTransformer {
// Connect references so ordering is correct // Connect references so ordering is correct
&ReferenceTransformer{}, &ReferenceTransformer{},
// Add the node to fix the state count boundaries
&CountBoundaryTransformer{},
// Target // Target
&TargetsTransformer{Targets: b.Targets}, &TargetsTransformer{Targets: b.Targets},

View File

@ -113,6 +113,9 @@ func (b *PlanGraphBuilder) Steps() []GraphTransformer {
// have to connect again later for providers and so on. // have to connect again later for providers and so on.
&ReferenceTransformer{}, &ReferenceTransformer{},
// Add the node to fix the state count boundaries
&CountBoundaryTransformer{},
// Target // Target
&TargetsTransformer{Targets: b.Targets}, &TargetsTransformer{Targets: b.Targets},
@ -120,9 +123,6 @@ func (b *PlanGraphBuilder) Steps() []GraphTransformer {
&CloseProviderTransformer{}, &CloseProviderTransformer{},
&CloseProvisionerTransformer{}, &CloseProvisionerTransformer{},
// Add the node to fix the state count boundaries
&CountBoundaryTransformer{},
// Single root // Single root
&RootTransformer{}, &RootTransformer{},
} }

View File

@ -29,7 +29,7 @@ func TestPlanGraphBuilder(t *testing.T) {
actual := strings.TrimSpace(g.String()) actual := strings.TrimSpace(g.String())
expected := strings.TrimSpace(testPlanGraphBuilderStr) expected := strings.TrimSpace(testPlanGraphBuilderStr)
if actual != expected { if actual != expected {
t.Fatalf("bad: %s", actual) t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
} }
} }
@ -61,6 +61,14 @@ aws_load_balancer.weblb
provider.aws provider.aws
aws_security_group.firewall aws_security_group.firewall
provider.aws provider.aws
meta.count-boundary (count boundary fixup)
aws_instance.web
aws_load_balancer.weblb
aws_security_group.firewall
openstack_floating_ip.random
provider.aws
provider.openstack
var.foo
openstack_floating_ip.random openstack_floating_ip.random
provider.openstack provider.openstack
provider.aws provider.aws
@ -75,6 +83,7 @@ provider.openstack (close)
openstack_floating_ip.random openstack_floating_ip.random
provider.openstack provider.openstack
root root
meta.count-boundary (count boundary fixup)
provider.aws (close) provider.aws (close)
provider.openstack (close) provider.openstack (close)
var.foo var.foo

View File

@ -0,0 +1,11 @@
resource "aws_instance" "foo" {
count = 2
}
resource "aws_instance" "bar" {
count = "${length(aws_instance.foo.*.id)}"
}
resource "aws_instance" "baz" {
count = "${length(aws_instance.bar.*.id)}"
}