From ad83cb892880af9eb5a048f0d5bd708eac3567e0 Mon Sep 17 00:00:00 2001 From: Rolf Neugebauer Date: Wed, 4 Oct 2017 17:37:22 +0100 Subject: [PATCH] Use containerd reference.Spec in place of the Image string Instead of passing the image name as string use the a reference to a containerd reference.Spec. This allows us, for example, to update the reference in place when verifying content trust with more specific information, such as the sha256 Signed-off-by: Rolf Neugebauer --- src/moby/build.go | 13 ++++++------- src/moby/config.go | 2 +- src/moby/docker.go | 38 ++++++++++++++++++++++---------------- src/moby/image.go | 43 ++++++++++++++++++++++--------------------- 4 files changed, 51 insertions(+), 45 deletions(-) diff --git a/src/moby/build.go b/src/moby/build.go index b94ef68ca..9b5da1a9d 100644 --- a/src/moby/build.go +++ b/src/moby/build.go @@ -134,7 +134,7 @@ func outputImage(image *Image, section string, prefix string, m Moby, idMap map[ } path := path.Join("containers", section, prefix+image.Name) readonly := oci.Root.Readonly - err = ImageBundle(path, image.Image, config, runtime, iw, useTrust, pull, readonly, dupMap) + err = ImageBundle(path, image.ref, config, runtime, iw, useTrust, pull, readonly, dupMap) if err != nil { return fmt.Errorf("Failed to extract root filesystem for %s: %v", image.Image, err) } @@ -171,11 +171,11 @@ func Build(m Moby, w io.Writer, pull bool, tp string) error { // deduplicate containers with the same image dupMap := map[string]string{} - if m.Kernel.Image != "" { + if m.Kernel.ref != nil { // get kernel and initrd tarball from container - log.Infof("Extract kernel image: %s", m.Kernel.Image) + log.Infof("Extract kernel image: %s", m.Kernel.ref) kf := newKernelFilter(iw, m.Kernel.Cmdline, m.Kernel.Binary, m.Kernel.Tar) - err := ImageTar(m.Kernel.Image, "", kf, enforceContentTrust(m.Kernel.Image, &m.Trust), pull, "") + err := ImageTar(m.Kernel.ref, "", kf, enforceContentTrust(m.Kernel.ref.String(), &m.Trust), pull, "") if err != nil { return fmt.Errorf("Failed to extract kernel image and tarball: %v", err) } @@ -189,9 +189,8 @@ func Build(m Moby, w io.Writer, pull bool, tp string) error { if len(m.Init) != 0 { log.Infof("Add init containers:") } - for _, ii := range m.Init { - log.Infof("Process init image: %s", ii) - err := ImageTar(ii, "", iw, enforceContentTrust(ii, &m.Trust), pull, resolvconfSymlink) + for _, ii := range m.initRefs { + err := ImageTar(ii, "", iw, enforceContentTrust(ii.String(), &m.Trust), pull, resolvconfSymlink) if err != nil { return fmt.Errorf("Failed to build init tarball from %s: %v", ii, err) } diff --git a/src/moby/config.go b/src/moby/config.go index 5d16e514e..13a0cb0dc 100644 --- a/src/moby/config.go +++ b/src/moby/config.go @@ -351,7 +351,7 @@ func ConfigToOCI(image *Image, trust bool, idMap map[string]uint32) (specs.Spec, if err != nil { return specs.Spec{}, Runtime{}, err } - inspect, err := dockerInspectImage(cli, image.Image, trust) + inspect, err := dockerInspectImage(cli, image.ref, trust) if err != nil { return specs.Spec{}, Runtime{}, err } diff --git a/src/moby/docker.go b/src/moby/docker.go index 81e24fc9c..e00be6f62 100644 --- a/src/moby/docker.go +++ b/src/moby/docker.go @@ -14,6 +14,7 @@ import ( "strings" log "github.com/Sirupsen/logrus" + "github.com/containerd/containerd/reference" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/filters" @@ -97,18 +98,18 @@ func dockerRm(container string) error { return nil } -func dockerPull(image string, forcePull, trustedPull bool) error { - log.Debugf("docker pull: %s", image) +func dockerPull(ref *reference.Spec, forcePull, trustedPull bool) error { + log.Debugf("docker pull: %s", ref) cli, err := dockerClient() if err != nil { return errors.New("could not initialize Docker API client") } if trustedPull { - log.Debugf("pulling %s with content trust", image) - trustedImg, err := TrustedReference(image) + log.Debugf("pulling %s with content trust", ref) + trustedImg, err := TrustedReference(ref.String()) if err != nil { - return fmt.Errorf("Trusted pull for %s failed: %v", image, err) + return fmt.Errorf("Trusted pull for %s failed: %v", ref, err) } // tag the image on a best-effort basis after pulling with content trust, @@ -117,10 +118,15 @@ func dockerPull(image string, forcePull, trustedPull bool) error { if err := cli.ImageTag(context.Background(), src, dst); err != nil { log.Debugf("could not tag trusted image %s to %s", src, dst) } - }(trustedImg.String(), image) + }(trustedImg.String(), ref.String()) log.Debugf("successfully verified trusted reference %s from notary", trustedImg.String()) - image = trustedImg.String() + trustedSpec, err := reference.Parse(trustedImg.String()) + if err != nil { + return fmt.Errorf("failed to convert trusted img %s to Spec: %v", trustedImg, err) + } + ref.Locator = trustedSpec.Locator + ref.Object = trustedSpec.Object imageSearchArg := filters.NewArgs() imageSearchArg.Add("reference", trustedImg.String()) @@ -130,8 +136,8 @@ func dockerPull(image string, forcePull, trustedPull bool) error { } } - log.Infof("Pull image: %s", image) - r, err := cli.ImagePull(context.Background(), image, types.ImagePullOptions{}) + log.Infof("Pull image: %s", ref) + r, err := cli.ImagePull(context.Background(), ref.String(), types.ImagePullOptions{}) if err != nil { return err } @@ -140,7 +146,7 @@ func dockerPull(image string, forcePull, trustedPull bool) error { if err != nil { return err } - log.Debugf("docker pull: %s...Done", image) + log.Debugf("docker pull: %s...Done", ref) return nil } @@ -153,17 +159,17 @@ func dockerClient() (*client.Client, error) { return client.NewEnvClient() } -func dockerInspectImage(cli *client.Client, image string, trustedPull bool) (types.ImageInspect, error) { - log.Debugf("docker inspect image: %s", image) +func dockerInspectImage(cli *client.Client, ref *reference.Spec, trustedPull bool) (types.ImageInspect, error) { + log.Debugf("docker inspect image: %s", ref) - inspect, _, err := cli.ImageInspectWithRaw(context.Background(), image) + inspect, _, err := cli.ImageInspectWithRaw(context.Background(), ref.String()) if err != nil { if client.IsErrImageNotFound(err) { - pullErr := dockerPull(image, true, trustedPull) + pullErr := dockerPull(ref, true, trustedPull) if pullErr != nil { return types.ImageInspect{}, pullErr } - inspect, _, err = cli.ImageInspectWithRaw(context.Background(), image) + inspect, _, err = cli.ImageInspectWithRaw(context.Background(), ref.String()) if err != nil { return types.ImageInspect{}, err } @@ -172,7 +178,7 @@ func dockerInspectImage(cli *client.Client, image string, trustedPull bool) (typ } } - log.Debugf("docker inspect image: %s...Done", image) + log.Debugf("docker inspect image: %s...Done", ref) return inspect, nil } diff --git a/src/moby/image.go b/src/moby/image.go index 1b7451625..350c3730f 100644 --- a/src/moby/image.go +++ b/src/moby/image.go @@ -11,6 +11,7 @@ import ( "strings" log "github.com/Sirupsen/logrus" + "github.com/containerd/containerd/reference" "github.com/opencontainers/runtime-spec/specs-go" ) @@ -81,8 +82,8 @@ func tarPrefix(path string, tw tarWriter) error { } // ImageTar takes a Docker image and outputs it to a tar stream -func ImageTar(image, prefix string, tw tarWriter, trust bool, pull bool, resolv string) error { - log.Debugf("image tar: %s %s", image, prefix) +func ImageTar(ref *reference.Spec, prefix string, tw tarWriter, trust bool, pull bool, resolv string) error { + log.Debugf("image tar: %s %s", ref, prefix) if prefix != "" && prefix[len(prefix)-1] != byte('/') { return fmt.Errorf("prefix does not end with /: %s", prefix) } @@ -93,25 +94,25 @@ func ImageTar(image, prefix string, tw tarWriter, trust bool, pull bool, resolv } if pull || trust { - err := dockerPull(image, pull, trust) + err := dockerPull(ref, pull, trust) if err != nil { - return fmt.Errorf("Could not pull image %s: %v", image, err) + return fmt.Errorf("Could not pull image %s: %v", ref, err) } } - container, err := dockerCreate(image) + container, err := dockerCreate(ref.String()) if err != nil { // if the image wasn't found, pull it down. Bail on other errors. if strings.Contains(err.Error(), "No such image") { - err := dockerPull(image, true, trust) + err := dockerPull(ref, true, trust) if err != nil { - return fmt.Errorf("Could not pull image %s: %v", image, err) + return fmt.Errorf("Could not pull image %s: %v", ref, err) } - container, err = dockerCreate(image) + container, err = dockerCreate(ref.String()) if err != nil { - return fmt.Errorf("Failed to docker create image %s: %v", image, err) + return fmt.Errorf("Failed to docker create image %s: %v", ref, err) } } else { - return fmt.Errorf("Failed to create docker image %s: %v", image, err) + return fmt.Errorf("Failed to create docker image %s: %v", ref, err) } } contents, err := dockerExport(container) @@ -137,7 +138,7 @@ func ImageTar(image, prefix string, tw tarWriter, trust bool, pull bool, resolv return err } if exclude[hdr.Name] { - log.Debugf("image tar: %s %s exclude %s", image, prefix, hdr.Name) + log.Debugf("image tar: %s %s exclude %s", ref, prefix, hdr.Name) _, err = io.Copy(ioutil.Discard, tr) if err != nil { return err @@ -147,7 +148,7 @@ func ImageTar(image, prefix string, tw tarWriter, trust bool, pull bool, resolv contents := replace[hdr.Name] hdr.Size = int64(len(contents)) hdr.Name = prefix + hdr.Name - log.Debugf("image tar: %s %s add %s", image, prefix, hdr.Name) + log.Debugf("image tar: %s %s add %s", ref, prefix, hdr.Name) if err := tw.WriteHeader(hdr); err != nil { return err } @@ -162,7 +163,7 @@ func ImageTar(image, prefix string, tw tarWriter, trust bool, pull bool, resolv hdr.Size = 0 hdr.Typeflag = tar.TypeSymlink hdr.Linkname = resolv - log.Debugf("image tar: %s %s add resolv symlink /etc/resolv.conf -> %s", image, prefix, resolv) + log.Debugf("image tar: %s %s add resolv symlink /etc/resolv.conf -> %s", ref, prefix, resolv) if err := tw.WriteHeader(hdr); err != nil { return err } @@ -172,7 +173,7 @@ func ImageTar(image, prefix string, tw tarWriter, trust bool, pull bool, resolv return err } } else { - log.Debugf("image tar: %s %s add %s", image, prefix, hdr.Name) + log.Debugf("image tar: %s %s add %s", ref, prefix, hdr.Name) hdr.Name = prefix + hdr.Name if hdr.Typeflag == tar.TypeLink { // hard links are referenced by full path so need to be adjusted @@ -191,7 +192,7 @@ func ImageTar(image, prefix string, tw tarWriter, trust bool, pull bool, resolv } // ImageBundle produces an OCI bundle at the given path in a tarball, given an image and a config.json -func ImageBundle(prefix string, image string, config []byte, runtime Runtime, tw tarWriter, trust bool, pull bool, readonly bool, dupMap map[string]string) error { +func ImageBundle(prefix string, ref *reference.Spec, config []byte, runtime Runtime, tw tarWriter, trust bool, pull bool, readonly bool, dupMap map[string]string) error { // if read only, just unpack in rootfs/ but otherwise set up for overlay rootExtract := "rootfs" if !readonly { @@ -200,17 +201,17 @@ func ImageBundle(prefix string, image string, config []byte, runtime Runtime, tw // See if we have extracted this image previously root := path.Join(prefix, rootExtract) - var foundElsewhere = dupMap[image] != "" + var foundElsewhere = dupMap[ref.String()] != "" if !foundElsewhere { - if err := ImageTar(image, root+"/", tw, trust, pull, ""); err != nil { + if err := ImageTar(ref, root+"/", tw, trust, pull, ""); err != nil { return err } - dupMap[image] = root + dupMap[ref.String()] = root } else { if err := tarPrefix(prefix+"/", tw); err != nil { return err } - root = dupMap[image] + root = dupMap[ref.String()] } hdr := &tar.Header{ @@ -274,7 +275,7 @@ func ImageBundle(prefix string, image string, config []byte, runtime Runtime, tw // write the runtime config runtimeConfig, err := json.MarshalIndent(runtime, "", " ") if err != nil { - return fmt.Errorf("Failed to create runtime config for %s: %v", image, err) + return fmt.Errorf("Failed to create runtime config for %s: %v", ref, err) } hdr = &tar.Header{ @@ -290,7 +291,7 @@ func ImageBundle(prefix string, image string, config []byte, runtime Runtime, tw return err } - log.Debugf("image bundle: %s %s cfg: %s runtime: %s", prefix, image, string(config), string(runtimeConfig)) + log.Debugf("image bundle: %s %s cfg: %s runtime: %s", prefix, ref, string(config), string(runtimeConfig)) return nil }