diff --git a/pkg/dockerregistry/server/imagestream.go b/pkg/dockerregistry/server/imagestream.go index 0549649fa..1311d8ff5 100644 --- a/pkg/dockerregistry/server/imagestream.go +++ b/pkg/dockerregistry/server/imagestream.go @@ -22,6 +22,7 @@ import ( "github.com/openshift/image-registry/pkg/dockerregistry/server/cache" "github.com/openshift/image-registry/pkg/dockerregistry/server/client" registrymanifest "github.com/openshift/image-registry/pkg/dockerregistry/server/manifest" + "github.com/openshift/image-registry/pkg/imagestream" imageapi "github.com/openshift/image-registry/pkg/origin-common/image/apis/image" quotautil "github.com/openshift/image-registry/pkg/origin-common/quota/util" util "github.com/openshift/image-registry/pkg/origin-common/util" @@ -74,10 +75,10 @@ func (is *imageStream) createImageStream(ctx context.Context) (*imageapiv1.Image return stream, nil } -// getImage retrieves the Image with digest `dgst`. No authorization check is done. -func (is *imageStream) getImage(ctx context.Context, dgst digest.Digest) (*imageapiv1.Image, error) { +// GetImage retrieves the Image with digest `dgst`. No authorization check is done. +func (is *imageStream) GetImage(ctx context.Context, dgst digest.Digest) (*imageapiv1.Image, error) { if image, exists := is.cachedImages[dgst]; exists { - context.GetLogger(ctx).Infof("(*imageStream).getImage: returning cached copy of %s", image.Name) + context.GetLogger(ctx).Infof("(*imageStream).GetImage: returning cached copy of %s", image.Name) return image, nil } @@ -87,7 +88,7 @@ func (is *imageStream) getImage(ctx context.Context, dgst digest.Digest) (*image return nil, wrapKStatusErrorOnGetImage(is.name, dgst, err) } - context.GetLogger(ctx).Infof("(*imageStream).getImage: got image %s", image.Name) + context.GetLogger(ctx).Infof("(*imageStream).GetImage: got image %s", image.Name) if err := util.ImageWithMetadata(image); err != nil { return nil, err } @@ -95,7 +96,7 @@ func (is *imageStream) getImage(ctx context.Context, dgst digest.Digest) (*image return image, nil } -// getStoredImageOfImageStream retrieves the Image with digest `dgst` and +// GetStoredImageOfImageStream retrieves the Image with digest `dgst` and // ensures that the image belongs to the image stream `is`. It uses two // queries to master API: // @@ -105,8 +106,8 @@ func (is *imageStream) getImage(ctx context.Context, dgst digest.Digest) (*image // This allows us to cache the image stream for later use. // // If you need the image object to be modified according to image stream tag, -// please use getImageOfImageStream. -func (is *imageStream) getStoredImageOfImageStream(ctx context.Context, dgst digest.Digest) (*imageapiv1.Image, *imageapiv1.TagEvent, *imageapiv1.ImageStream, error) { +// please use GetImageOfImageStream. +func (is *imageStream) GetStoredImageOfImageStream(ctx context.Context, dgst digest.Digest) (*imageapiv1.Image, *imageapiv1.TagEvent, *imageapiv1.ImageStream, error) { stream, err := is.imageStreamGetter.get() if err != nil { context.GetLogger(ctx).Errorf("failed to get ImageStream: %v", err) @@ -119,7 +120,7 @@ func (is *imageStream) getStoredImageOfImageStream(ctx context.Context, dgst dig return nil, nil, nil, wrapKStatusErrorOnGetImage(is.name, dgst, err) } - image, err := is.getImage(ctx, dgst) + image, err := is.GetImage(ctx, dgst) if err != nil { return nil, nil, nil, wrapKStatusErrorOnGetImage(is.name, dgst, err) } @@ -127,7 +128,7 @@ func (is *imageStream) getStoredImageOfImageStream(ctx context.Context, dgst dig return image, tagEvent, stream, nil } -// getImageOfImageStream retrieves the Image with digest `dgst` for the image +// GetImageOfImageStream retrieves the Image with digest `dgst` for the image // stream. The image's field DockerImageReference is modified on the fly to // pretend that we've got the image from the source from which the image was // tagged to match tag's DockerImageReference. @@ -135,8 +136,8 @@ func (is *imageStream) getStoredImageOfImageStream(ctx context.Context, dgst dig // NOTE: due to on the fly modification, the returned image object should // not be sent to the master API. If you need unmodified version of the // image object, please use getStoredImageOfImageStream. -func (is *imageStream) getImageOfImageStream(ctx context.Context, dgst digest.Digest) (*imageapiv1.Image, *imageapiv1.ImageStream, error) { - image, tagEvent, stream, err := is.getStoredImageOfImageStream(ctx, dgst) +func (is *imageStream) GetImageOfImageStream(ctx context.Context, dgst digest.Digest) (*imageapiv1.Image, *imageapiv1.ImageStream, error) { + image, tagEvent, stream, err := is.GetStoredImageOfImageStream(ctx, dgst) if err != nil { return nil, nil, err } @@ -146,13 +147,13 @@ func (is *imageStream) getImageOfImageStream(ctx context.Context, dgst digest.Di return image, stream, nil } -// updateImage modifies the Image. -func (is *imageStream) updateImage(image *imageapiv1.Image) (*imageapiv1.Image, error) { +// UpdateImage modifies the Image. +func (is *imageStream) UpdateImage(image *imageapiv1.Image) (*imageapiv1.Image, error) { return is.registryOSClient.Images().Update(image) } -// rememberLayersOfImage caches the layer digests of given image -func (is *imageStream) rememberLayersOfImage(ctx context.Context, image *imageapiv1.Image, cacheName string) { +// RememberLayersOfImage caches the layer digests of given image +func (is *imageStream) RememberLayersOfImage(ctx context.Context, image *imageapiv1.Image, cacheName string) { if len(image.DockerImageLayers) > 0 { for _, layer := range image.DockerImageLayers { _ = is.cache.AddDigest(digest.Digest(layer.Name), cacheName) @@ -179,7 +180,7 @@ func (is *imageStream) rememberLayersOfImage(ctx context.Context, image *imageap } } -func (is *imageStream) getSecrets() ([]corev1.Secret, error) { +func (is *imageStream) GetSecrets() ([]corev1.Secret, error) { secrets, err := is.registryOSClient.ImageStreamSecrets(is.namespace).Secrets(is.name, metav1.ListOptions{}) if err != nil { return nil, fmt.Errorf("error getting secrets for repository %s: %v", is.Reference(), err) @@ -187,9 +188,9 @@ func (is *imageStream) getSecrets() ([]corev1.Secret, error) { return secrets.Items, nil } -// tagIsInsecure returns true if the given image stream or its tag allow for +// TagIsInsecure returns true if the given image stream or its tag allow for // insecure transport. -func (is *imageStream) tagIsInsecure(tag string, dgst digest.Digest) (bool, error) { +func (is *imageStream) TagIsInsecure(tag string, dgst digest.Digest) (bool, error) { stream, err := is.imageStreamGetter.get() if err != nil { return false, err @@ -239,7 +240,7 @@ func (is *imageStream) localRegistry() (string, error) { return local.Registry, nil } -func (is *imageStream) IdentifyCandidateRepositories(primary bool) ([]string, map[string]ImagePullthroughSpec, error) { +func (is *imageStream) IdentifyCandidateRepositories(primary bool) ([]string, map[string]imagestream.ImagePullthroughSpec, error) { stream, err := is.imageStreamGetter.get() if err != nil { return nil, nil, err @@ -324,7 +325,7 @@ func (is *imageStream) Untag(ctx context.Context, tag string, pullthroughEnabled return err } - image, err := is.getImage(ctx, dgst) + image, err := is.GetImage(ctx, dgst) if err != nil { return err } diff --git a/pkg/dockerregistry/server/imagestreamhasblob.go b/pkg/dockerregistry/server/imagestreamhasblob.go index 01d465ccb..0dae69cfd 100644 --- a/pkg/dockerregistry/server/imagestreamhasblob.go +++ b/pkg/dockerregistry/server/imagestreamhasblob.go @@ -81,7 +81,7 @@ func (is *imageStream) HasBlob(ctx context.Context, dgst digest.Digest, requireM processedImages[tagEvent.Image] = struct{}{} context.GetLogger(ctx).Debugf("getting image %s", tagEvent.Image) - image, err := is.getImage(ctx, digest.Digest(tagEvent.Image)) + image, err := is.GetImage(ctx, digest.Digest(tagEvent.Image)) if err != nil { if kerrors.IsNotFound(err) { context.GetLogger(ctx).Debugf("image %q not found", tagEvent.Image) @@ -102,7 +102,7 @@ func (is *imageStream) HasBlob(ctx context.Context, dgst digest.Digest, requireM tagName := event2Name[tagEvent] context.GetLogger(ctx).Debugf("blob found under istag %s:%s in image %s", is.Reference(), tagName, tagEvent.Image) // remember all the layers of matching image - is.rememberLayersOfImage(ctx, image, repoCacheName) + is.RememberLayersOfImage(ctx, image, repoCacheName) return logFound(true) } } diff --git a/pkg/dockerregistry/server/manifestservice.go b/pkg/dockerregistry/server/manifestservice.go index 2f7b5d269..9237aad74 100644 --- a/pkg/dockerregistry/server/manifestservice.go +++ b/pkg/dockerregistry/server/manifestservice.go @@ -15,6 +15,7 @@ import ( imageapiv1 "github.com/openshift/api/image/v1" registrymanifest "github.com/openshift/image-registry/pkg/dockerregistry/server/manifest" + "github.com/openshift/image-registry/pkg/imagestream" imageapi "github.com/openshift/image-registry/pkg/origin-common/image/apis/image" ) @@ -39,7 +40,7 @@ type manifestService struct { blobStore distribution.BlobStore serverAddr string - imageStream *imageStream + imageStream imagestream.ImageStream // acceptSchema2 allows to refuse the manifest schema version 2 acceptSchema2 bool @@ -49,7 +50,7 @@ type manifestService struct { func (m *manifestService) Exists(ctx context.Context, dgst digest.Digest) (bool, error) { context.GetLogger(ctx).Debugf("(*manifestService).Exists") - image, _, err := m.imageStream.getImageOfImageStream(ctx, dgst) + image, _, err := m.imageStream.GetImageOfImageStream(ctx, dgst) if err != nil { return false, err } @@ -60,7 +61,7 @@ func (m *manifestService) Exists(ctx context.Context, dgst digest.Digest) (bool, func (m *manifestService) Get(ctx context.Context, dgst digest.Digest, options ...distribution.ManifestServiceOption) (distribution.Manifest, error) { context.GetLogger(ctx).Debugf("(*manifestService).Get") - image, _, _, err := m.imageStream.getStoredImageOfImageStream(ctx, dgst) + image, _, _, err := m.imageStream.GetStoredImageOfImageStream(ctx, dgst) if err != nil { return nil, err } @@ -76,7 +77,7 @@ func (m *manifestService) Get(ctx context.Context, dgst digest.Digest, options . manifest, err := m.manifests.Get(ctx, dgst, options...) if err == nil { - m.imageStream.rememberLayersOfImage(ctx, image, ref) + m.imageStream.RememberLayersOfImage(ctx, image, ref) m.migrateManifest(ctx, image, dgst, manifest, true) return manifest, nil } else if _, ok := err.(distribution.ErrManifestUnknownRevision); !ok { @@ -86,7 +87,7 @@ func (m *manifestService) Get(ctx context.Context, dgst digest.Digest, options . manifest, err = registrymanifest.NewFromImage(image) if err == nil { - m.imageStream.rememberLayersOfImage(ctx, image, ref) + m.imageStream.RememberLayersOfImage(ctx, image, ref) m.migrateManifest(ctx, image, dgst, manifest, false) return manifest, nil } else { @@ -228,7 +229,7 @@ func (m *manifestService) storeManifestLocally(ctx context.Context, image *image } image.Annotations[imageapi.ImageManifestBlobStoredAnnotation] = "true" - if _, err := m.imageStream.updateImage(image); err != nil { + if _, err := m.imageStream.UpdateImage(image); err != nil { context.GetLogger(ctx).Errorf("error updating Image: %v", err) } } diff --git a/pkg/dockerregistry/server/projectcache.go b/pkg/dockerregistry/server/projectcache.go index 6d81cc2eb..b0db4148e 100644 --- a/pkg/dockerregistry/server/projectcache.go +++ b/pkg/dockerregistry/server/projectcache.go @@ -6,24 +6,19 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/tools/cache" -) -// projectObjectListStore represents a cache of objects indexed by a project name. -// Used to store a list of items per namespace. -type projectObjectListStore interface { - add(namespace string, obj runtime.Object) error - get(namespace string) (obj runtime.Object, exists bool, err error) -} + "github.com/openshift/image-registry/pkg/imagestream" +) // projectObjectListCache implements projectObjectListStore. type projectObjectListCache struct { store cache.Store } -var _ projectObjectListStore = &projectObjectListCache{} +var _ imagestream.ProjectObjectListStore = &projectObjectListCache{} // newProjectObjectListCache creates a cache to hold object list objects that will expire with the given ttl. -func newProjectObjectListCache(ttl time.Duration) projectObjectListStore { +func newProjectObjectListCache(ttl time.Duration) imagestream.ProjectObjectListStore { return &projectObjectListCache{ store: cache.NewTTLStore(metaProjectObjectListKeyFunc, ttl), } @@ -31,7 +26,7 @@ func newProjectObjectListCache(ttl time.Duration) projectObjectListStore { // add stores given list object under the given namespace. Any prior object under this // key will be replaced. -func (c *projectObjectListCache) add(namespace string, obj runtime.Object) error { +func (c *projectObjectListCache) Add(namespace string, obj runtime.Object) error { if namespace == "" { return fmt.Errorf("namespace cannot be empty") } @@ -43,7 +38,7 @@ func (c *projectObjectListCache) add(namespace string, obj runtime.Object) error } // get retrieves a cached list object if present and not expired. -func (c *projectObjectListCache) get(namespace string) (runtime.Object, bool, error) { +func (c *projectObjectListCache) Get(namespace string) (runtime.Object, bool, error) { entry, exists, err := c.store.GetByKey(namespace) if err != nil { return nil, exists, err diff --git a/pkg/dockerregistry/server/pullthroughblobstore_test.go b/pkg/dockerregistry/server/pullthroughblobstore_test.go index d98f8ffb9..5bfe51c87 100644 --- a/pkg/dockerregistry/server/pullthroughblobstore_test.go +++ b/pkg/dockerregistry/server/pullthroughblobstore_test.go @@ -141,7 +141,7 @@ func TestPullthroughServeBlob(t *testing.T) { remoteBlobGetter := NewBlobGetterService( imageStream, - imageStream.getSecrets, + imageStream.GetSecrets, imageStream.cache) ptbs := &pullthroughBlobStore{ @@ -562,7 +562,7 @@ func TestPullthroughServeBlobInsecure(t *testing.T) { remoteBlobGetter := NewBlobGetterService( imageStream, - imageStream.getSecrets, + imageStream.GetSecrets, imageStream.cache) ptbs := &pullthroughBlobStore{ diff --git a/pkg/dockerregistry/server/pullthroughmanifestservice.go b/pkg/dockerregistry/server/pullthroughmanifestservice.go index 0ace4a3a2..c30d9382e 100644 --- a/pkg/dockerregistry/server/pullthroughmanifestservice.go +++ b/pkg/dockerregistry/server/pullthroughmanifestservice.go @@ -5,6 +5,7 @@ import ( "github.com/docker/distribution/context" "github.com/docker/distribution/digest" + "github.com/openshift/image-registry/pkg/imagestream" imageapi "github.com/openshift/image-registry/pkg/origin-common/image/apis/image" ) @@ -15,7 +16,7 @@ import ( type pullthroughManifestService struct { distribution.ManifestService localManifestService distribution.ManifestService - imageStream *imageStream + imageStream imagestream.ImageStream mirror bool } @@ -38,7 +39,7 @@ func (m *pullthroughManifestService) Get(ctx context.Context, dgst digest.Digest func (m *pullthroughManifestService) remoteGet(ctx context.Context, dgst digest.Digest, options ...distribution.ManifestServiceOption) (distribution.Manifest, error) { context.GetLogger(ctx).Debugf("(*pullthroughManifestService).remoteGet: starting with dgst=%s", dgst.String()) - image, _, err := m.imageStream.getImageOfImageStream(ctx, dgst) + image, _, err := m.imageStream.GetImageOfImageStream(ctx, dgst) if err != nil { return nil, err } @@ -70,7 +71,7 @@ func (m *pullthroughManifestService) remoteGet(ctx context.Context, dgst digest. context.GetLogger(ctx).Errorf("failed to mirror manifest %s: %v", ref.Exact(), putErr) } } - m.imageStream.rememberLayersOfImage(ctx, image, ref.Exact()) + m.imageStream.RememberLayersOfImage(ctx, image, ref.Exact()) case distribution.ErrManifestUnknownRevision: break default: @@ -81,7 +82,7 @@ func (m *pullthroughManifestService) remoteGet(ctx context.Context, dgst digest. } func (m *pullthroughManifestService) getRemoteRepositoryClient(ctx context.Context, ref *imageapi.DockerImageReference, dgst digest.Digest, options ...distribution.ManifestServiceOption) (distribution.Repository, error) { - retriever := getImportContext(ctx, m.imageStream.getSecrets) + retriever := getImportContext(ctx, m.imageStream.GetSecrets) // determine, whether to fall-back to insecure transport based on a specification of image's tag // if the client pulls by tag, use that @@ -93,7 +94,7 @@ func (m *pullthroughManifestService) getRemoteRepositoryClient(ctx context.Conte } } - insecure, err := m.imageStream.tagIsInsecure(tag, dgst) + insecure, err := m.imageStream.TagIsInsecure(tag, dgst) if err != nil { return nil, err } diff --git a/pkg/dockerregistry/server/quotarestrictedblobstore.go b/pkg/dockerregistry/server/quotarestrictedblobstore.go index 7fcd2589c..2965e116f 100644 --- a/pkg/dockerregistry/server/quotarestrictedblobstore.go +++ b/pkg/dockerregistry/server/quotarestrictedblobstore.go @@ -23,6 +23,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/openshift/image-registry/pkg/dockerregistry/server/configuration" + "github.com/openshift/image-registry/pkg/imagestream" imageapi "github.com/openshift/image-registry/pkg/origin-common/image/apis/image" ) @@ -55,7 +56,7 @@ type quotaEnforcingConfig struct { // if set, enables quota enforcement enforcementEnabled bool // if set, enables caching of quota objects per project - limitRanges projectObjectListStore + limitRanges imagestream.ProjectObjectListStore } // quotaRestrictedBlobStore wraps upstream blob store with a guard preventing big layers exceeding image quotas @@ -120,10 +121,10 @@ func (bw *quotaRestrictedBlobWriter) Commit(ctx context.Context, provisional dis return bw.BlobWriter.Commit(ctx, provisional) } -// getLimitRangeList returns list of limit ranges for repo. -func (is *imageStream) getLimitRangeList(ctx context.Context, cache projectObjectListStore) (*corev1.LimitRangeList, error) { +// GetLimitRangeList returns list of limit ranges for repo. +func (is *imageStream) GetLimitRangeList(ctx context.Context, cache imagestream.ProjectObjectListStore) (*corev1.LimitRangeList, error) { if cache != nil { - obj, exists, _ := cache.get(is.namespace) + obj, exists, _ := cache.Get(is.namespace) if exists { return obj.(*corev1.LimitRangeList), nil } @@ -138,7 +139,7 @@ func (is *imageStream) getLimitRangeList(ctx context.Context, cache projectObjec } if cache != nil { - err = cache.add(is.namespace, lrs) + err = cache.Add(is.namespace, lrs) if err != nil { context.GetLogger(ctx).Errorf("failed to cache limit range list: %v", err) } @@ -154,7 +155,7 @@ func admitBlobWrite(ctx context.Context, repo *repository, size int64) error { return nil } - lrs, err := repo.imageStream.getLimitRangeList(ctx, repo.app.quotaEnforcing.limitRanges) + lrs, err := repo.imageStream.GetLimitRangeList(ctx, repo.app.quotaEnforcing.limitRanges) if err != nil { return err } diff --git a/pkg/dockerregistry/server/remoteblobgetter.go b/pkg/dockerregistry/server/remoteblobgetter.go index 75f0b3a3d..d25e38ada 100644 --- a/pkg/dockerregistry/server/remoteblobgetter.go +++ b/pkg/dockerregistry/server/remoteblobgetter.go @@ -14,6 +14,7 @@ import ( imageapiv1 "github.com/openshift/api/image/v1" "github.com/openshift/image-registry/pkg/dockerregistry/server/cache" + "github.com/openshift/image-registry/pkg/imagestream" imageapi "github.com/openshift/image-registry/pkg/origin-common/image/apis/image" "github.com/openshift/image-registry/pkg/origin-common/image/registryclient" ) @@ -57,7 +58,7 @@ func (c *digestBlobStoreCache) Put(dgst digest.Digest, bs distribution.BlobStore // remoteBlobGetterService implements BlobGetterService and allows to serve blobs from remote // repositories. type remoteBlobGetterService struct { - imageStream *imageStream + imageStream imagestream.ImageStream getSecrets secretsGetter cache cache.RepositoryDigest digestToStore *digestBlobStoreCache @@ -68,7 +69,7 @@ var _ BlobGetterService = &remoteBlobGetterService{} // NewBlobGetterService returns a getter for remote blobs. Its cache will be shared among different middleware // wrappers, which is a must at least for stat calls made on manifest's dependencies during its verification. func NewBlobGetterService( - imageStream *imageStream, + imageStream imagestream.ImageStream, secretsGetter secretsGetter, cache cache.RepositoryDigest, ) BlobGetterService { @@ -80,13 +81,6 @@ func NewBlobGetterService( } } -// ImagePullthroughSpec contains a reference of remote image to pull associated with an insecure flag for the -// corresponding registry. -type ImagePullthroughSpec struct { - dockerImageReference *imageapi.DockerImageReference - insecure bool -} - // Stat provides metadata about a blob identified by the digest. If the // blob is unknown to the describer, ErrBlobUnknown will be returned. func (rbgs *remoteBlobGetterService) Stat(ctx context.Context, dgst digest.Digest) (distribution.Descriptor, error) { @@ -176,16 +170,16 @@ func (rbgs *remoteBlobGetterService) ServeBlob(ctx context.Context, w http.Respo func (rbgs *remoteBlobGetterService) proxyStat( ctx context.Context, retriever registryclient.RepositoryRetriever, - spec *ImagePullthroughSpec, + spec *imagestream.ImagePullthroughSpec, dgst digest.Digest, ) (distribution.Descriptor, error) { - ref := spec.dockerImageReference + ref := spec.DockerImageReference insecureNote := "" - if spec.insecure { + if spec.Insecure { insecureNote = " with a fall-back to insecure transport" } context.GetLogger(ctx).Infof("Trying to stat %q from %q%s", dgst, ref.AsRepository().Exact(), insecureNote) - repo, err := retriever.Repository(ctx, ref.RegistryURL(), ref.RepositoryName(), spec.insecure) + repo, err := retriever.Repository(ctx, ref.RegistryURL(), ref.RepositoryName(), spec.Insecure) if err != nil { context.GetLogger(ctx).Errorf("Error getting remote repository for image %q: %v", ref.AsRepository().Exact(), err) return distribution.Descriptor{}, err @@ -230,7 +224,7 @@ func (rbgs *remoteBlobGetterService) Get(ctx context.Context, dgst digest.Digest func (rbgs *remoteBlobGetterService) findCandidateRepository( ctx context.Context, repositoryCandidates []string, - search map[string]ImagePullthroughSpec, + search map[string]imagestream.ImagePullthroughSpec, cachedRepos []string, dgst digest.Digest, retriever registryclient.RepositoryRetriever, @@ -276,7 +270,7 @@ func (rbgs *remoteBlobGetterService) findCandidateRepository( type byInsecureFlag struct { repositories []string - specs []*ImagePullthroughSpec + specs []*imagestream.ImagePullthroughSpec } func (by *byInsecureFlag) Len() int { @@ -290,17 +284,17 @@ func (by *byInsecureFlag) Swap(i, j int) { by.specs[i], by.specs[j] = by.specs[j], by.specs[i] } func (by *byInsecureFlag) Less(i, j int) bool { - if by.specs[i].insecure == by.specs[j].insecure { + if by.specs[i].Insecure == by.specs[j].Insecure { switch { case by.repositories[i] < by.repositories[j]: return true case by.repositories[i] > by.repositories[j]: return false default: - return by.specs[i].dockerImageReference.Exact() < by.specs[j].dockerImageReference.Exact() + return by.specs[i].DockerImageReference.Exact() < by.specs[j].DockerImageReference.Exact() } } - return !by.specs[i].insecure + return !by.specs[i].Insecure } // identifyCandidateRepositories returns a list of remote repository names sorted from the best candidate to @@ -310,7 +304,7 @@ func identifyCandidateRepositories( is *imageapiv1.ImageStream, localRegistry string, primary bool, -) ([]string, map[string]ImagePullthroughSpec) { +) ([]string, map[string]imagestream.ImagePullthroughSpec) { insecureByDefault := false if insecure, ok := is.Annotations[imageapi.InsecureRepositoryAnnotation]; ok { insecureByDefault = insecure == "true" @@ -362,14 +356,14 @@ func identifyCandidateRepositories( } repositories := make([]string, 0, len(search)) - results := make(map[string]ImagePullthroughSpec) - specs := []*ImagePullthroughSpec{} + results := make(map[string]imagestream.ImagePullthroughSpec) + specs := []*imagestream.ImagePullthroughSpec{} for repo, ref := range search { repositories = append(repositories, repo) // accompany the reference with corresponding registry's insecure flag - spec := ImagePullthroughSpec{ - dockerImageReference: ref, - insecure: insecureRegistries[ref.Registry], + spec := imagestream.ImagePullthroughSpec{ + DockerImageReference: ref, + Insecure: insecureRegistries[ref.Registry], } results[repo] = spec specs = append(specs, &spec) diff --git a/pkg/dockerregistry/server/remoteblobgetter_test.go b/pkg/dockerregistry/server/remoteblobgetter_test.go index 40365380d..1134096d1 100644 --- a/pkg/dockerregistry/server/remoteblobgetter_test.go +++ b/pkg/dockerregistry/server/remoteblobgetter_test.go @@ -10,6 +10,8 @@ import ( "k8s.io/apimachinery/pkg/util/diff" imageapiv1 "github.com/openshift/api/image/v1" + + "github.com/openshift/image-registry/pkg/imagestream" imageapi "github.com/openshift/image-registry/pkg/origin-common/image/apis/image" ) @@ -20,7 +22,7 @@ func TestIdentifyCandidateRepositories(t *testing.T) { localRegistry string primary bool expectedRepositories []string - expectedSearch map[string]ImagePullthroughSpec + expectedSearch map[string]imagestream.ImagePullthroughSpec }{ { name: "empty image stream", @@ -43,7 +45,7 @@ func TestIdentifyCandidateRepositories(t *testing.T) { localRegistry: "localhost:5000", primary: true, expectedRepositories: []string{"docker.io/library/busybox"}, - expectedSearch: map[string]ImagePullthroughSpec{ + expectedSearch: map[string]imagestream.ImagePullthroughSpec{ "docker.io/library/busybox": makeTestImagePullthroughSpec(t, "docker.io/library/busybox:latest", false), }, }, @@ -81,7 +83,7 @@ func TestIdentifyCandidateRepositories(t *testing.T) { localRegistry: "localhost:5000", primary: true, expectedRepositories: []string{"example.org/user/app", "registry.example.org/user/app"}, - expectedSearch: map[string]ImagePullthroughSpec{ + expectedSearch: map[string]imagestream.ImagePullthroughSpec{ "example.org/user/app": makeTestImagePullthroughSpec(t, "example.org/user/app:tag", false), "registry.example.org/user/app": makeTestImagePullthroughSpec(t, "registry.example.org/user/app:latest", true), }, @@ -120,7 +122,7 @@ func TestIdentifyCandidateRepositories(t *testing.T) { localRegistry: "localhost:5000", primary: false, expectedRepositories: []string{"example.org/app"}, - expectedSearch: map[string]ImagePullthroughSpec{ + expectedSearch: map[string]imagestream.ImagePullthroughSpec{ "example.org/app": makeTestImagePullthroughSpec(t, "example.org/app:tag2", true), }, }, @@ -180,7 +182,7 @@ func TestIdentifyCandidateRepositories(t *testing.T) { localRegistry: "localhost:5000", primary: true, expectedRepositories: []string{"a.a/app", "other.b/bar", "a.b/app", "a.b/c", "a.b/c/foo"}, - expectedSearch: map[string]ImagePullthroughSpec{ + expectedSearch: map[string]imagestream.ImagePullthroughSpec{ "a.a/app": makeTestImagePullthroughSpec(t, "a.a/app:latest", false), "other.b/bar": makeTestImagePullthroughSpec(t, "other.b/bar:latest", false), "a.b/app": makeTestImagePullthroughSpec(t, "a.b/app:latest", true), @@ -210,7 +212,7 @@ func TestIdentifyCandidateRepositories(t *testing.T) { localRegistry: "localhost:5000", primary: true, expectedRepositories: []string{"a.b.c/app", "a.b/app", "a.b/foo"}, - expectedSearch: map[string]ImagePullthroughSpec{ + expectedSearch: map[string]imagestream.ImagePullthroughSpec{ "a.b.c/app": makeTestImagePullthroughSpec(t, "a.b.c/app:latest", false), "a.b/app": makeTestImagePullthroughSpec(t, "a.b/app:latest", true), "a.b/foo": makeTestImagePullthroughSpec(t, "a.b/foo:latest", true), @@ -240,10 +242,10 @@ func TestIdentifyCandidateRepositories(t *testing.T) { } } -func makeTestImagePullthroughSpec(t *testing.T, ref string, insecure bool) ImagePullthroughSpec { +func makeTestImagePullthroughSpec(t *testing.T, ref string, insecure bool) imagestream.ImagePullthroughSpec { r, err := imageapi.ParseDockerImageReference(ref) if err != nil { t.Fatal(err) } - return ImagePullthroughSpec{dockerImageReference: &r, insecure: insecure} + return imagestream.ImagePullthroughSpec{DockerImageReference: &r, Insecure: insecure} } diff --git a/pkg/dockerregistry/server/repository.go b/pkg/dockerregistry/server/repository.go index fd82f2072..75ed3b963 100644 --- a/pkg/dockerregistry/server/repository.go +++ b/pkg/dockerregistry/server/repository.go @@ -12,9 +12,11 @@ import ( restclient "k8s.io/client-go/rest" imageapiv1 "github.com/openshift/api/image/v1" + "github.com/openshift/image-registry/pkg/dockerregistry/server/audit" "github.com/openshift/image-registry/pkg/dockerregistry/server/cache" "github.com/openshift/image-registry/pkg/dockerregistry/server/metrics" + "github.com/openshift/image-registry/pkg/imagestream" ) var ( @@ -44,7 +46,7 @@ type repository struct { app *App crossmount bool - imageStream *imageStream + imageStream imagestream.ImageStream // remoteBlobGetter is used to fetch blobs from remote registries if pullthrough is enabled. remoteBlobGetter BlobGetterService @@ -64,11 +66,8 @@ func (app *App) Repository(ctx context.Context, repo distribution.Repository, cr return nil, nil, err } - imageStreamGetter := &cachedImageStreamGetter{ - ctx: ctx, - namespace: namespace, - name: name, - isNamespacer: registryOSClient, + imageStreamCache := &cache.RepoDigest{ + Cache: app.cache, } r := &repository{ @@ -79,22 +78,25 @@ func (app *App) Repository(ctx context.Context, repo distribution.Repository, cr crossmount: crossmount, imageStream: &imageStream{ - namespace: namespace, - name: name, - registryOSClient: registryOSClient, - cachedImages: make(map[digest.Digest]*imageapiv1.Image), - imageStreamGetter: imageStreamGetter, - cache: &cache.RepoDigest{ - Cache: app.cache, + namespace: namespace, + name: name, + registryOSClient: registryOSClient, + cachedImages: make(map[digest.Digest]*imageapiv1.Image), + imageStreamGetter: &cachedImageStreamGetter{ + ctx: ctx, + namespace: namespace, + name: name, + isNamespacer: registryOSClient, }, + cache: imageStreamCache, }, } if app.config.Pullthrough.Enabled { r.remoteBlobGetter = NewBlobGetterService( r.imageStream, - r.imageStream.getSecrets, - r.imageStream.cache) + r.imageStream.GetSecrets, + imageStreamCache) } bdsf := blobDescriptorServiceFactoryFunc(r.BlobDescriptorService) diff --git a/pkg/dockerregistry/server/tagservice.go b/pkg/dockerregistry/server/tagservice.go index bd982d65b..37ac9ee91 100644 --- a/pkg/dockerregistry/server/tagservice.go +++ b/pkg/dockerregistry/server/tagservice.go @@ -3,12 +3,14 @@ package server import ( "github.com/docker/distribution" "github.com/docker/distribution/context" + + "github.com/openshift/image-registry/pkg/imagestream" ) type tagService struct { distribution.TagService - imageStream *imageStream + imageStream imagestream.ImageStream pullthroughEnabled bool } @@ -32,7 +34,7 @@ func (t tagService) Get(ctx context.Context, tag string) (distribution.Descripto } if !t.pullthroughEnabled { - image, err := t.imageStream.getImage(ctx, dgst) + image, err := t.imageStream.GetImage(ctx, dgst) if err != nil { return distribution.Descriptor{}, err } @@ -69,7 +71,7 @@ func (t tagService) All(ctx context.Context) ([]string, error) { managed, found := managedImages[dgst.String()] if !found { - image, err := t.imageStream.getImage(ctx, dgst) + image, err := t.imageStream.GetImage(ctx, dgst) if err != nil { context.GetLogger(ctx).Errorf("unable to get image %s %s: %v", t.imageStream.Reference(), dgst.String(), err) continue @@ -115,7 +117,7 @@ func (t tagService) Lookup(ctx context.Context, desc distribution.Descriptor) ([ managed, found := managedImages[dgst.String()] if !found { - image, err := t.imageStream.getImage(ctx, dgst) + image, err := t.imageStream.GetImage(ctx, dgst) if err != nil { context.GetLogger(ctx).Errorf("unable to get image %s %s: %v", t.imageStream.Reference(), dgst.String(), err) continue diff --git a/pkg/imagestream/imagestream.go b/pkg/imagestream/imagestream.go new file mode 100644 index 000000000..e254f3163 --- /dev/null +++ b/pkg/imagestream/imagestream.go @@ -0,0 +1,49 @@ +package imagestream + +import ( + "github.com/docker/distribution/context" + "github.com/docker/distribution/digest" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" + + imageapiv1 "github.com/openshift/api/image/v1" + + imageapi "github.com/openshift/image-registry/pkg/origin-common/image/apis/image" +) + +// ProjectObjectListStore represents a cache of objects indexed by a project name. +// Used to store a list of items per namespace. +type ProjectObjectListStore interface { + Add(namespace string, obj runtime.Object) error + Get(namespace string) (obj runtime.Object, exists bool, err error) +} + +// ImagePullthroughSpec contains a reference of remote image to pull associated with an insecure flag for the +// corresponding registry. +type ImagePullthroughSpec struct { + DockerImageReference *imageapi.DockerImageReference + Insecure bool +} + +type ImageStream interface { + Reference() string + Exists() (bool, error) + + GetStoredImageOfImageStream(ctx context.Context, dgst digest.Digest) (*imageapiv1.Image, *imageapiv1.TagEvent, *imageapiv1.ImageStream, error) + GetImageOfImageStream(ctx context.Context, dgst digest.Digest) (*imageapiv1.Image, *imageapiv1.ImageStream, error) + CreateImageStreamMapping(ctx context.Context, tag string, image *imageapiv1.Image) error + UpdateImage(image *imageapiv1.Image) (*imageapiv1.Image, error) + GetImage(ctx context.Context, dgst digest.Digest) (*imageapiv1.Image, error) + RememberLayersOfImage(ctx context.Context, image *imageapiv1.Image, cacheName string) + + HasBlob(ctx context.Context, dgst digest.Digest, requireManaged bool) bool + IdentifyCandidateRepositories(primary bool) ([]string, map[string]ImagePullthroughSpec, error) + GetLimitRangeList(ctx context.Context, cache ProjectObjectListStore) (*corev1.LimitRangeList, error) + GetSecrets() ([]corev1.Secret, error) + + TagIsInsecure(tag string, dgst digest.Digest) (bool, error) + Tags(ctx context.Context) (map[string]digest.Digest, error) + Tag(ctx context.Context, tag string, dgst digest.Digest, pullthroughEnabled bool) error + Untag(ctx context.Context, tag string, pullthroughEnabled bool) error +}