Files
linuxkit/cmd/moby/docker.go
Riyaz Faizullabhoy abf0028ee8 Use docker and notary API for pull
Signed-off-by: Riyaz Faizullabhoy <riyaz.faizullabhoy@docker.com>
2017-05-11 10:11:19 -07:00

215 lines
5.5 KiB
Go

package main
// We want to replace much of this with use of containerd tools
// and also using the Docker API not shelling out
import (
"bytes"
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"strings"
log "github.com/Sirupsen/logrus"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/client"
"golang.org/x/net/context"
)
func dockerRunInput(input io.Reader, image string, args ...string) ([]byte, error) {
log.Debugf("docker run (input): %s %s", image, strings.Join(args, " "))
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
}
if err := cli.ContainerStart(context.Background(), resp.ID, types.ContainerStartOptions{}); err != nil {
return []byte{}, err
}
if _, err = cli.ContainerWait(context.Background(), resp.ID); err != nil {
return []byte{}, err
}
out, _ := ioutil.ReadAll(hijackedResp.Reader)
log.Debugf("docker run (input): %s...Done", strings.Join(args, " "))
return out, nil
}
func dockerCreate(image string) (string, error) {
log.Debugf("docker create: %s", image)
cli, err := dockerClient()
if err != nil {
return "", errors.New("could not initialize Docker API client")
}
// we do not ever run the container, so /dev/null is used as command
config := &container.Config{
Cmd: []string{"/dev/null"},
Image: image,
}
respBody, err := cli.ContainerCreate(context.Background(), config, nil, nil, "")
if err != nil {
return "", err
}
log.Debugf("docker create: %s...Done", image)
return respBody.ID, nil
}
func dockerExport(container string) ([]byte, error) {
log.Debugf("docker export: %s", container)
cli, err := dockerClient()
if err != nil {
return []byte{}, errors.New("could not initialize Docker API client")
}
responseBody, err := cli.ContainerExport(context.Background(), container)
if err != nil {
return []byte{}, err
}
defer responseBody.Close()
output := bytes.NewBuffer(nil)
_, err = io.Copy(output, responseBody)
if err != nil {
return []byte{}, err
}
return output.Bytes(), nil
}
func dockerRm(container string) error {
log.Debugf("docker rm: %s", container)
cli, err := dockerClient()
if err != nil {
return errors.New("could not initialize Docker API client")
}
if err = cli.ContainerRemove(context.Background(), container, types.ContainerRemoveOptions{}); err != nil {
return err
}
log.Debugf("docker rm: %s...Done", container)
return nil
}
func dockerPull(image string, trustedPull bool) error {
log.Debugf("docker pull: %s", image)
if trustedPull {
log.Debugf("pulling %s with content trust", image)
trustedImg, err := TrustedReference(image)
if err != nil {
return fmt.Errorf("Trusted pull for %s failed: %v", image, err)
}
image = trustedImg.String()
}
cli, err := dockerClient()
if err != nil {
return errors.New("could not initialize Docker API client")
}
if _, err := cli.ImagePull(context.Background(), image, types.ImagePullOptions{}); err != nil {
return err
}
log.Debugf("docker pull: %s...Done", image)
return nil
}
func dockerClient() (*client.Client, error) {
// for maximum compatibility as we use nothing new
err := os.Setenv("DOCKER_API_VERSION", "1.23")
if err != nil {
return nil, err
}
return client.NewEnvClient()
}
func dockerInspectImage(cli *client.Client, image string) (types.ImageInspect, error) {
log.Debugf("docker inspect image: %s", image)
inspect, _, err := cli.ImageInspectWithRaw(context.Background(), image)
if err != nil {
if client.IsErrImageNotFound(err) {
pullErr := dockerPull(image, false)
if pullErr != nil {
return types.ImageInspect{}, pullErr
}
inspect, _, err = cli.ImageInspectWithRaw(context.Background(), image)
if err != nil {
return types.ImageInspect{}, err
}
} else {
return types.ImageInspect{}, err
}
}
log.Debugf("docker inspect image: %s...Done", image)
return inspect, nil
}