From c504beacc61167e1769265a0121678a543ad8bcb Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 24 Jul 2013 23:29:21 -0500 Subject: [PATCH] builder/amazon/instance: upload bundle --- builder/amazon/instance/builder.go | 47 +++++++++------ builder/amazon/instance/step_upload_bundle.go | 57 +++++++++++++++++++ 2 files changed, 87 insertions(+), 17 deletions(-) create mode 100644 builder/amazon/instance/step_upload_bundle.go diff --git a/builder/amazon/instance/builder.go b/builder/amazon/instance/builder.go index ac4631cba..d9b367b2f 100644 --- a/builder/amazon/instance/builder.go +++ b/builder/amazon/instance/builder.go @@ -26,14 +26,15 @@ type Config struct { awscommon.AccessConfig `mapstructure:",squash"` awscommon.RunConfig `mapstructure:",squash"` - AccountId string `mapstructure:"account_id"` - BundleDestination string `mapstructure:"bundle_destination"` - BundlePrefix string `mapstructure:"bundle_prefix"` - BundleVolCommand string `mapstructure:"bundle_vol_command"` - S3Bucket string `mapstructure:"s3_bucket"` - X509CertPath string `mapstructure:"x509_cert_path"` - X509KeyPath string `mapstructure:"x509_key_path"` - X509UploadPath string `mapstructure:"x509_upload_path"` + AccountId string `mapstructure:"account_id"` + BundleDestination string `mapstructure:"bundle_destination"` + BundlePrefix string `mapstructure:"bundle_prefix"` + BundleUploadCommand string `mapstructure:"bundle_upload_command"` + BundleVolCommand string `mapstructure:"bundle_vol_command"` + S3Bucket string `mapstructure:"s3_bucket"` + X509CertPath string `mapstructure:"x509_cert_path"` + X509KeyPath string `mapstructure:"x509_key_path"` + X509UploadPath string `mapstructure:"x509_upload_path"` } type Builder struct { @@ -55,15 +56,15 @@ func (b *Builder) Prepare(raws ...interface{}) error { b.config.BundlePrefix = "image" } - // Accumulate any errors - errs := common.CheckUnusedConfig(md) - errs = packer.MultiErrorAppend(errs, b.config.AccessConfig.Prepare()...) - errs = packer.MultiErrorAppend(errs, b.config.RunConfig.Prepare()...) - - if b.config.AccountId == "" { - errs = packer.MultiErrorAppend(errs, errors.New("account_id is required")) - } else { - b.config.AccountId = strings.Replace(b.config.AccountId, "-", "", -1) + if b.config.BundleUploadCommand == "" { + b.config.BundleUploadCommand = "sudo -n ec2-upload-bundle " + + "-b {{.BucketName}} " + + "-m {{.ManifestPath}} " + + "-a {{.AccessKey}} " + + "-s {{.SecretKey}} " + + "-d {{.BundleDirectory}} " + + "--batch " + + "--retry" } if b.config.BundleVolCommand == "" { @@ -78,6 +79,17 @@ func (b *Builder) Prepare(raws ...interface{}) error { "--batch" } + // Accumulate any errors + errs := common.CheckUnusedConfig(md) + errs = packer.MultiErrorAppend(errs, b.config.AccessConfig.Prepare()...) + errs = packer.MultiErrorAppend(errs, b.config.RunConfig.Prepare()...) + + if b.config.AccountId == "" { + errs = packer.MultiErrorAppend(errs, errors.New("account_id is required")) + } else { + b.config.AccountId = strings.Replace(b.config.AccountId, "-", "", -1) + } + if b.config.S3Bucket == "" { errs = packer.MultiErrorAppend(errs, errors.New("s3_bucket is required")) } @@ -150,6 +162,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe &common.StepProvision{}, &StepUploadX509Cert{}, &StepBundleVolume{}, + &StepUploadBundle{}, } // Run! diff --git a/builder/amazon/instance/step_upload_bundle.go b/builder/amazon/instance/step_upload_bundle.go new file mode 100644 index 000000000..87cfb7e6e --- /dev/null +++ b/builder/amazon/instance/step_upload_bundle.go @@ -0,0 +1,57 @@ +package instance + +import ( + "bytes" + "fmt" + "github.com/mitchellh/multistep" + "github.com/mitchellh/packer/packer" + "text/template" +) + +type uploadCmdData struct { + AccessKey string + BucketName string + BundleDirectory string + ManifestPath string + SecretKey string +} + +type StepUploadBundle struct{} + +func (s *StepUploadBundle) Run(state map[string]interface{}) multistep.StepAction { + comm := state["communicator"].(packer.Communicator) + config := state["config"].(*Config) + ui := state["ui"].(packer.Ui) + + var uploadCmd bytes.Buffer + tData := uploadCmdData{ + AccessKey: config.AccessKey, + BucketName: config.S3Bucket, + BundleDirectory: config.BundleDestination, + ManifestPath: fmt.Sprintf( + "%s/%s.manifest.xml", config.BundleDestination, config.BundlePrefix), + SecretKey: config.SecretKey, + } + t := template.Must(template.New("uploadCmd").Parse(config.BundleUploadCommand)) + t.Execute(&uploadCmd, tData) + + ui.Say("Uploading the bundle...") + cmd := &packer.RemoteCmd{Command: uploadCmd.String()} + if err := cmd.StartWithUi(comm, ui); err != nil { + state["error"] = fmt.Errorf("Error uploading volume: %s", err) + ui.Error(state["error"].(error).Error()) + return multistep.ActionHalt + } + + if cmd.ExitStatus != 0 { + state["error"] = fmt.Errorf( + "Bundle upload failed. Please see the output above for more\n" + + "details on what went wrong.") + ui.Error(state["error"].(error).Error()) + return multistep.ActionHalt + } + + return multistep.ActionContinue +} + +func (s *StepUploadBundle) Cleanup(state map[string]interface{}) {}