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:
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user