github.com/iqoqo/nomad@v0.11.3-0.20200911112621-d7021c74d101/helper/pluginutils/hclutils/util.go (about) 1 package hclutils 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 8 "github.com/hashicorp/go-msgpack/codec" 9 "github.com/hashicorp/hcl2/hcl" 10 hjson "github.com/hashicorp/hcl2/hcl/json" 11 "github.com/hashicorp/hcl2/hcldec" 12 "github.com/hashicorp/nomad/nomad/structs" 13 "github.com/zclconf/go-cty/cty" 14 "github.com/zclconf/go-cty/cty/function" 15 "github.com/zclconf/go-cty/cty/function/stdlib" 16 ) 17 18 // ParseHclInterface is used to convert an interface value representing a hcl2 19 // body and return the interpolated value. Vars may be nil if there are no 20 // variables to interpolate. 21 func ParseHclInterface(val interface{}, spec hcldec.Spec, vars map[string]cty.Value) (cty.Value, hcl.Diagnostics, []error) { 22 evalCtx := &hcl.EvalContext{ 23 Variables: vars, 24 Functions: GetStdlibFuncs(), 25 } 26 27 // Encode to json 28 var buf bytes.Buffer 29 enc := codec.NewEncoder(&buf, structs.JsonHandle) 30 err := enc.Encode(val) 31 if err != nil { 32 // Convert to a hcl diagnostics message 33 errorMessage := fmt.Sprintf("Label encoding failed: %v", err) 34 return cty.NilVal, 35 hcl.Diagnostics([]*hcl.Diagnostic{{ 36 Severity: hcl.DiagError, 37 Summary: "Failed to encode label value", 38 Detail: errorMessage, 39 }}), 40 []error{errors.New(errorMessage)} 41 } 42 43 // Parse the json as hcl2 44 hclFile, diag := hjson.Parse(buf.Bytes(), "") 45 if diag.HasErrors() { 46 return cty.NilVal, diag, formattedDiagnosticErrors(diag) 47 } 48 49 value, decDiag := hcldec.Decode(hclFile.Body, spec, evalCtx) 50 diag = diag.Extend(decDiag) 51 if diag.HasErrors() { 52 return cty.NilVal, diag, formattedDiagnosticErrors(diag) 53 } 54 55 return value, diag, nil 56 } 57 58 // GetStdlibFuncs returns the set of stdlib functions. 59 func GetStdlibFuncs() map[string]function.Function { 60 return map[string]function.Function{ 61 "abs": stdlib.AbsoluteFunc, 62 "coalesce": stdlib.CoalesceFunc, 63 "concat": stdlib.ConcatFunc, 64 "hasindex": stdlib.HasIndexFunc, 65 "int": stdlib.IntFunc, 66 "jsondecode": stdlib.JSONDecodeFunc, 67 "jsonencode": stdlib.JSONEncodeFunc, 68 "length": stdlib.LengthFunc, 69 "lower": stdlib.LowerFunc, 70 "max": stdlib.MaxFunc, 71 "min": stdlib.MinFunc, 72 "reverse": stdlib.ReverseFunc, 73 "strlen": stdlib.StrlenFunc, 74 "substr": stdlib.SubstrFunc, 75 "upper": stdlib.UpperFunc, 76 } 77 } 78 79 // TODO: update hcl2 library with better diagnostics formatting for streamed configs 80 // - should be arbitrary labels not JSON https://github.com/hashicorp/hcl2/blob/4fba5e1a75e382aed7f7a7993f2c4836a5e1cd52/hcl/json/structure.go#L66 81 // - should not print diagnostic subject https://github.com/hashicorp/hcl2/blob/4fba5e1a75e382aed7f7a7993f2c4836a5e1cd52/hcl/diagnostic.go#L77 82 func formattedDiagnosticErrors(diag hcl.Diagnostics) []error { 83 var errs []error 84 for _, d := range diag { 85 if d.Summary == "Extraneous JSON object property" { 86 d.Summary = "Invalid label" 87 } 88 err := errors.New(fmt.Sprintf("%s: %s", d.Summary, d.Detail)) 89 errs = append(errs, err) 90 } 91 return errs 92 }