Commit d8ad9ca1 authored by Mitchell Hashimoto's avatar Mitchell Hashimoto

communicator/ssh: A first pass at SCP uploading

parent 35a947e3
......@@ -3,10 +3,12 @@ package ssh
import (
"bytes"
"code.google.com/p/go.crypto/ssh"
"fmt"
"github.com/mitchellh/packer/packer"
"io"
"log"
"net"
"path/filepath"
)
type comm struct {
......@@ -72,7 +74,64 @@ func (c *comm) Start(cmd string) (remote *packer.RemoteCommand, err error) {
return
}
func (c *comm) Upload(string, io.Reader) error {
func (c *comm) Upload(path string, input io.Reader) error {
session, err := c.client.NewSession()
if err != nil {
return err
}
defer session.Close()
// Get a pipe to stdin so that we can send data down
w, err := session.StdinPipe()
if err != nil {
return err
}
// 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.
defer func() {
if w != nil {
w.Close()
}
}()
// The target directory and file for talking the SCP protocol
target_dir := filepath.Dir(path)
target_file := filepath.Base(path)
// Start the sink mode on the other side
// TODO(mitchellh): There are probably issues with shell escaping the path
log.Println("Starting remote scp process in sink mode")
if err = session.Start("scp -t " + target_dir); err != nil {
return err
}
// Determine the length of the upload content by copying it
// into an in-memory buffer. Note that this means what we upload
// must fit into memory.
log.Println("Copying input data into in-memory buffer so we can get the length")
input_memory := new(bytes.Buffer)
if _, err = io.Copy(input_memory, input); err != nil {
return err
}
// Start the protocol
fmt.Fprintln(w, "C0644", input_memory.Len(), target_file)
io.Copy(w, input_memory)
// Close the stdin, which sends an EOF, and then set w to nil so that
// our defer func doesn't close it again since that is unsafe with
// the Go SSH package.
w.Close()
w = nil
// Wait for the SCP connection to close, meaning it has consumed all
// our data and has completed. Or has errored.
session.Wait()
// TODO(mitchellh): Check for return data (expect a 0 or error)
return nil
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment