From e67e4cfa16b2cc4d39bd192b32ab3ab5c2b0f9bd Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sat, 20 Jul 2013 19:40:45 -0700 Subject: [PATCH] builder/amazon: extract StepKeyPair for both --- .../step_key_pair.go} | 12 ++-- builder/amazon/ebs/builder.go | 2 +- builder/amazon/instance/builder.go | 68 +++++++++++++++++++ builder/amazon/instance/builder_test.go | 16 +++++ 4 files changed, 90 insertions(+), 8 deletions(-) rename builder/amazon/{ebs/step_keypair.go => common/step_key_pair.go} (81%) diff --git a/builder/amazon/ebs/step_keypair.go b/builder/amazon/common/step_key_pair.go similarity index 81% rename from builder/amazon/ebs/step_keypair.go rename to builder/amazon/common/step_key_pair.go index 498dcb65c..3e49e3d32 100644 --- a/builder/amazon/ebs/step_keypair.go +++ b/builder/amazon/common/step_key_pair.go @@ -1,4 +1,4 @@ -package ebs +package common import ( "cgl.tideland.biz/identifier" @@ -10,11 +10,11 @@ import ( "log" ) -type stepKeyPair struct { +type StepKeyPair struct { keyName string } -func (s *stepKeyPair) Run(state map[string]interface{}) multistep.StepAction { +func (s *StepKeyPair) Run(state map[string]interface{}) multistep.StepAction { ec2conn := state["ec2"].(*ec2.EC2) ui := state["ui"].(packer.Ui) @@ -23,9 +23,7 @@ func (s *stepKeyPair) Run(state map[string]interface{}) multistep.StepAction { log.Printf("temporary keypair name: %s", keyName) keyResp, err := ec2conn.CreateKeyPair(keyName) if err != nil { - err := fmt.Errorf("Error creating temporary keypair: %s", err) - state["error"] = err - ui.Error(err.Error()) + state["error"] = fmt.Errorf("Error creating temporary keypair: %s", err) return multistep.ActionHalt } @@ -39,7 +37,7 @@ func (s *stepKeyPair) Run(state map[string]interface{}) multistep.StepAction { return multistep.ActionContinue } -func (s *stepKeyPair) Cleanup(state map[string]interface{}) { +func (s *StepKeyPair) Cleanup(state map[string]interface{}) { // If no key name is set, then we never created it, so just return if s.keyName == "" { return diff --git a/builder/amazon/ebs/builder.go b/builder/amazon/ebs/builder.go index ab241e145..81e839b9f 100644 --- a/builder/amazon/ebs/builder.go +++ b/builder/amazon/ebs/builder.go @@ -90,7 +90,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe // Build the steps steps := []multistep.Step{ - &stepKeyPair{}, + &awscommon.StepKeyPair{}, &stepSecurityGroup{}, &stepRunSourceInstance{}, &common.StepConnectSSH{ diff --git a/builder/amazon/instance/builder.go b/builder/amazon/instance/builder.go index ae717ef4e..8aa17633d 100644 --- a/builder/amazon/instance/builder.go +++ b/builder/amazon/instance/builder.go @@ -3,7 +3,11 @@ package instance import ( + "github.com/mitchellh/goamz/aws" + "github.com/mitchellh/goamz/ec2" "github.com/mitchellh/multistep" + awscommon "github.com/mitchellh/packer/builder/amazon/common" + "github.com/mitchellh/packer/builder/common" "github.com/mitchellh/packer/packer" "log" ) @@ -14,6 +18,9 @@ const BuilderId = "mitchellh.amazon.instance" // Config is the configuration that is chained through the steps and // settable from the template. type Config struct { + common.PackerConfig `mapstructure:",squash"` + awscommon.AccessConfig `mapstructure:",squash"` + awscommon.RunConfig `mapstructure:",squash"` } type Builder struct { @@ -22,10 +29,71 @@ type Builder struct { } func (b *Builder) Prepare(raws ...interface{}) error { + md, err := common.DecodeConfig(&b.config, raws...) + if err != nil { + return err + } + + // Accumulate any errors + errs := common.CheckUnusedConfig(md) + errs = packer.MultiErrorAppend(errs, b.config.AccessConfig.Prepare()...) + errs = packer.MultiErrorAppend(errs, b.config.RunConfig.Prepare()...) + + if errs != nil && len(errs.Errors) > 0 { + return errs + } + + log.Printf("Config: %+v", b.config) return nil } func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) { + region, ok := aws.Regions[b.config.Region] + if !ok { + panic("region not found") + } + + auth, err := b.config.AccessConfig.Auth() + if err != nil { + return nil, err + } + + ec2conn := ec2.New(auth, region) + + // Setup the state bag and initial state for the steps + state := make(map[string]interface{}) + state["config"] = b.config + state["ec2"] = ec2conn + state["hook"] = hook + state["ui"] = ui + + // Build the steps + steps := []multistep.Step{ + &awscommon.StepKeyPair{}, + } + + // Run! + if b.config.PackerDebug { + b.runner = &multistep.DebugRunner{ + Steps: steps, + PauseFn: common.MultistepDebugFn(ui), + } + } else { + b.runner = &multistep.BasicRunner{Steps: steps} + } + + b.runner.Run(state) + + // If there was an error, return that + if rawErr, ok := state["error"]; ok { + return nil, rawErr.(error) + } + + // If there are no AMIs, then just return + if _, ok := state["amis"]; !ok { + return nil, nil + } + return nil, nil } diff --git a/builder/amazon/instance/builder_test.go b/builder/amazon/instance/builder_test.go index 76c72f772..9e77886d8 100644 --- a/builder/amazon/instance/builder_test.go +++ b/builder/amazon/instance/builder_test.go @@ -5,6 +5,10 @@ import ( "testing" ) +func testConfig() map[string]interface{} { + return map[string]interface{}{} +} + func TestBuilder_ImplementsBuilder(t *testing.T) { var raw interface{} raw = &Builder{} @@ -12,3 +16,15 @@ func TestBuilder_ImplementsBuilder(t *testing.T) { t.Fatalf("Builder should be a builder") } } + +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") + } +}