Skip to content

Commit

Permalink
Relocate the run image to the builder tag
Browse files Browse the repository at this point in the history
- Also make sure the builder is tagged with the name and kind if a tag is not provided

Signed-off-by: Tom Kennedy <ktom@vmware.com>
  • Loading branch information
tomkennedy513 committed Feb 21, 2024
1 parent 03acfbb commit 581ec0a
Show file tree
Hide file tree
Showing 9 changed files with 205 additions and 87 deletions.
4 changes: 2 additions & 2 deletions pkg/cnb/builder_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
}

Expand All @@ -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
Expand Down
44 changes: 38 additions & 6 deletions pkg/cnb/create_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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 {
Expand Down Expand Up @@ -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
}
Expand All @@ -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()),
Expand All @@ -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 {
Expand Down
85 changes: 54 additions & 31 deletions pkg/cnb/create_builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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}

Expand Down Expand Up @@ -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"},
Expand All @@ -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",
Expand Down Expand Up @@ -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 (
Expand Down Expand Up @@ -355,16 +358,16 @@ 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)
assert.Contains(t, builderRecord.Buildpacks, corev1alpha1.BuildpackMetadata{Id: "io.buildpack.1", Version: "v1", Homepage: "buildpack.1.com"})
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)
Expand All @@ -388,16 +391,20 @@ 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)
assert.Equal(t, "/layers", workingDir)

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)
Expand Down Expand Up @@ -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),
},
})
})
Expand Down Expand Up @@ -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
}
},
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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")
})

Expand All @@ -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")
})

Expand Down Expand Up @@ -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)
})

Expand All @@ -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")
})

Expand All @@ -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")
})

Expand Down Expand Up @@ -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)
})
})
Expand All @@ -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)
Expand All @@ -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)
})

Expand All @@ -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)
Expand Down Expand Up @@ -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()
}
Loading

0 comments on commit 581ec0a

Please sign in to comment.