Fix layer exclusion bug on multiple tag push
Ensure that layers are not excluded from manifests based on previous pushes. Continue skipping pushes on layers which were pushed by a previous tag. Update push multiple tag tests. Ensure that each tag pushed exists on the registry and is pullable. Add output comparison on multiple tag push check. fixes #15536 Signed-off-by: Derek McGowan <derek@mcgstyle.net> (github: dmcgowan)
This commit is contained in:
parent
72f355e466
commit
a0d9ffd6f7
|
@ -5,6 +5,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
|
"github.com/docker/distribution/digest"
|
||||||
"github.com/docker/docker/cliconfig"
|
"github.com/docker/docker/cliconfig"
|
||||||
"github.com/docker/docker/pkg/streamformatter"
|
"github.com/docker/docker/pkg/streamformatter"
|
||||||
"github.com/docker/docker/registry"
|
"github.com/docker/docker/registry"
|
||||||
|
@ -44,12 +45,13 @@ func (s *TagStore) NewPusher(endpoint registry.APIEndpoint, localRepo Repository
|
||||||
switch endpoint.Version {
|
switch endpoint.Version {
|
||||||
case registry.APIVersion2:
|
case registry.APIVersion2:
|
||||||
return &v2Pusher{
|
return &v2Pusher{
|
||||||
TagStore: s,
|
TagStore: s,
|
||||||
endpoint: endpoint,
|
endpoint: endpoint,
|
||||||
localRepo: localRepo,
|
localRepo: localRepo,
|
||||||
repoInfo: repoInfo,
|
repoInfo: repoInfo,
|
||||||
config: imagePushConfig,
|
config: imagePushConfig,
|
||||||
sf: sf,
|
sf: sf,
|
||||||
|
layersPushed: make(map[digest.Digest]bool),
|
||||||
}, nil
|
}, nil
|
||||||
case registry.APIVersion1:
|
case registry.APIVersion1:
|
||||||
return &v1Pusher{
|
return &v1Pusher{
|
||||||
|
|
|
@ -27,6 +27,11 @@ type v2Pusher struct {
|
||||||
config *ImagePushConfig
|
config *ImagePushConfig
|
||||||
sf *streamformatter.StreamFormatter
|
sf *streamformatter.StreamFormatter
|
||||||
repo distribution.Repository
|
repo distribution.Repository
|
||||||
|
|
||||||
|
// layersPushed is the set of layers known to exist on the remote side.
|
||||||
|
// This avoids redundant queries when pushing multiple tags that
|
||||||
|
// involve the same layers.
|
||||||
|
layersPushed map[digest.Digest]bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *v2Pusher) Push() (fallback bool, err error) {
|
func (p *v2Pusher) Push() (fallback bool, err error) {
|
||||||
|
@ -117,6 +122,10 @@ func (p *v2Pusher) pushV2Tag(tag string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// break early if layer has already been seen in this image,
|
||||||
|
// this prevents infinite loops on layers which loopback, this
|
||||||
|
// cannot be prevented since layer IDs are not merkle hashes
|
||||||
|
// TODO(dmcgowan): throw error if no valid use case is found
|
||||||
if layersSeen[layer.ID] {
|
if layersSeen[layer.ID] {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -138,6 +147,13 @@ func (p *v2Pusher) pushV2Tag(tag string) error {
|
||||||
dgst, err := p.graph.GetDigest(layer.ID)
|
dgst, err := p.graph.GetDigest(layer.ID)
|
||||||
switch err {
|
switch err {
|
||||||
case nil:
|
case nil:
|
||||||
|
if p.layersPushed[dgst] {
|
||||||
|
exists = true
|
||||||
|
// break out of switch, it is already known that
|
||||||
|
// the push is not needed and therefore doing a
|
||||||
|
// stat is unnecessary
|
||||||
|
break
|
||||||
|
}
|
||||||
_, err := p.repo.Blobs(context.Background()).Stat(context.Background(), dgst)
|
_, err := p.repo.Blobs(context.Background()).Stat(context.Background(), dgst)
|
||||||
switch err {
|
switch err {
|
||||||
case nil:
|
case nil:
|
||||||
|
@ -173,6 +189,7 @@ func (p *v2Pusher) pushV2Tag(tag string) error {
|
||||||
m.History = append(m.History, manifest.History{V1Compatibility: string(jsonData)})
|
m.History = append(m.History, manifest.History{V1Compatibility: string(jsonData)})
|
||||||
|
|
||||||
layersSeen[layer.ID] = true
|
layersSeen[layer.ID] = true
|
||||||
|
p.layersPushed[dgst] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
logrus.Infof("Signed manifest for %s:%s using daemon's key: %s", p.repo.Name(), tag, p.trustKey.KeyID())
|
logrus.Infof("Signed manifest for %s:%s using daemon's key: %s", p.repo.Name(), tag, p.trustKey.KeyID())
|
||||||
|
|
Loading…
Reference in New Issue