Do nothing if we detect destination is a directory

We can't modify the destination path in the communicator because it
breaks assumptions in the provisioners. For example, we try to chmod in
the shell provisioner. The chmod command uses the path as supplied by
the user. If the communicator decides to rewrite the path, the
provisioner doesn't know that, and so tries to chmod the wrong thing.

The best we can do is detect that the destination is a directory and
fail.

Also correctly surface output from sftp uploader.
This commit is contained in:
Matthew Hooker 2018-03-20 16:29:09 -07:00
parent 732a532d0e
commit c5e0710a9a
No known key found for this signature in database
GPG Key ID: 7B5F933D9CE8C6A1
1 changed files with 17 additions and 22 deletions

View File

@ -413,11 +413,9 @@ func (c *comm) sftpUploadFile(path string, input io.Reader, client *sftp.Client,
// find out if destination is a directory (this is to replicate rsync behavior) // find out if destination is a directory (this is to replicate rsync behavior)
testDirectoryCommand := fmt.Sprintf(`test -d "%s"`, path) testDirectoryCommand := fmt.Sprintf(`test -d "%s"`, path)
var stdout, stderr bytes.Buffer
cmd := &packer.RemoteCmd{ cmd := &packer.RemoteCmd{
Command: testDirectoryCommand, Command: testDirectoryCommand,
Stdout: &stdout,
Stderr: &stderr,
} }
err := c.Start(cmd) err := c.Start(cmd)
@ -427,18 +425,10 @@ func (c *comm) sftpUploadFile(path string, input io.Reader, client *sftp.Client,
return err return err
} }
cmd.Wait() cmd.Wait()
if stdout.Len() > 0 {
return fmt.Errorf("%s", stdout.Bytes())
}
if stderr.Len() > 0 {
return fmt.Errorf("%s", stderr.Bytes())
}
if cmd.ExitStatus == 0 { if cmd.ExitStatus == 0 {
if fi == nil { return fmt.Errorf(
return fmt.Errorf("Upload path is a directory, unable to continue.") "Destination path (%s) is a directory that already exists. "+
} "Please ensure the destination is writable.", path)
log.Printf("path is a directory; copying file into directory.")
path = filepath.Join(path, filepath.Base((*fi).Name()))
} }
f, err := client.Create(path) f, err := client.Create(path)
@ -553,7 +543,7 @@ func (c *comm) sftpDownloadSession(path string, output io.Writer) error {
func (c *comm) sftpSession(f func(*sftp.Client) error) error { func (c *comm) sftpSession(f func(*sftp.Client) error) error {
client, err := c.newSftpClient() client, err := c.newSftpClient()
if err != nil { if err != nil {
return err return fmt.Errorf("sftpSession error: %s", err.Error())
} }
defer client.Close() defer client.Close()
@ -579,7 +569,15 @@ func (c *comm) newSftpClient() (*sftp.Client, error) {
return nil, err return nil, err
} }
return sftp.NewClientPipe(pr, pw) // Capture stdout so we can return errors to the user
var stdout bytes.Buffer
tee := io.TeeReader(pr, &stdout)
client, err := sftp.NewClientPipe(tee, pw)
if err != nil && stdout.Len() > 0 {
log.Printf("[ERROR] Upload failed: %s", stdout.Bytes())
}
return client, err
} }
func (c *comm) scpUploadSession(path string, input io.Reader, fi *os.FileInfo) error { func (c *comm) scpUploadSession(path string, input io.Reader, fi *os.FileInfo) error {
@ -611,12 +609,9 @@ func (c *comm) scpUploadSession(path string, input io.Reader, fi *os.FileInfo) e
return fmt.Errorf("%s", stderr.Bytes()) return fmt.Errorf("%s", stderr.Bytes())
} }
if cmd.ExitStatus == 0 { if cmd.ExitStatus == 0 {
if fi == nil { return fmt.Errorf(
return fmt.Errorf("Upload path is a directory, unable to continue.") "Destination path (%s) is a directory that already exists. "+
} "Please ensure the destination is writable.", path)
log.Printf("path is a directory; copying file into directory.")
target_dir = path
target_file = filepath.Base((*fi).Name())
} }
// On windows, filepath.Dir uses backslash separators (ie. "\tmp"). // On windows, filepath.Dir uses backslash separators (ie. "\tmp").