From 4e78b87c6f1bd198ceb847807d97fd93c671dc98 Mon Sep 17 00:00:00 2001 From: Suraj Deshmukh Date: Sun, 17 Jun 2018 00:11:43 +0530 Subject: [PATCH] create a new docker-daemon fetcher --- rkt/image/docker-daemon-fetcher.go | 111 +++++++++++++++++++++++++++++ rkt/image/fetcher.go | 59 ++------------- 2 files changed, 115 insertions(+), 55 deletions(-) diff --git a/rkt/image/docker-daemon-fetcher.go b/rkt/image/docker-daemon-fetcher.go index 1da0d734f0..4266452805 100644 --- a/rkt/image/docker-daemon-fetcher.go +++ b/rkt/image/docker-daemon-fetcher.go @@ -1 +1,112 @@ package image + +import ( + "context" + "fmt" + "io" + "os" + + docker2aci "github.com/appc/docker2aci/lib" + d2acommon "github.com/appc/docker2aci/lib/common" + dockerCli "github.com/docker/docker/client" +) + +type dockerDaemonFetcher struct { + *Fetcher + ImageName string +} + +func (d *dockerDaemonFetcher) Hash() (string, error) { + // image verification is not supported for docker images so adding this check + // incase the user has forgotten to give such a flag then indicate such + if !d.InsecureFlags.SkipImageCheck() { + return "", fmt.Errorf("signature verification for docker images is not supported (try --insecure-options=image)") + } + + // fetch the image from docker's store as tar file + tarFilePath, tarCleaner, err := d.dockerToTar() + if err != nil { + return "", err + } + defer tarCleaner() + + // convert the tar file into rkt readable ACI format + aciFilePath, aciCleaner, err := d.tarToACI(tarFilePath) + if err != nil { + return "", err + } + defer aciCleaner() + + // now that we have the ACI format image import into rkt store + return d.importToRktStore(aciFilePath) +} + +// dockerToTar fetches the image from docker's store and save it as +// a tar file in temporary place +func (d *dockerDaemonFetcher) dockerToTar() (string, func(), error) { + // create a docker client to interact with docker daemon + cli, err := dockerCli.NewEnvClient() + if err != nil { + return "", nil, fmt.Errorf("creating the docker client: %v", err) + } + + // fetch the image from docker's store + tar, err := cli.ImageSave( + context.Background(), + []string{d.ImageName}, + ) + if err != nil { + return "", nil, fmt.Errorf("fetching the image from docker store: %v", err) + } + defer tar.Close() + + // create a temporary file to copy the tar data we just received + tmpTarFile, err := d.S.TmpFile() + if err != nil { + return "", nil, fmt.Errorf("creating tar file: %v", err) + } + defer tmpTarFile.Close() + + // now copy that tar content into a temporary file + if _, err = io.Copy(tmpTarFile, tar); err != nil { + return "", nil, fmt.Errorf("copying to tar file: %v", err) + } + tmpTarFile.Close() + + path := tmpTarFile.Name() + return path, func() { + os.Remove(path) + }, nil +} + +// tarToACI converts the tar file fetched from docker's store into +// rkt readable ACI image format +func (d *dockerDaemonFetcher) tarToACI(tarFilePath string) (string, func(), error) { + // we will save all the temporary artifacts in this directory + tempDir, err := d.S.TmpDir() + if err != nil { + return "", nil, fmt.Errorf("creating temporary directory: %v", err) + } + + // Now convert that tar file into aci + out, err := docker2aci.ConvertSavedFile(tarFilePath, docker2aci.FileConfig{ + CommonConfig: docker2aci.CommonConfig{ + Squash: true, + OutputDir: tempDir, + TmpDir: tempDir, + Compression: d2acommon.GzipCompression, + }, + }) + if err != nil { + return "", nil, fmt.Errorf("converting tar to aci: %v", err) + } + + return out[0], func() { + os.RemoveAll(tempDir) + }, nil +} + +func (d *dockerDaemonFetcher) importToRktStore(aciFilePath string) (string, error) { + // TODO: implement the way to handle the image security options + return d.fetchSingleImageByPath(aciFilePath, nil) +} diff --git a/rkt/image/fetcher.go b/rkt/image/fetcher.go index 17423137af..8957c034d1 100644 --- a/rkt/image/fetcher.go +++ b/rkt/image/fetcher.go @@ -16,15 +16,11 @@ package image import ( "container/list" - "context" "errors" "fmt" - "io" - "io/ioutil" "net/url" "os" - dockerCli "github.com/docker/docker/client" "github.com/hashicorp/errwrap" "github.com/rkt/rkt/common" "github.com/rkt/rkt/common/apps" @@ -32,7 +28,6 @@ import ( "github.com/rkt/rkt/stage0" "github.com/rkt/rkt/store/imagestore" - docker2aci "github.com/appc/docker2aci/lib" "github.com/appc/spec/discovery" "github.com/appc/spec/schema/types" ) @@ -239,57 +234,11 @@ func (f *Fetcher) fetchSingleImageByDockerURL(d *dist.Docker) (string, error) { } func (f *Fetcher) fetchSingleImageByDockerDaemonURL(d *dist.DockerDaemon) (string, error) { - // the image to export from the docker daemon - imageName := d.ReferenceURL() - imageIDs := []string{imageName} - - // extract the image as tar in temporary directory - cli, err := dockerCli.NewEnvClient() - if err != nil { - return "", fmt.Errorf("could not create the docker client: %v", err) - } - - tar, err := cli.ImageSave(context.Background(), imageIDs) - if err != nil { - return "", fmt.Errorf("could not fetch the image: %v", err) - } - defer tar.Close() - - tmpTarredFile, err := ioutil.TempFile("", "tarred-file") - if err != nil { - return "", fmt.Errorf("failed creating tarred file: %v", err) - } - defer tmpTarredFile.Close() - - if _, err = io.Copy(tmpTarredFile, tar); err != nil { - return "", fmt.Errorf("copying file error: %v", err) + ddf := &dockerDaemonFetcher{ + Fetcher: f, + ImageName: d.ReferenceURL(), } - - tarFilePath := tmpTarredFile.Name() - // delete this file - tmpTarredFile.Close() - - // we will save the aci image - dir, err := ioutil.TempDir("", "convdir") - if err != nil { - log.Fatal(err) - } - fmt.Println("output dir:", dir) - - // Now convert that stringtar file into aci - out, err := docker2aci.ConvertSavedFile(tarFilePath, docker2aci.FileConfig{ - DockerURL: imageName, - CommonConfig: docker2aci.CommonConfig{ - OutputDir: dir, - TmpDir: dir, - }, - }) - if err != nil { - return "", fmt.Errorf("converting tar failed: %v", err) - } - - // Now import that aci into rkt environment - return f.fetchSingleImageByPath(out[0], nil) + return ddf.Hash() } func (f *Fetcher) maybeCheckRemoteFromStore(rem *imagestore.Remote) string {