Skip to content

Commit cf46e1c

Browse files
committed
terraform: don't validate computed values in validate
This disables the computed value check for `count` during the validation pass. This enables partial support for #3888 or #1497: as long as the value is non-computed during the plan, complex values will work in counts. **Notably, this allows data source values to be present in counts!** The "count" value can be disabled during validation safely because we can treat it as if any field that uses `count.index` is computed for validation. We then validate a single instance (as if `count = 1`) just to make sure all required fields are set.
1 parent 0ba3fcd commit cf46e1c

File tree

8 files changed

+56
-36
lines changed

8 files changed

+56
-36
lines changed

config/config.go

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -505,23 +505,17 @@ func (c *Config) Validate() error {
505505
"%s: resource count can't reference count variable: %s",
506506
n,
507507
v.FullKey()))
508-
case *ModuleVariable:
509-
errs = append(errs, fmt.Errorf(
510-
"%s: resource count can't reference module variable: %s",
511-
n,
512-
v.FullKey()))
513-
case *ResourceVariable:
514-
errs = append(errs, fmt.Errorf(
515-
"%s: resource count can't reference resource variable: %s",
516-
n,
517-
v.FullKey()))
518508
case *SimpleVariable:
519509
errs = append(errs, fmt.Errorf(
520510
"%s: resource count can't reference variable: %s",
521511
n,
522512
v.FullKey()))
513+
514+
// Good
515+
case *ModuleVariable:
516+
case *ResourceVariable:
523517
case *UserVariable:
524-
// Good
518+
525519
default:
526520
panic(fmt.Sprintf("Unknown type in count var in %s: %T", n, v))
527521
}

config/config_test.go

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -254,34 +254,13 @@ func TestConfigValidate_countCountVar(t *testing.T) {
254254
}
255255
}
256256

257-
func TestConfigValidate_countModuleVar(t *testing.T) {
258-
c := testConfig(t, "validate-count-module-var")
259-
if err := c.Validate(); err == nil {
260-
t.Fatal("should not be valid")
261-
}
262-
}
263-
264257
func TestConfigValidate_countNotInt(t *testing.T) {
265258
c := testConfig(t, "validate-count-not-int")
266259
if err := c.Validate(); err == nil {
267260
t.Fatal("should not be valid")
268261
}
269262
}
270263

271-
func TestConfigValidate_countResourceVar(t *testing.T) {
272-
c := testConfig(t, "validate-count-resource-var")
273-
if err := c.Validate(); err == nil {
274-
t.Fatal("should not be valid")
275-
}
276-
}
277-
278-
func TestConfigValidate_countResourceVarMulti(t *testing.T) {
279-
c := testConfig(t, "validate-count-resource-var-multi")
280-
if err := c.Validate(); err == nil {
281-
t.Fatal("should not be valid")
282-
}
283-
}
284-
285264
func TestConfigValidate_countUserVar(t *testing.T) {
286265
c := testConfig(t, "validate-count-user-var")
287266
if err := c.Validate(); err != nil {

terraform/context_validate_test.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,28 @@ func TestContext2Validate_computedVar(t *testing.T) {
115115
}
116116
}
117117

118+
// Test that validate allows through computed counts. We do this and allow
119+
// them to fail during "plan" since we can't know if the computed values
120+
// can be realized during a plan.
121+
func TestContext2Validate_countComputed(t *testing.T) {
122+
p := testProvider("aws")
123+
m := testModule(t, "validate-count-computed")
124+
c := testContext2(t, &ContextOpts{
125+
Module: m,
126+
Providers: map[string]ResourceProviderFactory{
127+
"aws": testProviderFuncFixed(p),
128+
},
129+
})
130+
131+
w, e := c.Validate()
132+
if len(w) > 0 {
133+
t.Fatalf("bad: %#v", w)
134+
}
135+
if len(e) > 0 {
136+
t.Fatalf("bad: %s", e)
137+
}
138+
}
139+
118140
func TestContext2Validate_countNegative(t *testing.T) {
119141
p := testProvider("aws")
120142
m := testModule(t, "validate-count-negative")

terraform/eval_sequence.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ type EvalSequence struct {
77

88
func (n *EvalSequence) Eval(ctx EvalContext) (interface{}, error) {
99
for _, n := range n.Nodes {
10+
if n == nil {
11+
continue
12+
}
13+
1014
if _, err := EvalRaw(n, ctx); err != nil {
1115
return nil, err
1216
}

terraform/eval_validate.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ func (n *EvalValidateCount) Eval(ctx EvalContext) (interface{}, error) {
4242
c[n.Resource.RawCount.Key] = "1"
4343
count = 1
4444
}
45+
err = nil
4546

4647
if count < 0 {
4748
errs = append(errs, fmt.Errorf(

terraform/node_resource_abstract_count.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,14 @@ type NodeAbstractCountResource struct {
1414

1515
// GraphNodeEvalable
1616
func (n *NodeAbstractCountResource) EvalTree() EvalNode {
17+
// We only check if the count is computed if we're not validating.
18+
// If we're validating we allow computed counts since they just turn
19+
// into more computed values.
20+
var evalCountCheckComputed EvalNode
21+
if !n.Validate {
22+
evalCountCheckComputed = &EvalCountCheckComputed{Resource: n.Config}
23+
}
24+
1725
return &EvalSequence{
1826
Nodes: []EvalNode{
1927
// The EvalTree for a plannable resource primarily involves
@@ -24,7 +32,8 @@ func (n *NodeAbstractCountResource) EvalTree() EvalNode {
2432
// into the proper number of instances.
2533
&EvalInterpolate{Config: n.Config.RawCount},
2634

27-
&EvalCountCheckComputed{Resource: n.Config},
35+
// Check if the count is computed
36+
evalCountCheckComputed,
2837

2938
// If validation is enabled, perform the validation
3039
&EvalIf{

terraform/node_resource_validate.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,13 @@ func (n *NodeValidatableResource) DynamicExpand(ctx EvalContext) (*Graph, error)
2626
defer lock.RUnlock()
2727

2828
// Expand the resource count which must be available by now from EvalTree
29-
count, err := n.Config.Count()
30-
if err != nil {
31-
return nil, err
29+
count := 1
30+
if n.Config.RawCount.Value() != unknownValue() {
31+
var err error
32+
count, err = n.Config.Count()
33+
if err != nil {
34+
return nil, err
35+
}
3236
}
3337

3438
// The concrete resource factory we'll use
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
data "aws_data_source" "foo" {
2+
compute = "value"
3+
}
4+
5+
resource "aws_instance" "bar" {
6+
count = "${data.aws_data_source.foo.value}"
7+
}

0 commit comments

Comments
 (0)