Support force-building metadata layers into snapshot (#1731)

* feat: add support for forcing build metadata

* Chore: Added snapshot forceBuildMetadata flag tests.
This commit is contained in:
Rhianna 2021-10-18 13:43:51 -05:00 committed by GitHub
parent 7e3954ac73
commit b525d1e27b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 56 additions and 10 deletions

View File

@ -216,6 +216,7 @@ func addKanikoOptionsFlags() {
RootCmd.PersistentFlags().Var(&opts.Git, "git", "Branch to clone if build context is a git repository") RootCmd.PersistentFlags().Var(&opts.Git, "git", "Branch to clone if build context is a git repository")
RootCmd.PersistentFlags().BoolVarP(&opts.CacheCopyLayers, "cache-copy-layers", "", false, "Caches copy layers") RootCmd.PersistentFlags().BoolVarP(&opts.CacheCopyLayers, "cache-copy-layers", "", false, "Caches copy layers")
RootCmd.PersistentFlags().VarP(&opts.IgnorePaths, "ignore-path", "", "Ignore these paths when taking a snapshot. Set it repeatedly for multiple paths.") RootCmd.PersistentFlags().VarP(&opts.IgnorePaths, "ignore-path", "", "Ignore these paths when taking a snapshot. Set it repeatedly for multiple paths.")
RootCmd.PersistentFlags().BoolVarP(&opts.ForceBuildMetadata, "force-build-metadata", "", false, "Force add metadata layers to build image")
} }
// addHiddenFlags marks certain flags as hidden from the executor help text // addHiddenFlags marks certain flags as hidden from the executor help text

View File

@ -74,6 +74,7 @@ type KanikoOptions struct {
Git KanikoGitOptions Git KanikoGitOptions
IgnorePaths multiArg IgnorePaths multiArg
ImageFSExtractRetry int ImageFSExtractRetry int
ForceBuildMetadata bool
} }
type KanikoGitOptions struct { type KanikoGitOptions struct {

View File

@ -60,7 +60,7 @@ type cachePusher func(*config.KanikoOptions, string, string, string) error
type snapShotter interface { type snapShotter interface {
Init() error Init() error
TakeSnapshotFS() (string, error) TakeSnapshotFS() (string, error)
TakeSnapshot([]string, bool) (string, error) TakeSnapshot([]string, bool, bool) (string, error)
} }
// stageBuilder contains all fields necessary to build one stage of a Dockerfile // stageBuilder contains all fields necessary to build one stage of a Dockerfile
@ -375,7 +375,8 @@ func (s *stageBuilder) build() error {
files = command.FilesToSnapshot() files = command.FilesToSnapshot()
timing.DefaultRun.Stop(t) timing.DefaultRun.Stop(t)
if !s.shouldTakeSnapshot(index, command.MetadataOnly()) { if !s.shouldTakeSnapshot(index, command.MetadataOnly()) && !s.opts.ForceBuildMetadata{
logrus.Debugf("build: skipping snapshot for [%v]" , command.String())
continue continue
} }
if isCacheCommand { if isCacheCommand {
@ -429,7 +430,7 @@ func (s *stageBuilder) takeSnapshot(files []string, shdDelete bool) (string, err
} else { } else {
// Volumes are very weird. They get snapshotted in the next command. // Volumes are very weird. They get snapshotted in the next command.
files = append(files, util.Volumes()...) files = append(files, util.Volumes()...)
snapshot, err = s.snapshotter.TakeSnapshot(files, shdDelete) snapshot, err = s.snapshotter.TakeSnapshot(files, shdDelete, s.opts.ForceBuildMetadata)
} }
timing.DefaultRun.Stop(t) timing.DefaultRun.Stop(t)
return snapshot, err return snapshot, err
@ -473,7 +474,7 @@ func (s *stageBuilder) saveSnapshotToLayer(tarPath string) (v1.Layer, error) {
if err != nil { if err != nil {
return nil, errors.Wrap(err, "tar file path does not exist") return nil, errors.Wrap(err, "tar file path does not exist")
} }
if fi.Size() <= emptyTarSize { if fi.Size() <= emptyTarSize && !s.opts.ForceBuildMetadata{
logrus.Info("No files were changed, appending empty layer to config. No layer added to image.") logrus.Info("No files were changed, appending empty layer to config. No layer added to image.")
return nil, nil return nil, nil
} }

View File

@ -35,6 +35,9 @@ import (
// For testing // For testing
var snapshotPathPrefix = "" var snapshotPathPrefix = ""
// for user layer flag
var addUserLayer bool = true
// Snapshotter holds the root directory from which to take snapshots, and a list of snapshots taken // Snapshotter holds the root directory from which to take snapshots, and a list of snapshots taken
type Snapshotter struct { type Snapshotter struct {
l *LayeredMap l *LayeredMap
@ -60,7 +63,7 @@ func (s *Snapshotter) Key() (string, error) {
// TakeSnapshot takes a snapshot of the specified files, avoiding directories in the ignorelist, and creates // TakeSnapshot takes a snapshot of the specified files, avoiding directories in the ignorelist, and creates
// a tarball of the changed files. Return contents of the tarball, and whether or not any files were changed // a tarball of the changed files. Return contents of the tarball, and whether or not any files were changed
func (s *Snapshotter) TakeSnapshot(files []string, shdCheckDelete bool) (string, error) { func (s *Snapshotter) TakeSnapshot(files []string, shdCheckDelete bool, forceBuildMetadata bool) (string, error) {
f, err := ioutil.TempFile(config.KanikoDir, "") f, err := ioutil.TempFile(config.KanikoDir, "")
if err != nil { if err != nil {
return "", err return "", err
@ -68,7 +71,7 @@ func (s *Snapshotter) TakeSnapshot(files []string, shdCheckDelete bool) (string,
defer f.Close() defer f.Close()
s.l.Snapshot() s.l.Snapshot()
if len(files) == 0 { if len(files) == 0 && !forceBuildMetadata {
logrus.Info("No files changed in this command, skipping snapshotting.") logrus.Info("No files changed in this command, skipping snapshotting.")
return "", nil return "", nil
} }

View File

@ -214,7 +214,7 @@ func TestSnapshotFiles(t *testing.T) {
filesToSnapshot := []string{ filesToSnapshot := []string{
filepath.Join(testDir, "foo"), filepath.Join(testDir, "foo"),
} }
tarPath, err := snapshotter.TakeSnapshot(filesToSnapshot, false) tarPath, err := snapshotter.TakeSnapshot(filesToSnapshot, false, false)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -361,7 +361,7 @@ func TestSnasphotPreservesFileOrder(t *testing.T) {
} }
// Take a snapshot // Take a snapshot
tarPath, err := snapshotter.TakeSnapshot(filesToSnapshot, false) tarPath, err := snapshotter.TakeSnapshot(filesToSnapshot, false, false)
if err != nil { if err != nil {
t.Fatalf("Error taking snapshot of fs: %s", err) t.Fatalf("Error taking snapshot of fs: %s", err)
@ -391,6 +391,46 @@ func TestSnasphotPreservesFileOrder(t *testing.T) {
} }
} }
func TestSnapshotWithForceBuildMetadataSet(t *testing.T) {
_, snapshotter, cleanup, err := setUpTest()
defer cleanup()
if err != nil {
t.Fatal(err)
}
filesToSnapshot := []string{}
// snapshot should be taken regardless, if forceBuildMetadata flag is set
filename, err := snapshotter.TakeSnapshot(filesToSnapshot, false, true)
if err != nil {
t.Fatalf("Error taking snapshot of fs: %s", err)
}
if filename == "" {
t.Fatalf("Filename returned from snapshot is empty.")
}
}
func TestSnapshotWithForceBuildMetadataIsNotSet(t *testing.T) {
_, snapshotter, cleanup, err := setUpTest()
defer cleanup()
if err != nil {
t.Fatal(err)
}
filesToSnapshot := []string{}
// snapshot should not be taken
filename, err := snapshotter.TakeSnapshot(filesToSnapshot, false, false)
if err != nil {
t.Fatalf("Error taking snapshot of fs: %s", err)
}
if filename != "" {
t.Fatalf("Filename returned is expected to be empty.")
}
}
func TestSnasphotPreservesWhiteoutOrder(t *testing.T) { func TestSnasphotPreservesWhiteoutOrder(t *testing.T) {
newFiles := map[string]string{ newFiles := map[string]string{
"foo": "newbaz1", "foo": "newbaz1",
@ -430,7 +470,7 @@ func TestSnasphotPreservesWhiteoutOrder(t *testing.T) {
} }
// Take a snapshot // Take a snapshot
_, err = snapshotter.TakeSnapshot(filesToSnapshot, false) _, err = snapshotter.TakeSnapshot(filesToSnapshot, false, false)
if err != nil { if err != nil {
t.Fatalf("Error taking snapshot of fs: %s", err) t.Fatalf("Error taking snapshot of fs: %s", err)
} }
@ -444,7 +484,7 @@ func TestSnasphotPreservesWhiteoutOrder(t *testing.T) {
} }
// Take a snapshot again // Take a snapshot again
tarPath, err := snapshotter.TakeSnapshot(filesToSnapshot, true) tarPath, err := snapshotter.TakeSnapshot(filesToSnapshot, true, false)
if err != nil { if err != nil {
t.Fatalf("Error taking snapshot of fs: %s", err) t.Fatalf("Error taking snapshot of fs: %s", err)
} }