Error if unknown root level key in template [GH-180]
This commit is contained in:
parent
a354f5fc08
commit
b358a0ea6e
@ -5,6 +5,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/mitchellh/mapstructure"
|
"github.com/mitchellh/mapstructure"
|
||||||
|
"sort"
|
||||||
)
|
)
|
||||||
|
|
||||||
// The rawTemplate struct represents the structure of a template read
|
// The rawTemplate struct represents the structure of a template read
|
||||||
@ -15,7 +16,7 @@ type rawTemplate struct {
|
|||||||
Builders []map[string]interface{}
|
Builders []map[string]interface{}
|
||||||
Hooks map[string][]string
|
Hooks map[string][]string
|
||||||
Provisioners []map[string]interface{}
|
Provisioners []map[string]interface{}
|
||||||
PostProcessors []interface{} `json:"post-processors"`
|
PostProcessors []interface{} `mapstructure:"post-processors"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// The Template struct represents a parsed template, parsed into the most
|
// The Template struct represents a parsed template, parsed into the most
|
||||||
@ -63,8 +64,8 @@ type rawProvisionerConfig struct {
|
|||||||
// and checking for this can be useful, if you wish to format it in a certain
|
// and checking for this can be useful, if you wish to format it in a certain
|
||||||
// way.
|
// way.
|
||||||
func ParseTemplate(data []byte) (t *Template, err error) {
|
func ParseTemplate(data []byte) (t *Template, err error) {
|
||||||
var rawTpl rawTemplate
|
var rawTplInterface interface{}
|
||||||
err = json.Unmarshal(data, &rawTpl)
|
err = json.Unmarshal(data, &rawTplInterface)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
syntaxErr, ok := err.(*json.SyntaxError)
|
syntaxErr, ok := err.(*json.SyntaxError)
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -92,14 +93,41 @@ func ParseTemplate(data []byte) (t *Template, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Decode the raw template interface into the actual rawTemplate
|
||||||
|
// structure, checking for any extranneous keys along the way.
|
||||||
|
var md mapstructure.Metadata
|
||||||
|
var rawTpl rawTemplate
|
||||||
|
decoderConfig := &mapstructure.DecoderConfig{
|
||||||
|
Metadata: &md,
|
||||||
|
Result: &rawTpl,
|
||||||
|
}
|
||||||
|
|
||||||
|
decoder, err := mapstructure.NewDecoder(decoderConfig)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = decoder.Decode(rawTplInterface)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
errors := make([]error, 0)
|
||||||
|
|
||||||
|
if len(md.Unused) > 0 {
|
||||||
|
sort.Strings(md.Unused)
|
||||||
|
for _, unused := range md.Unused {
|
||||||
|
errors = append(
|
||||||
|
errors, fmt.Errorf("Unknown root level key in template: '%s'", unused))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
t = &Template{}
|
t = &Template{}
|
||||||
t.Builders = make(map[string]rawBuilderConfig)
|
t.Builders = make(map[string]rawBuilderConfig)
|
||||||
t.Hooks = rawTpl.Hooks
|
t.Hooks = rawTpl.Hooks
|
||||||
t.PostProcessors = make([][]rawPostProcessorConfig, len(rawTpl.PostProcessors))
|
t.PostProcessors = make([][]rawPostProcessorConfig, len(rawTpl.PostProcessors))
|
||||||
t.Provisioners = make([]rawProvisionerConfig, len(rawTpl.Provisioners))
|
t.Provisioners = make([]rawProvisionerConfig, len(rawTpl.Provisioners))
|
||||||
|
|
||||||
errors := make([]error, 0)
|
|
||||||
|
|
||||||
// Gather all the builders
|
// Gather all the builders
|
||||||
for i, v := range rawTpl.Builders {
|
for i, v := range rawTpl.Builders {
|
||||||
var raw rawBuilderConfig
|
var raw rawBuilderConfig
|
||||||
@ -203,6 +231,7 @@ func ParseTemplate(data []byte) (t *Template, err error) {
|
|||||||
// If there were errors, we put it into a MultiError and return
|
// If there were errors, we put it into a MultiError and return
|
||||||
if len(errors) > 0 {
|
if len(errors) > 0 {
|
||||||
err = &MultiError{errors}
|
err = &MultiError{errors}
|
||||||
|
t = nil
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,6 +37,23 @@ func TestParseTemplate_Invalid(t *testing.T) {
|
|||||||
assert.Nil(result, "should have no result")
|
assert.Nil(result, "should have no result")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestParseTemplate_InvalidKeys(t *testing.T) {
|
||||||
|
assert := asserts.NewTestingAsserts(t, true)
|
||||||
|
|
||||||
|
// Note there is an extra comma below for a purposeful
|
||||||
|
// syntax error in the JSON.
|
||||||
|
data := `
|
||||||
|
{
|
||||||
|
"builders": [{"type": "foo"}],
|
||||||
|
"what is this": ""
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
result, err := ParseTemplate([]byte(data))
|
||||||
|
assert.NotNil(err, "should have an error")
|
||||||
|
assert.Nil(result, "should have no result")
|
||||||
|
}
|
||||||
|
|
||||||
func TestParseTemplate_BuilderWithoutType(t *testing.T) {
|
func TestParseTemplate_BuilderWithoutType(t *testing.T) {
|
||||||
assert := asserts.NewTestingAsserts(t, true)
|
assert := asserts.NewTestingAsserts(t, true)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user