1
0
mirror of https://github.com/openshift/image-registry.git synced 2026-02-05 09:45:55 +01:00

[OCPNODE-1258] Migrate icsp to idms

Signed-off-by: Qi Wang <qiwan@redhat.com>
This commit is contained in:
Qi Wang
2022-09-22 17:44:55 -04:00
parent 03416247c9
commit 45da6c3765
13 changed files with 791 additions and 204 deletions

View File

@@ -5,6 +5,7 @@ import (
coreclientv1 "k8s.io/client-go/kubernetes/typed/core/v1"
restclient "k8s.io/client-go/rest"
cfgv1 "github.com/openshift/client-go/config/clientset/versioned/typed/config/v1"
imageclientv1 "github.com/openshift/client-go/image/clientset/versioned/typed/image/v1"
operatorclientv1alpha1 "github.com/openshift/client-go/operator/clientset/versioned/typed/operator/v1alpha1"
userclientv1 "github.com/openshift/client-go/user/clientset/versioned/typed/user/v1"
@@ -42,6 +43,7 @@ type apiClient struct {
image imageclientv1.ImageV1Interface
user userclientv1.UserV1Interface
operator operatorclientv1alpha1.OperatorV1alpha1Interface
config cfgv1.ConfigV1Interface
}
func newAPIClient(
@@ -50,6 +52,7 @@ func newAPIClient(
imageClient imageclientv1.ImageV1Interface,
userClient userclientv1.UserV1Interface,
operatorClient operatorclientv1alpha1.OperatorV1alpha1Interface,
configClient cfgv1.ConfigV1Interface,
) Interface {
return &apiClient{
kube: kc,
@@ -57,6 +60,7 @@ func newAPIClient(
image: imageClient,
user: userClient,
operator: operatorClient,
config: configClient,
}
}
@@ -64,6 +68,14 @@ func (c *apiClient) ImageContentSourcePolicy() operatorclientv1alpha1.ImageConte
return c.operator.ImageContentSourcePolicies()
}
func (c *apiClient) ImageDigestMirrorSet() cfgv1.ImageDigestMirrorSetInterface {
return c.config.ImageDigestMirrorSets()
}
func (c *apiClient) ImageTagMirrorSet() cfgv1.ImageTagMirrorSetInterface {
return c.config.ImageTagMirrorSets()
}
func (c *apiClient) Users() UserInterface {
return c.user.Users()
}
@@ -127,6 +139,7 @@ func (c *registryClient) Client() (Interface, error) {
imageclientv1.NewForConfigOrDie(c.kubeConfig),
userclientv1.NewForConfigOrDie(c.kubeConfig),
operatorclientv1alpha1.NewForConfigOrDie(c.kubeConfig),
cfgv1.NewForConfigOrDie(c.kubeConfig),
), nil
}

View File

@@ -15,6 +15,7 @@ import (
operatorclientv1alpha1 "github.com/openshift/client-go/operator/clientset/versioned/typed/operator/v1alpha1"
userclientv1 "github.com/openshift/client-go/user/clientset/versioned/typed/user/v1"
cfgv1 "github.com/openshift/client-go/config/clientset/versioned/typed/config/v1"
authclientv1 "k8s.io/client-go/kubernetes/typed/authorization/v1"
)
@@ -24,6 +25,8 @@ type UsersInterfacer interface {
type ImageContentSourcePolicyInterfacer interface {
ImageContentSourcePolicy() operatorclientv1alpha1.ImageContentSourcePolicyInterface
ImageDigestMirrorSet() cfgv1.ImageDigestMirrorSetInterface
ImageTagMirrorSet() cfgv1.ImageTagMirrorSetInterface
}
type ImagesInterfacer interface {

View File

@@ -3,6 +3,7 @@ package client
import (
coreclientv1 "k8s.io/client-go/kubernetes/typed/core/v1"
cfgfake "github.com/openshift/client-go/config/clientset/versioned/fake"
imageclientv1 "github.com/openshift/client-go/image/clientset/versioned/typed/image/v1"
operatorfake "github.com/openshift/client-go/operator/clientset/versioned/fake"
)
@@ -22,10 +23,12 @@ func NewFakeRegistryClient(imageclient imageclientv1.ImageV1Interface) RegistryC
func (c *fakeRegistryClient) Client() (Interface, error) {
icsp := operatorfake.NewSimpleClientset().OperatorV1alpha1()
return newAPIClient(nil, nil, c.images, nil, icsp), nil
cfgclient := cfgfake.NewSimpleClientset().ConfigV1()
return newAPIClient(nil, nil, c.images, nil, icsp, cfgclient), nil
}
func NewFakeRegistryAPIClient(kc coreclientv1.CoreV1Interface, imageclient imageclientv1.ImageV1Interface) Interface {
icsp := operatorfake.NewSimpleClientset().OperatorV1alpha1()
return newAPIClient(nil, nil, imageclient, nil, icsp)
idms := cfgfake.NewSimpleClientset().ConfigV1()
return newAPIClient(nil, nil, imageclient, nil, icsp, idms)
}

View File

@@ -20,6 +20,7 @@ import (
"github.com/opencontainers/go-digest"
imageapiv1 "github.com/openshift/api/image/v1"
cfgfake "github.com/openshift/client-go/config/clientset/versioned/fake"
operatorfake "github.com/openshift/client-go/operator/clientset/versioned/fake"
"github.com/openshift/library-go/pkg/image/registryclient"
@@ -35,6 +36,8 @@ import (
func TestPullthroughServeBlob(t *testing.T) {
icsp := operatorfake.NewSimpleClientset().OperatorV1alpha1().ImageContentSourcePolicies()
idms := cfgfake.NewSimpleClientset().ConfigV1().ImageDigestMirrorSets()
itms := cfgfake.NewSimpleClientset().ConfigV1().ImageTagMirrorSets()
ctx := context.Background()
ctx = testutil.WithTestLogger(ctx, t)
@@ -171,6 +174,8 @@ func TestPullthroughServeBlob(t *testing.T) {
cache,
metrics.NewNoopMetrics(),
icsp,
idms,
itms,
)
ptbs := &pullthroughBlobStore{
@@ -331,6 +336,8 @@ func TestPullthroughServeNotSeekableBlob(t *testing.T) {
func TestPullthroughServeBlobInsecure(t *testing.T) {
icsp := operatorfake.NewSimpleClientset().OperatorV1alpha1().ImageContentSourcePolicies()
idms := cfgfake.NewSimpleClientset().ConfigV1().ImageDigestMirrorSets()
itms := cfgfake.NewSimpleClientset().ConfigV1().ImageTagMirrorSets()
namespace := "user"
repo1 := "app1"
repo2 := "app2"
@@ -608,6 +615,8 @@ func TestPullthroughServeBlobInsecure(t *testing.T) {
cache,
metrics.NewNoopMetrics(),
icsp,
idms,
itms,
)
ptbs := &pullthroughBlobStore{
@@ -675,6 +684,8 @@ func TestPullthroughServeBlobInsecure(t *testing.T) {
func TestPullthroughMetrics(t *testing.T) {
icsp := operatorfake.NewSimpleClientset().OperatorV1alpha1().ImageContentSourcePolicies()
idms := cfgfake.NewSimpleClientset().ConfigV1().ImageDigestMirrorSets()
itms := cfgfake.NewSimpleClientset().ConfigV1().ImageTagMirrorSets()
ctx := context.Background()
ctx = testutil.WithTestLogger(ctx, t)
@@ -735,6 +746,8 @@ func TestPullthroughMetrics(t *testing.T) {
cache,
metrics.NewMetrics(sink),
icsp,
idms,
itms,
)
ptbs := &pullthroughBlobStore{

View File

@@ -11,6 +11,7 @@ import (
"github.com/distribution/distribution/v3/registry/client"
"github.com/opencontainers/go-digest"
cfgv1 "github.com/openshift/client-go/config/clientset/versioned/typed/config/v1"
operatorv1alpha1 "github.com/openshift/client-go/operator/clientset/versioned/typed/operator/v1alpha1"
"github.com/openshift/image-registry/pkg/dockerregistry/server/cache"
@@ -32,6 +33,8 @@ type pullthroughManifestService struct {
mirror bool
registryAddr string
metrics metrics.Pullthrough
idms cfgv1.ImageDigestMirrorSetInterface
itms cfgv1.ImageTagMirrorSetInterface
icsp operatorv1alpha1.ImageContentSourcePolicyInterface
}
@@ -129,7 +132,7 @@ func (m *pullthroughManifestService) getRemoteRepositoryClient(ctx context.Conte
dcontext.GetLogger(ctx).Errorf("error getting secrets: %v", err)
}
retriever, impErr := getImportContext(ctx, ref, secrets, m.metrics, m.icsp)
retriever, impErr := getImportContext(ctx, ref, secrets, m.metrics, m.icsp, m.idms, m.itms)
if impErr != nil {
return nil, impErr
}

View File

@@ -18,6 +18,7 @@ import (
"github.com/opencontainers/go-digest"
imageapiv1 "github.com/openshift/api/image/v1"
cfgfake "github.com/openshift/client-go/config/clientset/versioned/fake"
operatorfake "github.com/openshift/client-go/operator/clientset/versioned/fake"
"github.com/openshift/image-registry/pkg/dockerregistry/server/cache"
@@ -55,6 +56,8 @@ func createTestRegistryServer(t *testing.T, ctx context.Context) *httptest.Serve
func TestPullthroughManifests(t *testing.T) {
icsp := operatorfake.NewSimpleClientset().OperatorV1alpha1().ImageContentSourcePolicies()
idms := cfgfake.NewSimpleClientset().ConfigV1().ImageDigestMirrorSets()
itms := cfgfake.NewSimpleClientset().ConfigV1().ImageTagMirrorSets()
namespace := "fuser"
repo := "zapp"
repoName := fmt.Sprintf("%s/%s", namespace, repo)
@@ -188,6 +191,8 @@ func TestPullthroughManifests(t *testing.T) {
cache: cache,
registryAddr: "localhost:5000",
metrics: metrics.NewNoopMetrics(),
idms: idms,
itms: itms,
icsp: icsp,
}
@@ -228,6 +233,8 @@ func TestPullthroughManifests(t *testing.T) {
func TestPullthroughManifestInsecure(t *testing.T) {
icsp := operatorfake.NewSimpleClientset().OperatorV1alpha1().ImageContentSourcePolicies()
idms := cfgfake.NewSimpleClientset().ConfigV1().ImageDigestMirrorSets()
itms := cfgfake.NewSimpleClientset().ConfigV1().ImageTagMirrorSets()
namespace := "fuser"
repo := "zapp"
repoName := fmt.Sprintf("%s/%s", namespace, repo)
@@ -431,6 +438,8 @@ func TestPullthroughManifestInsecure(t *testing.T) {
imageStream: imageStream,
cache: cache,
metrics: metrics.NewNoopMetrics(),
idms: idms,
itms: itms,
icsp: icsp,
}
@@ -473,6 +482,8 @@ func TestPullthroughManifestInsecure(t *testing.T) {
func TestPullthroughManifestDockerReference(t *testing.T) {
icsp := operatorfake.NewSimpleClientset().OperatorV1alpha1().ImageContentSourcePolicies()
idms := cfgfake.NewSimpleClientset().ConfigV1().ImageDigestMirrorSets()
itms := cfgfake.NewSimpleClientset().ConfigV1().ImageTagMirrorSets()
namespace := "user"
repo1 := "repo1"
repo2 := "repo2"
@@ -572,6 +583,8 @@ func TestPullthroughManifestDockerReference(t *testing.T) {
ManifestService: newTestManifestService(tc.repoName, nil),
imageStream: imageStream,
metrics: metrics.NewNoopMetrics(),
idms: idms,
itms: itms,
icsp: icsp,
}
@@ -668,6 +681,8 @@ func (ms *putWaiterManifestService) Put(ctx context.Context, manifest distributi
func TestPullthroughManifestMirroring(t *testing.T) {
icsp := operatorfake.NewSimpleClientset().OperatorV1alpha1().ImageContentSourcePolicies()
idms := cfgfake.NewSimpleClientset().ConfigV1().ImageDigestMirrorSets()
itms := cfgfake.NewSimpleClientset().ConfigV1().ImageTagMirrorSets()
const timeout = 5 * time.Second
namespace := "myproject"
@@ -732,6 +747,8 @@ func TestPullthroughManifestMirroring(t *testing.T) {
imageStream: imageStream,
mirror: true,
metrics: metrics.NewNoopMetrics(),
idms: idms,
itms: itms,
icsp: icsp,
}
@@ -749,6 +766,8 @@ func TestPullthroughManifestMirroring(t *testing.T) {
func TestPullthroughManifestMetrics(t *testing.T) {
icsp := operatorfake.NewSimpleClientset().OperatorV1alpha1().ImageContentSourcePolicies()
idms := cfgfake.NewSimpleClientset().ConfigV1().ImageDigestMirrorSets()
itms := cfgfake.NewSimpleClientset().ConfigV1().ImageTagMirrorSets()
namespace := "myproject"
repo := "myapp"
repoName := fmt.Sprintf("%s/%s", namespace, repo)
@@ -810,6 +829,8 @@ func TestPullthroughManifestMetrics(t *testing.T) {
newLocalManifestService: func(ctx context.Context) (distribution.ManifestService, error) { return ms, nil },
imageStream: imageStream,
metrics: metrics.NewMetrics(sink),
idms: idms,
itms: itms,
icsp: icsp,
}

View File

@@ -13,6 +13,7 @@ import (
corev1 "k8s.io/api/core/v1"
cfgv1 "github.com/openshift/client-go/config/clientset/versioned/typed/config/v1"
operatorv1alpha1 "github.com/openshift/client-go/operator/clientset/versioned/typed/operator/v1alpha1"
"github.com/openshift/library-go/pkg/image/registryclient"
@@ -72,6 +73,8 @@ type remoteBlobGetterService struct {
digestToStore *digestBlobStoreCache
metrics metrics.Pullthrough
icsp operatorv1alpha1.ImageContentSourcePolicyInterface
idms cfgv1.ImageDigestMirrorSetInterface
itms cfgv1.ImageTagMirrorSetInterface
}
var _ BlobGetterService = &remoteBlobGetterService{}
@@ -84,6 +87,8 @@ func NewBlobGetterService(
cache cache.RepositoryDigest,
m metrics.Pullthrough,
icsp operatorv1alpha1.ImageContentSourcePolicyInterface,
idms cfgv1.ImageDigestMirrorSetInterface,
itms cfgv1.ImageTagMirrorSetInterface,
) BlobGetterService {
return &remoteBlobGetterService{
imageStream: imageStream,
@@ -92,6 +97,8 @@ func NewBlobGetterService(
digestToStore: newDigestBlobStoreCache(m),
metrics: m,
icsp: icsp,
idms: idms,
itms: itms,
}
}
@@ -295,7 +302,7 @@ func (rbgs *remoteBlobGetterService) findCandidateRepository(
continue
}
retriever, impErr := getImportContext(ctx, spec.DockerImageReference, secrets, rbgs.metrics, rbgs.icsp)
retriever, impErr := getImportContext(ctx, spec.DockerImageReference, secrets, rbgs.metrics, rbgs.icsp, rbgs.idms, rbgs.itms)
if impErr != nil {
return distribution.Descriptor{}, nil, impErr
}
@@ -317,7 +324,7 @@ func (rbgs *remoteBlobGetterService) findCandidateRepository(
continue
}
retriever, impErr := getImportContext(ctx, spec.DockerImageReference, secrets, rbgs.metrics, rbgs.icsp)
retriever, impErr := getImportContext(ctx, spec.DockerImageReference, secrets, rbgs.metrics, rbgs.icsp, rbgs.idms, rbgs.itms)
if impErr != nil {
return distribution.Descriptor{}, nil, impErr
}

View File

@@ -11,6 +11,7 @@ import (
restclient "k8s.io/client-go/rest"
cfgv1 "github.com/openshift/client-go/config/clientset/versioned/typed/config/v1"
operatorv1alpha1 "github.com/openshift/client-go/operator/clientset/versioned/typed/operator/v1alpha1"
"github.com/openshift/image-registry/pkg/dockerregistry/server/audit"
@@ -47,6 +48,8 @@ type repository struct {
imageStream imagestream.ImageStream
icsp operatorv1alpha1.ImageContentSourcePolicyInterface
idms cfgv1.ImageDigestMirrorSetInterface
itms cfgv1.ImageTagMirrorSetInterface
// remoteBlobGetter is used to fetch blobs from remote registries if pullthrough is enabled.
remoteBlobGetter BlobGetterService
@@ -75,6 +78,8 @@ func (app *App) Repository(ctx context.Context, repo distribution.Repository, cr
imageStream: imagestream.New(ctx, namespace, name, registryOSClient),
cache: cache.NewRepositoryDigest(app.cache),
icsp: registryOSClient.ImageContentSourcePolicy(),
idms: registryOSClient.ImageDigestMirrorSet(),
itms: registryOSClient.ImageTagMirrorSet(),
}
r.remoteBlobGetter = NewBlobGetterService(
@@ -83,6 +88,8 @@ func (app *App) Repository(ctx context.Context, repo distribution.Repository, cr
r.cache,
r.app.metrics,
r.icsp,
r.idms,
r.itms,
)
repo = distribution.Repository(r)
@@ -128,7 +135,9 @@ func (r *repository) Manifests(ctx context.Context, options ...distribution.Mani
mirror: r.app.config.Pullthrough.Mirror,
registryAddr: r.app.config.Server.Addr,
metrics: r.app.metrics,
idms: r.idms,
icsp: r.icsp,
itms: r.itms,
}
ms = newPendingErrorsManifestService(ms, r)

View File

@@ -2,36 +2,46 @@ package server
import (
"context"
"fmt"
"strings"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/klog/v2"
cfgv1 "github.com/openshift/api/config/v1"
operatorv1alpha1 "github.com/openshift/api/operator/v1alpha1"
cfgv1client "github.com/openshift/client-go/config/clientset/versioned/typed/config/v1"
operatorv1alpha1client "github.com/openshift/client-go/operator/clientset/versioned/typed/operator/v1alpha1"
reference "github.com/openshift/library-go/pkg/image/reference"
"github.com/openshift/library-go/pkg/image/registryclient"
)
// simpleLookupICSP holds ImageContentSourcePolicy variables to look up image sources. Satisfies
// simpleLookupImageMirrorSets holds ImageContentSourcePolicy, ImageDigestMirrorSet, and ImageTagMirrorSet variables to look up image sources. Satisfies
// *Context AlternativeBlobSourceStrategy interface.
type simpleLookupICSP struct {
type simpleLookupImageMirrorSets struct {
icspClient operatorv1alpha1client.ImageContentSourcePolicyInterface
idmsClient cfgv1client.ImageDigestMirrorSetInterface
itmsClient cfgv1client.ImageTagMirrorSetInterface
}
// NewSimpleLookupICSPStrategy returns a new entity of simpleLookupICSP using provided client
// to obtain cluster wide ICSP configuration.
func NewSimpleLookupICSPStrategy(
cli operatorv1alpha1client.ImageContentSourcePolicyInterface,
// NewSimpleLookupImageMirrorSetsStrategy returns a new entity of simpleLookupImageMirrorSets using provided client
// to obtain cluster wide ICSP or IDMS and ITMS configuration.
func NewSimpleLookupImageMirrorSetsStrategy(
icspcli operatorv1alpha1client.ImageContentSourcePolicyInterface,
idmscli cfgv1client.ImageDigestMirrorSetInterface,
itmscli cfgv1client.ImageTagMirrorSetInterface,
) registryclient.AlternateBlobSourceStrategy {
return &simpleLookupICSP{
icspClient: cli,
return &simpleLookupImageMirrorSets{
icspClient: icspcli,
idmsClient: idmscli,
itmsClient: itmscli,
}
}
// FirstRequest returns a list of sources to use when searching for a given repository. Returns
// the whole list of mirrors followed by the original image reference.
func (s *simpleLookupICSP) FirstRequest(
func (s *simpleLookupImageMirrorSets) FirstRequest(
ctx context.Context, ref reference.DockerImageReference,
) ([]reference.DockerImageReference, error) {
klog.V(5).Infof("reading ICSP from cluster")
@@ -41,7 +51,29 @@ func (s *simpleLookupICSP) FirstRequest(
return []reference.DockerImageReference{ref.AsRepository()}, nil
}
imageRefList, err := s.alternativeImageSources(ref, icspList.Items)
idmsList, err := s.idmsClient.List(ctx, metav1.ListOptions{})
if err != nil {
klog.Errorf("unable to list IDMS config: %s", err)
return []reference.DockerImageReference{ref.AsRepository()}, nil
}
itmsList, err := s.itmsClient.List(ctx, metav1.ListOptions{})
if err != nil {
klog.Errorf("unable to list ITMS config: %s", err)
return []reference.DockerImageReference{ref.AsRepository()}, nil
}
if len(icspList.Items) > 0 && len(idmsList.Items) > 0 {
err := fmt.Errorf("found both ICSP and IDMS resources, but only one or the other is supported")
return []reference.DockerImageReference{ref.AsRepository()}, err
}
if len(icspList.Items) > 0 && len(itmsList.Items) > 0 {
err := fmt.Errorf("found both ICSP and ITMS resources, but only one or the other is supported")
return []reference.DockerImageReference{ref.AsRepository()}, err
}
imageRefList, err := s.alternativeImageSources(ref, icspList.Items, idmsList.Items, itmsList.Items)
if err != nil {
klog.Errorf("error looking for alternate repositories: %s", err)
return []reference.DockerImageReference{ref.AsRepository()}, nil
@@ -51,7 +83,7 @@ func (s *simpleLookupICSP) FirstRequest(
return imageRefList, nil
}
func (s *simpleLookupICSP) OnFailure(
func (s *simpleLookupImageMirrorSets) OnFailure(
ctx context.Context, ref reference.DockerImageReference,
) ([]reference.DockerImageReference, error) {
return nil, nil
@@ -67,38 +99,74 @@ func isSubrepo(repo, ancestor string) bool {
return false
}
type mirrorSource struct {
source string
mirrors []string
}
// alternativeImageSources returns unique list of DockerImageReference objects from list of
// ImageContentSourcePolicy objects
func (s *simpleLookupICSP) alternativeImageSources(
// ImageContentSourcePolicy or ImageDigestMirrorSet, ImageTagMirrorSet objects
func (s *simpleLookupImageMirrorSets) alternativeImageSources(
ref reference.DockerImageReference, icspList []operatorv1alpha1.ImageContentSourcePolicy,
idmsList []cfgv1.ImageDigestMirrorSet, itmsList []cfgv1.ImageTagMirrorSet,
) ([]reference.DockerImageReference, error) {
repo := ref.AsRepository().Exact()
mirrorSources := []mirrorSource{}
for _, icsp := range icspList {
s := mirrorSource{}
for _, rdm := range icsp.Spec.RepositoryDigestMirrors {
s.source = rdm.Source
s.mirrors = rdm.Mirrors
mirrorSources = append(mirrorSources, s)
}
}
for _, idms := range idmsList {
s := mirrorSource{}
for _, idm := range idms.Spec.ImageDigestMirrors {
s.source = idm.Source
for _, m := range idm.Mirrors {
s.mirrors = append(s.mirrors, string(m))
}
mirrorSources = append(mirrorSources, s)
}
}
for _, itms := range itmsList {
s := mirrorSource{}
for _, itm := range itms.Spec.ImageTagMirrors {
s.source = itm.Source
for _, m := range itm.Mirrors {
s.mirrors = append(s.mirrors, string(m))
}
mirrorSources = append(mirrorSources, s)
}
}
imageSources := []reference.DockerImageReference{}
uniqueMirrors := map[reference.DockerImageReference]bool{}
for _, icsp := range icspList {
for _, rdm := range icsp.Spec.RepositoryDigestMirrors {
rdmRepo := rdm.Source
if !isSubrepo(repo, rdmRepo) {
for _, ms := range mirrorSources {
rdmRepo := ms.source
if !isSubrepo(repo, rdmRepo) {
continue
}
suffix := repo[len(rdmRepo):]
for _, m := range ms.mirrors {
mRef, err := reference.Parse(m + suffix)
if err != nil {
return nil, err
}
if _, ok := uniqueMirrors[mRef]; ok {
continue
}
suffix := repo[len(rdmRepo):]
for _, m := range rdm.Mirrors {
mRef, err := reference.Parse(m + suffix)
if err != nil {
return nil, err
}
if _, ok := uniqueMirrors[mRef]; ok {
continue
}
imageSources = append(imageSources, mRef)
uniqueMirrors[mRef] = true
}
imageSources = append(imageSources, mRef)
uniqueMirrors[mRef] = true
}
}

View File

@@ -5,18 +5,30 @@ import (
"reflect"
"testing"
v1 "github.com/openshift/api/config/v1"
"github.com/openshift/api/operator/v1alpha1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"github.com/openshift/api/operator/v1alpha1"
cfgfake "github.com/openshift/client-go/config/clientset/versioned/fake"
"github.com/openshift/client-go/operator/clientset/versioned/fake"
reference "github.com/openshift/library-go/pkg/image/reference"
)
type rule struct {
name string
ruleElement []element
}
type element struct {
source string
mirrors []string
}
func TestFirstRequest(t *testing.T) {
for _, tt := range []struct {
name string
rules []runtime.Object
rules []rule
ref string
res []reference.DockerImageReference
}{
@@ -45,22 +57,16 @@ func TestFirstRequest(t *testing.T) {
Name: "image",
},
},
rules: []runtime.Object{
&v1alpha1.ImageContentSourcePolicy{
ObjectMeta: metav1.ObjectMeta{
Name: "icsp-rule",
},
Spec: v1alpha1.ImageContentSourcePolicySpec{
RepositoryDigestMirrors: []v1alpha1.RepositoryDigestMirrors{
{
Source: "i.do.not.exist/repo/image",
Mirrors: []string{
"i.exist/ns0/img0",
"i.also.exist/ns1/img1",
"me.too/ns2/img2",
},
},
},
rules: []rule{
{
name: "rule",
ruleElement: []element{
{source: "i.do.not.exist/repo/image",
mirrors: []string{
"i.exist/ns0/img0",
"i.also.exist/ns1/img1",
"me.too/ns2/img2",
}},
},
},
},
@@ -80,20 +86,14 @@ func TestFirstRequest(t *testing.T) {
Name: "image",
},
},
rules: []runtime.Object{
&v1alpha1.ImageContentSourcePolicy{
ObjectMeta: metav1.ObjectMeta{
Name: "icsp-rule",
},
Spec: v1alpha1.ImageContentSourcePolicySpec{
RepositoryDigestMirrors: []v1alpha1.RepositoryDigestMirrors{
{
Source: "i.do.not.exist/repo/image",
Mirrors: []string{
"i.exist/namespace/img",
},
},
},
rules: []rule{
{
name: "rule",
ruleElement: []element{
{source: "i.do.not.exist/repo/image",
mirrors: []string{
"i.exist/namespace/img",
}},
},
},
},
@@ -113,20 +113,14 @@ func TestFirstRequest(t *testing.T) {
Name: "busybox",
},
},
rules: []runtime.Object{
&v1alpha1.ImageContentSourcePolicy{
ObjectMeta: metav1.ObjectMeta{
Name: "icsp-rule",
},
Spec: v1alpha1.ImageContentSourcePolicySpec{
RepositoryDigestMirrors: []v1alpha1.RepositoryDigestMirrors{
{
Source: "docker.io/library",
Mirrors: []string{
"mirror.example.com/dockerio-library",
},
},
},
rules: []rule{
{
name: "rule",
ruleElement: []element{
{source: "docker.io/library",
mirrors: []string{
"mirror.example.com/dockerio-library",
}},
},
},
},
@@ -146,20 +140,14 @@ func TestFirstRequest(t *testing.T) {
Name: "busybox",
},
},
rules: []runtime.Object{
&v1alpha1.ImageContentSourcePolicy{
ObjectMeta: metav1.ObjectMeta{
Name: "icsp-rule",
},
Spec: v1alpha1.ImageContentSourcePolicySpec{
RepositoryDigestMirrors: []v1alpha1.RepositoryDigestMirrors{
{
Source: "docker.io",
Mirrors: []string{
"mirror.example.com",
},
},
},
rules: []rule{
{
name: "rule",
ruleElement: []element{
{source: "docker.io",
mirrors: []string{
"mirror.example.com",
}},
},
},
},
@@ -174,26 +162,17 @@ func TestFirstRequest(t *testing.T) {
Name: "image",
},
},
rules: []runtime.Object{
&v1alpha1.ImageContentSourcePolicy{
ObjectMeta: metav1.ObjectMeta{
Name: "icsp-rule",
},
Spec: v1alpha1.ImageContentSourcePolicySpec{
RepositoryDigestMirrors: []v1alpha1.RepositoryDigestMirrors{
{
Source: "unrelated.io/repo/image",
Mirrors: []string{
"i.exist/namespace/img",
},
},
{
Source: "also.unrelated.io/repo/image",
Mirrors: []string{
"i.exist/namespace/img",
},
},
},
rules: []rule{
{
name: "rule",
ruleElement: []element{
{source: "unrelated.io/repo/image",
mirrors: []string{
"i.exist/namespace/img",
}},
{source: "also.unrelated.io/repo/image", mirrors: []string{
"i.exist/namespace/img",
}},
},
},
},
@@ -218,35 +197,22 @@ func TestFirstRequest(t *testing.T) {
Name: "image",
},
},
rules: []runtime.Object{
&v1alpha1.ImageContentSourcePolicy{
ObjectMeta: metav1.ObjectMeta{
Name: "icsp-rule-0",
},
Spec: v1alpha1.ImageContentSourcePolicySpec{
RepositoryDigestMirrors: []v1alpha1.RepositoryDigestMirrors{
{
Source: "i.do.not.exist/repo/image",
Mirrors: []string{
"i.exist/namespace/image",
},
},
},
rules: []rule{
{
name: "rule-0",
ruleElement: []element{
{source: "i.do.not.exist/repo/image",
mirrors: []string{
"i.exist/namespace/image",
}},
},
},
&v1alpha1.ImageContentSourcePolicy{
ObjectMeta: metav1.ObjectMeta{
Name: "icsp-rule-1",
},
Spec: v1alpha1.ImageContentSourcePolicySpec{
RepositoryDigestMirrors: []v1alpha1.RepositoryDigestMirrors{
{
Source: "i.do.not.exist/repo/image",
Mirrors: []string{
"i.also.exist/ns/img",
},
},
},
{
name: "rule-1",
ruleElement: []element{
{source: "i.do.not.exist/repo/image", mirrors: []string{
"i.also.exist/ns/img",
}},
},
},
},
@@ -266,35 +232,22 @@ func TestFirstRequest(t *testing.T) {
Name: "image",
},
},
rules: []runtime.Object{
&v1alpha1.ImageContentSourcePolicy{
ObjectMeta: metav1.ObjectMeta{
Name: "icsp-rule-0",
},
Spec: v1alpha1.ImageContentSourcePolicySpec{
RepositoryDigestMirrors: []v1alpha1.RepositoryDigestMirrors{
{
Source: "i.do.not.exist/repo/image",
Mirrors: []string{
"i.exist/namespace/image",
},
},
},
rules: []rule{
{
name: "rule-0",
ruleElement: []element{
{source: "i.do.not.exist/repo/image",
mirrors: []string{
"i.exist/namespace/image",
}},
},
},
&v1alpha1.ImageContentSourcePolicy{
ObjectMeta: metav1.ObjectMeta{
Name: "icsp-rule-1",
},
Spec: v1alpha1.ImageContentSourcePolicySpec{
RepositoryDigestMirrors: []v1alpha1.RepositoryDigestMirrors{
{
Source: "i.do.not.exist/repo/image",
Mirrors: []string{
"i.exist/namespace/image",
},
},
},
{
name: "rule-1",
ruleElement: []element{
{source: "i.do.not.exist/repo/image", mirrors: []string{
"i.exist/namespace/image",
}},
},
},
},
@@ -309,20 +262,14 @@ func TestFirstRequest(t *testing.T) {
Name: "image",
},
},
rules: []runtime.Object{
&v1alpha1.ImageContentSourcePolicy{
ObjectMeta: metav1.ObjectMeta{
Name: "icsp-rule",
},
Spec: v1alpha1.ImageContentSourcePolicySpec{
RepositoryDigestMirrors: []v1alpha1.RepositoryDigestMirrors{
{
Source: "-92</asdf",
Mirrors: []string{
"i.exist/namespace/img",
},
},
},
rules: []rule{
{
name: "rule",
ruleElement: []element{
{source: "-92</asdf",
mirrors: []string{
"i.exist/namespace/img",
}},
},
},
},
@@ -337,29 +284,88 @@ func TestFirstRequest(t *testing.T) {
Name: "image",
},
},
rules: []runtime.Object{
&v1alpha1.ImageContentSourcePolicy{
ObjectMeta: metav1.ObjectMeta{
Name: "icsp-rule",
},
Spec: v1alpha1.ImageContentSourcePolicySpec{
RepositoryDigestMirrors: []v1alpha1.RepositoryDigestMirrors{
{
Source: "i.do.not.exist/repo/image",
Mirrors: []string{
"-92</asfg",
},
},
},
rules: []rule{
{
name: "rule",
ruleElement: []element{
{source: "i.do.not.exist/repo/image",
mirrors: []string{
"-92</asfg",
}},
},
},
},
},
} {
t.Run(tt.name, func(t *testing.T) {
cli := fake.NewSimpleClientset(tt.rules...)
lookup := NewSimpleLookupICSPStrategy(
icspRules := []runtime.Object{}
for _, rule := range tt.rules {
icspRules = append(icspRules, newICSPRule(rule))
}
cli := fake.NewSimpleClientset(icspRules...)
cfgcli := cfgfake.NewSimpleClientset()
lookup := NewSimpleLookupImageMirrorSetsStrategy(
cli.OperatorV1alpha1().ImageContentSourcePolicies(),
cfgcli.ConfigV1().ImageDigestMirrorSets(),
cfgcli.ConfigV1().ImageTagMirrorSets(),
)
ref, err := reference.Parse(tt.ref)
if err != nil {
t.Fatalf("unexpected error parsing reference: %s", err)
}
alternates, err := lookup.FirstRequest(context.Background(), ref)
if err != nil {
t.Fatalf("FirstRequest does not return error, received: %s", err)
}
if !reflect.DeepEqual(alternates, tt.res) {
t.Errorf("expected %+v, received %+v", tt.res, alternates)
}
})
t.Run(tt.name, func(t *testing.T) {
tt.name = "idms-test-" + tt.name
idmsRules := []runtime.Object{}
for _, rule := range tt.rules {
idmsRules = append(idmsRules, newIDMSRule(rule))
}
cli := fake.NewSimpleClientset()
cfgcli := cfgfake.NewSimpleClientset(idmsRules...)
lookup := NewSimpleLookupImageMirrorSetsStrategy(
cli.OperatorV1alpha1().ImageContentSourcePolicies(),
cfgcli.ConfigV1().ImageDigestMirrorSets(),
cfgcli.ConfigV1().ImageTagMirrorSets(),
)
ref, err := reference.Parse(tt.ref)
if err != nil {
t.Fatalf("unexpected error parsing reference: %s", err)
}
alternates, err := lookup.FirstRequest(context.Background(), ref)
if err != nil {
t.Fatalf("FirstRequest does not return error, received: %s", err)
}
if !reflect.DeepEqual(alternates, tt.res) {
t.Errorf("expected %+v, received %+v", tt.res, alternates)
}
})
t.Run(tt.name, func(t *testing.T) {
tt.name = "itms-test-" + tt.name
itmsRules := []runtime.Object{}
for _, rule := range tt.rules {
itmsRules = append(itmsRules, newITMSRule(rule))
}
cli := fake.NewSimpleClientset()
cfgcli := cfgfake.NewSimpleClientset(itmsRules...)
lookup := NewSimpleLookupImageMirrorSetsStrategy(
cli.OperatorV1alpha1().ImageContentSourcePolicies(),
cfgcli.ConfigV1().ImageDigestMirrorSets(),
cfgcli.ConfigV1().ImageTagMirrorSets(),
)
ref, err := reference.Parse(tt.ref)
@@ -378,3 +384,61 @@ func TestFirstRequest(t *testing.T) {
})
}
}
func newICSPRule(r rule) runtime.Object {
rdms := []v1alpha1.RepositoryDigestMirrors{}
for _, e := range r.ruleElement {
rdm := v1alpha1.RepositoryDigestMirrors{}
rdm.Source = e.source
rdm.Mirrors = e.mirrors
rdms = append(rdms, rdm)
}
return &v1alpha1.ImageContentSourcePolicy{
ObjectMeta: metav1.ObjectMeta{
Name: r.name,
},
Spec: v1alpha1.ImageContentSourcePolicySpec{
RepositoryDigestMirrors: rdms,
},
}
}
func newIDMSRule(r rule) runtime.Object {
idms := []v1.ImageDigestMirrors{}
for _, e := range r.ruleElement {
idm := v1.ImageDigestMirrors{}
idm.Source = e.source
for _, m := range e.mirrors {
idm.Mirrors = append(idm.Mirrors, v1.ImageMirror(m))
}
idms = append(idms, idm)
}
return &v1.ImageDigestMirrorSet{
ObjectMeta: metav1.ObjectMeta{
Name: r.name,
},
Spec: v1.ImageDigestMirrorSetSpec{
ImageDigestMirrors: idms,
},
}
}
func newITMSRule(r rule) runtime.Object {
itms := []v1.ImageTagMirrors{}
for _, e := range r.ruleElement {
itm := v1.ImageTagMirrors{}
itm.Source = e.source
for _, m := range e.mirrors {
itm.Mirrors = append(itm.Mirrors, v1.ImageMirror(m))
}
itms = append(itms, itm)
}
return &v1.ImageTagMirrorSet{
ObjectMeta: metav1.ObjectMeta{
Name: r.name,
},
Spec: v1.ImageTagMirrorSetSpec{
ImageTagMirrors: itms,
},
}
}

View File

@@ -15,6 +15,7 @@ import (
dockerapiv10 "github.com/openshift/api/image/docker10"
imageapiv1 "github.com/openshift/api/image/v1"
apicfgv1 "github.com/openshift/client-go/config/clientset/versioned/typed/config/v1"
operatorv1alpha1 "github.com/openshift/client-go/operator/clientset/versioned/typed/operator/v1alpha1"
"github.com/openshift/library-go/pkg/image/registryclient"
@@ -48,7 +49,7 @@ func getNamespaceName(resourceName string) (string, string, error) {
// getImportContext loads secrets and returns a context for getting
// distribution clients to remote repositories.
func getImportContext(ctx context.Context, ref *reference.DockerImageReference, secrets []corev1.Secret, m metrics.Pullthrough, icsp operatorv1alpha1.ImageContentSourcePolicyInterface) (registryclient.RepositoryRetriever, error) {
func getImportContext(ctx context.Context, ref *reference.DockerImageReference, secrets []corev1.Secret, m metrics.Pullthrough, icsp operatorv1alpha1.ImageContentSourcePolicyInterface, idms apicfgv1.ImageDigestMirrorSetInterface, itms apicfgv1.ImageTagMirrorSetInterface) (registryclient.RepositoryRetriever, error) {
req, err := dcontext.GetRequest(ctx)
if err != nil {
dcontext.GetLogger(ctx).Errorf("unable to get request from context: %v", err)
@@ -76,7 +77,7 @@ func getImportContext(ctx context.Context, ref *reference.DockerImageReference,
).WithRequestModifiers(
requesttrace.New(ctx, req),
).WithAlternateBlobSourceStrategy(
NewSimpleLookupICSPStrategy(icsp),
NewSimpleLookupImageMirrorSetsStrategy(icsp, idms, itms),
).WithCredentialsFactory(
&credentialStoreFactory{
keyring: keyring,

View File

@@ -9,6 +9,7 @@ import (
corev1 "k8s.io/api/core/v1"
cfgfake "github.com/openshift/client-go/config/clientset/versioned/fake"
operatorfake "github.com/openshift/client-go/operator/clientset/versioned/fake"
"github.com/openshift/library-go/pkg/image/registryclient"
@@ -28,6 +29,8 @@ func (m *mockMetricsPullThrough) DigestBlobStoreCache() metrics.Cache {
func Test_getImportContext(t *testing.T) {
icsp := operatorfake.NewSimpleClientset().OperatorV1alpha1().ImageContentSourcePolicies()
idms := cfgfake.NewSimpleClientset().ConfigV1().ImageDigestMirrorSets()
itms := cfgfake.NewSimpleClientset().ConfigV1().ImageTagMirrorSets()
tmpCredDir, err := ioutil.TempDir("", "credentials")
if err != nil {
t.Fatalf("error creating temp dir: %v", err)
@@ -141,7 +144,7 @@ func Test_getImportContext(t *testing.T) {
}
retriever, err := getImportContext(
ctx, tt.ref, tt.secrets, &mockMetricsPullThrough{}, icsp,
ctx, tt.ref, tt.secrets, &mockMetricsPullThrough{}, icsp, idms, itms,
)
if err != nil {
if len(tt.err) == 0 {

View File

@@ -14,8 +14,10 @@ import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
cfgv1 "github.com/openshift/api/config/v1"
imageapiv1 "github.com/openshift/api/image/v1"
operatorapiv1alpha1 "github.com/openshift/api/operator/v1alpha1"
cfgclientv1 "github.com/openshift/client-go/config/clientset/versioned/typed/config/v1"
imageclientv1 "github.com/openshift/client-go/image/clientset/versioned/typed/image/v1"
operatorclientv1alpha1 "github.com/openshift/client-go/operator/clientset/versioned/typed/operator/v1alpha1"
@@ -296,6 +298,15 @@ func TestPullThroughICSP(t *testing.T) {
opclient := operatorclientv1alpha1.NewForConfigOrDie(master.AdminKubeConfig())
imgclient := imageclientv1.NewForConfigOrDie(testuser.KubeConfig())
cfgclient := cfgclientv1.NewForConfigOrDie(master.AdminKubeConfig())
idmsList, err := cfgclient.ImageDigestMirrorSets().List(ctx, metav1.ListOptions{})
if err != nil {
t.Fatal(err)
}
if len(idmsList.Items) > 0 {
t.Skip("default IDMS mirror configuration exists, can't create ImageContentSourcePolicy when ImageDigestMirrorSet resources exist. Consider update the test")
}
imageData, err := testframework.NewSchema2ImageData()
if err != nil {
@@ -453,3 +464,371 @@ func TestPullThroughICSP(t *testing.T) {
}
}
}
func TestPullThroughIDMS(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
defer cancel()
namespace := "image-registry-test-integration-idms"
reponame := "testrepo"
repotag := "testtag"
isname := "test/" + reponame
master := testframework.NewMaster(t)
defer master.Close()
testuser := master.CreateUser("testuser", "testp@ssw0rd")
master.CreateProject(namespace, testuser.Name)
opclient := operatorclientv1alpha1.NewForConfigOrDie(master.AdminKubeConfig())
cfgclient := cfgclientv1.NewForConfigOrDie(master.AdminKubeConfig())
imgclient := imageclientv1.NewForConfigOrDie(testuser.KubeConfig())
icspList, err := opclient.ImageContentSourcePolicies().List(ctx, metav1.ListOptions{})
if err != nil {
t.Fatal(err)
}
if len(icspList.Items) > 0 {
t.Skip("default ICSP mirror configuration exists, can't create ImageDigestMirrorSet when ImageContentSourcePolicy resources exist. Consider update the test")
}
imageData, err := testframework.NewSchema2ImageData()
if err != nil {
t.Fatal(err)
}
imgdgst := imageData.ManifestDigest.String()
descriptors := map[string]int64{
string(imageData.ConfigDigest): int64(len(imageData.Config)),
string(imageData.LayerDigest): int64(len(imageData.Layer)),
}
remoteRegistryAddr, _, _ := testframework.CreateEphemeralRegistry(
t, master.AdminKubeConfig(), namespace, nil,
)
remoteRepo, err := testutil.NewInsecureRepository(remoteRegistryAddr+"/"+isname, nil)
if err != nil {
t.Fatal(err)
}
if _, err := testframework.PushSchema2ImageData(
ctx, remoteRepo, repotag, imageData,
); err != nil {
t.Fatal(err)
}
idmsRule, err := cfgclient.ImageDigestMirrorSets().Create(
ctx,
&cfgv1.ImageDigestMirrorSet{
ObjectMeta: metav1.ObjectMeta{
Name: "image-registry-idms-testing",
},
Spec: cfgv1.ImageDigestMirrorSetSpec{
ImageDigestMirrors: []cfgv1.ImageDigestMirrors{
{
Source: "does.not.exist/repo/image",
Mirrors: []cfgv1.ImageMirror{
cfgv1.ImageMirror(remoteRegistryAddr + "/" + isname),
},
},
},
},
},
metav1.CreateOptions{},
)
if err != nil {
t.Fatalf("error creating IDMS rule: %s", err)
}
defer func() {
if err := cfgclient.ImageDigestMirrorSets().Delete(
ctx, idmsRule.Name, metav1.DeleteOptions{},
); err != nil {
t.Errorf("error deleting IDMS rule: %s", err)
}
}()
imgsrc := fmt.Sprintf("does.not.exist/repo/image@%s", imgdgst)
isi := &imageapiv1.ImageStreamImport{
ObjectMeta: metav1.ObjectMeta{
Namespace: namespace,
Name: "myimagestream",
Annotations: map[string]string{
imageapiv1.InsecureRepositoryAnnotation: "true",
},
},
Spec: imageapiv1.ImageStreamImportSpec{
Import: true,
Images: []imageapiv1.ImageImportSpec{
{
From: corev1.ObjectReference{
Kind: "DockerImage",
Name: imgsrc,
},
To: &corev1.LocalObjectReference{
Name: repotag,
},
ImportPolicy: imageapiv1.TagImportPolicy{
Insecure: true,
},
},
},
},
}
if isi, err = imgclient.ImageStreamImports(namespace).Create(
ctx, isi, metav1.CreateOptions{},
); err != nil {
t.Fatal(err)
}
if len(isi.Status.Images) != 1 {
t.Fatalf("imported unexpected number of images (%d != 1)", len(isi.Status.Images))
}
for i, image := range isi.Status.Images {
if image.Status.Status != metav1.StatusSuccess {
t.Fatalf("unexpected status %d: %#v", i, image.Status)
}
if image.Image == nil {
t.Fatalf("unexpected empty image %d", i)
}
if image.Image.Name != imgdgst {
t.Fatalf(
"unexpected image %d: %#v (expect %q)",
i, image.Image.Name, imgdgst,
)
}
}
istream, err := imgclient.ImageStreams(isi.Namespace).Get(
ctx, isi.Name, metav1.GetOptions{},
)
if err != nil {
t.Fatal(err)
}
if istream.Annotations == nil {
istream.Annotations = make(map[string]string)
}
istream.Annotations[imageapiv1.InsecureRepositoryAnnotation] = "true"
istream, err = imgclient.ImageStreams(istream.Namespace).Update(
ctx, istream, metav1.UpdateOptions{},
)
if err != nil {
t.Fatal(err)
}
t.Logf("Run registry...")
registry := master.StartRegistry(t, testframework.DisableMirroring{})
defer registry.Close()
t.Logf("Pulling manifest by tag...")
if err := testPullThroughGetManifest(
registry.BaseURL(), isi, testuser.Name, testuser.Token, repotag,
); err != nil {
t.Fatal(err)
}
t.Logf("Pulling manifest by digest...")
if err := testPullThroughGetManifest(
registry.BaseURL(), isi, testuser.Name, testuser.Token, imgdgst,
); err != nil {
t.Fatal(err)
}
t.Logf("Pulling image blobs...")
for digest := range descriptors {
if err := testPullThroughStatBlob(
registry.BaseURL(), isi, testuser.Name, testuser.Token, digest,
); err != nil {
t.Fatal(err)
}
}
}
func TestPullThroughITMS(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
defer cancel()
namespace := "image-registry-test-integration-itms"
reponame := "testrepo"
repotag := "testtag"
isname := "test/" + reponame
master := testframework.NewMaster(t)
defer master.Close()
testuser := master.CreateUser("testuser", "testp@ssw0rd")
master.CreateProject(namespace, testuser.Name)
opclient := operatorclientv1alpha1.NewForConfigOrDie(master.AdminKubeConfig())
cfgclient := cfgclientv1.NewForConfigOrDie(master.AdminKubeConfig())
imgclient := imageclientv1.NewForConfigOrDie(testuser.KubeConfig())
icspList, err := opclient.ImageContentSourcePolicies().List(ctx, metav1.ListOptions{})
if err != nil {
t.Fatal(err)
}
if len(icspList.Items) > 0 {
t.Skip("default ICSP mirror configuration exists, can't create ImageTagMirrorSet when ImageContentSourcePolicy resources exist. Consider update the test")
}
imageData, err := testframework.NewSchema2ImageData()
if err != nil {
t.Fatal(err)
}
imgdgst := imageData.ManifestDigest.String()
descriptors := map[string]int64{
string(imageData.ConfigDigest): int64(len(imageData.Config)),
string(imageData.LayerDigest): int64(len(imageData.Layer)),
}
remoteRegistryAddr, _, _ := testframework.CreateEphemeralRegistry(
t, master.AdminKubeConfig(), namespace, nil,
)
remoteRepo, err := testutil.NewInsecureRepository(remoteRegistryAddr+"/"+isname, nil)
if err != nil {
t.Fatal(err)
}
if _, err := testframework.PushSchema2ImageData(
ctx, remoteRepo, repotag, imageData,
); err != nil {
t.Fatal(err)
}
itmsRule, err := cfgclient.ImageTagMirrorSets().Create(
ctx,
&cfgv1.ImageTagMirrorSet{
ObjectMeta: metav1.ObjectMeta{
Name: "image-registry-itms-testing",
},
Spec: cfgv1.ImageTagMirrorSetSpec{
ImageTagMirrors: []cfgv1.ImageTagMirrors{
{
Source: "does.not.exist/repo/image",
Mirrors: []cfgv1.ImageMirror{
cfgv1.ImageMirror(remoteRegistryAddr + "/" + isname),
},
},
},
},
},
metav1.CreateOptions{},
)
if err != nil {
t.Fatalf("error creating ITMS rule: %s", err)
}
defer func() {
if err := cfgclient.ImageTagMirrorSets().Delete(
ctx, itmsRule.Name, metav1.DeleteOptions{},
); err != nil {
t.Errorf("error deleting ITMS rule: %s", err)
}
}()
imgsrc := fmt.Sprintf("does.not.exist/repo/image:%s", repotag)
isi := &imageapiv1.ImageStreamImport{
ObjectMeta: metav1.ObjectMeta{
Namespace: namespace,
Name: "myimagestream",
Annotations: map[string]string{
imageapiv1.InsecureRepositoryAnnotation: "true",
},
},
Spec: imageapiv1.ImageStreamImportSpec{
Import: true,
Images: []imageapiv1.ImageImportSpec{
{
From: corev1.ObjectReference{
Kind: "DockerImage",
Name: imgsrc,
},
To: &corev1.LocalObjectReference{
Name: repotag,
},
ImportPolicy: imageapiv1.TagImportPolicy{
Insecure: true,
},
},
},
},
}
if isi, err = imgclient.ImageStreamImports(namespace).Create(
ctx, isi, metav1.CreateOptions{},
); err != nil {
t.Fatal(err)
}
if len(isi.Status.Images) != 1 {
t.Fatalf("imported unexpected number of images (%d != 1)", len(isi.Status.Images))
}
for i, image := range isi.Status.Images {
if image.Status.Status != metav1.StatusSuccess {
t.Fatalf("unexpected status %d: %#v", i, image.Status)
}
if image.Image == nil {
t.Fatalf("unexpected empty image %d", i)
}
if image.Image.Name != imgdgst {
t.Fatalf(
"unexpected image %d: %#v (expect %q)",
i, image.Image.Name, imgdgst,
)
}
}
istream, err := imgclient.ImageStreams(isi.Namespace).Get(
ctx, isi.Name, metav1.GetOptions{},
)
if err != nil {
t.Fatal(err)
}
if istream.Annotations == nil {
istream.Annotations = make(map[string]string)
}
istream.Annotations[imageapiv1.InsecureRepositoryAnnotation] = "true"
istream, err = imgclient.ImageStreams(istream.Namespace).Update(
ctx, istream, metav1.UpdateOptions{},
)
if err != nil {
t.Fatal(err)
}
t.Logf("Run registry...")
registry := master.StartRegistry(t, testframework.DisableMirroring{})
defer registry.Close()
t.Logf("Pulling manifest by tag...")
if err := testPullThroughGetManifest(
registry.BaseURL(), isi, testuser.Name, testuser.Token, repotag,
); err != nil {
t.Fatal(err)
}
t.Logf("Pulling manifest by digest...")
if err := testPullThroughGetManifest(
registry.BaseURL(), isi, testuser.Name, testuser.Token, imgdgst,
); err != nil {
t.Fatal(err)
}
t.Logf("Pulling image blobs...")
for digest := range descriptors {
if err := testPullThroughStatBlob(
registry.BaseURL(), isi, testuser.Name, testuser.Token, digest,
); err != nil {
t.Fatal(err)
}
}
}