Merge pull request #27410 from hashicorp/pselle/count-validate
De-duplicate count validate code
This commit is contained in:
commit
45a5a3cc73
|
@ -11,8 +11,6 @@ import (
|
||||||
"github.com/hashicorp/terraform/provisioners"
|
"github.com/hashicorp/terraform/provisioners"
|
||||||
"github.com/hashicorp/terraform/tfdiags"
|
"github.com/hashicorp/terraform/tfdiags"
|
||||||
"github.com/zclconf/go-cty/cty"
|
"github.com/zclconf/go-cty/cty"
|
||||||
"github.com/zclconf/go-cty/cty/convert"
|
|
||||||
"github.com/zclconf/go-cty/cty/gocty"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// NodeValidatableResource represents a resource that is used for validation
|
// NodeValidatableResource represents a resource that is used for validation
|
||||||
|
@ -410,69 +408,16 @@ func (n *NodeValidatableResource) validateResource(ctx EvalContext) tfdiags.Diag
|
||||||
return diags
|
return diags
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateCount(ctx EvalContext, expr hcl.Expression) tfdiags.Diagnostics {
|
func validateCount(ctx EvalContext, expr hcl.Expression) (diags tfdiags.Diagnostics) {
|
||||||
if expr == nil {
|
val, countDiags := evaluateCountExpressionValue(expr, ctx)
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var diags tfdiags.Diagnostics
|
|
||||||
|
|
||||||
countVal, countDiags := ctx.EvaluateExpr(expr, cty.Number, nil)
|
|
||||||
diags = diags.Append(countDiags)
|
|
||||||
if diags.HasErrors() {
|
|
||||||
return diags
|
|
||||||
}
|
|
||||||
|
|
||||||
if countVal.IsNull() {
|
|
||||||
diags = diags.Append(&hcl.Diagnostic{
|
|
||||||
Severity: hcl.DiagError,
|
|
||||||
Summary: "Invalid count argument",
|
|
||||||
Detail: `The given "count" argument value is null. An integer is required.`,
|
|
||||||
Subject: expr.Range().Ptr(),
|
|
||||||
})
|
|
||||||
return diags
|
|
||||||
}
|
|
||||||
|
|
||||||
var err error
|
|
||||||
countVal, err = convert.Convert(countVal, cty.Number)
|
|
||||||
if err != nil {
|
|
||||||
diags = diags.Append(&hcl.Diagnostic{
|
|
||||||
Severity: hcl.DiagError,
|
|
||||||
Summary: "Invalid count argument",
|
|
||||||
Detail: fmt.Sprintf(`The given "count" argument value is unsuitable: %s.`, err),
|
|
||||||
Subject: expr.Range().Ptr(),
|
|
||||||
})
|
|
||||||
return diags
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the value isn't known then that's the best we can do for now, but
|
// If the value isn't known then that's the best we can do for now, but
|
||||||
// we'll check more thoroughly during the plan walk.
|
// we'll check more thoroughly during the plan walk
|
||||||
if !countVal.IsKnown() {
|
if !val.IsKnown() {
|
||||||
return diags
|
return diags
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we _do_ know the value, then we can do a few more checks here.
|
if countDiags.HasErrors() {
|
||||||
var count int
|
diags = diags.Append(countDiags)
|
||||||
err = gocty.FromCtyValue(countVal, &count)
|
|
||||||
if err != nil {
|
|
||||||
// Isn't a whole number, etc.
|
|
||||||
diags = diags.Append(&hcl.Diagnostic{
|
|
||||||
Severity: hcl.DiagError,
|
|
||||||
Summary: "Invalid count argument",
|
|
||||||
Detail: fmt.Sprintf(`The given "count" argument value is unsuitable: %s.`, err),
|
|
||||||
Subject: expr.Range().Ptr(),
|
|
||||||
})
|
|
||||||
return diags
|
|
||||||
}
|
|
||||||
|
|
||||||
if count < 0 {
|
|
||||||
diags = diags.Append(&hcl.Diagnostic{
|
|
||||||
Severity: hcl.DiagError,
|
|
||||||
Summary: "Invalid count argument",
|
|
||||||
Detail: `The given "count" argument value is unsuitable: count cannot be negative.`,
|
|
||||||
Subject: expr.Range().Ptr(),
|
|
||||||
})
|
|
||||||
return diags
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return diags
|
return diags
|
||||||
|
|
|
@ -202,6 +202,7 @@ func TestNodeValidatableResource_ValidateResource_managedResource(t *testing.T)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNodeValidatableResource_ValidateResource_managedResourceCount(t *testing.T) {
|
func TestNodeValidatableResource_ValidateResource_managedResourceCount(t *testing.T) {
|
||||||
|
// Setup
|
||||||
mp := simpleMockProvider()
|
mp := simpleMockProvider()
|
||||||
mp.ValidateResourceTypeConfigFn = func(req providers.ValidateResourceTypeConfigRequest) providers.ValidateResourceTypeConfigResponse {
|
mp.ValidateResourceTypeConfigFn = func(req providers.ValidateResourceTypeConfigRequest) providers.ValidateResourceTypeConfigResponse {
|
||||||
if got, want := req.TypeName, "test_object"; got != want {
|
if got, want := req.TypeName, "test_object"; got != want {
|
||||||
|
@ -214,35 +215,54 @@ func TestNodeValidatableResource_ValidateResource_managedResourceCount(t *testin
|
||||||
}
|
}
|
||||||
|
|
||||||
p := providers.Interface(mp)
|
p := providers.Interface(mp)
|
||||||
rc := &configs.Resource{
|
|
||||||
Mode: addrs.ManagedResourceMode,
|
|
||||||
Type: "test_object",
|
|
||||||
Name: "foo",
|
|
||||||
Count: hcltest.MockExprLiteral(cty.NumberIntVal(2)),
|
|
||||||
Config: configs.SynthBody("", map[string]cty.Value{
|
|
||||||
"test_string": cty.StringVal("bar"),
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
node := NodeValidatableResource{
|
|
||||||
NodeAbstractResource: &NodeAbstractResource{
|
|
||||||
Addr: mustConfigResourceAddr("test_foo.bar"),
|
|
||||||
Config: rc,
|
|
||||||
ResolvedProvider: mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx := &MockEvalContext{}
|
ctx := &MockEvalContext{}
|
||||||
ctx.installSimpleEval()
|
ctx.installSimpleEval()
|
||||||
ctx.ProviderSchemaSchema = mp.GetSchemaReturn
|
ctx.ProviderSchemaSchema = mp.GetSchemaReturn
|
||||||
ctx.ProviderProvider = p
|
ctx.ProviderProvider = p
|
||||||
|
|
||||||
diags := node.validateResource(ctx)
|
tests := []struct {
|
||||||
if diags.HasErrors() {
|
name string
|
||||||
t.Fatalf("err: %s", diags.Err())
|
count hcl.Expression
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"simple count",
|
||||||
|
hcltest.MockExprLiteral(cty.NumberIntVal(2)),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"marked count value",
|
||||||
|
hcltest.MockExprLiteral(cty.NumberIntVal(3).Mark("marked")),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if !mp.ValidateResourceTypeConfigCalled {
|
for _, test := range tests {
|
||||||
t.Fatal("Expected ValidateResourceTypeConfig to be called, but it was not!")
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
rc := &configs.Resource{
|
||||||
|
Mode: addrs.ManagedResourceMode,
|
||||||
|
Type: "test_object",
|
||||||
|
Name: "foo",
|
||||||
|
Count: test.count,
|
||||||
|
Config: configs.SynthBody("", map[string]cty.Value{
|
||||||
|
"test_string": cty.StringVal("bar"),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
node := NodeValidatableResource{
|
||||||
|
NodeAbstractResource: &NodeAbstractResource{
|
||||||
|
Addr: mustConfigResourceAddr("test_foo.bar"),
|
||||||
|
Config: rc,
|
||||||
|
ResolvedProvider: mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
diags := node.validateResource(ctx)
|
||||||
|
if diags.HasErrors() {
|
||||||
|
t.Fatalf("err: %s", diags.Err())
|
||||||
|
}
|
||||||
|
|
||||||
|
if !mp.ValidateResourceTypeConfigCalled {
|
||||||
|
t.Fatal("Expected ValidateResourceTypeConfig to be called, but it was not!")
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue