Skip to content

Commit

Permalink
template: move jobspec parsing into Levant to avoid dep hell.
Browse files Browse the repository at this point in the history
The Nomad module setup is not designed nor intended to have any
pkg apart from api imported. This caused problems when using the
jobspec package. The Nomad Terraform provider has exactly this
problem and has its own version of the Parse functionality. I
attempted to import this to avoid more duplication but ran into
hashicorp/terraform-provider-nomad#150.

This is therefore a temp solution so the project can be easily
used and released.
  • Loading branch information
jrasell committed Sep 2, 2020
1 parent 38324ae commit 09a8ce1
Show file tree
Hide file tree
Showing 12 changed files with 3,191 additions and 2 deletions.
14 changes: 13 additions & 1 deletion go.mod
Expand Up @@ -3,22 +3,34 @@ module github.com/hashicorp/levant
go 1.13

require (
cloud.google.com/go v0.63.0 // indirect
github.com/Masterminds/sprig/v3 v3.1.0
github.com/apparentlymart/go-cidr v0.0.0-20170616213631-2bd8b58cf427 // indirect
github.com/aws/aws-sdk-go v1.30.27 // indirect
github.com/blang/semver v3.5.1+incompatible // indirect
github.com/davecgh/go-spew v1.1.1
github.com/hashicorp/consul/api v1.4.1-0.20200730220852-12f574c9de39
github.com/hashicorp/go-hclog v0.14.1 // indirect
github.com/hashicorp/go-multierror v1.1.0
github.com/hashicorp/go-uuid v1.0.2 // indirect
github.com/hashicorp/hcl v1.0.1-0.20191016231534-914dc3f8dd7c
github.com/hashicorp/hil v0.0.0-20170627220502-fa9f258a9250 // indirect
github.com/hashicorp/nomad v0.12.3
github.com/hashicorp/nomad/api v0.0.0-20200820031125-ad48ad2c1f60
github.com/hashicorp/terraform v0.10.5
github.com/mattn/go-colorable v0.1.7 // indirect
github.com/mattn/go-isatty v0.0.12
github.com/mitchellh/cli v1.1.0
github.com/mitchellh/mapstructure v1.3.3 // indirect
github.com/mitchellh/mapstructure v1.3.3
github.com/pkg/errors v0.9.1
github.com/rs/zerolog v1.6.0
github.com/sean-/conswriter v0.0.0-20180208195008-f5ae3917a627
github.com/sean-/pager v0.0.0-20180208200047-666be9bf53b5 // indirect
github.com/stretchr/testify v1.5.1
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a // indirect
golang.org/x/net v0.0.0-20200822124328-c89045814202 // indirect
golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a // indirect
golang.org/x/tools v0.0.0-20200814230902-9882f1d1823d // indirect
google.golang.org/genproto v0.0.0-20200815001618-f69a88009b70 // indirect
gopkg.in/yaml.v2 v2.3.0
)
264 changes: 264 additions & 0 deletions go.sum

Large diffs are not rendered by default.

110 changes: 110 additions & 0 deletions template/helper/funcs.go
@@ -0,0 +1,110 @@
package helper

import (
"fmt"
"reflect"
"strings"
"time"

multierror "github.com/hashicorp/go-multierror"
"github.com/hashicorp/hcl/hcl/ast"
)

// boolToPtr returns the pointer to a boolean
func BoolToPtr(b bool) *bool {
return &b
}

// StringToPtr returns the pointer to a string
func StringToPtr(str string) *string {
return &str
}

// TimeToPtr returns the pointer to a time stamp
func TimeToPtr(t time.Duration) *time.Duration {
return &t
}

func CheckHCLKeys(node ast.Node, valid []string) error {
var list *ast.ObjectList
switch n := node.(type) {
case *ast.ObjectList:
list = n
case *ast.ObjectType:
list = n.List
default:
return fmt.Errorf("cannot check HCL keys of type %T", n)
}

validMap := make(map[string]struct{}, len(valid))
for _, v := range valid {
validMap[v] = struct{}{}
}

var result error
for _, item := range list.Items {
key := item.Keys[0].Token.Value().(string)
if _, ok := validMap[key]; !ok {
result = multierror.Append(result, fmt.Errorf(
"invalid key: %s", key))
}
}

return result
}

// UnusedKeys returns a pretty-printed error if any `hcl:",unusedKeys"` is not empty
func UnusedKeys(obj interface{}) error {
val := reflect.ValueOf(obj)
if val.Kind() == reflect.Ptr {
val = reflect.Indirect(val)
}
return unusedKeysImpl([]string{}, val)
}

func unusedKeysImpl(path []string, val reflect.Value) error {
stype := val.Type()
for i := 0; i < stype.NumField(); i++ {
ftype := stype.Field(i)
fval := val.Field(i)
tags := strings.Split(ftype.Tag.Get("hcl"), ",")
name := tags[0]
tags = tags[1:]

if fval.Kind() == reflect.Ptr {
fval = reflect.Indirect(fval)
}

// struct? recurse. Add the struct's key to the path
if fval.Kind() == reflect.Struct {
err := unusedKeysImpl(append([]string{name}, path...), fval)
if err != nil {
return err
}
continue
}

// Search the hcl tags for "unusedKeys"
unusedKeys := false
for _, p := range tags {
if p == "unusedKeys" {
unusedKeys = true
break
}
}

if unusedKeys {
ks, ok := fval.Interface().([]string)
if ok && len(ks) != 0 {
ps := ""
if len(path) > 0 {
ps = strings.Join(path, ".") + " "
}
return fmt.Errorf("%sunexpected keys %s",
ps,
strings.Join(ks, ", "))
}
}
}
return nil
}

0 comments on commit 09a8ce1

Please sign in to comment.