Skip to content

Commit

Permalink
Restore cached launch layers not found in appLayers (#1346)
Browse files Browse the repository at this point in the history
* Restore cached launch layers not found in appLayers

Co-authored-by: Ralf Pannemans <ralf.pannemans@sap.com>
Signed-off-by: Pavel Busko <pavel.busko@sap.com>

* add platform api guard

Signed-off-by: Pavel Busko <pavel.busko@sap.com>

---------

Signed-off-by: Pavel Busko <pavel.busko@sap.com>
Co-authored-by: Ralf Pannemans <ralf.pannemans@sap.com>
  • Loading branch information
pbusko and c0d1ngm0nk3y committed Jul 3, 2024
1 parent a02be03 commit f2a3bd7
Show file tree
Hide file tree
Showing 7 changed files with 52 additions and 25 deletions.
2 changes: 1 addition & 1 deletion api/apis.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ var (
// Platform is a pair of lists of Platform API versions:
// 1. All supported versions (including deprecated versions)
// 2. The versions that are deprecated
Platform = newApisMustParse([]string{"0.7", "0.8", "0.9", "0.10", "0.11", "0.12", "0.13"}, []string{})
Platform = newApisMustParse([]string{"0.7", "0.8", "0.9", "0.10", "0.11", "0.12", "0.13", "0.14"}, []string{})
// Buildpack is a pair of lists of Buildpack API versions:
// 1. All supported versions (including deprecated versions)
// 2. The versions that are deprecated
Expand Down
2 changes: 1 addition & 1 deletion cmd/lifecycle/restorer.go
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ func (r *restoreCmd) restore(layerMetadata files.LayersMetadata, group buildpack
Buildpacks: group.Group,
Logger: cmd.DefaultLogger,
PlatformAPI: r.PlatformAPI,
LayerMetadataRestorer: layer.NewDefaultMetadataRestorer(r.LayersDir, r.SkipLayers, cmd.DefaultLogger),
LayerMetadataRestorer: layer.NewDefaultMetadataRestorer(r.LayersDir, r.SkipLayers, cmd.DefaultLogger, r.PlatformAPI),
LayersMetadata: layerMetadata,
SBOMRestorer: layer.NewSBOMRestorer(layer.SBOMRestorerOpts{
LayersDir: r.LayersDir,
Expand Down
26 changes: 16 additions & 10 deletions internal/layer/metadata_restorer.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

"github.com/pkg/errors"

"github.com/buildpacks/lifecycle/api"
"github.com/buildpacks/lifecycle/buildpack"
"github.com/buildpacks/lifecycle/internal/encoding"
"github.com/buildpacks/lifecycle/launch"
Expand All @@ -24,18 +25,21 @@ type MetadataRestorer interface {
Restore(buildpacks []buildpack.GroupElement, appMeta files.LayersMetadata, cacheMeta platform.CacheMetadata, layerSHAStore SHAStore) error
}

func NewDefaultMetadataRestorer(layersDir string, skipLayers bool, logger log.Logger) *DefaultMetadataRestorer {
// NewDefaultMetadataRestorer returns an instance of the DefaultMetadataRestorer struct
func NewDefaultMetadataRestorer(layersDir string, skipLayers bool, logger log.Logger, platformAPI *api.Version) *DefaultMetadataRestorer {
return &DefaultMetadataRestorer{
Logger: logger,
LayersDir: layersDir,
SkipLayers: skipLayers,
Logger: logger,
LayersDir: layersDir,
SkipLayers: skipLayers,
PlatformAPI: platformAPI,
}
}

type DefaultMetadataRestorer struct {
LayersDir string
SkipLayers bool
Logger log.Logger
LayersDir string
SkipLayers bool
Logger log.Logger
PlatformAPI *api.Version
}

func (r *DefaultMetadataRestorer) Restore(buildpacks []buildpack.GroupElement, appMeta files.LayersMetadata, cacheMeta platform.CacheMetadata, layerSHAStore SHAStore) error {
Expand Down Expand Up @@ -113,10 +117,12 @@ func (r *DefaultMetadataRestorer) restoreLayerMetadata(layerSHAStore SHAStore, a
r.Logger.Debugf("Not restoring %q from cache, marked as cache=false", identifier)
continue
}
// If launch=true, the metadata was restored from the app image or the layer is stale.
// If launch=true, the metadata was restored from the appLayers if present.
if layer.Launch {
r.Logger.Debugf("Not restoring %q from cache, marked as launch=true", identifier)
continue
if _, ok := appLayers[layerName]; ok || r.PlatformAPI.LessThan("0.14") {
r.Logger.Debugf("Not restoring %q from cache, marked as launch=true", identifier)
continue
}
}
r.Logger.Infof("Restoring metadata for %q from cache", identifier)
if err := r.writeLayerMetadata(layerSHAStore, buildpackDir, layerName, layer, bp.ID); err != nil {
Expand Down
41 changes: 31 additions & 10 deletions internal/layer/metadata_restorer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func testLayerMetadataRestorer(t *testing.T, when spec.G, it spec.S) {
layerDir, err = os.MkdirTemp("", "lifecycle-layer-dir")
h.AssertNil(t, err)
logger = log.Logger{Handler: &discard.Handler{}}
layerMetadataRestorer = layer.NewDefaultMetadataRestorer(layerDir, skipLayers, &logger)
layerMetadataRestorer = layer.NewDefaultMetadataRestorer(layerDir, skipLayers, &logger, api.Platform.Latest())
layerSHAStore = layer.NewSHAStore()
})

Expand Down Expand Up @@ -136,13 +136,42 @@ func testLayerMetadataRestorer(t *testing.T, when spec.G, it spec.S) {
{"no.cache.buildpack/some-layer.toml", "[metadata]\n some-layer-key = \"some-layer-value\""},
// Cache-image-only layers.
{"metadata.buildpack/cache.toml", "[metadata]\n cache-key = \"cache-value\""},
// Cached launch layers not in app
{"metadata.buildpack/launch-cache-not-in-app.toml", "[metadata]\n cache-only-key = \"cache-only-value\"\n launch-cache-key = \"cache-specific-value\""},
} {
got := h.MustReadFile(t, filepath.Join(layerDir, data.name))
h.AssertStringContains(t, string(got), data.want)
h.AssertStringDoesNotContain(t, string(got), unsetFlags) // The [types] table shouldn't exist. The build, cache and launch flags are set to false.
}
})

when("platformAPI is less than 0.14", func() {
it.Before(func() {
layerMetadataRestorer = layer.NewDefaultMetadataRestorer(layerDir, skipLayers, &logger, api.MustParse("0.13"))
})

it("ignores launch-cache-not-in-app", func() {
err := layerMetadataRestorer.Restore(buildpacks, layersMetadata, cacheMetadata, layerSHAStore)
h.AssertNil(t, err)

h.AssertPathDoesNotExist(t, filepath.Join(layerDir, "metadata.buildpack/launch-cache-not-in-app.toml"))
unsetFlags := "[types]"
for _, data := range []struct{ name, want string }{
// App layers.
{"metadata.buildpack/launch.toml", "[metadata]\n launch-key = \"launch-value\""},
{"metadata.buildpack/launch-build-cache.toml", "[metadata]\n launch-build-cache-key = \"launch-build-cache-value\""},
{"metadata.buildpack/launch-cache.toml", "[metadata]\n launch-cache-key = \"launch-cache-value\""},
{"no.cache.buildpack/some-layer.toml", "[metadata]\n some-layer-key = \"some-layer-value\""},
// Cache-image-only layers.
{"metadata.buildpack/cache.toml", "[metadata]\n cache-key = \"cache-value\""},
} {
got := h.MustReadFile(t, filepath.Join(layerDir, data.name))
h.AssertStringContains(t, string(got), data.want)
h.AssertStringDoesNotContain(t, string(got), unsetFlags) // The [types] table shouldn't exist. The build, cache and launch flags are set to false.
}
})
})

it("restores layer metadata without the launch, build and cache flags", func() {
buildpacks = []buildpack.GroupElement{
{ID: "metadata.buildpack", API: api.Buildpack.Latest().String()},
Expand Down Expand Up @@ -186,14 +215,6 @@ func testLayerMetadataRestorer(t *testing.T, when spec.G, it spec.S) {
h.AssertPathDoesNotExist(t, filepath.Join(layerDir, "no.group.buildpack"))
})

it("does not restore launch=true layer metadata", func() {
err := layerMetadataRestorer.Restore(buildpacks, layersMetadata, cacheMetadata, layerSHAStore)
h.AssertNil(t, err)

h.AssertPathDoesNotExist(t, filepath.Join(layerDir, "metadata.buildpack", "launch-cache-not-in-app.toml"))
h.AssertPathDoesNotExist(t, filepath.Join(layerDir, "metadata.buildpack", "launch-cache-not-in-app.sha"))
})

it("does not restore cache=false layer metadata", func() {
err := layerMetadataRestorer.Restore(buildpacks, layersMetadata, cacheMetadata, layerSHAStore)
h.AssertNil(t, err)
Expand Down Expand Up @@ -299,7 +320,7 @@ func testLayerMetadataRestorer(t *testing.T, when spec.G, it spec.S) {
when("skip layers is true", func() {
it.Before(func() {
skipLayers = true
layerMetadataRestorer = layer.NewDefaultMetadataRestorer(layerDir, skipLayers, &logger)
layerMetadataRestorer = layer.NewDefaultMetadataRestorer(layerDir, skipLayers, &logger, api.Platform.Latest())
})

it("does not write buildpack layer metadata", func() {
Expand Down
2 changes: 1 addition & 1 deletion internal/layer/testdata/cache_metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
"launch": true,
"sha": "launch-cache-old-sha"
},
"launch-cache-not-in-app": {
"launch-cache-not-in-app": {
"cache": true,
"data": {
"launch-cache-key": "cache-specific-value",
Expand Down
2 changes: 1 addition & 1 deletion phase/restorer.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func (r *Restorer) Restore(cache Cache) error {
}

if r.LayerMetadataRestorer == nil {
r.LayerMetadataRestorer = layer.NewDefaultMetadataRestorer(r.LayersDir, false, r.Logger)
r.LayerMetadataRestorer = layer.NewDefaultMetadataRestorer(r.LayersDir, false, r.Logger, r.PlatformAPI)
}

if r.SBOMRestorer == nil {
Expand Down
2 changes: 1 addition & 1 deletion phase/restorer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ func testRestorer(buildpackAPI, platformAPI string) func(t *testing.T, when spec
{ID: "buildpack.id", API: buildpackAPI},
{ID: "escaped/buildpack/id", API: buildpackAPI},
},
LayerMetadataRestorer: layer.NewDefaultMetadataRestorer(layersDir, skipLayers, &logger),
LayerMetadataRestorer: layer.NewDefaultMetadataRestorer(layersDir, skipLayers, &logger, api.Platform.Latest()),
SBOMRestorer: sbomRestorer,
PlatformAPI: api.MustParse(platformAPI),
}
Expand Down

0 comments on commit f2a3bd7

Please sign in to comment.