add Variable.validateValue func
This commit is contained in:
parent
4d386dd806
commit
9932fd1217
|
@ -2,6 +2,7 @@ package hcl2template
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"strings"
|
"strings"
|
||||||
"unicode"
|
"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{
|
for _, value := range []cty.Value{
|
||||||
v.CmdValue,
|
v.CmdValue,
|
||||||
v.VarfileValue,
|
v.VarfileValue,
|
||||||
|
@ -75,18 +145,18 @@ func (v *Variable) Value() (cty.Value, *hcl.Diagnostic) {
|
||||||
v.DefaultValue,
|
v.DefaultValue,
|
||||||
} {
|
} {
|
||||||
if value != cty.NilVal {
|
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,
|
Severity: hcl.DiagError,
|
||||||
Summary: fmt.Sprintf("Unset variable %q", v.Name),
|
Summary: fmt.Sprintf("Unset variable %q", v.Name),
|
||||||
Detail: "A used variable must be set or have a default value; see " +
|
Detail: "A used variable must be set or have a default value; see " +
|
||||||
"https://packer.io/docs/configuration/from-1.5/syntax for " +
|
"https://packer.io/docs/configuration/from-1.5/syntax for " +
|
||||||
"details.",
|
"details.",
|
||||||
Context: v.Range.Ptr(),
|
Context: v.Range.Ptr(),
|
||||||
}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Variables map[string]*Variable
|
type Variables map[string]*Variable
|
||||||
|
@ -103,10 +173,8 @@ func (variables Variables) Values() (map[string]cty.Value, hcl.Diagnostics) {
|
||||||
res := map[string]cty.Value{}
|
res := map[string]cty.Value{}
|
||||||
var diags hcl.Diagnostics
|
var diags hcl.Diagnostics
|
||||||
for k, v := range variables {
|
for k, v := range variables {
|
||||||
value, diag := v.Value()
|
value, moreDiags := v.Value()
|
||||||
if diag != nil {
|
diags = append(diags, moreDiags...)
|
||||||
diags = append(diags, diag)
|
|
||||||
}
|
|
||||||
res[k] = value
|
res[k] = value
|
||||||
}
|
}
|
||||||
return res, diags
|
return res, diags
|
||||||
|
@ -486,7 +554,7 @@ func (cfg *PackerConfig) collectInputVariableValues(env []string, files []*hcl.F
|
||||||
})
|
})
|
||||||
for _, block := range content.Blocks {
|
for _, block := range content.Blocks {
|
||||||
name := block.Labels[0]
|
name := block.Labels[0]
|
||||||
diags = diags.Append(&hcl.Diagnostic{
|
diags = append(diags, &hcl.Diagnostic{
|
||||||
Severity: hcl.DiagError,
|
Severity: hcl.DiagError,
|
||||||
Summary: "Variable declaration in a .pkrvar file",
|
Summary: "Variable declaration in a .pkrvar file",
|
||||||
Detail: fmt.Sprintf("A .pkrvar file is used to assign "+
|
Detail: fmt.Sprintf("A .pkrvar file is used to assign "+
|
||||||
|
|
Loading…
Reference in New Issue