Update graph to use digest type

Update get and set functions to use digests.
Update push code to use the digest type instead of string

Signed-off-by: Derek McGowan <derek@mcgstyle.net> (github: dmcgowan)
This commit is contained in:
Derek McGowan 2015-06-05 18:07:41 -07:00
parent bb50a4159b
commit c0b4421819
3 changed files with 43 additions and 49 deletions

View file

@ -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.

View file

@ -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, &registry.FSLayer{BlobSum: checksum})
manifest.FSLayers = append(manifest.FSLayers, &registry.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

View file

@ -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] = &registry.FSLayer{BlobSum: checksum}
m.FSLayers[i] = &registry.FSLayer{BlobSum: dgst.String()}
m.History[i] = &registry.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.