Update code to compile against new manifest interface

Also, digest.FromBytes no longer returns an error.

Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
This commit is contained in:
Aaron Lehmann 2015-12-08 11:14:02 -08:00
parent 290ba41c00
commit c168a0059f
13 changed files with 91 additions and 147 deletions

View File

@ -14,6 +14,7 @@ import (
"github.com/docker/distribution/digest"
"github.com/docker/distribution/manifest/schema1"
"github.com/docker/distribution/registry/api/errcode"
"github.com/docker/distribution/registry/client"
"github.com/docker/docker/distribution/metadata"
"github.com/docker/docker/distribution/xfer"
"github.com/docker/docker/image"
@ -61,18 +62,12 @@ func (p *v2Puller) Pull(ctx context.Context, ref reference.Named) (err error) {
func (p *v2Puller) pullV2Repository(ctx context.Context, ref reference.Named) (err error) {
var layersDownloaded bool
if !reference.IsNameOnly(ref) {
var err error
layersDownloaded, err = p.pullV2Tag(ctx, ref)
if err != nil {
return err
}
} else {
manSvc, err := p.repo.Manifests(ctx)
if err != nil {
return err
}
tags, err := manSvc.Tags()
tags, err := p.repo.Tags(ctx).All(ctx)
if err != nil {
// If this repository doesn't exist on V2, we should
// permit a fallback to V1.
@ -84,8 +79,6 @@ func (p *v2Puller) pullV2Repository(ctx context.Context, ref reference.Named) (e
// error later on.
p.confirmedV2 = true
// This probably becomes a lot nicer after the manifest
// refactor...
for _, tag := range tags {
tagRef, err := reference.WithTag(ref, tag)
if err != nil {
@ -203,58 +196,92 @@ func (ld *v2LayerDescriptor) Registered(diffID layer.DiffID) {
}
func (p *v2Puller) pullV2Tag(ctx context.Context, ref reference.Named) (tagUpdated bool, err error) {
tagOrDigest := ""
if tagged, isTagged := ref.(reference.NamedTagged); isTagged {
tagOrDigest = tagged.Tag()
} else if digested, isCanonical := ref.(reference.Canonical); isCanonical {
tagOrDigest = digested.Digest().String()
} else {
return false, fmt.Errorf("internal error: reference has neither a tag nor a digest: %s", ref.String())
}
logrus.Debugf("Pulling ref from V2 registry: %s:%s", ref.FullName(), tagOrDigest)
manSvc, err := p.repo.Manifests(ctx)
if err != nil {
return false, err
}
unverifiedManifest, err := manSvc.GetByTag(tagOrDigest)
if err != nil {
// If this manifest did not exist, we should allow a possible
// fallback to the v1 protocol, because dual-version setups may
// not host all manifests with the v2 protocol. We may also get
// a "not authorized" error if the manifest doesn't exist.
return false, allowV1Fallback(err)
var (
manifest distribution.Manifest
tagOrDigest string // Used for logging/progress only
)
if tagged, isTagged := ref.(reference.NamedTagged); isTagged {
// NOTE: not using TagService.Get, since it uses HEAD requests
// against the manifests endpoint, which are not supported by
// all registry versions.
manifest, err = manSvc.Get(ctx, "", client.WithTag(tagged.Tag()))
if err != nil {
return false, allowV1Fallback(err)
}
tagOrDigest = tagged.Tag()
} else if digested, isDigested := ref.(reference.Canonical); isDigested {
manifest, err = manSvc.Get(ctx, digested.Digest())
if err != nil {
return false, err
}
tagOrDigest = digested.Digest().String()
} else {
return false, fmt.Errorf("internal error: reference has neither a tag nor a digest: %s", ref.String())
}
if unverifiedManifest == nil {
if manifest == nil {
return false, fmt.Errorf("image manifest does not exist for tag or digest %q", tagOrDigest)
}
// If GetByTag succeeded, we can be confident that the registry on
// If manSvc.Get succeeded, we can be confident that the registry on
// the other side speaks the v2 protocol.
p.confirmedV2 = true
logrus.Debugf("Pulling ref from V2 registry: %s", ref.String())
progress.Message(p.config.ProgressOutput, tagOrDigest, "Pulling from "+p.repo.Name())
var imageID image.ID
switch v := manifest.(type) {
case *schema1.SignedManifest:
imageID, err = p.pullSchema1(ctx, ref, v)
if err != nil {
return false, err
}
default:
return false, errors.New("unsupported manifest format")
}
oldTagImageID, err := p.config.ReferenceStore.Get(ref)
if err == nil && oldTagImageID == imageID {
return false, nil
}
if canonical, ok := ref.(reference.Canonical); ok {
if err = p.config.ReferenceStore.AddDigest(canonical, imageID, true); err != nil {
return false, err
}
} else if err = p.config.ReferenceStore.AddTag(ref, imageID, true); err != nil {
return false, err
}
return true, nil
}
func (p *v2Puller) pullSchema1(ctx context.Context, ref reference.Named, unverifiedManifest *schema1.SignedManifest) (imageID image.ID, err error) {
var verifiedManifest *schema1.Manifest
verifiedManifest, err = verifyManifest(unverifiedManifest, ref)
if err != nil {
return false, err
return "", err
}
rootFS := image.NewRootFS()
if err := detectBaseLayer(p.config.ImageStore, verifiedManifest, rootFS); err != nil {
return false, err
return "", err
}
// remove duplicate layers and check parent chain validity
err = fixManifestLayers(verifiedManifest)
if err != nil {
return false, err
return "", err
}
progress.Message(p.config.ProgressOutput, tagOrDigest, "Pulling from "+p.repo.Name())
var descriptors []xfer.DownloadDescriptor
// Image history converted to the new format
@ -269,12 +296,12 @@ func (p *v2Puller) pullV2Tag(ctx context.Context, ref reference.Named) (tagUpdat
ThrowAway bool `json:"throwaway,omitempty"`
}
if err := json.Unmarshal([]byte(verifiedManifest.History[i].V1Compatibility), &throwAway); err != nil {
return false, err
return "", err
}
h, err := v1.HistoryFromConfig([]byte(verifiedManifest.History[i].V1Compatibility), throwAway.ThrowAway)
if err != nil {
return false, err
return "", err
}
history = append(history, h)
@ -293,43 +320,30 @@ func (p *v2Puller) pullV2Tag(ctx context.Context, ref reference.Named) (tagUpdat
resultRootFS, release, err := p.config.DownloadManager.Download(ctx, *rootFS, descriptors, p.config.ProgressOutput)
if err != nil {
return false, err
return "", err
}
defer release()
config, err := v1.MakeConfigFromV1Config([]byte(verifiedManifest.History[0].V1Compatibility), &resultRootFS, history)
if err != nil {
return false, err
return "", err
}
imageID, err := p.config.ImageStore.Create(config)
imageID, err = p.config.ImageStore.Create(config)
if err != nil {
return false, err
return "", err
}
manifestDigest, _, err := digestFromManifest(unverifiedManifest, p.repoInfo)
if err != nil {
return false, err
return "", err
}
if manifestDigest != "" {
progress.Message(p.config.ProgressOutput, "", "Digest: "+manifestDigest.String())
}
oldTagImageID, err := p.config.ReferenceStore.Get(ref)
if err == nil && oldTagImageID == imageID {
return false, nil
}
if canonical, ok := ref.(reference.Canonical); ok {
if err = p.config.ReferenceStore.AddDigest(canonical, imageID, true); err != nil {
return false, err
}
} else if err = p.config.ReferenceStore.AddTag(ref, imageID, true); err != nil {
return false, err
}
return true, nil
return imageID, nil
}
// allowV1Fallback checks if the error is a possible reason to fallback to v1
@ -362,13 +376,7 @@ func verifyManifest(signedManifest *schema1.SignedManifest, ref reference.Named)
if err != nil {
return nil, err
}
payload, err := signedManifest.Payload()
if err != nil {
// If this failed, the signatures section was corrupted
// or missing. Treat the entire manifest as the payload.
payload = signedManifest.Raw
}
if _, err := verifier.Write(payload); err != nil {
if _, err := verifier.Write(signedManifest.Canonical); err != nil {
return nil, err
}
if !verifier.Verified() {
@ -376,15 +384,8 @@ func verifyManifest(signedManifest *schema1.SignedManifest, ref reference.Named)
logrus.Error(err)
return nil, err
}
var verifiedManifest schema1.Manifest
if err = json.Unmarshal(payload, &verifiedManifest); err != nil {
return nil, err
}
m = &verifiedManifest
} else {
m = &signedManifest.Manifest
}
m = &signedManifest.Manifest
if m.SchemaVersion != 1 {
return nil, fmt.Errorf("unsupported schema version %d for %q", m.SchemaVersion, ref.String())

View File

@ -194,7 +194,9 @@ func (p *v2Pusher) pushV2Tag(ctx context.Context, association reference.Associat
if err != nil {
return err
}
return manSvc.Put(signed)
_, err = manSvc.Put(ctx, signed)
// FIXME create a tag
return err
}
type v2PushDescriptor struct {
@ -370,10 +372,7 @@ func CreateV2Manifest(name, tag string, img *image.Image, fsLayers map[layer.Dif
if !present {
return nil, fmt.Errorf("missing layer in CreateV2Manifest: %s", diffID.String())
}
dgst, err := digest.FromBytes([]byte(fsLayer.Hex() + " " + parent))
if err != nil {
return nil, err
}
dgst := digest.FromBytes([]byte(fsLayer.Hex() + " " + parent))
v1ID := dgst.Hex()
v1Compatibility := v1Compatibility{
@ -414,11 +413,8 @@ func CreateV2Manifest(name, tag string, img *image.Image, fsLayers map[layer.Dif
return nil, fmt.Errorf("missing layer in CreateV2Manifest: %s", diffID.String())
}
dgst, err := digest.FromBytes([]byte(fsLayer.Hex() + " " + parent + " " + string(img.RawJSON())))
if err != nil {
return nil, err
}
fsLayerList[0] = schema1.FSLayer{BlobSum: fsLayer}
dgst := digest.FromBytes([]byte(fsLayer.Hex() + " " + parent + " " + string(img.RawJSON())))
// Top-level v1compatibility string should be a modified version of the
// image config.

View File

@ -8,7 +8,6 @@ import (
"strings"
"time"
"github.com/Sirupsen/logrus"
"github.com/docker/distribution"
"github.com/docker/distribution/digest"
"github.com/docker/distribution/manifest/schema1"
@ -126,17 +125,7 @@ func NewV2Repository(ctx context.Context, repoInfo *registry.RepositoryInfo, end
}
func digestFromManifest(m *schema1.SignedManifest, name reference.Named) (digest.Digest, int, error) {
payload, err := m.Payload()
if err != nil {
// If this failed, the signatures section was corrupted
// or missing. Treat the entire manifest as the payload.
payload = m.Raw
}
manifestDigest, err := digest.FromBytes(payload)
if err != nil {
logrus.Infof("Could not compute manifest digest for %s:%s : %v", name.Name(), m.Tag, err)
}
return manifestDigest, len(payload), nil
return digest.FromBytes(m.Canonical), len(m.Canonical), nil
}
type existingTokenHandler struct {

View File

@ -65,12 +65,7 @@ func createChainIDFromParent(parent layer.ChainID, dgsts ...layer.DiffID) layer.
return createChainIDFromParent(layer.ChainID(dgsts[0]), dgsts[1:]...)
}
// H = "H(n-1) SHA256(n)"
dgst, err := digest.FromBytes([]byte(string(parent) + " " + string(dgsts[0])))
if err != nil {
// Digest calculation is not expected to throw an error,
// any error at this point is a program error
panic(err)
}
dgst := digest.FromBytes([]byte(string(parent) + " " + string(dgsts[0])))
return createChainIDFromParent(layer.ChainID(dgst), dgsts[1:]...)
}
@ -92,11 +87,7 @@ func (ls *mockLayerStore) Register(reader io.Reader, parentID layer.ChainID) (la
if err != nil {
return nil, err
}
diffID, err := digest.FromBytes(l.layerData.Bytes())
if err != nil {
return nil, err
}
l.diffID = layer.DiffID(diffID)
l.diffID = layer.DiffID(digest.FromBytes(l.layerData.Bytes()))
l.chainID = createChainIDFromParent(parentID, l.diffID)
ls.layers[l.chainID] = l

View File

@ -62,7 +62,7 @@ func (u *mockUploadDescriptor) Upload(ctx context.Context, progressOutput progre
// For the mock implementation, use SHA256(DiffID) as the returned
// digest.
return digest.FromBytes([]byte(u.diffID.String()))
return digest.FromBytes([]byte(u.diffID.String())), nil
}
func uploadDescriptors(currentUploads *int32) []UploadDescriptor {

View File

@ -101,11 +101,7 @@ func (s *fs) get(id ID) ([]byte, error) {
}
// todo: maybe optional
validated, err := digest.FromBytes(content)
if err != nil {
return nil, err
}
if ID(validated) != id {
if ID(digest.FromBytes(content)) != id {
return nil, fmt.Errorf("failed to verify image: %v", id)
}
@ -121,11 +117,7 @@ func (s *fs) Set(data []byte) (ID, error) {
return "", fmt.Errorf("Invalid empty data")
}
dgst, err := digest.FromBytes(data)
if err != nil {
return "", err
}
id := ID(dgst)
id := ID(digest.FromBytes(data))
filePath := s.contentFile(id)
tempFilePath := s.contentFile(id) + ".tmp"
if err := ioutil.WriteFile(tempFilePath, data, 0600); err != nil {

View File

@ -67,10 +67,7 @@ func TestFSInvalidSet(t *testing.T) {
t.Fatal(err)
}
id, err := digest.FromBytes([]byte("foobar"))
if err != nil {
t.Fatal(err)
}
id := digest.FromBytes([]byte("foobar"))
err = os.Mkdir(filepath.Join(tmpdir, contentDirName, string(id.Algorithm()), id.Hex()), 0700)
if err != nil {
t.Fatal(err)
@ -160,11 +157,7 @@ func testMetadataGetSet(t *testing.T, store StoreBackend) {
t.Fatal("Expected error for getting metadata for unknown key")
}
id3, err := digest.FromBytes([]byte("baz"))
if err != nil {
t.Fatal(err)
}
id3 := digest.FromBytes([]byte("baz"))
err = store.SetMetadata(ID(id3), "tkey", []byte("tval"))
if err == nil {
t.Fatal("Expected error for setting metadata for unknown ID.")

View File

@ -27,7 +27,7 @@ func (r *RootFS) BaseLayerID() string {
// ChainID returns the ChainID for the top layer in RootFS.
func (r *RootFS) ChainID() layer.ChainID {
baseDiffID, _ := digest.FromBytes([]byte(r.BaseLayerID())) // can never error
baseDiffID := digest.FromBytes([]byte(r.BaseLayerID()))
return layer.CreateChainID(append([]layer.DiffID{layer.DiffID(baseDiffID)}, r.DiffIDs...))
}

View File

@ -63,7 +63,7 @@ func CreateID(v1Image image.V1Image, layerID layer.ChainID, parent digest.Digest
}
logrus.Debugf("CreateV1ID %s", configJSON)
return digest.FromBytes(configJSON)
return digest.FromBytes(configJSON), nil
}
// MakeConfigFromV1Config creates an image config from the legacy V1 config format.

View File

@ -15,12 +15,8 @@ import (
func randomLayerID(seed int64) ChainID {
r := rand.New(rand.NewSource(seed))
dgst, err := digest.FromBytes([]byte(fmt.Sprintf("%d", r.Int63())))
if err != nil {
panic(err)
}
return ChainID(dgst)
return ChainID(digest.FromBytes([]byte(fmt.Sprintf("%d", r.Int63()))))
}
func newFileMetadataStore(t *testing.T) (*fileMetadataStore, string, func()) {

View File

@ -233,12 +233,7 @@ func createChainIDFromParent(parent ChainID, dgsts ...DiffID) ChainID {
return createChainIDFromParent(ChainID(dgsts[0]), dgsts[1:]...)
}
// H = "H(n-1) SHA256(n)"
dgst, err := digest.FromBytes([]byte(string(parent) + " " + string(dgsts[0])))
if err != nil {
// Digest calculation is not expected to throw an error,
// any error at this point is a program error
panic(err)
}
dgst := digest.FromBytes([]byte(string(parent) + " " + string(dgsts[0])))
return createChainIDFromParent(ChainID(dgst), dgsts[1:]...)
}

View File

@ -548,10 +548,7 @@ func TestTarStreamStability(t *testing.T) {
}
func assertLayerDiff(t *testing.T, expected []byte, layer Layer) {
expectedDigest, err := digest.FromBytes(expected)
if err != nil {
t.Fatal(err)
}
expectedDigest := digest.FromBytes(expected)
if digest.Digest(layer.DiffID()) != expectedDigest {
t.Fatalf("Mismatched diff id for %s, got %s, expected %s", layer.ChainID(), layer.DiffID(), expected)
@ -573,10 +570,7 @@ func assertLayerDiff(t *testing.T, expected []byte, layer Layer) {
t.Fatalf("Mismatched tar stream size for %s, got %d, expected %d", layer.ChainID(), len(actual), len(expected))
}
actualDigest, err := digest.FromBytes(actual)
if err != nil {
t.Fatal(err)
}
actualDigest := digest.FromBytes(actual)
if actualDigest != expectedDigest {
logByteDiff(t, actual, expected)

View File

@ -37,10 +37,7 @@ func GetLayerPath(s Store, layer ChainID) (string, error) {
func (ls *layerStore) RegisterDiffID(graphID string, size int64) (Layer, error) {
var err error // this is used for cleanup in existingLayer case
diffID, err := digest.FromBytes([]byte(graphID))
if err != nil {
return nil, err
}
diffID := digest.FromBytes([]byte(graphID))
// Create new roLayer
layer := &roLayer{