Return errors from remote scp command

Currently file provisioners will silently fail when there is an error
with the remote side. This commit checks the scp error code and will
return the error message from the remote.
This commit is contained in:
Mark Peek 2013-07-17 18:15:42 -07:00
parent 104178080c
commit a8a53fb0b4
1 changed files with 35 additions and 7 deletions

View File

@ -1,6 +1,7 @@
package ssh package ssh
import ( import (
"bufio"
"bytes" "bytes"
"code.google.com/p/go.crypto/ssh" "code.google.com/p/go.crypto/ssh"
"errors" "errors"
@ -106,12 +107,6 @@ func (c *comm) Upload(path string, input io.Reader) error {
return err return err
} }
// Set stderr/stdout to a bytes buffer
stderr := new(bytes.Buffer)
stdout := new(bytes.Buffer)
session.Stderr = stderr
session.Stdout = stdout
// We only want to close once, so we nil w after we close it, // We only want to close once, so we nil w after we close it,
// and only close in the defer if it hasn't been closed already. // and only close in the defer if it hasn't been closed already.
defer func() { defer func() {
@ -120,6 +115,17 @@ func (c *comm) Upload(path string, input io.Reader) error {
} }
}() }()
// Get a pipe to stdout so that we can get responses back
scp_reader, err := session.StdoutPipe()
if err != nil {
return err
}
r := bufio.NewReader(scp_reader)
// Set stderr to a bytes buffer
stderr := new(bytes.Buffer)
session.Stderr = stderr
// The target directory and file for talking the SCP protocol // The target directory and file for talking the SCP protocol
target_dir := filepath.Dir(path) target_dir := filepath.Dir(path)
target_file := filepath.Base(path) target_file := filepath.Base(path)
@ -143,8 +149,17 @@ func (c *comm) Upload(path string, input io.Reader) error {
// Start the protocol // Start the protocol
log.Println("Beginning file upload...") log.Println("Beginning file upload...")
fmt.Fprintln(w, "C0644", input_memory.Len(), target_file) fmt.Fprintln(w, "C0644", input_memory.Len(), target_file)
err = check_response(r)
if err != nil {
return err
}
io.Copy(w, input_memory) io.Copy(w, input_memory)
fmt.Fprint(w, "\x00") fmt.Fprint(w, "\x00")
err = check_response(r)
if err != nil {
return err
}
// TODO(mitchellh): Each step above results in a 0/1/2 being sent by // TODO(mitchellh): Each step above results in a 0/1/2 being sent by
// the remote side to confirm. We should check for those confirmations. // the remote side to confirm. We should check for those confirmations.
@ -178,7 +193,6 @@ func (c *comm) Upload(path string, input io.Reader) error {
return err return err
} }
log.Printf("scp stdout (length %d): %#v", stdout.Len(), stdout.Bytes())
log.Printf("scp stderr (length %d): %s", stderr.Len(), stderr.String()) log.Printf("scp stderr (length %d): %s", stderr.Len(), stderr.String())
return nil return nil
@ -223,3 +237,17 @@ func (c *comm) reconnect() (err error) {
return return
} }
func check_response(r *bufio.Reader) (err error) {
scp_status_code, err := r.ReadByte()
if err != nil {
return err
}
if scp_status_code != 0 {
// Treat any non-zero (really 1 and 2) as fatal errors
error_message, _, err := r.ReadLine()
err = fmt.Errorf(string(error_message[:]))
return err
}
return nil
}