Use Docker API for run

Signed-off-by: Riyaz Faizullabhoy <riyaz.faizullabhoy@docker.com>
This commit is contained in:
Riyaz Faizullabhoy 2017-04-28 09:46:18 -07:00
parent d504afe479
commit ec6fea1d67
2 changed files with 73 additions and 75 deletions

View File

@ -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) {

View File

@ -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
}