Skip to content

Instantly share code, notes, and snippets.

@pwaller
Last active October 20, 2016 15:58
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pwaller/314c7591a8bfd32f8999 to your computer and use it in GitHub Desktop.
Save pwaller/314c7591a8bfd32f8999 to your computer and use it in GitHub Desktop.
Dockerclient binary stdout bug
package main
import (
"fmt"
"io"
"log"
"os"
docker "github.com/fsouza/go-dockerclient"
)
func main() {
if len(os.Args) < 2 {
log.Fatal("usage: t <docker image> [args]")
}
imageName := os.Args[1]
c, err := docker.NewClient("unix:///run/docker.sock")
if err != nil {
log.Println("Connecting to Docker failed:", err)
return
}
r, err := DockerRun(c, imageName, os.Args[2:])
defer func() {
err := r.Close()
if err != nil {
log.Printf("r.Close(): %v", err)
}
}()
n, err := io.Copy(os.Stdout, r)
log.Printf("io.Copy: %v, %v", n, err)
}
func DockerRun(c *docker.Client, imageName string, args []string) (io.ReadCloser, error) {
log.Printf("Create container...")
cont, err := c.CreateContainer(docker.CreateContainerOptions{
Config: &docker.Config{
AttachStdout: true,
AttachStderr: true,
Image: imageName,
Cmd: args,
},
})
if err != nil {
log.Printf("Create container... failed: %v", err)
return nil, err
}
attached := make(chan struct{})
r, w := io.Pipe()
go func() {
log.Printf("AttachToContainer")
err := c.AttachToContainer(docker.AttachToContainerOptions{
Container: cont.ID,
OutputStream: &WriteMonitor{w},
ErrorStream: os.Stderr,
Logs: true,
Stdout: true,
Stderr: true,
Stream: true,
Success: attached,
})
log.Printf("~AttachToContainer")
// io.Pipe hardwired to never return error here.
_ = w.CloseWithError(err)
}()
<-attached
attached <- struct{}{}
log.Printf("Start container...")
err = c.StartContainer(cont.ID, &docker.HostConfig{})
if err != nil {
log.Printf("Start container... failed: %v", err)
return nil, err
}
removeContainer := func() {
err := c.RemoveContainer(docker.RemoveContainerOptions{
ID: cont.ID,
RemoveVolumes: true,
Force: true,
})
if err != nil {
log.Printf("Error removing intermediate container: %v", err)
}
}
log.Printf("DockerRun returned")
return struct {
io.Reader
io.Closer
}{
Reader: r,
Closer: CloseFunc(func() error {
defer removeContainer()
log.Printf("Wait")
status, err := c.WaitContainer(cont.ID)
if err != nil {
return err
}
if status != 0 {
return fmt.Errorf("non-zero exit status: %v", err)
}
return nil
}),
}, err
}
type WriteMonitor struct{ io.Writer }
func (w *WriteMonitor) Write(bs []byte) (int, error) {
n, err := w.Writer.Write(bs)
log.Printf("Write() (%v, %v)", n, err)
return n, err
}
type CloseFunc func() error
func (fn CloseFunc) Close() error { return fn() }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment