Skip to content

Commit

Permalink
Add oci:// prefix
Browse files Browse the repository at this point in the history
Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
  • Loading branch information
stefanprodan committed Jul 5, 2022
1 parent 47e5a90 commit 28def20
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 13 deletions.
4 changes: 4 additions & 0 deletions api/v1beta2/ocirepository_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,16 @@ import (
const (
// OCIRepositoryKind is the string representation of a OCIRepository.
OCIRepositoryKind = "OCIRepository"

// OCIRepositoryPrefix is the prefix used for OCIRepository URLs.
OCIRepositoryPrefix = "oci://"
)

// OCIRepositorySpec defines the desired state of OCIRepository
type OCIRepositorySpec struct {
// URL is a reference to an OCI artifact repository hosted
// on a remote container registry.
// +kubebuilder:validation:Pattern="^oci://"
// +required
URL string `json:"url"`

Expand Down
2 changes: 1 addition & 1 deletion config/samples/source_v1beta2_ocirepository.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ metadata:
name: ocirepository-sample
spec:
interval: 1m
url: ghcr.io/stefanprodan/manifests/podinfo
url: oci://ghcr.io/stefanprodan/manifests/podinfo
ref:
tag: 6.1.6
29 changes: 25 additions & 4 deletions controllers/ocirepository_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ import (
"context"
"errors"
"fmt"
"github.com/google/go-containerregistry/pkg/name"
"os"
"sort"
"strings"
"time"

"github.com/Masterminds/semver/v3"
Expand Down Expand Up @@ -363,24 +365,43 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, obj *sour
return sreconcile.ResultSuccess, nil
}

// parseRepositoryURL extracts the repository URL.
func (r *OCIRepositoryReconciler) parseRepositoryURL(obj *sourcev1.OCIRepository) (string, error) {
if !strings.HasPrefix(obj.Spec.URL, sourcev1.OCIRepositoryPrefix) {
return "", fmt.Errorf("URL must be in format 'oci://<domain>/<org>/<repo>'")
}

url := strings.TrimPrefix(obj.Spec.URL, sourcev1.OCIRepositoryPrefix)
ref, err := name.ParseReference(url)
if err != nil {
return "", fmt.Errorf("'%s' invalid URL: %w", obj.Spec.URL, err)
}

return ref.Context().Name(), nil
}

// getArtifactURL determines which tag or digest should be used and returns the OCI artifact FQN.
func (r *OCIRepositoryReconciler) getArtifactURL(ctx context.Context, obj *sourcev1.OCIRepository, keychain authn.Keychain) (string, error) {
url := obj.Spec.URL
url, err := r.parseRepositoryURL(obj)
if err != nil {
return "", err
}

if obj.Spec.Reference != nil {
if obj.Spec.Reference.Digest != "" {
return fmt.Sprintf("%s@%s", obj.Spec.URL, obj.Spec.Reference.Digest), nil
return fmt.Sprintf("%s@%s", url, obj.Spec.Reference.Digest), nil
}

if obj.Spec.Reference.SemVer != "" {
tag, err := r.getTagBySemver(ctx, url, obj.Spec.Reference.SemVer, keychain)
if err != nil {
return "", err
}
return fmt.Sprintf("%s:%s", obj.Spec.URL, tag), nil
return fmt.Sprintf("%s:%s", url, tag), nil
}

if obj.Spec.Reference.Tag != "" {
return fmt.Sprintf("%s:%s", obj.Spec.URL, obj.Spec.Reference.Tag), nil
return fmt.Sprintf("%s:%s", url, obj.Spec.Reference.Tag), nil
}
}

Expand Down
18 changes: 10 additions & 8 deletions controllers/ocirepository_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ func TestOCIRepository_SecretRef(t *testing.T) {
g.Expect(err).ToNot(HaveOccurred())

repositoryURL := fmt.Sprintf("%s/podinfo", regServer.registryHost)
ociURL := fmt.Sprintf("oci://%s", repositoryURL)

// Push Test Image
err = crane.Push(image, repositoryURL, crane.WithAuth(&authn.Basic{
Expand All @@ -260,14 +261,14 @@ func TestOCIRepository_SecretRef(t *testing.T) {
}{
{
name: "private-registry-access-via-secretref",
url: repositoryURL,
url: ociURL,
digest: podinfoImageDigest,
includeSecretRef: true,
includeServiceAccount: false,
},
{
name: "private-registry-access-via-serviceaccount",
url: repositoryURL,
url: ociURL,
digest: podinfoImageDigest,
includeSecretRef: false,
includeServiceAccount: true,
Expand All @@ -289,7 +290,7 @@ func TestOCIRepository_SecretRef(t *testing.T) {
},
Type: corev1.SecretTypeDockerConfigJson,
StringData: map[string]string{
".dockerconfigjson": fmt.Sprintf(`{"auths": {%q: {"username": %q, "password": %q}}}`, tt.url, testRegistryUsername, testRegistryPassword),
".dockerconfigjson": fmt.Sprintf(`{"auths": {%q: {"username": %q, "password": %q}}}`, repositoryURL, testRegistryUsername, testRegistryPassword),
},
}
g.Expect(testEnv.CreateAndWait(ctx, secret)).To(Succeed())
Expand Down Expand Up @@ -435,6 +436,7 @@ func TestOCIRepository_FailedAuth(t *testing.T) {
g.Expect(err).ToNot(HaveOccurred())

repositoryURL := fmt.Sprintf("%s/podinfo", regServer.registryHost)
ociURL := fmt.Sprintf("oci://%s", repositoryURL)

// Push Test Image
err = crane.Push(image, repositoryURL, crane.WithAuth(&authn.Basic{
Expand All @@ -458,7 +460,7 @@ func TestOCIRepository_FailedAuth(t *testing.T) {
}{
{
name: "missing-auth",
url: repositoryURL,
url: ociURL,
repoUsername: "",
repoPassword: "",
digest: podinfoImageDigest,
Expand All @@ -467,7 +469,7 @@ func TestOCIRepository_FailedAuth(t *testing.T) {
},
{
name: "invalid-auth-via-secret",
url: repositoryURL,
url: ociURL,
repoUsername: "InvalidUser",
repoPassword: "InvalidPassword",
digest: podinfoImageDigest,
Expand All @@ -476,7 +478,7 @@ func TestOCIRepository_FailedAuth(t *testing.T) {
},
{
name: "invalid-auth-via-service-account",
url: repositoryURL,
url: ociURL,
repoUsername: "InvalidUser",
repoPassword: "InvalidPassword",
digest: podinfoImageDigest,
Expand All @@ -500,7 +502,7 @@ func TestOCIRepository_FailedAuth(t *testing.T) {
},
Type: corev1.SecretTypeDockerConfigJson,
StringData: map[string]string{
".dockerconfigjson": fmt.Sprintf(`{"auths": {%q: {"username": %q, "password": %q}}}`, tt.url, tt.repoUsername, tt.repoPassword),
".dockerconfigjson": fmt.Sprintf(`{"auths": {%q: {"username": %q, "password": %q}}}`, repositoryURL, tt.repoUsername, tt.repoPassword),
},
}
g.Expect(testEnv.CreateAndWait(ctx, secret)).To(Succeed())
Expand Down Expand Up @@ -623,7 +625,7 @@ func createPodinfoImageFromTar(tarFileName, tag string, imageServer *httptest.Se
}

return &podinfoImage{
url: repositoryURL,
url: "oci://" + repositoryURL,
tag: tag,
digest: podinfoImageDigest,
}, nil
Expand Down

0 comments on commit 28def20

Please sign in to comment.