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:
parent
290ba41c00
commit
c168a0059f
13 changed files with 91 additions and 147 deletions
|
@ -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())
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
12
image/fs.go
12
image/fs.go
|
@ -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 {
|
||||
|
|
|
@ -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.")
|
||||
|
|
|
@ -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...))
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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:]...)
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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{
|
||||
|
|
Loading…
Add table
Reference in a new issue