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" "compress/gzip"
"crypto/sha256" "crypto/sha256"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
@ -36,6 +37,13 @@ type Graph struct {
driver graphdriver.Driver 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. // NewGraph instantiates a new graph at the given root path in the filesystem.
// `root` will be created if it doesn't exist. // `root` will be created if it doesn't exist.
func NewGraph(root string, driver graphdriver.Driver) (*Graph, error) { func NewGraph(root string, driver graphdriver.Driver) (*Graph, error) {
@ -507,26 +515,26 @@ func (graph *Graph) saveSize(root string, size int) error {
return nil return nil
} }
// SetCheckSum sets the checksum for the image layer to the provided value. // SetDigest sets the digest for the image layer to the provided value.
func (graph *Graph) SetCheckSum(id, checksum string) error { func (graph *Graph) SetDigest(id string, dgst digest.Digest) error {
root := graph.imageRoot(id) root := graph.imageRoot(id)
if err := ioutil.WriteFile(filepath.Join(root, "checksum"), []byte(checksum), 0600); err != nil { if err := ioutil.WriteFile(filepath.Join(root, "checksum"), []byte(dgst.String()), 0600); err != nil {
return fmt.Errorf("Error storing checksum in %s/checksum: %s", root, err) return fmt.Errorf("Error storing digest in %s/checksum: %s", root, err)
} }
return nil return nil
} }
// GetCheckSum gets the checksum for the provide image layer id. // GetDigest gets the digest for the provide image layer id.
func (graph *Graph) GetCheckSum(id string) (string, error) { func (graph *Graph) GetDigest(id string) (digest.Digest, error) {
root := graph.imageRoot(id) root := graph.imageRoot(id)
cs, err := ioutil.ReadFile(filepath.Join(root, "checksum")) cs, err := ioutil.ReadFile(filepath.Join(root, "checksum"))
if err != nil { if err != nil {
if os.IsNotExist(err) { if os.IsNotExist(err) {
return "", nil return "", ErrDigestNotSet
} }
return "", err return "", err
} }
return string(cs), err return digest.ParseDigest(string(cs))
} }
// RawJSON returns the JSON representation for an image as a byte array. // RawJSON returns the JSON representation for an image as a byte array.

View File

@ -3,14 +3,11 @@ package graph
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io"
"io/ioutil"
"os" "os"
"testing" "testing"
"github.com/docker/distribution/digest" "github.com/docker/distribution/digest"
"github.com/docker/docker/image" "github.com/docker/docker/image"
"github.com/docker/docker/pkg/tarsum"
"github.com/docker/docker/registry" "github.com/docker/docker/registry"
"github.com/docker/docker/runconfig" "github.com/docker/docker/runconfig"
"github.com/docker/docker/utils" "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) dgst, err := s.graph.GetDigest(layer.ID)
if err != nil { if err == ErrDigestNotSet {
return nil, fmt.Errorf("Error getting image checksum: %s", err)
}
if tarsum.VersionLabelForChecksum(checksum) != tarsum.Version1.String() {
archive, err := s.graph.TarLayer(layer) archive, err := s.graph.TarLayer(layer)
if err != nil { if err != nil {
return nil, err return nil, err
@ -84,20 +78,17 @@ func (s *TagStore) newManifest(localName, remoteName, tag string) ([]byte, error
defer archive.Close() defer archive.Close()
tarSum, err := tarsum.NewTarSum(archive, true, tarsum.Version1) dgst, err = digest.FromReader(archive)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if _, err := io.Copy(ioutil.Discard, tarSum); err != nil {
return nil, err
}
checksum = tarSum.Sum(nil)
// Save checksum value // 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 return nil, err
} }
} else if err != nil {
return nil, fmt.Errorf("Error getting image checksum: %s", err)
} }
jsonData, err := s.graph.RawJSON(layer.ID) 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) 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 layersSeen[layer.ID] = true
@ -141,10 +132,10 @@ func TestManifestTarsumCache(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
if cs, err := store.graph.GetCheckSum(testManifestImageID); err != nil { if _, err := store.graph.GetDigest(testManifestImageID); err == nil {
t.Fatal(err)
} else if cs != "" {
t.Fatalf("Non-empty checksum file after register") t.Fatalf("Non-empty checksum file after register")
} else if err != ErrDigestNotSet {
t.Fatal(err)
} }
// Generate manifest // Generate manifest
@ -153,7 +144,7 @@ func TestManifestTarsumCache(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
manifestChecksum, err := store.graph.GetCheckSum(testManifestImageID) manifestChecksum, err := store.graph.GetDigest(testManifestImageID)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -167,7 +158,7 @@ func TestManifestTarsumCache(t *testing.T) {
t.Fatalf("Unexpected number of layers, expecting 1: %d", len(manifest.FSLayers)) 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) 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) t.Fatal(err)
} }
if cs, err := store.graph.GetCheckSum(testManifestImageID); err != nil { if _, err := store.graph.GetDigest(testManifestImageID); err == nil {
t.Fatal(err)
} else if cs != "" {
t.Fatalf("Non-empty checksum file after register") t.Fatalf("Non-empty checksum file after register")
} else if err != ErrDigestNotSet {
t.Fatal(err)
} }
// Generate manifest // 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) 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 var exists bool
if len(checksum) > 0 { dgst, err := s.graph.GetDigest(layer.ID)
dgst, err := digest.ParseDigest(checksum) if err != nil {
if err != nil { if err != ErrDigestNotSet {
return fmt.Errorf("Invalid checksum %s: %s", checksum, err) return fmt.Errorf("error getting image checksum: %s", err)
} }
} else {
// Call mount blob // Call mount blob
exists, err = r.HeadV2ImageBlob(endpoint, repoInfo.RemoteName, dgst, auth) exists, err = r.HeadV2ImageBlob(endpoint, repoInfo.RemoteName, dgst, auth)
if err != nil { if err != nil {
@ -395,19 +390,19 @@ func (s *TagStore) pushV2Repository(r *registry.Session, localRepo Repository, o
} }
} }
if !exists { 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 return err
} else if cs != checksum { } else if pushDigest != dgst {
// Cache new checksum // 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 return err
} }
checksum = cs dgst = pushDigest
} }
} else { } else {
out.Write(sf.FormatProgress(stringid.TruncateID(layer.ID), "Image already exists", nil)) 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)} 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 // 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)) out.Write(sf.FormatProgress(stringid.TruncateID(img.ID), "Buffering to Disk", nil))
image, err := s.graph.Get(img.ID) image, err := s.graph.Get(img.ID)
@ -488,7 +483,7 @@ func (s *TagStore) pushV2Image(r *registry.Session, img *image.Image, endpoint *
return "", err return "", err
} }
out.Write(sf.FormatProgress(stringid.TruncateID(img.ID), "Image successfully pushed", nil)) 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. // FIXME: Allow to interrupt current push when new push of same image is done.