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:
parent
2802d319d2
commit
d41b806789
|
@ -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) {
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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},
|
||||||
|
|
||||||
|
|
|
@ -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{},
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)}"
|
||||||
|
}
|
Loading…
Reference in New Issue