From de8666a5fa5e82a682d556f3acab53972c3a2c25 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sat, 18 Apr 2015 16:07:11 -0700 Subject: [PATCH] helper/ssh: add random number to script [GH-1545] --- .../remote-exec/resource_provisioner.go | 8 +++-- helper/ssh/provisioner.go | 11 ++++++- helper/ssh/provisioner_test.go | 30 +++++++++++++++++++ 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/builtin/provisioners/remote-exec/resource_provisioner.go b/builtin/provisioners/remote-exec/resource_provisioner.go index 046e0e860cfb..a4c169b2274f 100644 --- a/builtin/provisioners/remote-exec/resource_provisioner.go +++ b/builtin/provisioners/remote-exec/resource_provisioner.go @@ -213,11 +213,13 @@ func (p *ResourceProvisioner) runScripts( go p.copyOutput(o, errR, errDoneCh) err := retryFunc(conf.TimeoutVal, func() error { - if err := comm.Upload(conf.ScriptPath, script); err != nil { + remotePath := conf.RemotePath() + + if err := comm.Upload(remotePath, script); err != nil { return fmt.Errorf("Failed to upload script: %v", err) } cmd = &helper.RemoteCmd{ - Command: fmt.Sprintf("chmod 0777 %s", conf.ScriptPath), + Command: fmt.Sprintf("chmod 0777 %s", remotePath), } if err := comm.Start(cmd); err != nil { return fmt.Errorf( @@ -227,7 +229,7 @@ func (p *ResourceProvisioner) runScripts( cmd.Wait() cmd = &helper.RemoteCmd{ - Command: conf.ScriptPath, + Command: remotePath, Stdout: outW, Stderr: errW, } diff --git a/helper/ssh/provisioner.go b/helper/ssh/provisioner.go index bf8f526373d6..69468de7dbaf 100644 --- a/helper/ssh/provisioner.go +++ b/helper/ssh/provisioner.go @@ -5,8 +5,11 @@ import ( "fmt" "io/ioutil" "log" + "math/rand" "net" "os" + "strconv" + "strings" "time" "github.com/hashicorp/terraform/terraform" @@ -25,7 +28,7 @@ const ( // DefaultScriptPath is used as the path to copy the file to // for remote execution if not provided otherwise. - DefaultScriptPath = "/tmp/script.sh" + DefaultScriptPath = "/tmp/script_%RAND%.sh" // DefaultTimeout is used if there is no timeout given DefaultTimeout = 5 * time.Minute @@ -46,6 +49,12 @@ type SSHConfig struct { TimeoutVal time.Duration `mapstructure:"-"` } +func (c *SSHConfig) RemotePath() string { + return strings.Replace( + c.ScriptPath, "%RAND%", + strconv.FormatInt(int64(rand.Int31()), 10), -1) +} + // VerifySSH is used to verify the ConnInfo is usable by remote-exec func VerifySSH(s *terraform.InstanceState) error { connType := s.Ephemeral.ConnInfo["type"] diff --git a/helper/ssh/provisioner_test.go b/helper/ssh/provisioner_test.go index 54f2a5ff6d71..4559a4f20e00 100644 --- a/helper/ssh/provisioner_test.go +++ b/helper/ssh/provisioner_test.go @@ -1,11 +1,41 @@ package ssh import ( + "regexp" "testing" "github.com/hashicorp/terraform/terraform" ) +func TestSSHConfig_RemotePath(t *testing.T) { + cases := []struct { + Input string + Pattern string + }{ + { + "/tmp/script.sh", + `^/tmp/script\.sh$`, + }, + { + "/tmp/script_%RAND%.sh", + `^/tmp/script_(\d+)\.sh$`, + }, + } + + for _, tc := range cases { + config := &SSHConfig{ScriptPath: tc.Input} + output := config.RemotePath() + + match, err := regexp.Match(tc.Pattern, []byte(output)) + if err != nil { + t.Fatalf("bad: %s\n\nerr: %s", tc.Input, err) + } + if !match { + t.Fatalf("bad: %s\n\n%s", tc.Input, output) + } + } +} + func TestResourceProvider_verifySSH(t *testing.T) { r := &terraform.InstanceState{ Ephemeral: terraform.EphemeralState{