-
Notifications
You must be signed in to change notification settings - Fork 4.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Take care of manifest config blob #10759
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -660,7 +660,9 @@ function install_registry() { | |
readonly -f install_registry | ||
|
||
function wait_for_registry() { | ||
wait_for_command "oc get endpoints docker-registry --template='{{ len .subsets }}' --config='${ADMIN_KUBECONFIG}' | grep -q '[1-9][0-9]*'" $((5*TIME_MIN)) | ||
local generation=$(oc get dc/docker-registry -o jsonpath='{.metadata.generation}') | ||
local onereplicajs='{.status.observedGeneration},{.status.replicas},{.status.updatedReplicas},{.status.availableReplicas}' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Quote expansions There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry, thats for the line above this |
||
wait_for_command "oc get dc/docker-registry -o jsonpath='$onereplicajs' --config='${ADMIN_KUBECONFIG}' | grep '^$generation,1,1,1$'" $((5*TIME_MIN)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use |
||
local readyjs='{.items[*].status.conditions[?(@.type=="Ready")].status}' | ||
wait_for_command "oc get pod -l deploymentconfig=docker-registry -o jsonpath='$readyjs' --config='${ADMIN_KUBECONFIG}' | grep -qi true" $TIME_MIN | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -43,6 +43,12 @@ func (r *pullthroughBlobStore) Stat(ctx context.Context, dgst digest.Digest) (di | |
return desc, err | ||
} | ||
|
||
return r.remoteStat(ctx, dgst) | ||
} | ||
|
||
// remoteStat attempts to find requested blob in candidate remote repositories and if found, it updates | ||
// digestToRepository store. ErrBlobUnknown will be returned if not found. | ||
func (r *pullthroughBlobStore) remoteStat(ctx context.Context, dgst digest.Digest) (distribution.Descriptor, error) { | ||
// look up the potential remote repositories that this blob could be part of (at this time, | ||
// we don't know which image in the image stream surfaced the content). | ||
is, err := r.repo.getImageStream() | ||
|
@@ -112,13 +118,13 @@ func (r *pullthroughBlobStore) ServeBlob(ctx context.Context, w http.ResponseWri | |
|
||
desc, err := store.Stat(ctx, dgst) | ||
if err != nil { | ||
context.GetLogger(ctx).Errorf("Failed to stat digest %q: %v", dgst.String(), err) | ||
context.GetLogger(ctx).Errorf("failed to stat digest %q: %v", dgst.String(), err) | ||
return err | ||
} | ||
|
||
remoteReader, err := store.Open(ctx, dgst) | ||
if err != nil { | ||
context.GetLogger(ctx).Errorf("Failure to open remote store for digest %q: %v", dgst.String(), err) | ||
context.GetLogger(ctx).Errorf("failure to open remote store for digest %q: %v", dgst.String(), err) | ||
return err | ||
} | ||
defer remoteReader.Close() | ||
|
@@ -130,6 +136,30 @@ func (r *pullthroughBlobStore) ServeBlob(ctx context.Context, w http.ResponseWri | |
return nil | ||
} | ||
|
||
// Get attempts to fetch the requested blob by digest using a remote proxy store if necessary. | ||
func (r *pullthroughBlobStore) Get(ctx context.Context, dgst digest.Digest) ([]byte, error) { | ||
store, ok := r.digestToStore[dgst.String()] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. return early in the ok case and unindent the rest of the function?
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. pullthroughBlobStore instances are per-request, right? just making sure we don't have to worry about locking/races on the digestToStore map, or about long-term growth/retention There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
good suggestion, I'll rewrite There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
That's right. |
||
if ok { | ||
return store.Get(ctx, dgst) | ||
} | ||
|
||
data, originalErr := r.BlobStore.Get(ctx, dgst) | ||
if originalErr == nil { | ||
return data, nil | ||
} | ||
|
||
desc, err := r.remoteStat(ctx, dgst) | ||
if err != nil { | ||
context.GetLogger(ctx).Errorf("failed to stat blob %q in remote repositories: %v", dgst.String(), err) | ||
return nil, originalErr | ||
} | ||
store, ok = r.digestToStore[desc.Digest.String()] | ||
if !ok { | ||
return nil, originalErr | ||
} | ||
return store.Get(ctx, desc.Digest) | ||
} | ||
|
||
// findCandidateRepository looks in search for a particular blob, referring to previously cached items | ||
func (r *pullthroughBlobStore) findCandidateRepository(ctx context.Context, search map[string]*imageapi.DockerImageReference, cachedLayers []string, dgst digest.Digest, retriever importer.RepositoryRetriever) (distribution.Descriptor, error) { | ||
// no possible remote locations to search, exit early | ||
|
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -452,7 +452,7 @@ func (r *repository) signedManifestFillImageMetadata(manifest *schema1.SignedMan | |||
|
||||
refs := manifest.References() | ||||
|
||||
layerSet := sets.NewString() | ||||
blobSet := sets.NewString() | ||||
image.DockerImageMetadata.Size = int64(0) | ||||
|
||||
blobs := r.Blobs(r.ctx) | ||||
|
@@ -473,11 +473,15 @@ func (r *repository) signedManifestFillImageMetadata(manifest *schema1.SignedMan | |||
} | ||||
layer.LayerSize = desc.Size | ||||
// count empty layer just once (empty layer may actually have non-zero size) | ||||
if !layerSet.Has(layer.Name) { | ||||
if !blobSet.Has(layer.Name) { | ||||
image.DockerImageMetadata.Size += desc.Size | ||||
layerSet.Insert(layer.Name) | ||||
blobSet.Insert(layer.Name) | ||||
} | ||||
} | ||||
if len(image.DockerImageConfig) > 0 && !blobSet.Has(image.DockerImageMetadata.ID) { | ||||
blobSet.Insert(image.DockerImageMetadata.ID) | ||||
image.DockerImageMetadata.Size += int64(len(image.DockerImageConfig)) | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the size of the ID is not already included? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. would like a test around this size calculation There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The ID is a name of the config. It's actually a digest - similar to layer's digests. The size needs to be updated for the size of the config itself, not its ID. Update of
|
||||
} | ||||
|
||||
return nil | ||||
} | ||||
|
@@ -544,7 +548,7 @@ func (r *repository) getImageStreamImage(dgst digest.Digest) (*imageapi.ImageStr | |||
|
||||
// rememberLayersOfImage caches the layer digests of given image | ||||
func (r *repository) rememberLayersOfImage(image *imageapi.Image, cacheName string) { | ||||
if len(image.DockerImageLayers) == 0 && len(image.DockerImageManifestMediaType) > 0 { | ||||
if len(image.DockerImageLayers) == 0 && len(image.DockerImageManifestMediaType) > 0 && len(image.DockerImageConfig) == 0 { | ||||
// image has no layers | ||||
return | ||||
} | ||||
|
@@ -553,6 +557,10 @@ func (r *repository) rememberLayersOfImage(image *imageapi.Image, cacheName stri | |||
for _, layer := range image.DockerImageLayers { | ||||
r.cachedLayers.RememberDigest(digest.Digest(layer.Name), r.blobrepositorycachettl, cacheName) | ||||
} | ||||
// remember reference to manifest config as well for schema 2 | ||||
if image.DockerImageManifestMediaType == schema2.MediaTypeManifest && len(image.DockerImageMetadata.ID) > 0 { | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should we only do this if There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
To make it comply with the other conditions, I'll use this instead. |
||||
r.cachedLayers.RememberDigest(digest.Digest(image.DockerImageMetadata.ID), r.blobrepositorycachettl, cacheName) | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
For schema 2, it is parsed from manifest which is immutable: origin/pkg/image/api/helper.go Line 543 in e22f4b2
|
||||
} | ||||
return | ||||
} | ||||
|
||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -310,15 +310,15 @@ func formatRepositoryError(repository *importRepository, refName string, refID s | |
func (isi *ImageStreamImporter) calculateImageSize(ctx gocontext.Context, repo distribution.Repository, image *api.Image) error { | ||
bs := repo.Blobs(ctx) | ||
|
||
layerSet := sets.NewString() | ||
blobSet := sets.NewString() | ||
size := int64(0) | ||
for i := range image.DockerImageLayers { | ||
layer := &image.DockerImageLayers[i] | ||
|
||
if layerSet.Has(layer.Name) { | ||
if blobSet.Has(layer.Name) { | ||
continue | ||
} | ||
layerSet.Insert(layer.Name) | ||
blobSet.Insert(layer.Name) | ||
|
||
if layerSize, ok := isi.digestToLayerSizeCache[layer.Name]; ok { | ||
size += layerSize | ||
|
@@ -335,6 +335,11 @@ func (isi *ImageStreamImporter) calculateImageSize(ctx gocontext.Context, repo d | |
size += desc.Size | ||
} | ||
|
||
if len(image.DockerImageConfig) > 0 && !blobSet.Has(image.DockerImageMetadata.ID) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should we only do this if There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Both conditions should be equivalent:
I'll use the first everywhere. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using |
||
blobSet.Insert(image.DockerImageMetadata.ID) | ||
size += int64(len(image.DockerImageConfig)) | ||
} | ||
|
||
image.DockerImageMetadata.Size = size | ||
return nil | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
need to make sure the status has observed the current generation as well:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense, added.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO: put a comment that all the registry re-deployments wipe out registry storage.