mirror of
https://github.com/GoogleContainerTools/kaniko
synced 2026-10-18 06:31:59 +02:00
add caching copy layers back (#1518)
* add caching copy layers back * fix test * lint * fix test - 2 * Add integration test * fix lint
This commit is contained in:
@@ -127,7 +127,7 @@ func newStageBuilder(opts *config.KanikoOptions, stage config.KanikoStage, cross
|
||||
}
|
||||
|
||||
for _, cmd := range s.stage.Commands {
|
||||
command, err := commands.GetCommand(cmd, fileContext, opts.RunV2)
|
||||
command, err := commands.GetCommand(cmd, fileContext, opts.RunV2, opts.CacheCopyLayers)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -184,6 +184,7 @@ func (s *stageBuilder) populateCompositeKey(command fmt.Stringer, files []string
|
||||
compositeKey.AddKey(resolvedCmd)
|
||||
switch v := command.(type) {
|
||||
case *commands.CopyCommand:
|
||||
case *commands.CachingCopyCommand:
|
||||
compositeKey = s.populateCopyCmdCompositeKey(command, v.From(), compositeKey)
|
||||
}
|
||||
|
||||
|
||||
+151
-9
@@ -795,6 +795,135 @@ func Test_stageBuilder_build(t *testing.T) {
|
||||
retrieve: true,
|
||||
},
|
||||
},
|
||||
func() testcase {
|
||||
dir, filenames := tempDirAndFile(t)
|
||||
filename := filenames[0]
|
||||
filepath := filepath.Join(dir, filename)
|
||||
|
||||
tarContent := generateTar(t, dir, filename)
|
||||
|
||||
ch := NewCompositeCache("", fmt.Sprintf("COPY %s foo.txt", filename))
|
||||
ch.AddPath(filepath, util.FileContext{})
|
||||
|
||||
hash, err := ch.Hash()
|
||||
if err != nil {
|
||||
t.Errorf("couldn't create hash %v", err)
|
||||
}
|
||||
copyCommandCacheKey := hash
|
||||
dockerFile := fmt.Sprintf(`
|
||||
FROM ubuntu:16.04
|
||||
COPY %s foo.txt
|
||||
`, filename)
|
||||
f, _ := ioutil.TempFile("", "")
|
||||
ioutil.WriteFile(f.Name(), []byte(dockerFile), 0755)
|
||||
opts := &config.KanikoOptions{
|
||||
DockerfilePath: f.Name(),
|
||||
Cache: true,
|
||||
CacheCopyLayers: true,
|
||||
}
|
||||
|
||||
testStages, metaArgs, err := dockerfile.ParseStages(opts)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to parse test dockerfile to stages: %s", err)
|
||||
}
|
||||
|
||||
kanikoStages, err := dockerfile.MakeKanikoStages(opts, testStages, metaArgs)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to parse stages to Kaniko Stages: %s", err)
|
||||
}
|
||||
_ = ResolveCrossStageInstructions(kanikoStages)
|
||||
stage := kanikoStages[0]
|
||||
|
||||
cmds := stage.Commands
|
||||
|
||||
return testcase{
|
||||
description: "copy command cache enabled and key in cache",
|
||||
opts: opts,
|
||||
image: fakeImage{
|
||||
ImageLayers: []v1.Layer{
|
||||
fakeLayer{
|
||||
TarContent: tarContent,
|
||||
},
|
||||
},
|
||||
},
|
||||
layerCache: &fakeLayerCache{
|
||||
retrieve: true,
|
||||
img: fakeImage{
|
||||
ImageLayers: []v1.Layer{
|
||||
fakeLayer{
|
||||
TarContent: tarContent,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
rootDir: dir,
|
||||
expectedCacheKeys: []string{copyCommandCacheKey},
|
||||
// CachingCopyCommand is not pushed to the cache
|
||||
pushedCacheKeys: []string{},
|
||||
commands: getCommands(util.FileContext{Root: dir}, cmds, true),
|
||||
fileName: filename,
|
||||
}
|
||||
}(),
|
||||
func() testcase {
|
||||
dir, filenames := tempDirAndFile(t)
|
||||
filename := filenames[0]
|
||||
tarContent := []byte{}
|
||||
destDir, err := ioutil.TempDir("", "baz")
|
||||
if err != nil {
|
||||
t.Errorf("could not create temp dir %v", err)
|
||||
}
|
||||
filePath := filepath.Join(dir, filename)
|
||||
ch := NewCompositeCache("", fmt.Sprintf("COPY %s foo.txt", filename))
|
||||
ch.AddPath(filePath, util.FileContext{})
|
||||
|
||||
hash, err := ch.Hash()
|
||||
if err != nil {
|
||||
t.Errorf("couldn't create hash %v", err)
|
||||
}
|
||||
dockerFile := fmt.Sprintf(`
|
||||
FROM ubuntu:16.04
|
||||
COPY %s foo.txt
|
||||
`, filename)
|
||||
f, _ := ioutil.TempFile("", "")
|
||||
ioutil.WriteFile(f.Name(), []byte(dockerFile), 0755)
|
||||
opts := &config.KanikoOptions{
|
||||
DockerfilePath: f.Name(),
|
||||
Cache: true,
|
||||
CacheCopyLayers: true,
|
||||
}
|
||||
|
||||
testStages, metaArgs, err := dockerfile.ParseStages(opts)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to parse test dockerfile to stages: %s", err)
|
||||
}
|
||||
|
||||
kanikoStages, err := dockerfile.MakeKanikoStages(opts, testStages, metaArgs)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to parse stages to Kaniko Stages: %s", err)
|
||||
}
|
||||
_ = ResolveCrossStageInstructions(kanikoStages)
|
||||
stage := kanikoStages[0]
|
||||
|
||||
cmds := stage.Commands
|
||||
return testcase{
|
||||
description: "copy command cache enabled and key is not in cache",
|
||||
opts: opts,
|
||||
config: &v1.ConfigFile{Config: v1.Config{WorkingDir: destDir}},
|
||||
layerCache: &fakeLayerCache{},
|
||||
image: fakeImage{
|
||||
ImageLayers: []v1.Layer{
|
||||
fakeLayer{
|
||||
TarContent: tarContent,
|
||||
},
|
||||
},
|
||||
},
|
||||
rootDir: dir,
|
||||
expectedCacheKeys: []string{hash},
|
||||
pushedCacheKeys: []string{hash},
|
||||
commands: getCommands(util.FileContext{Root: dir}, cmds, true),
|
||||
fileName: filename,
|
||||
}
|
||||
}(),
|
||||
func() testcase {
|
||||
dir, filenames := tempDirAndFile(t)
|
||||
filename := filenames[0]
|
||||
@@ -804,14 +933,26 @@ func Test_stageBuilder_build(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Errorf("could not create temp dir %v", err)
|
||||
}
|
||||
filePath := filepath.Join(dir, filename)
|
||||
|
||||
ch := NewCompositeCache("", fmt.Sprintf("RUN foobar"))
|
||||
ch := NewCompositeCache("", "RUN foobar")
|
||||
|
||||
hash1, err := ch.Hash()
|
||||
if err != nil {
|
||||
t.Errorf("couldn't create hash %v", err)
|
||||
}
|
||||
|
||||
ch.AddKey(fmt.Sprintf("COPY %s bar.txt", filename))
|
||||
ch.AddPath(filePath, util.FileContext{})
|
||||
|
||||
hash2, err := ch.Hash()
|
||||
if err != nil {
|
||||
t.Errorf("couldn't create hash %v", err)
|
||||
}
|
||||
ch = NewCompositeCache("", fmt.Sprintf("COPY %s foo.txt", filename))
|
||||
ch.AddKey(fmt.Sprintf("COPY %s bar.txt", filename))
|
||||
ch.AddPath(filePath, util.FileContext{})
|
||||
|
||||
image := fakeImage{
|
||||
ImageLayers: []v1.Layer{
|
||||
fakeLayer{
|
||||
@@ -845,8 +986,8 @@ COPY %s bar.txt
|
||||
|
||||
cmds := stage.Commands
|
||||
return testcase{
|
||||
description: "cached run command followed by copy command results in consistent read and write hashes",
|
||||
opts: &config.KanikoOptions{Cache: true},
|
||||
description: "cached run command followed by uncached copy command results in consistent read and write hashes",
|
||||
opts: &config.KanikoOptions{Cache: true, CacheCopyLayers: true},
|
||||
rootDir: dir,
|
||||
config: &v1.ConfigFile{Config: v1.Config{WorkingDir: destDir}},
|
||||
layerCache: &fakeLayerCache{
|
||||
@@ -855,9 +996,9 @@ COPY %s bar.txt
|
||||
},
|
||||
image: image,
|
||||
// hash1 is the read cachekey for the first layer
|
||||
expectedCacheKeys: []string{hash1},
|
||||
pushedCacheKeys: []string{},
|
||||
commands: getCommands(util.FileContext{Root: dir}, cmds),
|
||||
expectedCacheKeys: []string{hash1, hash2},
|
||||
pushedCacheKeys: []string{hash2},
|
||||
commands: getCommands(util.FileContext{Root: dir}, cmds, true),
|
||||
}
|
||||
}(),
|
||||
func() testcase {
|
||||
@@ -933,7 +1074,7 @@ RUN foobar
|
||||
image: image,
|
||||
expectedCacheKeys: []string{runHash},
|
||||
pushedCacheKeys: []string{},
|
||||
commands: getCommands(util.FileContext{Root: dir}, cmds),
|
||||
commands: getCommands(util.FileContext{Root: dir}, cmds, false),
|
||||
}
|
||||
}(),
|
||||
func() testcase {
|
||||
@@ -1107,7 +1248,7 @@ RUN foobar
|
||||
if err != nil {
|
||||
t.Errorf("Expected error to be nil but was %v", err)
|
||||
}
|
||||
|
||||
fmt.Println(lc.receivedKeys)
|
||||
assertCacheKeys(t, tc.expectedCacheKeys, lc.receivedKeys, "receive")
|
||||
assertCacheKeys(t, tc.pushedCacheKeys, keys, "push")
|
||||
|
||||
@@ -1140,13 +1281,14 @@ func assertCacheKeys(t *testing.T, expectedCacheKeys, actualCacheKeys []string,
|
||||
}
|
||||
}
|
||||
|
||||
func getCommands(fileContext util.FileContext, cmds []instructions.Command) []commands.DockerCommand {
|
||||
func getCommands(fileContext util.FileContext, cmds []instructions.Command, cacheCopy bool) []commands.DockerCommand {
|
||||
outCommands := make([]commands.DockerCommand, 0)
|
||||
for _, c := range cmds {
|
||||
cmd, err := commands.GetCommand(
|
||||
c,
|
||||
fileContext,
|
||||
false,
|
||||
cacheCopy,
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
||||
@@ -252,6 +252,7 @@ func DoPush(image v1.Image, opts *config.KanikoOptions) error {
|
||||
}
|
||||
}
|
||||
timing.DefaultRun.Stop(t)
|
||||
logrus.Infof("Pushed images to %d destinations", len(destRefs))
|
||||
return writeImageOutputs(image, destRefs)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user