diff --git a/pkg/cnb/builder_builder.go b/pkg/cnb/builder_builder.go index 13460ed3e..6fa5fe1ff 100644 --- a/pkg/cnb/builder_builder.go +++ b/pkg/cnb/builder_builder.go @@ -54,10 +54,11 @@ type builderBlder struct { additionalLabels map[string]string } -func newBuilderBldr(kpackVersion string) *builderBlder { +func newBuilderBldr(kpackVersion string, runImage string) *builderBlder { return &builderBlder{ buildpackLayers: map[DescriptiveBuildpackInfo]buildpackLayer{}, kpackVersion: kpackVersion, + runImage: runImage, } } @@ -70,7 +71,6 @@ func (bb *builderBlder) AddStack(baseImage v1.Image, clusterStack *buildapi.Clus bb.os = file.OS bb.baseImage = baseImage bb.stackId = clusterStack.Status.Id - bb.runImage = clusterStack.Status.RunImage.Image bb.mixins = clusterStack.Status.Mixins bb.cnbUserId = clusterStack.Status.UserID bb.cnbGroupId = clusterStack.Status.GroupID diff --git a/pkg/cnb/create_builder.go b/pkg/cnb/create_builder.go index 20e978c22..cbe159db0 100644 --- a/pkg/cnb/create_builder.go +++ b/pkg/cnb/create_builder.go @@ -2,12 +2,15 @@ package cnb import ( "context" + "fmt" "github.com/google/go-containerregistry/pkg/authn" + "github.com/google/go-containerregistry/pkg/name" ggcrv1 "github.com/google/go-containerregistry/pkg/v1" - "github.com/pivotal/kpack/pkg/cosign" corev1 "k8s.io/api/core/v1" + "github.com/pivotal/kpack/pkg/cosign" + buildapi "github.com/pivotal/kpack/pkg/apis/build/v1alpha2" corev1alpha1 "github.com/pivotal/kpack/pkg/apis/core/v1alpha1" "github.com/pivotal/kpack/pkg/registry" @@ -30,14 +33,29 @@ type RemoteBuilderCreator struct { ImageSigner cosign.BuilderSigner } -func (r *RemoteBuilderCreator) CreateBuilder(ctx context.Context, builderKeychain authn.Keychain, stackKeychain authn.Keychain, fetcher RemoteBuildpackFetcher, clusterStack *buildapi.ClusterStack, spec buildapi.BuilderSpec, serviceAccountSecrets []*corev1.Secret) (buildapi.BuilderRecord, error) { - buildImage, _, err := r.RegistryClient.Fetch(stackKeychain, clusterStack.Status.BuildImage.LatestImage) +func (r *RemoteBuilderCreator) CreateBuilder( + ctx context.Context, + builderKeychain authn.Keychain, + stackKeychain authn.Keychain, + fetcher RemoteBuildpackFetcher, + clusterStack *buildapi.ClusterStack, + spec buildapi.BuilderSpec, + serviceAccountSecrets []*corev1.Secret, + resolvedBuilderTag string, +) (buildapi.BuilderRecord, error) { + buildImage, _, err := r.RegistryClient.Fetch(stackKeychain, clusterStack.Status.BuildImage.LatestImage) + if err != nil { + return buildapi.BuilderRecord{}, err + } + runImage, _, err := r.RegistryClient.Fetch(stackKeychain, clusterStack.Status.RunImage.LatestImage) if err != nil { return buildapi.BuilderRecord{}, err } - builderBldr := newBuilderBldr(r.KpackVersion) + relocatedRunImage, err := r.RegistryClient.Save(builderKeychain, fmt.Sprintf("%s-run-image", resolvedBuilderTag), runImage) + + builderBldr := newBuilderBldr(r.KpackVersion, relocatedRunImage) err = builderBldr.AddStack(buildImage, clusterStack) if err != nil { @@ -72,7 +90,7 @@ func (r *RemoteBuilderCreator) CreateBuilder(ctx context.Context, builderKeychai return buildapi.BuilderRecord{}, err } - identifier, err := r.RegistryClient.Save(builderKeychain, spec.Tag, writeableImage) + identifier, err := r.RegistryClient.Save(builderKeychain, resolvedBuilderTag, writeableImage) if err != nil { return buildapi.BuilderRecord{}, err } @@ -96,7 +114,7 @@ func (r *RemoteBuilderCreator) CreateBuilder(ctx context.Context, builderKeychai builder := buildapi.BuilderRecord{ Image: identifier, Stack: corev1alpha1.BuildStack{ - RunImage: clusterStack.Status.RunImage.LatestImage, + RunImage: relocatedRunImage, ID: clusterStack.Status.Id, }, Buildpacks: buildpackMetadata(builderBldr.buildpacks()), @@ -110,6 +128,20 @@ func (r *RemoteBuilderCreator) CreateBuilder(ctx context.Context, builderKeychai return builder, nil } +func ResolveBuilderRef(ref, builderKind, builderName string) (string, error) { + parsedRef, err := name.ParseReference(ref) + if err != nil { + return "", err + } + + // this happens if there is no tag + if parsedRef.Identifier() == "latest" { + return parsedRef.Context().Tag(fmt.Sprintf("%s-%s", builderKind, builderName)).Name(), nil + } + + return parsedRef.Name(), nil +} + func buildpackMetadata(buildpacks []DescriptiveBuildpackInfo) corev1alpha1.BuildpackMetadataList { m := make(corev1alpha1.BuildpackMetadataList, 0, len(buildpacks)) for _, b := range buildpacks { diff --git a/pkg/cnb/create_builder_test.go b/pkg/cnb/create_builder_test.go index 40e8e7a5e..cb3268aff 100644 --- a/pkg/cnb/create_builder_test.go +++ b/pkg/cnb/create_builder_test.go @@ -41,9 +41,9 @@ func testCreateBuilderOs(os string, t *testing.T, when spec.G, it spec.S) { const ( stackID = "io.buildpacks.stacks.some-stack" mixin = "some-mixin" - tag = "custom/example" + builderTag = "custom/example:test-builder" buildImage = "index.docker.io/paketo-buildpacks/build@sha256:d19308ce0c1a9ec083432b2c850d615398f0c6a51095d589d58890a721925584" - runImage = "index.docker.io/paketo-buildpacks/run@sha256:469f092c28ab64c6798d6f5e24feb4252ae5b36c2ed79cc667ded85ffb49d996" + relocatedRunImageTag = "custom/example:test-builder-run-image" buildImageTag = "paketo-buildpacks/build:full-cnb" runImageTag = "paketo-buildpacks/run:full-cnb" buildImageLayers = 10 @@ -60,8 +60,10 @@ func testCreateBuilderOs(os string, t *testing.T, when spec.G, it spec.S) { builderKeychain = authn.NewMultiKeychain(authn.DefaultKeychain) stackKeychain = authn.NewMultiKeychain(authn.DefaultKeychain) secretRef = registry.SecretRef{} - - ctx = context.Background() + runImage = createRunImage(os) + runImageDigest = digest(runImage) + runImageRef = fmt.Sprintf("%s@%s", runImageTag, runImageDigest) + ctx = context.Background() fetcher = &fakeFetcher{buildpacks: map[string][]buildpackLayer{}, observedGeneration: 10} @@ -117,7 +119,7 @@ func testCreateBuilderOs(os string, t *testing.T, when spec.G, it spec.S) { Image: buildImageTag, }, RunImage: buildapi.ClusterStackStatusImage{ - LatestImage: runImage, + LatestImage: runImageRef, Image: runImageTag, }, Mixins: []string{"some-unused-mixin", mixin, "common-mixin", "build:another-common-mixin", "run:another-common-mixin"}, @@ -128,7 +130,7 @@ func testCreateBuilderOs(os string, t *testing.T, when spec.G, it spec.S) { } clusterBuilderSpec = buildapi.BuilderSpec{ - Tag: "custom/example", + Tag: builderTag, Stack: corev1.ObjectReference{ Kind: "stack", Name: "some-stack", @@ -309,7 +311,8 @@ func testCreateBuilderOs(os string, t *testing.T, when spec.G, it spec.S) { fetcher.AddBuildpack(t, "io.buildpack.4", "v4", []buildpackLayer{buildpackWithDuplicatLayer}) }) - registryClient.AddSaveKeychain("custom/example", builderKeychain) + registryClient.AddSaveKeychain(builderTag, builderKeychain) + registryClient.AddImage(runImageRef, runImage, stackKeychain) when("CreateBuilder", func() { var ( @@ -355,8 +358,8 @@ func testCreateBuilderOs(os string, t *testing.T, when spec.G, it spec.S) { } }) - it("creates a custom builder", func() { - builderRecord, err := subject.CreateBuilder(ctx, builderKeychain, stackKeychain, fetcher, stack, clusterBuilderSpec, []*corev1.Secret{}) + it("creates a custom builder with a relocated run image", func() { + builderRecord, err := subject.CreateBuilder(ctx, builderKeychain, stackKeychain, fetcher, stack, clusterBuilderSpec, []*corev1.Secret{}, builderTag) require.NoError(t, err) assert.Len(t, builderRecord.Buildpacks, 4) @@ -364,7 +367,7 @@ func testCreateBuilderOs(os string, t *testing.T, when spec.G, it spec.S) { assert.Contains(t, builderRecord.Buildpacks, corev1alpha1.BuildpackMetadata{Id: "io.buildpack.2", Version: "v2", Homepage: "buildpack.2.com"}) assert.Contains(t, builderRecord.Buildpacks, corev1alpha1.BuildpackMetadata{Id: "io.buildpack.3", Version: "v3", Homepage: "buildpack.3.com"}) assert.Contains(t, builderRecord.Buildpacks, corev1alpha1.BuildpackMetadata{Id: "io.buildpack.4", Version: "v4", Homepage: "buildpack.4.com"}) - assert.Equal(t, corev1alpha1.BuildStack{RunImage: runImage, ID: stackID}, builderRecord.Stack) + assert.Equal(t, corev1alpha1.BuildStack{RunImage: fmt.Sprintf("%s@%s", relocatedRunImageTag, runImageDigest), ID: stackID}, builderRecord.Stack) assert.Equal(t, int64(10), builderRecord.ObservedStoreGeneration) assert.Equal(t, int64(11), builderRecord.ObservedStackGeneration) assert.Equal(t, os, builderRecord.OS) @@ -388,8 +391,12 @@ func testCreateBuilderOs(os string, t *testing.T, when spec.G, it spec.S) { }, }) - assert.Len(t, registryClient.SavedImages(), 1) - savedImage := registryClient.SavedImages()[tag] + assert.Len(t, registryClient.SavedImages(), 2) + savedImage := registryClient.SavedImages()[builderTag] + require.Contains(t, registryClient.SavedImages(), relocatedRunImageTag) + digest, err := registryClient.SavedImages()[relocatedRunImageTag].Digest() + require.NoError(t, err) + require.Equal(t, digest.String(), runImageDigest) workingDir, err := imagehelpers.GetWorkingDir(savedImage) require.NoError(t, err) @@ -397,7 +404,7 @@ func testCreateBuilderOs(os string, t *testing.T, when spec.G, it spec.S) { hash, err := savedImage.Digest() require.NoError(t, err) - assert.Equal(t, fmt.Sprintf("%s@%s", tag, hash), builderRecord.Image) + assert.Equal(t, fmt.Sprintf("%s@%s", builderTag, hash), builderRecord.Image) layers, err := savedImage.Layers() require.NoError(t, err) @@ -487,9 +494,9 @@ func testCreateBuilderOs(os string, t *testing.T, when spec.G, it spec.S) { typeflag: tar.TypeReg, mode: 0644, fileContent: //language=toml - `[run-image] - image = "paketo-buildpacks/run:full-cnb" -`, + fmt.Sprintf(`[run-image] + image = "%s@%s" +`, relocatedRunImageTag, runImageDigest), }, }) }) @@ -528,11 +535,11 @@ func testCreateBuilderOs(os string, t *testing.T, when spec.G, it spec.S) { buildpackMetadata, err := imagehelpers.GetStringLabel(savedImage, buildpackMetadataLabel) assert.NoError(t, err) assert.JSONEq(t, //language=json - `{ + fmt.Sprintf(`{ "description": "Custom Builder built with kpack", "stack": { "runImage": { - "image": "paketo-buildpacks/run:full-cnb", + "image": "%s@%s", "mirrors": null } }, @@ -579,7 +586,7 @@ func testCreateBuilderOs(os string, t *testing.T, when spec.G, it spec.S) { "homepage": "buildpack.1.com" } ] -}`, buildpackMetadata) +}`, relocatedRunImageTag, runImageDigest), buildpackMetadata) buildpackLayers, err := imagehelpers.GetStringLabel(savedImage, buildpackLayersLabel) assert.NoError(t, err) @@ -653,11 +660,11 @@ func testCreateBuilderOs(os string, t *testing.T, when spec.G, it spec.S) { }) it("creates images deterministically ", func() { - original, err := subject.CreateBuilder(ctx, builderKeychain, stackKeychain, fetcher, stack, clusterBuilderSpec, []*corev1.Secret{}) + original, err := subject.CreateBuilder(ctx, builderKeychain, stackKeychain, fetcher, stack, clusterBuilderSpec, []*corev1.Secret{}, builderTag) require.NoError(t, err) for i := 1; i <= 50; i++ { - other, err := subject.CreateBuilder(ctx, builderKeychain, stackKeychain, fetcher, stack, clusterBuilderSpec, []*corev1.Secret{}) + other, err := subject.CreateBuilder(ctx, builderKeychain, stackKeychain, fetcher, stack, clusterBuilderSpec, []*corev1.Secret{}, builderTag) require.NoError(t, err) @@ -688,7 +695,7 @@ func testCreateBuilderOs(os string, t *testing.T, when spec.G, it spec.S) { }, } - _, err := subject.CreateBuilder(ctx, builderKeychain, stackKeychain, fetcher, stack, clusterBuilderSpec, []*corev1.Secret{}) + _, err := subject.CreateBuilder(ctx, builderKeychain, stackKeychain, fetcher, stack, clusterBuilderSpec, []*corev1.Secret{}, builderTag) require.EqualError(t, err, "validating buildpack io.buildpack.unsupported.stack@v4: stack io.buildpacks.stacks.some-stack is not supported") }) @@ -712,7 +719,7 @@ func testCreateBuilderOs(os string, t *testing.T, when spec.G, it spec.S) { }}, }} - _, err := subject.CreateBuilder(ctx, builderKeychain, stackKeychain, fetcher, stack, clusterBuilderSpec, []*corev1.Secret{}) + _, err := subject.CreateBuilder(ctx, builderKeychain, stackKeychain, fetcher, stack, clusterBuilderSpec, []*corev1.Secret{}, builderTag) require.EqualError(t, err, "validating buildpack io.buildpack.unsupported.mixin@v4: stack missing mixin(s): something-missing-mixin, something-missing-mixin2") }) @@ -757,7 +764,7 @@ func testCreateBuilderOs(os string, t *testing.T, when spec.G, it spec.S) { }}, }} - _, err := subject.CreateBuilder(ctx, builderKeychain, stackKeychain, fetcher, stack, clusterBuilderSpec, []*corev1.Secret{}) + _, err := subject.CreateBuilder(ctx, builderKeychain, stackKeychain, fetcher, stack, clusterBuilderSpec, []*corev1.Secret{}, builderTag) require.Nil(t, err) }) @@ -782,7 +789,7 @@ func testCreateBuilderOs(os string, t *testing.T, when spec.G, it spec.S) { }}, }} - _, err := subject.CreateBuilder(ctx, builderKeychain, nil, fetcher, stack, clusterBuilderSpec, []*corev1.Secret{}) + _, err := subject.CreateBuilder(ctx, builderKeychain, nil, fetcher, stack, clusterBuilderSpec, []*corev1.Secret{}, builderTag) require.Error(t, err, "validating buildpack io.buildpack.relaxed.old.mixin@v4: stack missing mixin(s): build:common-mixin, run:common-mixin, another-common-mixin") }) @@ -805,7 +812,7 @@ func testCreateBuilderOs(os string, t *testing.T, when spec.G, it spec.S) { }}, }} - _, err := subject.CreateBuilder(ctx, builderKeychain, stackKeychain, fetcher, stack, clusterBuilderSpec, []*corev1.Secret{}) + _, err := subject.CreateBuilder(ctx, builderKeychain, stackKeychain, fetcher, stack, clusterBuilderSpec, []*corev1.Secret{}, builderTag) require.EqualError(t, err, "validating buildpack io.buildpack.unsupported.buildpack.api@v4: unsupported buildpack api: 0.1, expecting: 0.2, 0.3") }) @@ -848,7 +855,7 @@ func testCreateBuilderOs(os string, t *testing.T, when spec.G, it spec.S) { }}, }} - _, err := subject.CreateBuilder(ctx, builderKeychain, stackKeychain, fetcher, stack, clusterBuilderSpec, []*corev1.Secret{}) + _, err := subject.CreateBuilder(ctx, builderKeychain, stackKeychain, fetcher, stack, clusterBuilderSpec, []*corev1.Secret{}, builderTag) require.NoError(t, err) }) }) @@ -875,14 +882,14 @@ func testCreateBuilderOs(os string, t *testing.T, when spec.G, it spec.S) { }, } - _, err := subject.CreateBuilder(ctx, builderKeychain, stackKeychain, fetcher, stack, clusterBuilderSpec, []*corev1.Secret{}) + _, err := subject.CreateBuilder(ctx, builderKeychain, stackKeychain, fetcher, stack, clusterBuilderSpec, []*corev1.Secret{}, builderTag) require.EqualError(t, err, "unsupported platform apis in kpack lifecycle: 0.1, 0.2, 0.999, expecting one of: 0.3, 0.4, 0.5, 0.6, 0.7, 0.8") }) }) when("signing a builder image", func() { it("does not populate the signature paths when no secrets were present", func() { - builderRecord, err := subject.CreateBuilder(ctx, builderKeychain, stackKeychain, fetcher, stack, clusterBuilderSpec, []*corev1.Secret{}) + builderRecord, err := subject.CreateBuilder(ctx, builderKeychain, stackKeychain, fetcher, stack, clusterBuilderSpec, []*corev1.Secret{}, builderTag) require.NoError(t, err) require.NotNil(t, builderRecord) require.Empty(t, builderRecord.SignaturePaths) @@ -902,7 +909,7 @@ func testCreateBuilderOs(os string, t *testing.T, when spec.G, it spec.S) { }, } - _, err := subject.CreateBuilder(ctx, builderKeychain, stackKeychain, fetcher, stack, clusterBuilderSpec, []*corev1.Secret{&fakeSecret}) + _, err := subject.CreateBuilder(ctx, builderKeychain, stackKeychain, fetcher, stack, clusterBuilderSpec, []*corev1.Secret{&fakeSecret}, builderTag) require.Error(t, err) }) @@ -925,7 +932,7 @@ func testCreateBuilderOs(os string, t *testing.T, when spec.G, it spec.S) { }, } - builderRecord, err := subject.CreateBuilder(ctx, builderKeychain, stackKeychain, fetcher, stack, clusterBuilderSpec, []*corev1.Secret{&fakeSecret}) + builderRecord, err := subject.CreateBuilder(ctx, builderKeychain, stackKeychain, fetcher, stack, clusterBuilderSpec, []*corev1.Secret{&fakeSecret}, builderTag) require.NoError(t, err) require.NotNil(t, builderRecord) require.NotEmpty(t, builderRecord.SignaturePaths) @@ -1073,3 +1080,19 @@ func layerToRemoteBuildpack(bpLayer buildpackLayer, layer *fakeLayer, secretRef SecretRef: secretRef, } } + +func createRunImage(os string) v1.Image { + runImg, _ := random.Image(1, int64(5)) + + config, _ := runImg.ConfigFile() + + config.OS = os + runImg, _ = mutate.ConfigFile(runImg, config) + + return runImg +} + +func digest(image v1.Image) string { + d, _ := image.Digest() + return d.String() +} diff --git a/pkg/reconciler/builder/builder.go b/pkg/reconciler/builder/builder.go index 07ffbc766..43f76de2b 100644 --- a/pkg/reconciler/builder/builder.go +++ b/pkg/reconciler/builder/builder.go @@ -2,6 +2,7 @@ package builder import ( "context" + "strings" corev1 "k8s.io/api/core/v1" @@ -35,7 +36,16 @@ const ( ) type BuilderCreator interface { - CreateBuilder(ctx context.Context, builderKeychain authn.Keychain, keychain authn.Keychain, fetcher cnb.RemoteBuildpackFetcher, clusterStack *buildapi.ClusterStack, spec buildapi.BuilderSpec, serviceAccountSecrets []*corev1.Secret) (buildapi.BuilderRecord, error) + CreateBuilder( + ctx context.Context, + builderKeychain authn.Keychain, + keychain authn.Keychain, + fetcher cnb.RemoteBuildpackFetcher, + clusterStack *buildapi.ClusterStack, + spec buildapi.BuilderSpec, + serviceAccountSecrets []*corev1.Secret, + resolvedBuilderRef string, + ) (buildapi.BuilderRecord, error) } type Fetcher interface { @@ -238,7 +248,21 @@ func (c *Reconciler) reconcileBuilder(ctx context.Context, builder *buildapi.Bui return buildapi.BuilderRecord{}, err } - buildRecord, err := c.BuilderCreator.CreateBuilder(ctx, builderKeychain, stackKeychain, fetcher, clusterStack, builder.Spec.BuilderSpec, serviceAccountSecrets) + resolvedBuilderRef, err := cnb.ResolveBuilderRef(builder.Spec.Tag, strings.ToLower(buildapi.BuilderKind), builder.Name) + if err != nil { + return buildapi.BuilderRecord{}, err + } + + buildRecord, err := c.BuilderCreator.CreateBuilder( + ctx, + builderKeychain, + stackKeychain, + fetcher, + clusterStack, + builder.Spec.BuilderSpec, + serviceAccountSecrets, + resolvedBuilderRef, + ) if err != nil { return buildapi.BuilderRecord{}, err } diff --git a/pkg/reconciler/builder/builder_test.go b/pkg/reconciler/builder/builder_test.go index 19a9366d1..768355936 100644 --- a/pkg/reconciler/builder/builder_test.go +++ b/pkg/reconciler/builder/builder_test.go @@ -37,12 +37,13 @@ func TestBuilderReconciler(t *testing.T) { func testBuilderReconciler(t *testing.T, when spec.G, it spec.S) { const ( - testNamespace = "some-namespace" - builderName = "custom-builder" - builderKey = testNamespace + "/" + builderName - builderTag = "example.com/custom-builder" - builderIdentifier = "example.com/custom-builder@sha256:resolved-builder-digest" - initialGeneration int64 = 1 + testNamespace = "some-namespace" + builderName = "custom-builder" + builderKey = testNamespace + "/" + builderName + builderTag = "example.com/custom-builder" + expectedResolvedTag = "example.com/custom-builder:builder-custom-builder" + builderIdentifier = "example.com/custom-builder@sha256:resolved-builder-digest" + initialGeneration int64 = 1 ) var ( @@ -293,13 +294,14 @@ func testBuilderReconciler(t *testing.T, when spec.G, it spec.S) { }) assert.Equal(t, []testhelpers.CreateBuilderArgs{{ - Context: context.Background(), - BuilderKeychain: ®istryfakes.FakeKeychain{}, - StackKeychain: ®istryfakes.FakeKeychain{}, - Fetcher: expectedFetcher, - ClusterStack: clusterStack, - BuilderSpec: builder.Spec.BuilderSpec, - SigningSecrets: []*corev1.Secret{}, + Context: context.Background(), + BuilderKeychain: ®istryfakes.FakeKeychain{}, + StackKeychain: ®istryfakes.FakeKeychain{}, + Fetcher: expectedFetcher, + ClusterStack: clusterStack, + BuilderSpec: builder.Spec.BuilderSpec, + SigningSecrets: []*corev1.Secret{}, + ResolvedBuilderTag: expectedResolvedTag, }}, builderCreator.CreateBuilderCalls) }) diff --git a/pkg/reconciler/clusterbuilder/clusterbuilder.go b/pkg/reconciler/clusterbuilder/clusterbuilder.go index 7da247731..188116028 100644 --- a/pkg/reconciler/clusterbuilder/clusterbuilder.go +++ b/pkg/reconciler/clusterbuilder/clusterbuilder.go @@ -2,6 +2,7 @@ package clusterbuilder import ( "context" + "strings" "go.uber.org/zap" corev1 "k8s.io/api/core/v1" @@ -34,7 +35,16 @@ const ( ) type BuilderCreator interface { - CreateBuilder(ctx context.Context, builderKeychain authn.Keychain, stackKeychain authn.Keychain, fetcher cnb.RemoteBuildpackFetcher, clusterStack *buildapi.ClusterStack, spec buildapi.BuilderSpec, serviceAccountSecrets []*corev1.Secret) (buildapi.BuilderRecord, error) + CreateBuilder( + ctx context.Context, + builderKeychain authn.Keychain, + stackKeychain authn.Keychain, + fetcher cnb.RemoteBuildpackFetcher, + clusterStack *buildapi.ClusterStack, + spec buildapi.BuilderSpec, + serviceAccountSecrets []*corev1.Secret, + resolvedBuilderRef string, + ) (buildapi.BuilderRecord, error) } type Fetcher interface { @@ -221,7 +231,21 @@ func (c *Reconciler) reconcileBuilder(ctx context.Context, builder *buildapi.Clu return buildapi.BuilderRecord{}, err } - buildRecord, err := c.BuilderCreator.CreateBuilder(ctx, builderKeychain, stackKeychain, fetcher, clusterStack, builder.Spec.BuilderSpec, serviceAccountSecrets) + resolvedBuilderRef, err := cnb.ResolveBuilderRef(builder.Spec.Tag, strings.ToLower(buildapi.ClusterBuilderKind), builder.Name) + if err != nil { + return buildapi.BuilderRecord{}, err + } + + buildRecord, err := c.BuilderCreator.CreateBuilder( + ctx, + builderKeychain, + stackKeychain, + fetcher, + clusterStack, + builder.Spec.BuilderSpec, + serviceAccountSecrets, + resolvedBuilderRef, + ) if err != nil { return buildapi.BuilderRecord{}, err } diff --git a/pkg/reconciler/clusterbuilder/clusterbuilder_test.go b/pkg/reconciler/clusterbuilder/clusterbuilder_test.go index 64e0c1cec..5614c8f9c 100644 --- a/pkg/reconciler/clusterbuilder/clusterbuilder_test.go +++ b/pkg/reconciler/clusterbuilder/clusterbuilder_test.go @@ -35,11 +35,12 @@ func TestClusterBuilderReconciler(t *testing.T) { func testClusterBuilderReconciler(t *testing.T, when spec.G, it spec.S) { const ( - builderName = "custom-builder" - builderKey = builderName - builderTag = "example.com/custom-builder" - builderIdentifier = "example.com/custom-builder@sha256:resolved-builder-digest" - initialGeneration int64 = 1 + builderName = "custom-builder" + builderKey = builderName + builderTag = "example.com/custom-builder" + expectedResolvedTag = "example.com/custom-builder:clusterbuilder-custom-builder" + builderIdentifier = "example.com/custom-builder@sha256:resolved-builder-digest" + initialGeneration int64 = 1 ) var ( @@ -279,13 +280,14 @@ func testClusterBuilderReconciler(t *testing.T, when spec.G, it spec.S) { }) assert.Equal(t, []testhelpers.CreateBuilderArgs{{ - Context: context.Background(), - BuilderKeychain: ®istryfakes.FakeKeychain{}, - StackKeychain: ®istryfakes.FakeKeychain{}, - Fetcher: expectedFetcher, - ClusterStack: clusterStack, - BuilderSpec: builder.Spec.BuilderSpec, - SigningSecrets: []*corev1.Secret{}, + Context: context.Background(), + BuilderKeychain: ®istryfakes.FakeKeychain{}, + StackKeychain: ®istryfakes.FakeKeychain{}, + Fetcher: expectedFetcher, + ClusterStack: clusterStack, + BuilderSpec: builder.Spec.BuilderSpec, + SigningSecrets: []*corev1.Secret{}, + ResolvedBuilderTag: expectedResolvedTag, }}, builderCreator.CreateBuilderCalls) }) diff --git a/pkg/reconciler/testhelpers/fake_builder_creator.go b/pkg/reconciler/testhelpers/fake_builder_creator.go index f7a07f53c..d4f5f6567 100644 --- a/pkg/reconciler/testhelpers/fake_builder_creator.go +++ b/pkg/reconciler/testhelpers/fake_builder_creator.go @@ -19,24 +19,26 @@ type FakeBuilderCreator struct { } type CreateBuilderArgs struct { - Context context.Context - BuilderKeychain authn.Keychain - StackKeychain authn.Keychain - Fetcher cnb.RemoteBuildpackFetcher - ClusterStack *buildapi.ClusterStack - BuilderSpec buildapi.BuilderSpec - SigningSecrets []*corev1.Secret + Context context.Context + BuilderKeychain authn.Keychain + StackKeychain authn.Keychain + Fetcher cnb.RemoteBuildpackFetcher + ClusterStack *buildapi.ClusterStack + BuilderSpec buildapi.BuilderSpec + SigningSecrets []*corev1.Secret + ResolvedBuilderTag string } -func (f *FakeBuilderCreator) CreateBuilder(ctx context.Context, builderKeychain authn.Keychain, stackKeychain authn.Keychain, fetcher cnb.RemoteBuildpackFetcher, clusterStack *buildapi.ClusterStack, spec buildapi.BuilderSpec, signingSecrets []*corev1.Secret) (buildapi.BuilderRecord, error) { +func (f *FakeBuilderCreator) CreateBuilder(ctx context.Context, builderKeychain authn.Keychain, stackKeychain authn.Keychain, fetcher cnb.RemoteBuildpackFetcher, clusterStack *buildapi.ClusterStack, spec buildapi.BuilderSpec, signingSecrets []*corev1.Secret, resolvedBuilderTag string) (buildapi.BuilderRecord, error) { f.CreateBuilderCalls = append(f.CreateBuilderCalls, CreateBuilderArgs{ - Context: ctx, - BuilderKeychain: builderKeychain, - StackKeychain: stackKeychain, - Fetcher: fetcher, - ClusterStack: clusterStack, - BuilderSpec: spec, - SigningSecrets: signingSecrets, + Context: ctx, + BuilderKeychain: builderKeychain, + StackKeychain: stackKeychain, + Fetcher: fetcher, + ClusterStack: clusterStack, + BuilderSpec: spec, + SigningSecrets: signingSecrets, + ResolvedBuilderTag: resolvedBuilderTag, }) return f.Record, f.CreateErr diff --git a/pkg/registry/registryfakes/fake_client.go b/pkg/registry/registryfakes/fake_client.go index 52327f3cb..092b55c48 100644 --- a/pkg/registry/registryfakes/fake_client.go +++ b/pkg/registry/registryfakes/fake_client.go @@ -32,7 +32,7 @@ func (f *FakeClient) Fetch(keychain authn.Keychain, repoName string) (v1.Image, return nil, "", f.fetchError } - if expectedKeychain, ok := f.readKeychains[repoName]; !ok || keychain != expectedKeychain { + if expectedKeychain, ok := f.readKeychains[tryParsingTag(repoName)]; !ok || keychain != expectedKeychain { return nil, "", errors.New("unexpected keychain") } @@ -55,7 +55,7 @@ func (f *FakeClient) Fetch(keychain authn.Keychain, repoName string) (v1.Image, } func (f *FakeClient) Save(keychain authn.Keychain, tag string, image v1.Image) (string, error) { - if expectedKeychain, ok := f.writeKeychains[tag]; !ok || keychain != expectedKeychain { + if expectedKeychain, ok := f.writeKeychains[tryParsingTag(tag)]; !ok || keychain != expectedKeychain { return "", errors.New("unexpected keychain") } @@ -67,11 +67,11 @@ func (f *FakeClient) Save(keychain authn.Keychain, tag string, image v1.Image) ( func (f *FakeClient) AddImage(repoName string, image v1.Image, keychain authn.Keychain) { f.images[repoName] = image - f.readKeychains[repoName] = keychain + f.readKeychains[tryParsingTag(repoName)] = keychain } func (f *FakeClient) AddSaveKeychain(tag string, keychain authn.Keychain) { - f.writeKeychains[tag] = keychain + f.writeKeychains[tryParsingTag(tag)] = keychain } func (f *FakeClient) SavedImages() map[string]v1.Image { @@ -81,3 +81,12 @@ func (f *FakeClient) SavedImages() map[string]v1.Image { func (f *FakeClient) SetFetchError(err error) { f.fetchError = err } + +func tryParsingTag(tag string) string { + ref, err := name.ParseReference(tag) + if err != nil { + return tag + } + + return ref.Context().Name() +}