add Variable.validateValue func

This commit is contained in:
Adrien Delorme 2020-10-30 15:38:29 +01:00
parent 4d386dd806
commit 9932fd1217
1 changed files with 77 additions and 9 deletions

View File

@ -2,6 +2,7 @@ package hcl2template
import (
"fmt"
"log"
"strings"
"unicode"
@ -67,7 +68,76 @@ func (v *Variable) GoString() string {
)
}
func (v *Variable) Value() (cty.Value, *hcl.Diagnostic) {
// validateValue ensures that all of the configured custom validations for a
// variable value are passing.
//
func (v *Variable) validateValue(val cty.Value) (diags hcl.Diagnostics) {
if len(v.Validations) == 0 {
log.Printf("[TRACE] validateValue: not active for %s, so skipping", v.Name)
return nil
}
hclCtx := &hcl.EvalContext{
Variables: map[string]cty.Value{
"var": cty.ObjectVal(map[string]cty.Value{
v.Name: val,
}),
},
Functions: Functions(""),
}
for _, validation := range v.Validations {
const errInvalidCondition = "Invalid variable validation result"
const errInvalidValue = "Invalid value for variable"
result, moreDiags := validation.Condition.Value(hclCtx)
diags = append(diags, moreDiags...)
if moreDiags.HasErrors() {
log.Printf("[TRACE] evalVariableValidations: %s rule %s condition expression failed: %s", v.Name, validation.DeclRange, moreDiags.Error())
}
if !result.IsKnown() {
log.Printf("[TRACE] evalVariableValidations: %s rule %s condition value is unknown, so skipping validation for now", v.Name, validation.DeclRange)
continue // We'll wait until we've learned more, then.
}
if result.IsNull() {
diags = append(diags, &hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: errInvalidCondition,
Detail: "Validation condition expression must return either true or false, not null.",
Subject: validation.Condition.Range().Ptr(),
Expression: validation.Condition,
EvalContext: hclCtx,
})
continue
}
var err error
result, err = convert.Convert(result, cty.Bool)
if err != nil {
diags = append(diags, &hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: errInvalidCondition,
Detail: fmt.Sprintf("Invalid validation condition result value: %s.", err),
Subject: validation.Condition.Range().Ptr(),
Expression: validation.Condition,
EvalContext: hclCtx,
})
continue
}
if result.False() {
diags = append(diags, &hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: errInvalidValue,
Detail: fmt.Sprintf("%s\n\nThis was checked by the validation rule at %s.", validation.ErrorMessage, validation.DeclRange.String()),
Subject: validation.DeclRange.Ptr(),
})
}
}
return diags
}
func (v *Variable) Value() (cty.Value, hcl.Diagnostics) {
for _, value := range []cty.Value{
v.CmdValue,
v.VarfileValue,
@ -75,18 +145,18 @@ func (v *Variable) Value() (cty.Value, *hcl.Diagnostic) {
v.DefaultValue,
} {
if value != cty.NilVal {
return value, nil
return value, v.validateValue(value)
}
}
return cty.UnknownVal(v.Type), &hcl.Diagnostic{
return cty.UnknownVal(v.Type), hcl.Diagnostics{&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: fmt.Sprintf("Unset variable %q", v.Name),
Detail: "A used variable must be set or have a default value; see " +
"https://packer.io/docs/configuration/from-1.5/syntax for " +
"details.",
Context: v.Range.Ptr(),
}
}}
}
type Variables map[string]*Variable
@ -103,10 +173,8 @@ func (variables Variables) Values() (map[string]cty.Value, hcl.Diagnostics) {
res := map[string]cty.Value{}
var diags hcl.Diagnostics
for k, v := range variables {
value, diag := v.Value()
if diag != nil {
diags = append(diags, diag)
}
value, moreDiags := v.Value()
diags = append(diags, moreDiags...)
res[k] = value
}
return res, diags
@ -486,7 +554,7 @@ func (cfg *PackerConfig) collectInputVariableValues(env []string, files []*hcl.F
})
for _, block := range content.Blocks {
name := block.Labels[0]
diags = diags.Append(&hcl.Diagnostic{
diags = append(diags, &hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Variable declaration in a .pkrvar file",
Detail: fmt.Sprintf("A .pkrvar file is used to assign "+