diff --git a/graph/graph.go b/graph/graph.go index b405e1dd87..5ccb66c666 100644 --- a/graph/graph.go +++ b/graph/graph.go @@ -4,6 +4,7 @@ import ( "compress/gzip" "crypto/sha256" "encoding/json" + "errors" "fmt" "io" "io/ioutil" @@ -36,6 +37,13 @@ type Graph struct { driver graphdriver.Driver } +var ( + // ErrDigestNotSet is used when request the digest for a layer + // but the layer has no digest value or content to compute the + // the digest. + ErrDigestNotSet = errors.New("digest is not set for layer") +) + // NewGraph instantiates a new graph at the given root path in the filesystem. // `root` will be created if it doesn't exist. func NewGraph(root string, driver graphdriver.Driver) (*Graph, error) { @@ -507,26 +515,26 @@ func (graph *Graph) saveSize(root string, size int) error { return nil } -// SetCheckSum sets the checksum for the image layer to the provided value. -func (graph *Graph) SetCheckSum(id, checksum string) error { +// SetDigest sets the digest for the image layer to the provided value. +func (graph *Graph) SetDigest(id string, dgst digest.Digest) error { root := graph.imageRoot(id) - if err := ioutil.WriteFile(filepath.Join(root, "checksum"), []byte(checksum), 0600); err != nil { - return fmt.Errorf("Error storing checksum in %s/checksum: %s", root, err) + if err := ioutil.WriteFile(filepath.Join(root, "checksum"), []byte(dgst.String()), 0600); err != nil { + return fmt.Errorf("Error storing digest in %s/checksum: %s", root, err) } return nil } -// GetCheckSum gets the checksum for the provide image layer id. -func (graph *Graph) GetCheckSum(id string) (string, error) { +// GetDigest gets the digest for the provide image layer id. +func (graph *Graph) GetDigest(id string) (digest.Digest, error) { root := graph.imageRoot(id) cs, err := ioutil.ReadFile(filepath.Join(root, "checksum")) if err != nil { if os.IsNotExist(err) { - return "", nil + return "", ErrDigestNotSet } return "", err } - return string(cs), err + return digest.ParseDigest(string(cs)) } // RawJSON returns the JSON representation for an image as a byte array. diff --git a/graph/manifest_test.go b/graph/manifest_test.go index 0b8e7a2fb0..6b1a608073 100644 --- a/graph/manifest_test.go +++ b/graph/manifest_test.go @@ -3,14 +3,11 @@ package graph import ( "encoding/json" "fmt" - "io" - "io/ioutil" "os" "testing" "github.com/docker/distribution/digest" "github.com/docker/docker/image" - "github.com/docker/docker/pkg/tarsum" "github.com/docker/docker/registry" "github.com/docker/docker/runconfig" "github.com/docker/docker/utils" @@ -72,11 +69,8 @@ func (s *TagStore) newManifest(localName, remoteName, tag string) ([]byte, error } } - checksum, err := s.graph.GetCheckSum(layer.ID) - if err != nil { - return nil, fmt.Errorf("Error getting image checksum: %s", err) - } - if tarsum.VersionLabelForChecksum(checksum) != tarsum.Version1.String() { + dgst, err := s.graph.GetDigest(layer.ID) + if err == ErrDigestNotSet { archive, err := s.graph.TarLayer(layer) if err != nil { return nil, err @@ -84,20 +78,17 @@ func (s *TagStore) newManifest(localName, remoteName, tag string) ([]byte, error defer archive.Close() - tarSum, err := tarsum.NewTarSum(archive, true, tarsum.Version1) + dgst, err = digest.FromReader(archive) if err != nil { return nil, err } - if _, err := io.Copy(ioutil.Discard, tarSum); err != nil { - return nil, err - } - - checksum = tarSum.Sum(nil) // Save checksum value - if err := s.graph.SetCheckSum(layer.ID, checksum); err != nil { + if err := s.graph.SetDigest(layer.ID, dgst); err != nil { return nil, err } + } else if err != nil { + return nil, fmt.Errorf("Error getting image checksum: %s", err) } jsonData, err := s.graph.RawJSON(layer.ID) @@ -105,7 +96,7 @@ func (s *TagStore) newManifest(localName, remoteName, tag string) ([]byte, error return nil, fmt.Errorf("Cannot retrieve the path for {%s}: %s", layer.ID, err) } - manifest.FSLayers = append(manifest.FSLayers, ®istry.FSLayer{BlobSum: checksum}) + manifest.FSLayers = append(manifest.FSLayers, ®istry.FSLayer{BlobSum: dgst.String()}) layersSeen[layer.ID] = true @@ -141,10 +132,10 @@ func TestManifestTarsumCache(t *testing.T) { t.Fatal(err) } - if cs, err := store.graph.GetCheckSum(testManifestImageID); err != nil { - t.Fatal(err) - } else if cs != "" { + if _, err := store.graph.GetDigest(testManifestImageID); err == nil { t.Fatalf("Non-empty checksum file after register") + } else if err != ErrDigestNotSet { + t.Fatal(err) } // Generate manifest @@ -153,7 +144,7 @@ func TestManifestTarsumCache(t *testing.T) { t.Fatal(err) } - manifestChecksum, err := store.graph.GetCheckSum(testManifestImageID) + manifestChecksum, err := store.graph.GetDigest(testManifestImageID) if err != nil { t.Fatal(err) } @@ -167,7 +158,7 @@ func TestManifestTarsumCache(t *testing.T) { t.Fatalf("Unexpected number of layers, expecting 1: %d", len(manifest.FSLayers)) } - if manifest.FSLayers[0].BlobSum != manifestChecksum { + if manifest.FSLayers[0].BlobSum != manifestChecksum.String() { t.Fatalf("Unexpected blob sum, expecting %q, got %q", manifestChecksum, manifest.FSLayers[0].BlobSum) } @@ -207,10 +198,10 @@ func TestManifestDigestCheck(t *testing.T) { t.Fatal(err) } - if cs, err := store.graph.GetCheckSum(testManifestImageID); err != nil { - t.Fatal(err) - } else if cs != "" { + if _, err := store.graph.GetDigest(testManifestImageID); err == nil { t.Fatalf("Non-empty checksum file after register") + } else if err != ErrDigestNotSet { + t.Fatal(err) } // Generate manifest diff --git a/graph/push.go b/graph/push.go index 24526b4507..0de40b8c50 100644 --- a/graph/push.go +++ b/graph/push.go @@ -375,18 +375,13 @@ func (s *TagStore) pushV2Repository(r *registry.Session, localRepo Repository, o return fmt.Errorf("cannot retrieve the path for %s: %s", layer.ID, err) } - checksum, err := s.graph.GetCheckSum(layer.ID) - if err != nil { - return fmt.Errorf("error getting image checksum: %s", err) - } - var exists bool - if len(checksum) > 0 { - dgst, err := digest.ParseDigest(checksum) - if err != nil { - return fmt.Errorf("Invalid checksum %s: %s", checksum, err) + dgst, err := s.graph.GetDigest(layer.ID) + if err != nil { + if err != ErrDigestNotSet { + return fmt.Errorf("error getting image checksum: %s", err) } - + } else { // Call mount blob exists, err = r.HeadV2ImageBlob(endpoint, repoInfo.RemoteName, dgst, auth) if err != nil { @@ -395,19 +390,19 @@ func (s *TagStore) pushV2Repository(r *registry.Session, localRepo Repository, o } } if !exists { - if cs, err := s.pushV2Image(r, layer, endpoint, repoInfo.RemoteName, sf, out, auth); err != nil { + if pushDigest, err := s.pushV2Image(r, layer, endpoint, repoInfo.RemoteName, sf, out, auth); err != nil { return err - } else if cs != checksum { + } else if pushDigest != dgst { // Cache new checksum - if err := s.graph.SetCheckSum(layer.ID, cs); err != nil { + if err := s.graph.SetDigest(layer.ID, pushDigest); err != nil { return err } - checksum = cs + dgst = pushDigest } } else { out.Write(sf.FormatProgress(stringid.TruncateID(layer.ID), "Image already exists", nil)) } - m.FSLayers[i] = ®istry.FSLayer{BlobSum: checksum} + m.FSLayers[i] = ®istry.FSLayer{BlobSum: dgst.String()} m.History[i] = ®istry.ManifestHistory{V1Compatibility: string(jsonData)} } @@ -447,7 +442,7 @@ func (s *TagStore) pushV2Repository(r *registry.Session, localRepo Repository, o } // PushV2Image pushes the image content to the v2 registry, first buffering the contents to disk -func (s *TagStore) pushV2Image(r *registry.Session, img *image.Image, endpoint *registry.Endpoint, imageName string, sf *streamformatter.StreamFormatter, out io.Writer, auth *registry.RequestAuthorization) (string, error) { +func (s *TagStore) pushV2Image(r *registry.Session, img *image.Image, endpoint *registry.Endpoint, imageName string, sf *streamformatter.StreamFormatter, out io.Writer, auth *registry.RequestAuthorization) (digest.Digest, error) { out.Write(sf.FormatProgress(stringid.TruncateID(img.ID), "Buffering to Disk", nil)) image, err := s.graph.Get(img.ID) @@ -488,7 +483,7 @@ func (s *TagStore) pushV2Image(r *registry.Session, img *image.Image, endpoint * return "", err } out.Write(sf.FormatProgress(stringid.TruncateID(img.ID), "Image successfully pushed", nil)) - return dgst.String(), nil + return dgst, nil } // FIXME: Allow to interrupt current push when new push of same image is done.