Commit 3b4ef72e authored by Mitchell Hashimoto's avatar Mitchell Hashimoto

Unused keys are invalid in templates [GH-104]

parent 245deaf5
...@@ -13,6 +13,8 @@ FEATURES: ...@@ -13,6 +13,8 @@ FEATURES:
IMPROVEMENTS: IMPROVEMENTS:
* everything: invalid keys in configuration are now considered validation
errors. [GH-104]
* amazon-ebs: Verify the source AMI is EBS-backed before launching. [GH-169] * amazon-ebs: Verify the source AMI is EBS-backed before launching. [GH-169]
* vmware: error if shutdown command has non-zero exit status. * vmware: error if shutdown command has non-zero exit status.
......
...@@ -16,6 +16,8 @@ import ( ...@@ -16,6 +16,8 @@ import (
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
"log" "log"
"os" "os"
"sort"
"strings"
"text/template" "text/template"
"time" "time"
) )
...@@ -50,15 +52,38 @@ type Builder struct { ...@@ -50,15 +52,38 @@ type Builder struct {
} }
func (b *Builder) Prepare(raws ...interface{}) error { func (b *Builder) Prepare(raws ...interface{}) error {
var err error var md mapstructure.Metadata
decoderConfig := &mapstructure.DecoderConfig{
Metadata: &md,
Result: &b.config,
}
decoder, err := mapstructure.NewDecoder(decoderConfig)
if err != nil {
return err
}
for _, raw := range raws { for _, raw := range raws {
err := mapstructure.Decode(raw, &b.config) err := decoder.Decode(raw)
if err != nil { if err != nil {
return err return err
} }
} }
// Accumulate any errors
errs := make([]error, 0)
// Unused keys are errors
if len(md.Unused) > 0 {
sort.Strings(md.Unused)
for _, unused := range md.Unused {
if unused != "type" && !strings.HasPrefix(unused, "packer_") {
errs = append(
errs, fmt.Errorf("Unknown configuration key: %s", unused))
}
}
}
if b.config.AccessKey == "" { if b.config.AccessKey == "" {
b.config.AccessKey = os.Getenv("AWS_ACCESS_KEY_ID") b.config.AccessKey = os.Getenv("AWS_ACCESS_KEY_ID")
} }
...@@ -84,8 +109,6 @@ func (b *Builder) Prepare(raws ...interface{}) error { ...@@ -84,8 +109,6 @@ func (b *Builder) Prepare(raws ...interface{}) error {
} }
// Accumulate any errors // Accumulate any errors
errs := make([]error, 0)
if b.config.AccessKey == "" { if b.config.AccessKey == "" {
errs = append(errs, errors.New("An access_key must be specified")) errs = append(errs, errors.New("An access_key must be specified"))
} }
......
...@@ -148,6 +148,18 @@ func TestBuilderPrepare_InstanceType(t *testing.T) { ...@@ -148,6 +148,18 @@ func TestBuilderPrepare_InstanceType(t *testing.T) {
} }
} }
func TestBuilderPrepare_InvalidKey(t *testing.T) {
var b Builder
config := testConfig()
// Add a random key
config["i_should_not_be_valid"] = true
err := b.Prepare(config)
if err == nil {
t.Fatal("should have error")
}
}
func TestBuilderPrepare_Region(t *testing.T) { func TestBuilderPrepare_Region(t *testing.T) {
var b Builder var b Builder
config := testConfig() config := testConfig()
......
...@@ -13,7 +13,9 @@ import ( ...@@ -13,7 +13,9 @@ import (
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
"log" "log"
"os" "os"
"sort"
"strconv" "strconv"
"strings"
"text/template" "text/template"
"time" "time"
) )
...@@ -56,15 +58,39 @@ type Builder struct { ...@@ -56,15 +58,39 @@ type Builder struct {
} }
func (b *Builder) Prepare(raws ...interface{}) error { func (b *Builder) Prepare(raws ...interface{}) error {
var md mapstructure.Metadata
decoderConfig := &mapstructure.DecoderConfig{
Metadata: &md,
Result: &b.config,
}
decoder, err := mapstructure.NewDecoder(decoderConfig)
if err != nil {
return err
}
for _, raw := range raws { for _, raw := range raws {
err := mapstructure.Decode(raw, &b.config) err := decoder.Decode(raw)
if err != nil { if err != nil {
return err return err
} }
} }
// Accumulate any errors
errs := make([]error, 0)
// Unused keys are errors
if len(md.Unused) > 0 {
sort.Strings(md.Unused)
for _, unused := range md.Unused {
if unused != "type" && !strings.HasPrefix(unused, "packer_") {
errs = append(
errs, fmt.Errorf("Unknown configuration key: %s", unused))
}
}
}
// Optional configuration with defaults // Optional configuration with defaults
//
if b.config.APIKey == "" { if b.config.APIKey == "" {
// Default to environment variable for api_key, if it exists // Default to environment variable for api_key, if it exists
b.config.APIKey = os.Getenv("DIGITALOCEAN_API_KEY") b.config.APIKey = os.Getenv("DIGITALOCEAN_API_KEY")
...@@ -123,11 +149,7 @@ func (b *Builder) Prepare(raws ...interface{}) error { ...@@ -123,11 +149,7 @@ func (b *Builder) Prepare(raws ...interface{}) error {
b.config.RawStateTimeout = "6m" b.config.RawStateTimeout = "6m"
} }
// A list of errors on the configuration
errs := make([]error, 0)
// Required configurations that will display errors if not set // Required configurations that will display errors if not set
//
if b.config.ClientID == "" { if b.config.ClientID == "" {
errs = append(errs, errors.New("a client_id must be specified")) errs = append(errs, errors.New("a client_id must be specified"))
} }
......
...@@ -106,6 +106,18 @@ func TestBuilderPrepare_ClientID(t *testing.T) { ...@@ -106,6 +106,18 @@ func TestBuilderPrepare_ClientID(t *testing.T) {
} }
} }
func TestBuilderPrepare_InvalidKey(t *testing.T) {
var b Builder
config := testConfig()
// Add a random key
config["i_should_not_be_valid"] = true
err := b.Prepare(config)
if err == nil {
t.Fatal("should have error")
}
}
func TestBuilderPrepare_RegionID(t *testing.T) { func TestBuilderPrepare_RegionID(t *testing.T) {
var b Builder var b Builder
config := testConfig() config := testConfig()
......
...@@ -12,6 +12,7 @@ import ( ...@@ -12,6 +12,7 @@ import (
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"sort"
"strings" "strings"
"time" "time"
) )
...@@ -62,15 +63,38 @@ type config struct { ...@@ -62,15 +63,38 @@ type config struct {
} }
func (b *Builder) Prepare(raws ...interface{}) error { func (b *Builder) Prepare(raws ...interface{}) error {
var err error var md mapstructure.Metadata
decoderConfig := &mapstructure.DecoderConfig{
Metadata: &md,
Result: &b.config,
}
decoder, err := mapstructure.NewDecoder(decoderConfig)
if err != nil {
return err
}
for _, raw := range raws { for _, raw := range raws {
err := mapstructure.Decode(raw, &b.config) err := decoder.Decode(raw)
if err != nil { if err != nil {
return err return err
} }
} }
// Accumulate any errors
errs := make([]error, 0)
// Unused keys are errors
if len(md.Unused) > 0 {
sort.Strings(md.Unused)
for _, unused := range md.Unused {
if unused != "type" && !strings.HasPrefix(unused, "packer_") {
errs = append(
errs, fmt.Errorf("Unknown configuration key: %s", unused))
}
}
}
if b.config.DiskSize == 0 { if b.config.DiskSize == 0 {
b.config.DiskSize = 40000 b.config.DiskSize = 40000
} }
...@@ -127,8 +151,6 @@ func (b *Builder) Prepare(raws ...interface{}) error { ...@@ -127,8 +151,6 @@ func (b *Builder) Prepare(raws ...interface{}) error {
b.config.VMName = fmt.Sprintf("packer-%s", b.config.PackerBuildName) b.config.VMName = fmt.Sprintf("packer-%s", b.config.PackerBuildName)
} }
errs := make([]error, 0)
if b.config.HTTPPortMin > b.config.HTTPPortMax { if b.config.HTTPPortMin > b.config.HTTPPortMax {
errs = append(errs, errors.New("http_port_min must be less than http_port_max")) errs = append(errs, errors.New("http_port_min must be less than http_port_max"))
} }
......
...@@ -271,6 +271,18 @@ func TestBuilderPrepare_HTTPPort(t *testing.T) { ...@@ -271,6 +271,18 @@ func TestBuilderPrepare_HTTPPort(t *testing.T) {
} }
} }
func TestBuilderPrepare_InvalidKey(t *testing.T) {
var b Builder
config := testConfig()
// Add a random key
config["i_should_not_be_valid"] = true
err := b.Prepare(config)
if err == nil {
t.Fatal("should have error")
}
}
func TestBuilderPrepare_ISOMD5(t *testing.T) { func TestBuilderPrepare_ISOMD5(t *testing.T) {
var b Builder var b Builder
config := testConfig() config := testConfig()
......
...@@ -12,6 +12,7 @@ import ( ...@@ -12,6 +12,7 @@ import (
"net/url" "net/url"
"os" "os"
"path/filepath" "path/filepath"
"sort"
"strings" "strings"
"text/template" "text/template"
"time" "time"
...@@ -63,13 +64,38 @@ type config struct { ...@@ -63,13 +64,38 @@ type config struct {
} }
func (b *Builder) Prepare(raws ...interface{}) error { func (b *Builder) Prepare(raws ...interface{}) error {
var md mapstructure.Metadata
decoderConfig := &mapstructure.DecoderConfig{
Metadata: &md,
Result: &b.config,
}
decoder, err := mapstructure.NewDecoder(decoderConfig)
if err != nil {
return err
}
for _, raw := range raws { for _, raw := range raws {
err := mapstructure.Decode(raw, &b.config) err := decoder.Decode(raw)
if err != nil { if err != nil {
return err return err
} }
} }
// Accumulate any errors
errs := make([]error, 0)
// Unused keys are errors
if len(md.Unused) > 0 {
sort.Strings(md.Unused)
for _, unused := range md.Unused {
if unused != "type" && !strings.HasPrefix(unused, "packer_") {
errs = append(
errs, fmt.Errorf("Unknown configuration key: %s", unused))
}
}
}
if b.config.DiskName == "" { if b.config.DiskName == "" {
b.config.DiskName = "disk" b.config.DiskName = "disk"
} }
...@@ -122,10 +148,6 @@ func (b *Builder) Prepare(raws ...interface{}) error { ...@@ -122,10 +148,6 @@ func (b *Builder) Prepare(raws ...interface{}) error {
b.config.ToolsUploadPath = "{{ .Flavor }}.iso" b.config.ToolsUploadPath = "{{ .Flavor }}.iso"
} }
// Accumulate any errors
var err error
errs := make([]error, 0)
if b.config.HTTPPortMin > b.config.HTTPPortMax { if b.config.HTTPPortMin > b.config.HTTPPortMax {
errs = append(errs, errors.New("http_port_min must be less than http_port_max")) errs = append(errs, errors.New("http_port_min must be less than http_port_max"))
} }
......
...@@ -163,6 +163,18 @@ func TestBuilderPrepare_HTTPPort(t *testing.T) { ...@@ -163,6 +163,18 @@ func TestBuilderPrepare_HTTPPort(t *testing.T) {
} }
} }
func TestBuilderPrepare_InvalidKey(t *testing.T) {
var b Builder
config := testConfig()
// Add a random key
config["i_should_not_be_valid"] = true
err := b.Prepare(config)
if err == nil {
t.Fatal("should have error")
}
}
func TestBuilderPrepare_ISOMD5(t *testing.T) { func TestBuilderPrepare_ISOMD5(t *testing.T) {
var b Builder var b Builder
config := testConfig() config := testConfig()
......
...@@ -6,6 +6,8 @@ import ( ...@@ -6,6 +6,8 @@ import (
"github.com/mitchellh/mapstructure" "github.com/mitchellh/mapstructure"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
"os" "os"
"sort"
"strings"
) )
type config struct { type config struct {
...@@ -21,13 +23,37 @@ type Provisioner struct { ...@@ -21,13 +23,37 @@ type Provisioner struct {
} }
func (p *Provisioner) Prepare(raws ...interface{}) error { func (p *Provisioner) Prepare(raws ...interface{}) error {
var md mapstructure.Metadata
decoderConfig := &mapstructure.DecoderConfig{
Metadata: &md,
Result: &p.config,
}
decoder, err := mapstructure.NewDecoder(decoderConfig)
if err != nil {
return err
}
for _, raw := range raws { for _, raw := range raws {
if err := mapstructure.Decode(raw, &p.config); err != nil { err := decoder.Decode(raw)
if err != nil {
return err return err
} }
} }
errs := []error{} // Accumulate any errors
errs := make([]error, 0)
// Unused keys are errors
if len(md.Unused) > 0 {
sort.Strings(md.Unused)
for _, unused := range md.Unused {
if unused != "type" && !strings.HasPrefix(unused, "packer_") {
errs = append(
errs, fmt.Errorf("Unknown configuration key: %s", unused))
}
}
}
if _, err := os.Stat(p.config.Source); err != nil { if _, err := os.Stat(p.config.Source); err != nil {
errs = append(errs, errs = append(errs,
......
...@@ -23,6 +23,18 @@ func TestProvisioner_Impl(t *testing.T) { ...@@ -23,6 +23,18 @@ func TestProvisioner_Impl(t *testing.T) {
} }
} }
func TestProvisionerPrepare_InvalidKey(t *testing.T) {
var p Provisioner
config := testConfig()
// Add a random key
config["i_should_not_be_valid"] = true
err := p.Prepare(config)
if err == nil {
t.Fatal("should have error")
}
}
func TestProvisionerPrepare_InvalidSource(t *testing.T) { func TestProvisionerPrepare_InvalidSource(t *testing.T) {
var p Provisioner var p Provisioner
config := testConfig() config := testConfig()
......
...@@ -14,6 +14,7 @@ import ( ...@@ -14,6 +14,7 @@ import (
"io/ioutil" "io/ioutil"
"log" "log"
"os" "os"
"sort"
"strings" "strings"
"text/template" "text/template"
) )
...@@ -58,12 +59,38 @@ type ExecuteCommandTemplate struct { ...@@ -58,12 +59,38 @@ type ExecuteCommandTemplate struct {
} }
func (p *Provisioner) Prepare(raws ...interface{}) error { func (p *Provisioner) Prepare(raws ...interface{}) error {
var md mapstructure.Metadata
decoderConfig := &mapstructure.DecoderConfig{
Metadata: &md,
Result: &p.config,
}
decoder, err := mapstructure.NewDecoder(decoderConfig)
if err != nil {
return err
}
for _, raw := range raws { for _, raw := range raws {
if err := mapstructure.Decode(raw, &p.config); err != nil { err := decoder.Decode(raw)
if err != nil {
return err return err
} }
} }
// Accumulate any errors
errs := make([]error, 0)
// Unused keys are errors
if len(md.Unused) > 0 {
sort.Strings(md.Unused)
for _, unused := range md.Unused {
if unused != "type" && !strings.HasPrefix(unused, "packer_") {
errs = append(
errs, fmt.Errorf("Unknown configuration key: %s", unused))
}
}
}
if p.config.ExecuteCommand == "" { if p.config.ExecuteCommand == "" {
p.config.ExecuteCommand = "chmod +x {{.Path}}; {{.Vars}} {{.Path}}" p.config.ExecuteCommand = "chmod +x {{.Path}}; {{.Vars}} {{.Path}}"
} }
...@@ -88,8 +115,6 @@ func (p *Provisioner) Prepare(raws ...interface{}) error { ...@@ -88,8 +115,6 @@ func (p *Provisioner) Prepare(raws ...interface{}) error {
p.config.Vars = make([]string, 0) p.config.Vars = make([]string, 0)
} }
errs := make([]error, 0)
if p.config.Script != "" && len(p.config.Scripts) > 0 { if p.config.Script != "" && len(p.config.Scripts) > 0 {
errs = append(errs, errors.New("Only one of script or scripts can be specified.")) errs = append(errs, errors.New("Only one of script or scripts can be specified."))
} }
......
...@@ -62,6 +62,18 @@ func TestProvisionerPrepare_InlineShebang(t *testing.T) { ...@@ -62,6 +62,18 @@ func TestProvisionerPrepare_InlineShebang(t *testing.T) {
} }
} }
func TestProvisionerPrepare_InvalidKey(t *testing.T) {
var p Provisioner
config := testConfig()
// Add a random key
config["i_should_not_be_valid"] = true
err := p.Prepare(config)
if err == nil {
t.Fatal("should have error")
}
}
func TestProvisionerPrepare_Script(t *testing.T) { func TestProvisionerPrepare_Script(t *testing.T) {
config := testConfig() config := testConfig()
delete(config, "inline") delete(config, "inline")
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment