From 3ff374696919ddac49dc36d93d8a158b93780738 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Mon, 12 Aug 2013 11:52:43 -0700 Subject: [PATCH] builder/amazon/common: support user_data_file --- builder/amazon/common/run_config.go | 10 +++++ builder/amazon/common/run_config_test.go | 39 +++++++++++++++++++ .../amazon/common/step_run_source_instance.go | 15 ++++++- 3 files changed, 63 insertions(+), 1 deletion(-) diff --git a/builder/amazon/common/run_config.go b/builder/amazon/common/run_config.go index 6351a1731..d68026189 100644 --- a/builder/amazon/common/run_config.go +++ b/builder/amazon/common/run_config.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "github.com/mitchellh/packer/common" + "os" "time" ) @@ -14,6 +15,7 @@ type RunConfig struct { IamInstanceProfile string `mapstructure:"iam_instance_profile"` InstanceType string `mapstructure:"instance_type"` UserData string `mapstructure:"user_data"` + UserDataFile string `mapstructure:"user_data_file"` RawSSHTimeout string `mapstructure:"ssh_timeout"` SSHUsername string `mapstructure:"ssh_username"` SSHPort int `mapstructure:"ssh_port"` @@ -58,6 +60,14 @@ func (c *RunConfig) Prepare(t *common.Template) []error { errs = append(errs, errors.New("An ssh_username must be specified")) } + if c.UserData != "" && c.UserDataFile != "" { + errs = append(errs, fmt.Errorf("Only one of user_data or user_data_file can be specified.")) + } else if c.UserDataFile != "" { + if _, err := os.Stat(c.UserDataFile); err != nil { + errs = append(errs, fmt.Errorf("user_data_file not found: %s", c.UserDataFile)) + } + } + templates := map[string]*string{ "iam_instance_profile": &c.IamInstanceProfile, "instance_type": &c.InstanceType, diff --git a/builder/amazon/common/run_config_test.go b/builder/amazon/common/run_config_test.go index ddfe85069..d13320686 100644 --- a/builder/amazon/common/run_config_test.go +++ b/builder/amazon/common/run_config_test.go @@ -1,6 +1,7 @@ package common import ( + "io/ioutil" "os" "testing" ) @@ -87,3 +88,41 @@ func TestRunConfigPrepare_SSHUsername(t *testing.T) { t.Fatalf("err: %s", err) } } + +func TestRunConfigPrepare_UserData(t *testing.T) { + c := testConfig() + tf, err := ioutil.TempFile("", "packer") + if err != nil { + t.Fatalf("err: %s", err) + } + defer tf.Close() + + c.UserData = "foo" + c.UserDataFile = tf.Name() + if err := c.Prepare(nil); len(err) != 1 { + t.Fatalf("err: %s", err) + } +} + +func TestRunConfigPrepare_UserDataFile(t *testing.T) { + c := testConfig() + if err := c.Prepare(nil); len(err) != 0 { + t.Fatalf("err: %s", err) + } + + c.UserDataFile = "idontexistidontthink" + if err := c.Prepare(nil); len(err) != 1 { + t.Fatalf("err: %s", err) + } + + tf, err := ioutil.TempFile("", "packer") + if err != nil { + t.Fatalf("err: %s", err) + } + defer tf.Close() + + c.UserDataFile = tf.Name() + if err := c.Prepare(nil); len(err) != 0 { + t.Fatalf("err: %s", err) + } +} diff --git a/builder/amazon/common/step_run_source_instance.go b/builder/amazon/common/step_run_source_instance.go index 6d0ee83d8..1f9843a3f 100644 --- a/builder/amazon/common/step_run_source_instance.go +++ b/builder/amazon/common/step_run_source_instance.go @@ -5,6 +5,7 @@ import ( "github.com/mitchellh/goamz/ec2" "github.com/mitchellh/multistep" "github.com/mitchellh/packer/packer" + "io/ioutil" "log" ) @@ -12,6 +13,7 @@ type StepRunSourceInstance struct { ExpectedRootDevice string InstanceType string UserData string + UserDataFile string SourceAMI string IamInstanceProfile string SubnetId string @@ -25,11 +27,22 @@ func (s *StepRunSourceInstance) Run(state map[string]interface{}) multistep.Step securityGroupId := state["securityGroupId"].(string) ui := state["ui"].(packer.Ui) + userData := s.UserData + if s.UserDataFile != "" { + contents, err := ioutil.ReadFile(s.UserDataFile) + if err != nil { + state["error"] = fmt.Errorf("Problem reading user data file: %s", err) + return multistep.ActionHalt + } + + userData = string(contents) + } + runOpts := &ec2.RunInstances{ KeyName: keyName, ImageId: s.SourceAMI, InstanceType: s.InstanceType, - UserData: []byte(s.UserData), + UserData: []byte(userData), MinCount: 0, MaxCount: 0, SecurityGroups: []ec2.SecurityGroup{ec2.SecurityGroup{Id: securityGroupId}},