diff --git a/api/kuik/v1alpha1/cachedimage_utils.go b/api/kuik/v1alpha1/cachedimage_utils.go index a07df1bd..cd37905b 100644 --- a/api/kuik/v1alpha1/cachedimage_utils.go +++ b/api/kuik/v1alpha1/cachedimage_utils.go @@ -32,7 +32,7 @@ func (r *CachedImage) GetPullSecrets(apiReader client.Reader) ([]corev1.Secret, return nil, err } - pullSecrets, err := registry.GetPullSecrets(apiReader, repository.Spec.PullSecretsNamespace, repository.Spec.PullSecretNames) + pullSecrets, err := repository.GetPullSecrets(apiReader) if err != nil { return nil, err } diff --git a/api/kuik/v1alpha1/repository_utils.go b/api/kuik/v1alpha1/repository_utils.go index 85422d34..a057cc57 100644 --- a/api/kuik/v1alpha1/repository_utils.go +++ b/api/kuik/v1alpha1/repository_utils.go @@ -2,6 +2,10 @@ package v1alpha1 import ( "regexp" + + "github.com/enix/kube-image-keeper/internal/registry" + corev1 "k8s.io/api/core/v1" + "sigs.k8s.io/controller-runtime/pkg/client" ) func (r *Repository) CompileUpdateFilters() ([]regexp.Regexp, error) { @@ -17,3 +21,12 @@ func (r *Repository) CompileUpdateFilters() ([]regexp.Regexp, error) { return regexps, nil } + +func (r *Repository) GetPullSecrets(apiReader client.Reader) ([]corev1.Secret, error) { + pullSecrets, err := registry.GetPullSecrets(apiReader, r.Spec.PullSecretsNamespace, r.Spec.PullSecretNames) + if err != nil { + return nil, err + } + + return pullSecrets, nil +} diff --git a/internal/proxy/server.go b/internal/proxy/server.go index bb69b7ed..d68d85a9 100644 --- a/internal/proxy/server.go +++ b/internal/proxy/server.go @@ -22,6 +22,7 @@ import ( "github.com/google/go-containerregistry/pkg/v1/remote/transport" "golang.org/x/exp/slices" apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/types" utilerrors "k8s.io/apimachinery/pkg/util/errors" "k8s.io/klog/v2" "sigs.k8s.io/controller-runtime/pkg/client" @@ -149,15 +150,15 @@ func (p *Proxy) v2Endpoint(c *gin.Context) { } func (p *Proxy) routeProxy(c *gin.Context) { - repository := c.Param("repository") + repositoryName := c.Param("repository") originRegistry := c.Param("originRegistry") - klog.InfoS("proxying request", "repository", repository, "originRegistry", originRegistry) + klog.InfoS("proxying request", "repository", repositoryName, "originRegistry", originRegistry) if err := p.proxyRegistry(c, registry.Protocol+registry.Endpoint, false, nil); err != nil { klog.InfoS("cached image is not available, proxying origin", "originRegistry", originRegistry, "error", err) - cachedImage, err := p.getCachedImage(originRegistry, repository) + repository, err := p.getRepository(originRegistry, repositoryName) if err != nil { if statusError, isStatus := err.(*apierrors.StatusError); isStatus && statusError.ErrStatus.Code != 0 { _ = c.AbortWithError(int(statusError.ErrStatus.Code), err) @@ -167,7 +168,7 @@ func (p *Proxy) routeProxy(c *gin.Context) { return } - transport, err := p.getAuthentifiedTransport(cachedImage, "https://"+originRegistry) + transport, err := p.getAuthentifiedTransport(repository, "https://"+originRegistry) if err != nil { _ = c.AbortWithError(http.StatusUnauthorized, err) return @@ -250,42 +251,33 @@ func (p *Proxy) proxyRegistry(c *gin.Context, endpoint string, endpointIsOrigin return proxyError } -func (p *Proxy) getCachedImage(registryDomain string, repositoryName string) (*kuikv1alpha1.CachedImage, error) { - repositoryLabel := registry.RepositoryLabel(registryDomain + "/" + repositoryName) - cachedImages := &kuikv1alpha1.CachedImageList{} +func (p *Proxy) getRepository(registryDomain string, repositoryName string) (*kuikv1alpha1.Repository, error) { + sanitizedName := registry.SanitizeName(registryDomain + "/" + repositoryName) - klog.InfoS("listing CachedImages", "repositoryLabel", repositoryLabel) - if err := p.k8sClient.List(context.Background(), cachedImages, client.MatchingLabels{ - kuikv1alpha1.RepositoryLabelName: repositoryLabel, - }, client.Limit(1)); err != nil { + repository := &kuikv1alpha1.Repository{} + if err := p.k8sClient.Get(context.Background(), types.NamespacedName{Name: sanitizedName}, repository); err != nil { return nil, err } - if len(cachedImages.Items) == 0 { - return nil, errors.New("no CachedImage found for this repository") - } - - cachedImage := cachedImages.Items[0] // Images from the same repository should need the same pull-secret - - return &cachedImage, nil + return repository, nil } -func (p *Proxy) getKeychains(cachedImage *kuikv1alpha1.CachedImage) ([]authn.Keychain, error) { - pullSecrets, err := cachedImage.GetPullSecrets(p.k8sClient) +func (p *Proxy) getKeychains(repository *kuikv1alpha1.Repository) ([]authn.Keychain, error) { + pullSecrets, err := repository.GetPullSecrets(p.k8sClient) if err != nil { return nil, err } - return registry.GetKeychains(cachedImage.Spec.SourceImage, pullSecrets) + return registry.GetKeychains(repository.Spec.Name, pullSecrets) } -func (p *Proxy) getAuthentifiedTransport(cachedImage *kuikv1alpha1.CachedImage, originRegistry string) (http.RoundTripper, error) { - imageRef, err := name.ParseReference(cachedImage.Spec.SourceImage) +func (p *Proxy) getAuthentifiedTransport(repository *kuikv1alpha1.Repository, originRegistry string) (http.RoundTripper, error) { + imageRef, err := name.ParseReference(repository.Spec.Name) if err != nil { return nil, err } - keychains, err := p.getKeychains(cachedImage) + keychains, err := p.getKeychains(repository) if err != nil { return nil, err } diff --git a/internal/registry/keychain.go b/internal/registry/keychain.go index 942b883b..6a7226a9 100644 --- a/internal/registry/keychain.go +++ b/internal/registry/keychain.go @@ -23,7 +23,7 @@ func (a *authConfigKeychain) Resolve(target authn.Resource) (authn.Authenticator return authn.FromConfig(a.AuthConfig), nil } -func GetKeychains(imageName string, pullSecrets []corev1.Secret) ([]authn.Keychain, error) { +func GetKeychains(repositoryName string, pullSecrets []corev1.Secret) ([]authn.Keychain, error) { defaultKeyring := &credentialprovider.BasicDockerKeyring{} keyring, err := credentialprovidersecrets.MakeDockerKeyring(pullSecrets, defaultKeyring) @@ -33,7 +33,7 @@ func GetKeychains(imageName string, pullSecrets []corev1.Secret) ([]authn.Keycha keychains := []authn.Keychain{} - named, err := reference.ParseNormalizedNamed(imageName) + named, err := reference.ParseNormalizedNamed(repositoryName) if err != nil { return nil, fmt.Errorf("couldn't parse image name: %v", err) } diff --git a/internal/registry/keychain_test.go b/internal/registry/keychain_test.go index 5bc72853..85c8d103 100644 --- a/internal/registry/keychain_test.go +++ b/internal/registry/keychain_test.go @@ -143,7 +143,7 @@ func TestGetKeychains(t *testing.T) { tests := []struct { name string - imageName string + repositoryName string pullSecrets []corev1.Secret expectedKeychains []authn.Keychain wantErr error @@ -166,8 +166,8 @@ func TestGetKeychains(t *testing.T) { expectedKeychains: dockerHubKeychains, }, { - name: "Multiple secrets (localhost)", - imageName: "localhost:5000/alpine", + name: "Multiple secrets (localhost)", + repositoryName: "localhost:5000/alpine", pullSecrets: []corev1.Secret{ pullSecrets["foo"], pullSecrets["bar"], @@ -203,8 +203,8 @@ func TestGetKeychains(t *testing.T) { expectedKeychains: dockerHubKeychains, }, { - name: "Multiple secrets in one .dockerconfigjson (localhost)", - imageName: "localhost:5000/alpine", + name: "Multiple secrets in one .dockerconfigjson (localhost)", + repositoryName: "localhost:5000/alpine", pullSecrets: []corev1.Secret{ pullSecrets["foobar"], }, @@ -232,20 +232,20 @@ func TestGetKeychains(t *testing.T) { wantErr: errors.New("unable to parse auth field, must be formatted as base64(username:password)"), }, { - name: "Invalid image name", - imageName: ":::://::", - wantErr: errors.New("couldn't parse image name: invalid reference format"), + name: "Invalid image name", + repositoryName: ":::://::", + wantErr: errors.New("couldn't parse image name: invalid reference format"), }, } g := NewWithT(t) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if tt.imageName == "" { - tt.imageName = "alpine" + if tt.repositoryName == "" { + tt.repositoryName = "alpine" } - keychains, err := GetKeychains(tt.imageName, tt.pullSecrets) + keychains, err := GetKeychains(tt.repositoryName, tt.pullSecrets) if tt.wantErr == nil { g.Expect(err).To(Succeed())