From d11cabf893b239ed6eaf2b39ee377eef5274cc4c Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sat, 20 Jul 2013 21:00:12 -0700 Subject: [PATCH] builder/amazon/instance: upload x509 cert --- builder/amazon/instance/builder.go | 28 +++++- builder/amazon/instance/builder_test.go | 86 ++++++++++++++++++- .../amazon/instance/step_upload_x509_cert.go | 44 ++++++++++ 3 files changed, 156 insertions(+), 2 deletions(-) create mode 100644 builder/amazon/instance/step_upload_x509_cert.go diff --git a/builder/amazon/instance/builder.go b/builder/amazon/instance/builder.go index 6826c2c31..ba7224de0 100644 --- a/builder/amazon/instance/builder.go +++ b/builder/amazon/instance/builder.go @@ -3,6 +3,8 @@ package instance import ( + "errors" + "fmt" "github.com/mitchellh/goamz/aws" "github.com/mitchellh/goamz/ec2" "github.com/mitchellh/multistep" @@ -10,6 +12,7 @@ import ( "github.com/mitchellh/packer/builder/common" "github.com/mitchellh/packer/packer" "log" + "os" ) // The unique ID for this builder @@ -21,6 +24,10 @@ type Config struct { common.PackerConfig `mapstructure:",squash"` awscommon.AccessConfig `mapstructure:",squash"` awscommon.RunConfig `mapstructure:",squash"` + + X509CertPath string `mapstructure:"x509_cert_path"` + X509KeyPath string `mapstructure:"x509_key_path"` + X509UploadPath string `mapstructure:"x509_upload_path"` } type Builder struct { @@ -39,6 +46,24 @@ func (b *Builder) Prepare(raws ...interface{}) error { errs = packer.MultiErrorAppend(errs, b.config.AccessConfig.Prepare()...) errs = packer.MultiErrorAppend(errs, b.config.RunConfig.Prepare()...) + if b.config.X509CertPath == "" { + errs = packer.MultiErrorAppend(errs, errors.New("x509_cert_path is required")) + } else if _, err := os.Stat(b.config.X509CertPath); err != nil { + errs = packer.MultiErrorAppend( + errs, fmt.Errorf("x509_cert_path points to bad file: %s", err)) + } + + if b.config.X509KeyPath == "" { + errs = packer.MultiErrorAppend(errs, errors.New("x509_key_path is required")) + } else if _, err := os.Stat(b.config.X509KeyPath); err != nil { + errs = packer.MultiErrorAppend( + errs, fmt.Errorf("x509_key_path points to bad file: %s", err)) + } + + if b.config.X509UploadPath == "" { + errs = packer.MultiErrorAppend(errs, errors.New("x509_upload_path is required")) + } + if errs != nil && len(errs.Errors) > 0 { return errs } @@ -62,7 +87,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe // Setup the state bag and initial state for the steps state := make(map[string]interface{}) - state["config"] = b.config + state["config"] = &b.config state["ec2"] = ec2conn state["hook"] = hook state["ui"] = ui @@ -85,6 +110,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe SSHWaitTimeout: b.config.SSHTimeout(), }, &common.StepProvision{}, + &StepUploadX509Cert{}, } // Run! diff --git a/builder/amazon/instance/builder_test.go b/builder/amazon/instance/builder_test.go index 9e77886d8..d83ee9c33 100644 --- a/builder/amazon/instance/builder_test.go +++ b/builder/amazon/instance/builder_test.go @@ -2,11 +2,26 @@ package instance import ( "github.com/mitchellh/packer/packer" + "io/ioutil" + "os" "testing" ) func testConfig() map[string]interface{} { - return map[string]interface{}{} + tf, err := ioutil.TempFile("", "packer") + if err != nil { + panic(err) + } + + return map[string]interface{}{ + "instance_type": "m1.small", + "region": "us-east-1", + "source_ami": "foo", + "ssh_username": "bob", + "x509_cert_path": tf.Name(), + "x509_key_path": tf.Name(), + "x509_upload_path": "/foo", + } } func TestBuilder_ImplementsBuilder(t *testing.T) { @@ -28,3 +43,72 @@ func TestBuilderPrepare_InvalidKey(t *testing.T) { t.Fatal("should have error") } } + +func TestBuilderPrepare_X509CertPath(t *testing.T) { + b := &Builder{} + config := testConfig() + + config["x509_cert_path"] = "" + err := b.Prepare(config) + if err == nil { + t.Fatal("should have error") + } + + config["x509_cert_path"] = "i/am/a/file/that/doesnt/exist" + err = b.Prepare(config) + if err == nil { + t.Error("should have error") + } + + tf, err := ioutil.TempFile("", "packer") + if err != nil { + t.Fatalf("error tempfile: %s", err) + } + defer os.Remove(tf.Name()) + + config["x509_cert_path"] = tf.Name() + err = b.Prepare(config) + if err != nil { + t.Fatalf("should not have error: %s", err) + } +} + +func TestBuilderPrepare_X509KeyPath(t *testing.T) { + b := &Builder{} + config := testConfig() + + config["x509_key_path"] = "" + err := b.Prepare(config) + if err == nil { + t.Fatal("should have error") + } + + config["x509_key_path"] = "i/am/a/file/that/doesnt/exist" + err = b.Prepare(config) + if err == nil { + t.Error("should have error") + } + + tf, err := ioutil.TempFile("", "packer") + if err != nil { + t.Fatalf("error tempfile: %s", err) + } + defer os.Remove(tf.Name()) + + config["x509_key_path"] = tf.Name() + err = b.Prepare(config) + if err != nil { + t.Fatalf("should not have error: %s", err) + } +} + +func TestBuilderPrepare_X509UploadPath(t *testing.T) { + b := &Builder{} + config := testConfig() + + config["x509_upload_path"] = "" + err := b.Prepare(config) + if err == nil { + t.Fatal("should have error") + } +} diff --git a/builder/amazon/instance/step_upload_x509_cert.go b/builder/amazon/instance/step_upload_x509_cert.go new file mode 100644 index 000000000..22f710e64 --- /dev/null +++ b/builder/amazon/instance/step_upload_x509_cert.go @@ -0,0 +1,44 @@ +package instance + +import ( + "fmt" + "github.com/mitchellh/multistep" + "github.com/mitchellh/packer/packer" + "os" +) + +type StepUploadX509Cert struct{} + +func (s *StepUploadX509Cert) Run(state map[string]interface{}) multistep.StepAction { + comm := state["communicator"].(packer.Communicator) + config := state["config"].(*Config) + ui := state["ui"].(packer.Ui) + + x509RemoteCertPath := config.X509UploadPath + "/cert.pem" + x509RemoteKeyPath := config.X509UploadPath + "/key.pem" + + ui.Say("Uploading X509 Certificate...") + if err := s.uploadSingle(comm, x509RemoteCertPath, config.X509CertPath); err != nil { + state["error"] = fmt.Errorf("Error uploading X509 cert: %s", err) + return multistep.ActionHalt + } + + if err := s.uploadSingle(comm, x509RemoteKeyPath, config.X509KeyPath); err != nil { + state["error"] = fmt.Errorf("Error uploading X509 cert: %s", err) + return multistep.ActionHalt + } + + return multistep.ActionHalt +} + +func (s *StepUploadX509Cert) Cleanup(map[string]interface{}) {} + +func (s *StepUploadX509Cert) uploadSingle(comm packer.Communicator, dst, src string) error { + f, err := os.Open(src) + if err != nil { + return err + } + defer f.Close() + + return comm.Upload(dst, f) +}