Seperate remote_path into remote_folder and remote_script. (#3462)

Commonly /tmp is set as noexec, as a result packer scripts
fail to run. In order to get around this one can set a
remote_path, whoever, remote path requires full filename
and path.

By making remote_path a combination of
remote_folder/remote_script we can change remote_folder
and keep the default script_nnn.sh

Signed-off-by: Ian Duffy <ian@ianduffy.ie>
This commit is contained in:
Ian Duffy 2016-04-27 00:04:29 +01:00 committed by Chris Bednarski
parent d296260164
commit 7e653370b7
3 changed files with 157 additions and 5 deletions

View File

@ -44,8 +44,17 @@ type Config struct {
// your command(s) are executed. // your command(s) are executed.
Vars []string `mapstructure:"environment_vars"` Vars []string `mapstructure:"environment_vars"`
// The remote folder where the local shell script will be uploaded to.
// This should be set to a pre-existing directory, it defaults to /tmp
RemoteFolder string `mapstructure:"remote_folder"`
// The remote file name of the local shell script.
// This defaults to script_nnn.sh
RemoteFile string `mapstructure:"remote_file"`
// The remote path where the local shell script will be uploaded to. // The remote path where the local shell script will be uploaded to.
// This should be set to a writable file that is in a pre-existing directory. // This should be set to a writable file that is in a pre-existing directory.
// This defaults to remote_folder/remote_file
RemotePath string `mapstructure:"remote_path"` RemotePath string `mapstructure:"remote_path"`
// The command used to execute the script. The '{{ .Path }}' variable // The command used to execute the script. The '{{ .Path }}' variable
@ -104,9 +113,17 @@ func (p *Provisioner) Prepare(raws ...interface{}) error {
p.config.RawStartRetryTimeout = "5m" p.config.RawStartRetryTimeout = "5m"
} }
if p.config.RemoteFolder == "" {
p.config.RemoteFolder = "/tmp"
}
if p.config.RemoteFile == "" {
p.config.RemoteFile = fmt.Sprintf("script_%d.sh", rand.Intn(9999))
}
if p.config.RemotePath == "" { if p.config.RemotePath == "" {
p.config.RemotePath = fmt.Sprintf( p.config.RemotePath = fmt.Sprintf(
"/tmp/script_%d.sh", rand.Intn(9999)) "%s/%s", p.config.RemoteFolder, p.config.RemoteFile)
} }
if p.config.Scripts == nil { if p.config.Scripts == nil {

View File

@ -5,6 +5,8 @@ import (
"io/ioutil" "io/ioutil"
"os" "os"
"testing" "testing"
"strings"
"regexp"
) )
func testConfig() map[string]interface{} { func testConfig() map[string]interface{} {
@ -217,3 +219,131 @@ func TestProvisionerQuote_EnvironmentVars(t *testing.T) {
t.Fatalf("%s should be equal to %s", p.config.Vars[1], expectedValue) t.Fatalf("%s should be equal to %s", p.config.Vars[1], expectedValue)
} }
} }
func TestProvisioner_RemoteFolderSetSuccessfully(t *testing.T) {
config := testConfig()
expectedRemoteFolder := "/example/path"
config["remote_folder"] = expectedRemoteFolder
p := new(Provisioner)
err := p.Prepare(config)
if err != nil {
t.Fatalf("should not have error: %s", err)
}
if !strings.Contains(p.config.RemotePath, expectedRemoteFolder) {
t.Fatalf("remote path does not contain remote_folder")
}
}
func TestProvisioner_RemoteFolderDefaultsToTmp(t *testing.T) {
config := testConfig()
p := new(Provisioner)
err := p.Prepare(config)
if err != nil {
t.Fatalf("should not have error: %s", err)
}
if p.config.RemoteFolder != "/tmp" {
t.Fatalf("remote_folder did not default to /tmp")
}
if !strings.Contains(p.config.RemotePath, "/tmp") {
t.Fatalf("remote path does not contain remote_folder")
}
}
func TestProvisioner_RemoteFileSetSuccessfully(t *testing.T) {
config := testConfig()
expectedRemoteFile := "example.sh"
config["remote_file"] = expectedRemoteFile
p := new(Provisioner)
err := p.Prepare(config)
if err != nil {
t.Fatalf("should not have error: %s", err)
}
if !strings.Contains(p.config.RemotePath, expectedRemoteFile) {
t.Fatalf("remote path does not contain remote_file")
}
}
func TestProvisioner_RemoteFileDefaultsToScriptnnnn(t *testing.T) {
config := testConfig()
p := new(Provisioner)
err := p.Prepare(config)
if err != nil {
t.Fatalf("should not have error: %s", err)
}
remoteFileRegex := regexp.MustCompile("script_[0-9]{4}.sh")
if !remoteFileRegex.MatchString(p.config.RemoteFile) {
t.Fatalf("remote_file did not default to script_nnnn.sh")
}
if !remoteFileRegex.MatchString(p.config.RemotePath) {
t.Fatalf("remote_path did not match script_nnnn.sh")
}
}
func TestProvisioner_RemotePathSetViaRemotePathAndRemoteFile(t *testing.T) {
config := testConfig()
expectedRemoteFile := "example.sh"
expectedRemoteFolder := "/example/path"
config["remote_file"] = expectedRemoteFile
config["remote_folder"] = expectedRemoteFolder
p := new(Provisioner)
err := p.Prepare(config)
if err != nil {
t.Fatalf("should not have error: %s", err)
}
if p.config.RemotePath != expectedRemoteFolder + "/" + expectedRemoteFile {
t.Fatalf("remote path does not contain remote_file")
}
}
func TestProvisioner_RemotePathOverridesRemotePathAndRemoteFile(t *testing.T) {
config := testConfig()
expectedRemoteFile := "example.sh"
expectedRemoteFolder := "/example/path"
expectedRemotePath := "/example/remote/path/script.sh"
config["remote_file"] = expectedRemoteFile
config["remote_folder"] = expectedRemoteFolder
config["remote_path"] = expectedRemotePath
p := new(Provisioner)
err := p.Prepare(config)
if err != nil {
t.Fatalf("should not have error: %s", err)
}
if p.config.RemotePath != expectedRemotePath {
t.Fatalf("remote path does not contain remote_path")
}
}
func TestProvisionerRemotePathDefaultsSuccessfully(t *testing.T) {
config := testConfig()
p := new(Provisioner)
err := p.Prepare(config)
if err != nil {
t.Fatalf("should not have error: %s", err)
}
remotePathRegex := regexp.MustCompile("/tmp/script_[0-9]{4}.sh")
if !remotePathRegex.MatchString(p.config.RemotePath) {
t.Fatalf("remote path does not match the expected default regex")
}
}

View File

@ -78,10 +78,15 @@ Optional parameters:
**Important:** If you customize this, be sure to include something like the **Important:** If you customize this, be sure to include something like the
`-e` flag, otherwise individual steps failing won't fail the provisioner. `-e` flag, otherwise individual steps failing won't fail the provisioner.
- `remote_path` (string) - The filename where the script will be uploaded - `remote_folder` (string) - The folder where the uploaded script will reside on
to in the machine. This defaults to `/tmp/script_nnn.sh` where "nnn" is the machine. This defaults to '/tmp'.
a randomly generated number. This value must be a writable location and
any parent directories must already exist. - `remote_file` (string) - The filename the uploaded script will have on the machine.
This defaults to 'script_nnn.sh'.
- `remote_path` (string) - The full path to the uploaded script will have on the
machine. By default this is remote_folder/remote_file, if set this option will
override both remote_folder and remote_file.
- `skip_clean` (boolean) - If true, specifies that the helper scripts - `skip_clean` (boolean) - If true, specifies that the helper scripts
uploaded to the system will not be removed by Packer. This defaults to uploaded to the system will not be removed by Packer. This defaults to