114 lines
2.5 KiB
Go
114 lines
2.5 KiB
Go
package docker
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/mitchellh/packer/packer"
|
|
"io"
|
|
"io/ioutil"
|
|
"log"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"syscall"
|
|
"time"
|
|
)
|
|
|
|
type Communicator struct {
|
|
ContainerId string
|
|
HostDir string
|
|
ContainerDir string
|
|
}
|
|
|
|
func (c *Communicator) Start(remote *packer.RemoteCmd) error {
|
|
cmd := exec.Command("docker", "attach", c.ContainerId)
|
|
stdin_w, err := cmd.StdinPipe()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// TODO(mitchellh): We need to hijack the command to write the exit
|
|
// code to a temporary file in the shared folder so that we can read it
|
|
// out. Since we're going over a pty, we can't get the exit code another
|
|
// way.
|
|
|
|
cmd.Stdout = remote.Stdout
|
|
cmd.Stderr = remote.Stderr
|
|
|
|
log.Printf("Executing in container %s: %#v", c.ContainerId, remote.Command)
|
|
if err := cmd.Start(); err != nil {
|
|
return err
|
|
}
|
|
|
|
go func() {
|
|
defer stdin_w.Close()
|
|
|
|
// This sleep needs to be here because of the issue linked to below.
|
|
// Basically, without it, Docker will hang on reading stdin forever,
|
|
// and won't see what we write, for some reason.
|
|
//
|
|
// https://github.com/dotcloud/docker/issues/2628
|
|
time.Sleep(2 * time.Second)
|
|
|
|
stdin_w.Write([]byte(remote.Command + "\n"))
|
|
}()
|
|
|
|
var exitStatus int = 0
|
|
err = cmd.Wait()
|
|
if exitErr, ok := err.(*exec.ExitError); ok {
|
|
exitStatus = 1
|
|
|
|
// There is no process-independent way to get the REAL
|
|
// exit status so we just try to go deeper.
|
|
if status, ok := exitErr.Sys().(syscall.WaitStatus); ok {
|
|
exitStatus = status.ExitStatus()
|
|
}
|
|
}
|
|
|
|
// Say that we ended!
|
|
remote.SetExited(exitStatus)
|
|
|
|
return nil
|
|
}
|
|
|
|
func (c *Communicator) Upload(dst string, src io.Reader) error {
|
|
// Create a temporary file to store the upload
|
|
tempfile, err := ioutil.TempFile(c.HostDir, "upload")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer os.Remove(tempfile.Name())
|
|
|
|
// Copy the contents to the temporary file
|
|
_, err = io.Copy(tempfile, src)
|
|
tempfile.Close()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// TODO(mitchellh): Copy the file into place
|
|
cmd := &packer.RemoteCmd{
|
|
Command: fmt.Sprintf("cp %s/%s %s", c.ContainerDir,
|
|
filepath.Base(tempfile.Name()), dst),
|
|
}
|
|
|
|
if err := c.Start(cmd); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Wait for the copy to complete
|
|
cmd.Wait()
|
|
if cmd.ExitStatus != 0 {
|
|
return fmt.Errorf("Upload failed with non-zero exit status: %d", cmd.ExitStatus)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (c *Communicator) UploadDir(dst string, src string, exclude []string) error {
|
|
return nil
|
|
}
|
|
|
|
func (c *Communicator) Download(src string, dst io.Writer) error {
|
|
return nil
|
|
}
|