Skip to content

Commit

Permalink
When rebasing, update stack/runImage key in lifecycle metadata label
Browse files Browse the repository at this point in the history
if the provided run image does not match existing metadata.

See buildpacks/spec#360

Signed-off-by: Natalie Arellano <narellano@vmware.com>
  • Loading branch information
natalieparellano committed May 31, 2023
1 parent ae5c3e5 commit ead2a01
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 1 deletion.
20 changes: 20 additions & 0 deletions platform/files.go
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,26 @@ type RunImageForRebase struct {
Mirrors []string `toml:"mirrors,omitempty" json:"mirrors,omitempty"`
}

func (r *RunImageForRebase) Contains(ref string) bool {
ref = parseMaybe(ref)
if parseMaybe(r.Image) == ref {
return true
}
for _, m := range r.Mirrors {
if parseMaybe(m) == ref {
return true
}
}
return false
}

func parseMaybe(ref string) string {
if nameRef, err := name.ParseReference(ref); err == nil {
return nameRef.Context().Name()
}
return ref
}

func (r *RunImageForRebase) ToStackMetadata() StackMetadata {
return StackMetadata{
RunImage: RunImageForExport{
Expand Down
10 changes: 10 additions & 0 deletions rebaser.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,16 @@ func (r *Rebaser) Rebase(workingImage imgutil.Image, newBaseImage imgutil.Image,
}
origMetadata.RunImage.Reference = identifier.String()

if r.PlatformAPI.AtLeast("0.12") {
// update stack and runImage if needed
if !origMetadata.RunImage.Contains(newBaseImage.Name()) {
origMetadata.RunImage.Image = newBaseImage.Name()
origMetadata.RunImage.Mirrors = []string{}
newStackMD := origMetadata.RunImage.ToStackMetadata()
origMetadata.Stack = &newStackMD
}
}

data, err := json.Marshal(origMetadata)
if err != nil {
return RebaseReport{}, errors.Wrap(err, "marshall metadata")
Expand Down
115 changes: 114 additions & 1 deletion rebaser_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package lifecycle_test

import (
"encoding/json"
"math/rand"
"testing"
"time"
Expand Down Expand Up @@ -129,6 +130,117 @@ func testRebaser(t *testing.T, when spec.G, it spec.S) {
h.AssertEq(t, md.App, []interface{}{map[string]interface{}{"sha": "123456"}})
})

when("new base image has no run image metadata", func() {
it.Before(func() {
lifecycleMD := platform.LayersMetadata{
RunImage: platform.RunImageForRebase{
TopLayer: "some-top-layer",
Reference: "some-run-image-digest-reference",
Image: "some-run-image-tag-reference",
Mirrors: []string{"some-run-image-mirror"},
},
Stack: &platform.StackMetadata{RunImage: platform.RunImageForExport{
Image: "some-run-image-tag-reference",
Mirrors: []string{"some-run-image-mirror"},
}},
}
label, err := json.Marshal(lifecycleMD)
h.AssertNil(t, err)
h.AssertNil(t, fakeAppImage.SetLabel(platform.LayerMetadataLabel, string(label)))
})

when("platform API < 0.12", func() {
it.Before(func() {
rebaser.PlatformAPI = api.MustParse("0.11")
})

it("preserves the existing metadata", func() {
_, err := rebaser.Rebase(fakeAppImage, fakeNewBaseImage, fakeAppImage.Name(), additionalNames)
h.AssertNil(t, err)

h.AssertNil(t, image.DecodeLabel(fakeAppImage, platform.LayerMetadataLabel, &md))
h.AssertEq(t, md.RunImage.TopLayer, "new-top-layer-sha")
h.AssertEq(t, md.RunImage.Reference, "new-run-id")
h.AssertEq(t, md.RunImage.Image, "some-run-image-tag-reference")
h.AssertEq(t, md.RunImage.Mirrors, []string{"some-run-image-mirror"})
h.AssertEq(t, md.Stack.RunImage.Image, "some-run-image-tag-reference")
h.AssertEq(t, md.Stack.RunImage.Mirrors, []string{"some-run-image-mirror"})
})
})

when("platform API >= 0.12", func() {
it.Before(func() {
rebaser.PlatformAPI = api.MustParse("0.12")
})

it("overrides the existing metadata", func() {
_, err := rebaser.Rebase(fakeAppImage, fakeNewBaseImage, fakeAppImage.Name(), additionalNames)
h.AssertNil(t, err)

h.AssertNil(t, image.DecodeLabel(fakeAppImage, platform.LayerMetadataLabel, &md))
var empty []string
h.AssertEq(t, md.RunImage.TopLayer, "new-top-layer-sha")
h.AssertEq(t, md.RunImage.Reference, "new-run-id")
h.AssertEq(t, md.RunImage.Image, "some-repo/new-base-image")
h.AssertEq(t, md.RunImage.Mirrors, empty)
h.AssertEq(t, md.Stack.RunImage.Image, "some-repo/new-base-image")
h.AssertEq(t, md.Stack.RunImage.Mirrors, empty)
})

when("new base image is an existing mirror", func() {
it.Before(func() {
fakeNewBaseImage = fakes.NewImage(
"some-run-image-mirror",
"new-top-layer-sha",
local.IDIdentifier{
ImageID: "new-run-id",
},
)
h.AssertNil(t, fakeNewBaseImage.SetLabel(platform.StackIDLabel, "io.buildpacks.stacks.bionic"))
})

it("preserves the existing metadata", func() {
_, err := rebaser.Rebase(fakeAppImage, fakeNewBaseImage, fakeAppImage.Name(), additionalNames)
h.AssertNil(t, err)

h.AssertNil(t, image.DecodeLabel(fakeAppImage, platform.LayerMetadataLabel, &md))
h.AssertEq(t, md.RunImage.TopLayer, "new-top-layer-sha")
h.AssertEq(t, md.RunImage.Reference, "new-run-id")
h.AssertEq(t, md.RunImage.Image, "some-run-image-tag-reference")
h.AssertEq(t, md.RunImage.Mirrors, []string{"some-run-image-mirror"})
h.AssertEq(t, md.Stack.RunImage.Image, "some-run-image-tag-reference")
h.AssertEq(t, md.Stack.RunImage.Mirrors, []string{"some-run-image-mirror"})
})
})

when("reference includes docker registry", func() {
it.Before(func() {
fakeNewBaseImage = fakes.NewImage(
"index.docker.io/some-run-image-mirror",
"new-top-layer-sha",
local.IDIdentifier{
ImageID: "new-run-id",
},
)
h.AssertNil(t, fakeNewBaseImage.SetLabel(platform.StackIDLabel, "io.buildpacks.stacks.bionic"))
})

it("still matches", func() {
_, err := rebaser.Rebase(fakeAppImage, fakeNewBaseImage, fakeAppImage.Name(), additionalNames)
h.AssertNil(t, err)

h.AssertNil(t, image.DecodeLabel(fakeAppImage, platform.LayerMetadataLabel, &md))
h.AssertEq(t, md.RunImage.TopLayer, "new-top-layer-sha")
h.AssertEq(t, md.RunImage.Reference, "new-run-id")
h.AssertEq(t, md.RunImage.Image, "some-run-image-tag-reference")
h.AssertEq(t, md.RunImage.Mirrors, []string{"some-run-image-mirror"})
h.AssertEq(t, md.Stack.RunImage.Image, "some-run-image-tag-reference")
h.AssertEq(t, md.Stack.RunImage.Mirrors, []string{"some-run-image-mirror"})
})
})
})
})

when("image has io.buildpacks.stack.* labels", func() {
var tests = []struct {
label string
Expand Down Expand Up @@ -544,8 +656,9 @@ func testRebaser(t *testing.T, when spec.G, it spec.S) {
})

when("outputImageRef is different than workingImage name", func() {
var outputImageRef = "fizz"

it("saves using outputImageRef, not the app image name", func() {
outputImageRef := "fizz"
_, err := rebaser.Rebase(fakeAppImage, fakeNewBaseImage, outputImageRef, additionalNames)
h.AssertNil(t, err)
h.AssertContains(t, fakeAppImage.SavedNames(), append(additionalNames, outputImageRef)...)
Expand Down

0 comments on commit ead2a01

Please sign in to comment.