diff --git a/builder/amazon/common/ami_config.go b/builder/amazon/common/ami_config.go new file mode 100644 index 000000000..ac992c19e --- /dev/null +++ b/builder/amazon/common/ami_config.go @@ -0,0 +1,67 @@ +package common + +import ( + "fmt" + "github.com/mitchellh/packer/common" +) + +// AMIConfig is for common configuration related to creating AMIs. +type AMIConfig struct { + AMIName string `mapstructure:"ami_name"` + AMIDescription string `mapstructure:"ami_description"` + AMIUsers []string `mapstructure:"ami_users"` + AMIGroups []string `mapstructure:"ami_groups"` + AMIProductCodes []string `mapstructure:"ami_product_codes"` +} + +func (c *AMIConfig) Prepare(t *common.Template) []error { + if t == nil { + var err error + t, err = common.NewTemplate() + if err != nil { + return []error{err} + } + } + + templates := map[string]*string{ + "ami_name": &c.AMIName, + "ami_description": &c.AMIDescription, + } + + errs := make([]error, 0) + for n, ptr := range templates { + var err error + *ptr, err = t.Process(*ptr, nil) + if err != nil { + errs = append( + errs, fmt.Errorf("Error processing %s: %s", n, err)) + } + } + + sliceTemplates := map[string][]string{ + "ami_users": c.AMIUsers, + "ami_groups": c.AMIGroups, + "ami_product_codes": c.AMIProductCodes, + } + + for n, slice := range sliceTemplates { + for i, elem := range slice { + var err error + slice[i], err = t.Process(elem, nil) + if err != nil { + errs = append( + errs, fmt.Errorf("Error processing %s[%d]: %s", n, i, err)) + } + } + } + + if c.AMIName == "" { + errs = append(errs, fmt.Errorf("ami_name must be specified")) + } + + if len(errs) > 0 { + return errs + } + + return nil +} diff --git a/builder/amazon/common/ami_config_test.go b/builder/amazon/common/ami_config_test.go new file mode 100644 index 000000000..dc0cc93df --- /dev/null +++ b/builder/amazon/common/ami_config_test.go @@ -0,0 +1,23 @@ +package common + +import ( + "testing" +) + +func testAMIConfig() *AMIConfig { + return &AMIConfig{ + AMIName: "foo", + } +} + +func TestAMIConfigPrepare_Region(t *testing.T) { + c := testAMIConfig() + if err := c.Prepare(nil); err != nil { + t.Fatalf("shouldn't have err: %s", err) + } + + c.AMIName = "" + if err := c.Prepare(nil); err == nil { + t.Fatal("should have error") + } +} diff --git a/builder/amazon/ebs/builder.go b/builder/amazon/ebs/builder.go index 860f05c08..19fc3f721 100644 --- a/builder/amazon/ebs/builder.go +++ b/builder/amazon/ebs/builder.go @@ -6,7 +6,6 @@ package ebs import ( - "errors" "fmt" "github.com/mitchellh/goamz/ec2" "github.com/mitchellh/multistep" @@ -22,16 +21,9 @@ const BuilderId = "mitchellh.amazonebs" type config struct { common.PackerConfig `mapstructure:",squash"` awscommon.AccessConfig `mapstructure:",squash"` + awscommon.AMIConfig `mapstructure:",squash"` awscommon.RunConfig `mapstructure:",squash"` - // Configuration of the resulting AMI - AMIName string `mapstructure:"ami_name"` - - // AMI attributes - AMIDescription string `mapstructure:"ami_description"` - AMIUsers []string `mapstructure:"ami_users"` - AMIGroups []string `mapstructure:"ami_groups"` - // Tags for the AMI Tags map[string]string @@ -57,17 +49,10 @@ func (b *Builder) Prepare(raws ...interface{}) error { // Accumulate any errors errs := common.CheckUnusedConfig(md) errs = packer.MultiErrorAppend(errs, b.config.AccessConfig.Prepare(b.config.tpl)...) + errs = packer.MultiErrorAppend(errs, b.config.AMIConfig.Prepare(b.config.tpl)...) errs = packer.MultiErrorAppend(errs, b.config.RunConfig.Prepare(b.config.tpl)...) // Accumulate any errors - if b.config.AMIName == "" { - errs = packer.MultiErrorAppend( - errs, errors.New("ami_name must be specified")) - } else if b.config.AMIName, err = b.config.tpl.Process(b.config.AMIName, nil); err != nil { - errs = packer.MultiErrorAppend( - errs, fmt.Errorf("Error processing ami_name: %s", err)) - } - newTags := make(map[string]string) for k, v := range b.config.Tags { k, err = b.config.tpl.Process(k, nil) diff --git a/builder/amazon/instance/builder.go b/builder/amazon/instance/builder.go index 971dcfcfb..d9b4ad51a 100644 --- a/builder/amazon/instance/builder.go +++ b/builder/amazon/instance/builder.go @@ -23,10 +23,10 @@ const BuilderId = "mitchellh.amazon.instance" type Config struct { common.PackerConfig `mapstructure:",squash"` awscommon.AccessConfig `mapstructure:",squash"` + awscommon.AMIConfig `mapstructure:",squash"` awscommon.RunConfig `mapstructure:",squash"` AccountId string `mapstructure:"account_id"` - AMIName string `mapstructure:"ami_name"` BundleDestination string `mapstructure:"bundle_destination"` BundlePrefix string `mapstructure:"bundle_prefix"` BundleUploadCommand string `mapstructure:"bundle_upload_command"` @@ -37,12 +37,6 @@ type Config struct { X509KeyPath string `mapstructure:"x509_key_path"` X509UploadPath string `mapstructure:"x509_upload_path"` - // AMI attributes - AMIDescription string `mapstructure:"ami_description"` - AMIUsers []string `mapstructure:"ami_users"` - AMIGroups []string `mapstructure:"ami_groups"` - AMIProductCodes []string `mapstructure:"ami_product_codes"` - tpl *common.Template } @@ -100,6 +94,7 @@ func (b *Builder) Prepare(raws ...interface{}) error { // Accumulate any errors errs := common.CheckUnusedConfig(md) errs = packer.MultiErrorAppend(errs, b.config.AccessConfig.Prepare(b.config.tpl)...) + errs = packer.MultiErrorAppend(errs, b.config.AMIConfig.Prepare(b.config.tpl)...) errs = packer.MultiErrorAppend(errs, b.config.RunConfig.Prepare(b.config.tpl)...) validates := map[string]*string{ @@ -140,11 +135,6 @@ func (b *Builder) Prepare(raws ...interface{}) error { b.config.AccountId = strings.Replace(b.config.AccountId, "-", "", -1) } - if b.config.AMIName == "" { - errs = packer.MultiErrorAppend( - errs, errors.New("ami_name must be specified")) - } - if b.config.S3Bucket == "" { errs = packer.MultiErrorAppend(errs, errors.New("s3_bucket is required")) }