diff --git a/cmd/moby/docker.go b/cmd/moby/docker.go index 4bd4af5fd..a83ee766c 100644 --- a/cmd/moby/docker.go +++ b/cmd/moby/docker.go @@ -20,91 +20,89 @@ import ( "golang.org/x/net/context" ) -func dockerRun(args ...string) ([]byte, error) { - log.Debugf("docker run: %s", strings.Join(args, " ")) - docker, err := exec.LookPath("docker") - if err != nil { - return []byte{}, errors.New("Docker does not seem to be installed") - } - args = append([]string{"run", "--rm", "--log-driver=none"}, args...) - cmd := exec.Command(docker, args...) +func dockerRunInput(input io.Reader, image string, args ...string) ([]byte, error) { + log.Debugf("docker run (input): %s %s", image, strings.Join(args, " ")) - stderrPipe, err := cmd.StderrPipe() + cli, err := dockerClient() + if err != nil { + return []byte{}, errors.New("could not initialize Docker API client") + } + + origStdin := os.Stdin + defer func() { + os.Stdin = origStdin + }() + + // write input to a file + rawInput, err := ioutil.ReadAll(input) + if err != nil { + return []byte{}, errors.New("could not read input") + } + tmpInputFileName := "tmpInput" + if err := ioutil.WriteFile(tmpInputFileName, rawInput, 0644); err != nil { + return []byte{}, errors.New("could not stage input to file") + } + inputFile, err := os.Open(tmpInputFileName) + if err != nil { + return []byte{}, errors.New("could not open input file for container stdin") + } + defer os.Remove(tmpInputFileName) + + os.Stdin = inputFile + + var resp container.ContainerCreateCreatedBody + resp, err = cli.ContainerCreate(context.Background(), &container.Config{ + Image: image, + Cmd: args, + AttachStdout: true, + AttachStdin: true, + }, &container.HostConfig{ + AutoRemove: true, + LogConfig: container.LogConfig{Type: "none"}, + }, nil, "") + if err != nil { + // if the image wasn't found, try to do a pull and another create + if client.IsErrNotFound(err) { + if err := dockerPull(image, false); err != nil { + return []byte{}, err + } + resp, err = cli.ContainerCreate(context.Background(), &container.Config{ + Image: image, + Cmd: args, + AttachStdout: true, + AttachStdin: true, + }, &container.HostConfig{ + AutoRemove: true, + LogConfig: container.LogConfig{Type: "none"}, + }, nil, "") + // if we error again, bail + if err != nil { + return []byte{}, err + } + } + return []byte{}, err + } + + hijackedResp, err := cli.ContainerAttach(context.Background(), resp.ID, types.ContainerAttachOptions{ + Stdout: true, + Stdin: true, + Stream: true, + }) if err != nil { return []byte{}, err } - stdoutPipe, err := cmd.StdoutPipe() - if err != nil { + if err := cli.ContainerStart(context.Background(), resp.ID, types.ContainerStartOptions{}); err != nil { return []byte{}, err } - err = cmd.Start() - if err != nil { + if _, err = cli.ContainerWait(context.Background(), resp.ID); err != nil { return []byte{}, err } - stdout, err := ioutil.ReadAll(stdoutPipe) - if err != nil { - return []byte{}, err - } - - stderr, err := ioutil.ReadAll(stderrPipe) - if err != nil { - return []byte{}, err - } - - err = cmd.Wait() - if err != nil { - return []byte{}, fmt.Errorf("%v: %s", err, stderr) - } - - log.Debugf("docker run: %s...Done", strings.Join(args, " ")) - return stdout, nil -} - -func dockerRunInput(input io.Reader, args ...string) ([]byte, error) { - log.Debugf("docker run (input): %s", strings.Join(args, " ")) - docker, err := exec.LookPath("docker") - if err != nil { - return []byte{}, errors.New("Docker does not seem to be installed") - } - args = append([]string{"run", "--rm", "-i"}, args...) - cmd := exec.Command(docker, args...) - cmd.Stdin = input - - stderrPipe, err := cmd.StderrPipe() - if err != nil { - return []byte{}, err - } - - stdoutPipe, err := cmd.StdoutPipe() - if err != nil { - return []byte{}, err - } - - err = cmd.Start() - if err != nil { - return []byte{}, err - } - - stdout, err := ioutil.ReadAll(stdoutPipe) - if err != nil { - return []byte{}, err - } - - stderr, err := ioutil.ReadAll(stderrPipe) - if err != nil { - return []byte{}, err - } - - err = cmd.Wait() - if err != nil { - return []byte{}, fmt.Errorf("%v: %s", err, stderr) - } - + out, _ := ioutil.ReadAll(hijackedResp.Reader) log.Debugf("docker run (input): %s...Done", strings.Join(args, " ")) - return stdout, nil + return out, nil } func dockerCreate(image string) (string, error) { diff --git a/cmd/moby/output.go b/cmd/moby/output.go index c2f05a0b8..9838304d0 100644 --- a/cmd/moby/output.go +++ b/cmd/moby/output.go @@ -110,7 +110,7 @@ func outputImg(image, filename string, kernel []byte, initrd []byte, args ...str if err != nil { return err } - img, err := dockerRunInput(buf, append([]string{image}, args...)...) + img, err := dockerRunInput(buf, image, args...) if err != nil { return err } @@ -128,7 +128,7 @@ func outputISO(image, filename string, kernel []byte, initrd []byte, args ...str if err != nil { return err } - iso, err := dockerRunInput(buf, append([]string{image}, args...)...) + iso, err := dockerRunInput(buf, image, args...) if err != nil { return err }