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:
// dependency chain foo -> bar -> baz. This was failing because
// CountBoundaryTransformer is being run during apply instead of plan, which
// meant that it wasn't firing after data sources were potentially changing
// state and causing diff/interpolation issues.
// TestDataSource_dataSourceCountGrandChild tests that a grandchild data source
// that is based off of count works, ie: dependency chain foo -> bar -> baz.
// This was failing because CountBoundaryTransformer is being run during apply
// instead of plan, which meant that it wasn't firing after data sources were
// potentially changing state and causing diff/interpolation issues.
//
// This happens after the initial apply, after state is saved.
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)
}
}
// 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
&ReferenceTransformer{},
// Add the node to fix the state count boundaries
&CountBoundaryTransformer{},
// Target
&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.
&ReferenceTransformer{},
// Add the node to fix the state count boundaries
&CountBoundaryTransformer{},
// Target
&TargetsTransformer{Targets: b.Targets},
@ -120,9 +123,6 @@ func (b *PlanGraphBuilder) Steps() []GraphTransformer {
&CloseProviderTransformer{},
&CloseProvisionerTransformer{},
// Add the node to fix the state count boundaries
&CountBoundaryTransformer{},
// Single root
&RootTransformer{},
}

View File

@ -29,7 +29,7 @@ func TestPlanGraphBuilder(t *testing.T) {
actual := strings.TrimSpace(g.String())
expected := strings.TrimSpace(testPlanGraphBuilderStr)
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
aws_security_group.firewall
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
provider.openstack
provider.aws
@ -75,6 +83,7 @@ provider.openstack (close)
openstack_floating_ip.random
provider.openstack
root
meta.count-boundary (count boundary fixup)
provider.aws (close)
provider.openstack (close)
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)}"
}