diff --git a/cmd/moby/build.go b/cmd/moby/build.go index 97ad5a563..a835899ea 100644 --- a/cmd/moby/build.go +++ b/cmd/moby/build.go @@ -221,13 +221,6 @@ func buildInternal(m Moby, pull bool) []byte { w := new(bytes.Buffer) iw := tar.NewWriter(w) - if pull || enforceContentTrust(m.Kernel.Image, &m.Trust) { - log.Infof("Pull kernel image: %s", m.Kernel.Image) - err := dockerPull(m.Kernel.Image, enforceContentTrust(m.Kernel.Image, &m.Trust)) - if err != nil { - log.Fatalf("Could not pull image %s: %v", m.Kernel.Image, err) - } - } if m.Kernel.Image != "" { // get kernel and initrd tarball from container log.Infof("Extract kernel image: %s", m.Kernel.Image) @@ -269,13 +262,14 @@ func buildInternal(m Moby, pull bool) []byte { } for i, image := range m.Onboot { log.Infof(" Create OCI config for %s", image.Image) - config, err := ConfigToOCI(image) + useTrust := enforceContentTrust(image.Image, &m.Trust) + config, err := ConfigToOCI(image, useTrust) if err != nil { log.Fatalf("Failed to create config.json for %s: %v", image.Image, err) } so := fmt.Sprintf("%03d", i) path := "containers/onboot/" + so + "-" + image.Name - out, err := ImageBundle(path, image.Image, config, enforceContentTrust(image.Image, &m.Trust), pull) + out, err := ImageBundle(path, image.Image, config, useTrust, pull) if err != nil { log.Fatalf("Failed to extract root filesystem for %s: %v", image.Image, err) } @@ -288,12 +282,13 @@ func buildInternal(m Moby, pull bool) []byte { } for _, image := range m.Services { log.Infof(" Create OCI config for %s", image.Image) - config, err := ConfigToOCI(image) + useTrust := enforceContentTrust(image.Image, &m.Trust) + config, err := ConfigToOCI(image, useTrust) if err != nil { log.Fatalf("Failed to create config.json for %s: %v", image.Image, err) } path := "containers/services/" + image.Name - out, err := ImageBundle(path, image.Image, config, enforceContentTrust(image.Image, &m.Trust), pull) + out, err := ImageBundle(path, image.Image, config, useTrust, pull) if err != nil { log.Fatalf("Failed to extract root filesystem for %s: %v", image.Image, err) } diff --git a/cmd/moby/config.go b/cmd/moby/config.go index fa6c5a4d1..5d7ecf301 100644 --- a/cmd/moby/config.go +++ b/cmd/moby/config.go @@ -202,7 +202,7 @@ func NewImage(config []byte) (MobyImage, error) { } // ConfigToOCI converts a config specification to an OCI config file -func ConfigToOCI(image MobyImage) ([]byte, error) { +func ConfigToOCI(image MobyImage, trust bool) ([]byte, error) { // TODO pass through same docker client to all functions cli, err := dockerClient() @@ -210,7 +210,7 @@ func ConfigToOCI(image MobyImage) ([]byte, error) { return []byte{}, err } - inspect, err := dockerInspectImage(cli, image.Image) + inspect, err := dockerInspectImage(cli, image.Image, trust) if err != nil { return []byte{}, err } diff --git a/cmd/moby/docker.go b/cmd/moby/docker.go index ec2855c47..c297e4b38 100644 --- a/cmd/moby/docker.go +++ b/cmd/moby/docker.go @@ -16,6 +16,7 @@ import ( log "github.com/Sirupsen/logrus" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" + "github.com/docker/docker/api/types/filters" "github.com/docker/docker/client" "golang.org/x/net/context" ) @@ -118,7 +119,7 @@ func dockerRm(container string) error { return nil } -func dockerPull(image string, trustedPull bool) error { +func dockerPull(image string, forcePull, trustedPull bool) error { log.Debugf("docker pull: %s", image) cli, err := dockerClient() if err != nil { @@ -140,9 +141,18 @@ func dockerPull(image string, trustedPull bool) error { } }(trustedImg.String(), image) + log.Debugf("successfully verified trusted reference %s from notary", trustedImg.String()) image = trustedImg.String() + + imageSearchArg := filters.NewArgs() + imageSearchArg.Add("reference", trustedImg.String()) + if _, err := cli.ImageList(context.Background(), types.ImageListOptions{Filters: imageSearchArg}); err == nil && !forcePull { + log.Debugf("docker pull: trusted image %s already cached...Done", trustedImg.String()) + return nil + } } + log.Infof("Pull image: %s", image) r, err := cli.ImagePull(context.Background(), image, types.ImagePullOptions{}) if err != nil { return err @@ -165,13 +175,13 @@ func dockerClient() (*client.Client, error) { return client.NewEnvClient() } -func dockerInspectImage(cli *client.Client, image string) (types.ImageInspect, error) { +func dockerInspectImage(cli *client.Client, image string, trustedPull bool) (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) + pullErr := dockerPull(image, true, trustedPull) if pullErr != nil { return types.ImageInspect{}, pullErr } diff --git a/cmd/moby/image.go b/cmd/moby/image.go index dfbbd632c..bd05ad5bf 100644 --- a/cmd/moby/image.go +++ b/cmd/moby/image.go @@ -94,8 +94,7 @@ func imageTar(image, prefix string, tw *tar.Writer, trust bool, pull bool) error } if pull || trust { - log.Infof("Pull image: %s", image) - err := dockerPull(image, trust) + err := dockerPull(image, pull, trust) if err != nil { return fmt.Errorf("Could not pull image %s: %v", image, err) } @@ -104,8 +103,7 @@ func imageTar(image, prefix string, tw *tar.Writer, trust bool, pull bool) error if err != nil { // if the image wasn't found, pull it down. Bail on other errors. if strings.Contains(err.Error(), "No such image") { - log.Infof("Pull image: %s", image) - err := dockerPull(image, trust) + err := dockerPull(image, true, trust) if err != nil { return fmt.Errorf("Could not pull image %s: %v", image, err) } diff --git a/cmd/moby/trust.go b/cmd/moby/trust.go index 322f6e0bf..145075c7a 100644 --- a/cmd/moby/trust.go +++ b/cmd/moby/trust.go @@ -14,6 +14,7 @@ import ( "strings" "time" + log "github.com/Sirupsen/logrus" "github.com/docker/distribution/reference" "github.com/docker/distribution/registry/client/auth" "github.com/docker/distribution/registry/client/auth/challenge" @@ -59,7 +60,8 @@ func TrustedReference(image string) (reference.Reference, error) { rt, err := GetReadOnlyAuthTransport(server, []string{gun}, "", "", "") if err != nil { - return nil, err + log.Debugf("failed to reach %s notary server for repo: %s, falling back to cache: %v", server, gun, err) + rt = nil } nRepo, err := notaryClient.NewNotaryRepository(