Merge branch 'master' into snapshot-directories

This commit is contained in:
Gilbert Gilb's 2020-03-31 14:25:04 +02:00
commit fd8a2d6dd8
15 changed files with 379 additions and 80 deletions

View File

@ -17,7 +17,6 @@ limitations under the License.
package commands package commands
import ( import (
"github.com/GoogleContainerTools/kaniko/pkg/constants"
"github.com/GoogleContainerTools/kaniko/pkg/dockerfile" "github.com/GoogleContainerTools/kaniko/pkg/dockerfile"
v1 "github.com/google/go-containerregistry/pkg/v1" v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/moby/buildkit/frontend/dockerfile/instructions" "github.com/moby/buildkit/frontend/dockerfile/instructions"
@ -25,12 +24,6 @@ import (
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
var RootDir string
func init() {
RootDir = constants.RootDir
}
type CurrentCacheKey func() (string, error) type CurrentCacheKey func() (string, error)
type DockerCommand interface { type DockerCommand interface {

View File

@ -22,7 +22,7 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/GoogleContainerTools/kaniko/pkg/constants" kConfig "github.com/GoogleContainerTools/kaniko/pkg/config"
"github.com/moby/buildkit/frontend/dockerfile/instructions" "github.com/moby/buildkit/frontend/dockerfile/instructions"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
@ -47,7 +47,7 @@ type CopyCommand struct {
func (c *CopyCommand) ExecuteCommand(config *v1.Config, buildArgs *dockerfile.BuildArgs) error { func (c *CopyCommand) ExecuteCommand(config *v1.Config, buildArgs *dockerfile.BuildArgs) error {
// Resolve from // Resolve from
if c.cmd.From != "" { if c.cmd.From != "" {
c.buildcontext = filepath.Join(constants.KanikoDir, c.cmd.From) c.buildcontext = filepath.Join(kConfig.KanikoDir, c.cmd.From)
} }
replacementEnvs := buildArgs.ReplacementEnvs(config.Env) replacementEnvs := buildArgs.ReplacementEnvs(config.Env)
@ -74,7 +74,7 @@ func (c *CopyCommand) ExecuteCommand(config *v1.Config, buildArgs *dockerfile.Bu
} }
cwd := config.WorkingDir cwd := config.WorkingDir
if cwd == "" { if cwd == "" {
cwd = constants.RootDir cwd = kConfig.RootDir
} }
destPath, err := util.DestinationFilepath(fullPath, dest, cwd) destPath, err := util.DestinationFilepath(fullPath, dest, cwd)
@ -191,7 +191,7 @@ func (cr *CachingCopyCommand) ExecuteCommand(config *v1.Config, buildArgs *docke
cr.layer = layers[0] cr.layer = layers[0]
cr.readSuccess = true cr.readSuccess = true
cr.extractedFiles, err = util.GetFSFromLayers(RootDir, layers, util.ExtractFunc(cr.extractFn), util.IncludeWhiteout()) cr.extractedFiles, err = util.GetFSFromLayers(kConfig.RootDir, layers, util.ExtractFunc(cr.extractFn), util.IncludeWhiteout())
logrus.Debugf("extractedFiles: %s", cr.extractedFiles) logrus.Debugf("extractedFiles: %s", cr.extractedFiles)
if err != nil { if err != nil {

View File

@ -405,7 +405,6 @@ func TestCopyCommand_ExecuteCommand_Extended(t *testing.T) {
if err := os.MkdirAll(dir, 0777); err != nil { if err := os.MkdirAll(dir, 0777); err != nil {
t.Fatal(err) t.Fatal(err)
} }
file := filepath.Join(dir, "bam.txt") file := filepath.Join(dir, "bam.txt")
if err := ioutil.WriteFile(file, []byte("meow"), 0777); err != nil { if err := ioutil.WriteFile(file, []byte("meow"), 0777); err != nil {
@ -418,6 +417,7 @@ func TestCopyCommand_ExecuteCommand_Extended(t *testing.T) {
if err := os.Symlink("dam.txt", filepath.Join(dir, "sym.link")); err != nil { if err := os.Symlink("dam.txt", filepath.Join(dir, "sym.link")); err != nil {
t.Fatal(err) t.Fatal(err)
} }
return testDir, filepath.Base(dir) return testDir, filepath.Base(dir)
} }
@ -922,4 +922,42 @@ func TestCopyCommand_ExecuteCommand_Extended(t *testing.T) {
testutil.CheckNoError(t, err) testutil.CheckNoError(t, err)
} }
}) })
t.Run("copy src dir with relative symlinks in a dir", func(t *testing.T) {
testDir, srcDir := setupDirs(t)
defer os.RemoveAll(testDir)
// Make another dir inside bar with a relative symlink
dir := filepath.Join(testDir, srcDir, "another")
if err := os.MkdirAll(dir, 0777); err != nil {
t.Fatal(err)
}
os.Symlink("../bam.txt", filepath.Join(dir, "bam_relative.txt"))
dest := filepath.Join(testDir, "copy")
cmd := CopyCommand{
cmd: &instructions.CopyCommand{
SourcesAndDest: []string{srcDir, dest},
},
buildcontext: testDir,
}
cfg := &v1.Config{
Cmd: nil,
Env: []string{},
WorkingDir: testDir,
}
err := cmd.ExecuteCommand(cfg, dockerfile.NewBuildArgs([]string{}))
testutil.CheckNoError(t, err)
actual, err := ioutil.ReadDir(filepath.Join(dest, "another"))
if err != nil {
t.Fatal(err)
}
testutil.CheckDeepEqual(t, "bam_relative.txt", actual[0].Name())
linkName, err := os.Readlink(filepath.Join(dest, "another", "bam_relative.txt"))
if err != nil {
t.Fatal(err)
}
testutil.CheckDeepEqual(t, "../bam.txt", linkName)
})
} }

View File

@ -24,6 +24,7 @@ import (
"strings" "strings"
"syscall" "syscall"
kConfig "github.com/GoogleContainerTools/kaniko/pkg/config"
"github.com/GoogleContainerTools/kaniko/pkg/constants" "github.com/GoogleContainerTools/kaniko/pkg/constants"
"github.com/GoogleContainerTools/kaniko/pkg/dockerfile" "github.com/GoogleContainerTools/kaniko/pkg/dockerfile"
"github.com/GoogleContainerTools/kaniko/pkg/util" "github.com/GoogleContainerTools/kaniko/pkg/util"
@ -202,7 +203,7 @@ func (cr *CachingRunCommand) ExecuteCommand(config *v1.Config, buildArgs *docker
cr.readSuccess = true cr.readSuccess = true
cr.extractedFiles, err = util.GetFSFromLayers( cr.extractedFiles, err = util.GetFSFromLayers(
constants.RootDir, kConfig.RootDir,
layers, layers,
util.ExtractFunc(cr.extractFn), util.ExtractFunc(cr.extractFn),
util.IncludeWhiteout(), util.IncludeWhiteout(),

31
pkg/config/init.go Normal file
View File

@ -0,0 +1,31 @@
/*
Copyright 2020 Google LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package config
import (
"github.com/GoogleContainerTools/kaniko/pkg/constants"
)
var RootDir string
var KanikoDir string
var WhitelistPath string
func init() {
RootDir = constants.RootDir
KanikoDir = constants.KanikoDir
WhitelistPath = constants.WhitelistPath
}

View File

@ -98,7 +98,7 @@ func newStageBuilder(opts *config.KanikoOptions, stage config.KanikoStage, cross
return nil, err return nil, err
} }
l := snapshot.NewLayeredMap(hasher, util.CacheHasher()) l := snapshot.NewLayeredMap(hasher, util.CacheHasher())
snapshotter := snapshot.NewSnapshotter(l, constants.RootDir) snapshotter := snapshot.NewSnapshotter(l, config.RootDir)
digest, err := sourceImage.Digest() digest, err := sourceImage.Digest()
if err != nil { if err != nil {
@ -299,7 +299,7 @@ func (s *stageBuilder) build() error {
if shouldUnpack { if shouldUnpack {
t := timing.Start("FS Unpacking") t := timing.Start("FS Unpacking")
if _, err := util.GetFSFromImage(constants.RootDir, s.image, util.ExtractFile); err != nil { if _, err := util.GetFSFromImage(config.RootDir, s.image, util.ExtractFile); err != nil {
return errors.Wrap(err, "failed to get filesystem from image") return errors.Wrap(err, "failed to get filesystem from image")
} }
@ -308,7 +308,7 @@ func (s *stageBuilder) build() error {
logrus.Info("Skipping unpacking as no commands require it.") logrus.Info("Skipping unpacking as no commands require it.")
} }
if err := util.DetectFilesystemWhitelist(constants.WhitelistPath); err != nil { if err := util.DetectFilesystemWhitelist(config.WhitelistPath); err != nil {
return errors.Wrap(err, "failed to check filesystem whitelist") return errors.Wrap(err, "failed to check filesystem whitelist")
} }
@ -525,7 +525,6 @@ func CalculateDependencies(opts *config.KanikoOptions) (map[int][]string, error)
if err != nil { if err != nil {
return nil, err return nil, err
} }
depGraph[i] = append(depGraph[i], resolved[0:len(resolved)-1]...) depGraph[i] = append(depGraph[i], resolved[0:len(resolved)-1]...)
} }
case *instructions.EnvCommand: case *instructions.EnvCommand:
@ -641,20 +640,23 @@ func DoBuild(opts *config.KanikoOptions) (v1.Image, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
dstDir := filepath.Join(constants.KanikoDir, strconv.Itoa(index)) dstDir := filepath.Join(config.KanikoDir, strconv.Itoa(index))
if err := os.MkdirAll(dstDir, 0644); err != nil { if err := os.MkdirAll(dstDir, 0644); err != nil {
return nil, err return nil, errors.Wrap(err,
fmt.Sprintf("to create workspace for stage %s",
stageIdxToDigest[strconv.Itoa(index)],
))
} }
for _, p := range filesToSave { for _, p := range filesToSave {
logrus.Infof("Saving file %s for later use", p) logrus.Infof("Saving file %s for later use", p)
if err := util.CopyFileOrSymlink(p, dstDir); err != nil { if err := util.CopyFileOrSymlink(p, dstDir, config.RootDir); err != nil {
return nil, err return nil, errors.Wrap(err, "could not save file")
} }
} }
// Delete the filesystem // Delete the filesystem
if err := util.DeleteFilesystem(); err != nil { if err := util.DeleteFilesystem(); err != nil {
return nil, err return nil, errors.Wrap(err, fmt.Sprintf("deleting file system after satge %d", index))
} }
} }
@ -666,14 +668,22 @@ func DoBuild(opts *config.KanikoOptions) (v1.Image, error) {
func filesToSave(deps []string) ([]string, error) { func filesToSave(deps []string) ([]string, error) {
srcFiles := []string{} srcFiles := []string{}
for _, src := range deps { for _, src := range deps {
srcs, err := filepath.Glob(src) srcs, err := filepath.Glob(filepath.Join(config.RootDir, src))
if err != nil { if err != nil {
return nil, err return nil, err
} }
for _, f := range srcs { for _, f := range srcs {
if link, err := util.EvalSymLink(f); err == nil { if link, err := util.EvalSymLink(f); err == nil {
link, err = filepath.Rel(config.RootDir, link)
if err != nil {
return nil, errors.Wrap(err, fmt.Sprintf("could not find relative path to %s", config.RootDir))
}
srcFiles = append(srcFiles, link) srcFiles = append(srcFiles, link)
} }
f, err = filepath.Rel(config.RootDir, f)
if err != nil {
return nil, errors.Wrap(err, fmt.Sprintf("could not find relative path to %s", config.RootDir))
}
srcFiles = append(srcFiles, f) srcFiles = append(srcFiles, f)
} }
} }
@ -729,7 +739,7 @@ func fetchExtraStages(stages []config.KanikoStage, opts *config.KanikoOptions) e
func extractImageToDependencyDir(name string, image v1.Image) error { func extractImageToDependencyDir(name string, image v1.Image) error {
t := timing.Start("Extracting Image to Dependency Dir") t := timing.Start("Extracting Image to Dependency Dir")
defer timing.DefaultRun.Stop(t) defer timing.DefaultRun.Stop(t)
dependencyDir := filepath.Join(constants.KanikoDir, name) dependencyDir := filepath.Join(config.KanikoDir, name)
if err := os.MkdirAll(dependencyDir, 0755); err != nil { if err := os.MkdirAll(dependencyDir, 0755); err != nil {
return err return err
} }

View File

@ -371,10 +371,15 @@ func Test_filesToSave(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
tmpDir, err := ioutil.TempDir("", "") tmpDir, err := ioutil.TempDir("", "")
original := config.RootDir
config.RootDir = tmpDir
if err != nil { if err != nil {
t.Errorf("error creating tmpdir: %s", err) t.Errorf("error creating tmpdir: %s", err)
} }
defer os.RemoveAll(tmpDir) defer func() {
config.RootDir = original
os.RemoveAll(tmpDir)
}()
for _, f := range tt.files { for _, f := range tt.files {
p := filepath.Join(tmpDir, f) p := filepath.Join(tmpDir, f)
@ -391,22 +396,14 @@ func Test_filesToSave(t *testing.T) {
fp.Close() fp.Close()
} }
args := []string{} got, err := filesToSave(tt.args)
for _, arg := range tt.args {
args = append(args, filepath.Join(tmpDir, arg))
}
got, err := filesToSave(args)
if err != nil { if err != nil {
t.Errorf("got err: %s", err) t.Errorf("got err: %s", err)
} }
want := []string{} sort.Strings(tt.want)
for _, w := range tt.want {
want = append(want, filepath.Join(tmpDir, w))
}
sort.Strings(want)
sort.Strings(got) sort.Strings(got)
if !reflect.DeepEqual(got, want) { if !reflect.DeepEqual(got, tt.want) {
t.Errorf("filesToSave() = %v, want %v", got, want) t.Errorf("filesToSave() = %v, want %v", got, tt.want)
} }
}) })
} }
@ -1129,9 +1126,9 @@ COPY %s bar.txt
for key, value := range tc.args { for key, value := range tc.args {
sb.args.AddArg(key, &value) sb.args.AddArg(key, &value)
} }
tmp := commands.RootDir tmp := config.RootDir
if tc.rootDir != "" { if tc.rootDir != "" {
commands.RootDir = tc.rootDir config.RootDir = tc.rootDir
} }
err := sb.build() err := sb.build()
if err != nil { if err != nil {
@ -1141,7 +1138,7 @@ COPY %s bar.txt
assertCacheKeys(t, tc.expectedCacheKeys, lc.receivedKeys, "receive") assertCacheKeys(t, tc.expectedCacheKeys, lc.receivedKeys, "receive")
assertCacheKeys(t, tc.pushedCacheKeys, keys, "push") assertCacheKeys(t, tc.pushedCacheKeys, keys, "push")
commands.RootDir = tmp config.RootDir = tmp
}) })
} }

View File

@ -0,0 +1,187 @@
/*
Copyright 2020 Google LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package executor
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"testing"
"github.com/GoogleContainerTools/kaniko/pkg/config"
"github.com/GoogleContainerTools/kaniko/pkg/constants"
"github.com/GoogleContainerTools/kaniko/testutil"
)
func TestCopyCommand_Multistage(t *testing.T) {
t.Run("copy a file across multistage", func(t *testing.T) {
testDir, fn := setupMultistageTests(t)
defer fn()
dockerFile := fmt.Sprintf(`
FROM scratch as first
COPY foo/bam.txt copied/
ENV test test
From scratch as second
COPY --from=first copied/bam.txt output/bam.txt`)
ioutil.WriteFile(filepath.Join(testDir, "workspace", "Dockerfile"), []byte(dockerFile), 0755)
opts := &config.KanikoOptions{
DockerfilePath: filepath.Join(testDir, "workspace", "Dockerfile"),
SrcContext: filepath.Join(testDir, "workspace"),
SnapshotMode: constants.SnapshotModeFull,
}
_, err := DoBuild(opts)
testutil.CheckNoError(t, err)
// Check Image has one layer bam.txt
files, err := ioutil.ReadDir(filepath.Join(testDir, "output"))
if err != nil {
t.Fatal(err)
}
testutil.CheckDeepEqual(t, 1, len(files))
testutil.CheckDeepEqual(t, files[0].Name(), "bam.txt")
})
t.Run("copy a file across multistage into a directory", func(t *testing.T) {
testDir, fn := setupMultistageTests(t)
defer fn()
dockerFile := fmt.Sprintf(`
FROM scratch as first
COPY foo/bam.txt copied/
ENV test test
From scratch as second
COPY --from=first copied/bam.txt output/`)
ioutil.WriteFile(filepath.Join(testDir, "workspace", "Dockerfile"), []byte(dockerFile), 0755)
opts := &config.KanikoOptions{
DockerfilePath: filepath.Join(testDir, "workspace", "Dockerfile"),
SrcContext: filepath.Join(testDir, "workspace"),
SnapshotMode: constants.SnapshotModeFull,
}
_, err := DoBuild(opts)
testutil.CheckNoError(t, err)
files, err := ioutil.ReadDir(filepath.Join(testDir, "output"))
if err != nil {
t.Fatal(err)
}
testutil.CheckDeepEqual(t, 1, len(files))
testutil.CheckDeepEqual(t, files[0].Name(), "bam.txt")
})
t.Run("copy directory across multistage into a directory", func(t *testing.T) {
testDir, fn := setupMultistageTests(t)
defer fn()
dockerFile := fmt.Sprintf(`
FROM scratch as first
COPY foo copied
ENV test test
From scratch as second
COPY --from=first copied another`)
ioutil.WriteFile(filepath.Join(testDir, "workspace", "Dockerfile"), []byte(dockerFile), 0755)
opts := &config.KanikoOptions{
DockerfilePath: filepath.Join(testDir, "workspace", "Dockerfile"),
SrcContext: filepath.Join(testDir, "workspace"),
SnapshotMode: constants.SnapshotModeFull,
}
_, err := DoBuild(opts)
testutil.CheckNoError(t, err)
// Check Image has one layer bam.txt
files, err := ioutil.ReadDir(filepath.Join(testDir, "another"))
if err != nil {
t.Fatal(err)
}
testutil.CheckDeepEqual(t, 2, len(files))
testutil.CheckDeepEqual(t, files[0].Name(), "bam.link")
testutil.CheckDeepEqual(t, files[1].Name(), "bam.txt")
// TODO fix this
// path := filepath.Join(testDir, "output/another", "bam.link")
//linkName, err := os.Readlink(path)
//if err != nil {
// t.Fatal(err)
//}
//testutil.CheckDeepEqual(t, linkName, "bam.txt")
})
}
func setupMultistageTests(t *testing.T) (string, func()) {
testDir, err := ioutil.TempDir("", "")
if err != nil {
t.Fatal(err)
}
// Create workspace with files, dirs, and symlinks
// workspace tree:
// /root
// /kaniko
// /workspace
// - /foo
// - bam.txt
// - bam.link -> bam.txt
// - /bin
// - exec.link -> ../exec
// exec
// Make directory for stage or else the executor will create with permissions 0664
// and we will run into issue https://github.com/golang/go/issues/22323
if err := os.MkdirAll(filepath.Join(testDir, "kaniko/0"), 0755); err != nil {
t.Fatal(err)
}
workspace := filepath.Join(testDir, "workspace")
// Make foo
if err := os.MkdirAll(filepath.Join(workspace, "foo"), 0755); err != nil {
t.Fatal(err)
}
file := filepath.Join(workspace, "foo", "bam.txt")
if err := ioutil.WriteFile(file, []byte("meow"), 0755); err != nil {
t.Fatal(err)
}
os.Symlink("bam.txt", filepath.Join(workspace, "foo", "bam.link"))
// Make a file with contents link
file = filepath.Join(workspace, "exec")
if err := ioutil.WriteFile(file, []byte("woof"), 0755); err != nil {
t.Fatal(err)
}
// Make bin
if err := os.MkdirAll(filepath.Join(workspace, "bin"), 0755); err != nil {
t.Fatal(err)
}
os.Symlink("../exec", filepath.Join(workspace, "bin", "exec.link"))
// set up config
config.RootDir = testDir
config.KanikoDir = fmt.Sprintf("%s/%s", testDir, "kaniko")
// Write a whitelist path
if err := os.MkdirAll(filepath.Join(testDir, "proc"), 0755); err != nil {
t.Fatal(err)
}
mFile := filepath.Join(testDir, "proc/mountinfo")
mountInfo := fmt.Sprintf(
`36 35 98:0 /kaniko %s/kaniko rw,noatime master:1 - ext3 /dev/root rw,errors=continue
36 35 98:0 /proc %s/proc rw,noatime master:1 - ext3 /dev/root rw,errors=continue
`, testDir, testDir)
if err := ioutil.WriteFile(mFile, []byte(mountInfo), 0644); err != nil {
t.Fatal(err)
}
config.WhitelistPath = mFile
return testDir, func() {
config.KanikoDir = constants.KanikoDir
config.RootDir = constants.RootDir
config.WhitelistPath = constants.WhitelistPath
}
}

View File

@ -20,6 +20,7 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"github.com/GoogleContainerTools/kaniko/pkg/config"
"github.com/GoogleContainerTools/kaniko/pkg/util" "github.com/GoogleContainerTools/kaniko/pkg/util"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
@ -89,7 +90,6 @@ func ResolvePaths(paths []string, wl []util.WhitelistEntry) (pathsToAdd []string
// Also add parent directories to keep the permission of them correctly. // Also add parent directories to keep the permission of them correctly.
pathsToAdd = filesWithParentDirs(pathsToAdd) pathsToAdd = filesWithParentDirs(pathsToAdd)
return return
} }
@ -130,7 +130,7 @@ func resolveSymlinkAncestor(path string) (string, error) {
newPath := filepath.Clean(path) newPath := filepath.Clean(path)
loop: loop:
for newPath != "/" { for newPath != config.RootDir {
fi, err := os.Lstat(newPath) fi, err := os.Lstat(newPath)
if err != nil { if err != nil {
return "", errors.Wrap(err, "resolvePaths: failed to lstat") return "", errors.Wrap(err, "resolvePaths: failed to lstat")

View File

@ -28,14 +28,14 @@ import (
"github.com/GoogleContainerTools/kaniko/pkg/timing" "github.com/GoogleContainerTools/kaniko/pkg/timing"
"github.com/karrick/godirwalk" "github.com/karrick/godirwalk"
"github.com/GoogleContainerTools/kaniko/pkg/constants" "github.com/GoogleContainerTools/kaniko/pkg/config"
"github.com/GoogleContainerTools/kaniko/pkg/util" "github.com/GoogleContainerTools/kaniko/pkg/util"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
// For testing // For testing
var snapshotPathPrefix = constants.KanikoDir var snapshotPathPrefix = config.KanikoDir
// 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 {
@ -63,7 +63,7 @@ func (s *Snapshotter) Key() (string, error) {
// TakeSnapshot takes a snapshot of the specified files, avoiding directories in the whitelist, and creates // TakeSnapshot takes a snapshot of the specified files, avoiding directories in the whitelist, 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) (string, error) { func (s *Snapshotter) TakeSnapshot(files []string) (string, error) {
f, err := ioutil.TempFile(snapshotPathPrefix, "") f, err := ioutil.TempFile(config.KanikoDir, "")
if err != nil { if err != nil {
return "", err return "", err
} }

View File

@ -25,6 +25,7 @@ import (
"strings" "strings"
"testing" "testing"
"github.com/GoogleContainerTools/kaniko/pkg/config"
"github.com/GoogleContainerTools/kaniko/pkg/util" "github.com/GoogleContainerTools/kaniko/pkg/util"
"github.com/GoogleContainerTools/kaniko/testutil" "github.com/GoogleContainerTools/kaniko/testutil"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -174,7 +175,6 @@ func TestSnapshotFSChangePermissions(t *testing.T) {
if err == io.EOF { if err == io.EOF {
break break
} }
t.Logf("Info %s in tar", hdr.Name)
foundFiles = append(foundFiles, hdr.Name) foundFiles = append(foundFiles, hdr.Name)
if _, isFile := snapshotFiles[hdr.Name]; !isFile { if _, isFile := snapshotFiles[hdr.Name]; !isFile {
t.Fatalf("File %s unexpectedly in tar", hdr.Name) t.Fatalf("File %s unexpectedly in tar", hdr.Name)
@ -478,8 +478,11 @@ func setUpTest() (string, *Snapshotter, func(), error) {
return "", nil, nil, errors.Wrap(err, "initializing snapshotter") return "", nil, nil, errors.Wrap(err, "initializing snapshotter")
} }
original := config.KanikoDir
config.KanikoDir = testDir
cleanup := func() { cleanup := func() {
os.RemoveAll(snapshotPath) os.RemoveAll(snapshotPath)
config.KanikoDir = original
dirCleanUp() dirCleanUp()
} }

View File

@ -26,13 +26,14 @@ import (
"strconv" "strconv"
"strings" "strings"
"github.com/GoogleContainerTools/kaniko/pkg/constants"
v1 "github.com/google/go-containerregistry/pkg/v1" v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/moby/buildkit/frontend/dockerfile/instructions" "github.com/moby/buildkit/frontend/dockerfile/instructions"
"github.com/moby/buildkit/frontend/dockerfile/parser" "github.com/moby/buildkit/frontend/dockerfile/parser"
"github.com/moby/buildkit/frontend/dockerfile/shell" "github.com/moby/buildkit/frontend/dockerfile/shell"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/GoogleContainerTools/kaniko/pkg/config"
) )
// for testing // for testing
@ -130,7 +131,6 @@ func ResolveSources(srcs []string, root string) ([]string, error) {
return nil, errors.Wrap(err, "matching sources") return nil, errors.Wrap(err, "matching sources")
} }
logrus.Debugf("Resolved sources to %v", resolved) logrus.Debugf("Resolved sources to %v", resolved)
fmt.Println("end of resolve sources")
return resolved, nil return resolved, nil
} }
@ -145,7 +145,7 @@ func matchSources(srcs, files []string) ([]string, error) {
src = filepath.Clean(src) src = filepath.Clean(src)
for _, file := range files { for _, file := range files {
if filepath.IsAbs(src) { if filepath.IsAbs(src) {
file = filepath.Join(constants.RootDir, file) file = filepath.Join(config.RootDir, file)
} }
matched, err := filepath.Match(src, file) matched, err := filepath.Match(src, file)
if err != nil { if err != nil {

View File

@ -33,7 +33,7 @@ import (
otiai10Cpy "github.com/otiai10/copy" otiai10Cpy "github.com/otiai10/copy"
"github.com/GoogleContainerTools/kaniko/pkg/constants" "github.com/GoogleContainerTools/kaniko/pkg/config"
"github.com/docker/docker/builder/dockerignore" "github.com/docker/docker/builder/dockerignore"
"github.com/docker/docker/pkg/fileutils" "github.com/docker/docker/pkg/fileutils"
v1 "github.com/google/go-containerregistry/pkg/v1" v1 "github.com/google/go-containerregistry/pkg/v1"
@ -51,7 +51,7 @@ type WhitelistEntry struct {
var initialWhitelist = []WhitelistEntry{ var initialWhitelist = []WhitelistEntry{
{ {
Path: "/kaniko", Path: config.KanikoDir,
PrefixMatchOnly: false, PrefixMatchOnly: false,
}, },
{ {
@ -125,7 +125,7 @@ func GetFSFromLayers(root string, layers []v1.Layer, opts ...FSOpt) ([]string, e
return nil, errors.New("must supply an extract function") return nil, errors.New("must supply an extract function")
} }
if err := DetectFilesystemWhitelist(constants.WhitelistPath); err != nil { if err := DetectFilesystemWhitelist(config.WhitelistPath); err != nil {
return nil, err return nil, err
} }
@ -185,7 +185,7 @@ func GetFSFromLayers(root string, layers []v1.Layer, opts ...FSOpt) ([]string, e
// DeleteFilesystem deletes the extracted image file system // DeleteFilesystem deletes the extracted image file system
func DeleteFilesystem() error { func DeleteFilesystem() error {
logrus.Info("Deleting filesystem...") logrus.Info("Deleting filesystem...")
return filepath.Walk(constants.RootDir, func(path string, info os.FileInfo, err error) error { return filepath.Walk(config.RootDir, func(path string, info os.FileInfo, err error) error {
if err != nil { if err != nil {
// ignore errors when deleting. // ignore errors when deleting.
return nil return nil
@ -206,7 +206,7 @@ func DeleteFilesystem() error {
logrus.Debugf("Not deleting %s, as it contains a whitelisted path", path) logrus.Debugf("Not deleting %s, as it contains a whitelisted path", path)
return nil return nil
} }
if path == constants.RootDir { if path == config.RootDir {
return nil return nil
} }
return os.RemoveAll(path) return os.RemoveAll(path)
@ -385,7 +385,7 @@ func CheckWhitelist(path string) bool {
} }
func checkWhitelistRoot(root string) bool { func checkWhitelistRoot(root string) bool {
if root == constants.RootDir { if root == config.RootDir {
return false return false
} }
return CheckWhitelist(root) return CheckWhitelist(root)
@ -420,7 +420,7 @@ func DetectFilesystemWhitelist(path string) error {
} }
continue continue
} }
if lineArr[4] != constants.RootDir { if lineArr[4] != config.RootDir {
logrus.Tracef("Appending %s from line: %s", lineArr[4], line) logrus.Tracef("Appending %s from line: %s", lineArr[4], line)
whitelist = append(whitelist, WhitelistEntry{ whitelist = append(whitelist, WhitelistEntry{
Path: lineArr[4], Path: lineArr[4],
@ -460,16 +460,18 @@ func RelativeFiles(fp string, root string) ([]string, error) {
// ParentDirectories returns a list of paths to all parent directories // ParentDirectories returns a list of paths to all parent directories
// Ex. /some/temp/dir -> [/, /some, /some/temp, /some/temp/dir] // Ex. /some/temp/dir -> [/, /some, /some/temp, /some/temp/dir]
func ParentDirectories(path string) []string { func ParentDirectories(path string) []string {
path = filepath.Clean(path) dir := filepath.Clean(path)
dirs := strings.Split(path, "/") var paths []string
dirPath := constants.RootDir for {
paths := []string{constants.RootDir} if dir == filepath.Clean(config.RootDir) || dir == "" || dir == "." {
for index, dir := range dirs { break
if dir == "" || index == (len(dirs)-1) {
continue
} }
dirPath = filepath.Join(dirPath, dir) dir, _ = filepath.Split(dir)
paths = append(paths, dirPath) dir = filepath.Clean(dir)
paths = append(paths, dir)
}
if len(paths) == 0 {
paths = append(paths, config.RootDir)
} }
return paths return paths
} }
@ -481,7 +483,7 @@ func ParentDirectoriesWithoutLeadingSlash(path string) []string {
path = filepath.Clean(path) path = filepath.Clean(path)
dirs := strings.Split(path, "/") dirs := strings.Split(path, "/")
dirPath := "" dirPath := ""
paths := []string{constants.RootDir} paths := []string{config.RootDir}
for index, dir := range dirs { for index, dir := range dirs {
if dir == "" || index == (len(dirs)-1) { if dir == "" || index == (len(dirs)-1) {
continue continue
@ -725,7 +727,7 @@ func mkdirAllWithPermissions(path string, mode os.FileMode, uid, gid int64) erro
} }
if uid > math.MaxUint32 || gid > math.MaxUint32 { if uid > math.MaxUint32 || gid > math.MaxUint32 {
// due to https://github.com/golang/go/issues/8537 // due to https://github.com/golang/go/issues/8537
return errors.New(fmt.Sprintf("Numeric User-ID or Group-ID greater than %v are not properly supported.", math.MaxUint32)) return errors.New(fmt.Sprintf("Numeric User-ID or Group-ID greater than %v are not properly supported.", uint64(math.MaxUint32)))
} }
if err := os.Chown(path, int(uid), int(gid)); err != nil { if err := os.Chown(path, int(uid), int(gid)); err != nil {
return err return err
@ -821,12 +823,13 @@ func getSymlink(path string) error {
// For cross stage dependencies kaniko must persist the referenced path so that it can be used in // For cross stage dependencies kaniko must persist the referenced path so that it can be used in
// the dependent stage. For symlinks we copy the target path because copying the symlink would // the dependent stage. For symlinks we copy the target path because copying the symlink would
// result in a dead link // result in a dead link
func CopyFileOrSymlink(src string, destDir string) error { func CopyFileOrSymlink(src string, destDir string, root string) error {
destFile := filepath.Join(destDir, src) destFile := filepath.Join(destDir, src)
src = filepath.Join(root, src)
if fi, _ := os.Lstat(src); IsSymlink(fi) { if fi, _ := os.Lstat(src); IsSymlink(fi) {
link, err := os.Readlink(src) link, err := os.Readlink(src)
if err != nil { if err != nil {
return err return errors.Wrap(err, "copying file or symlink")
} }
if err := createParentDirectory(destFile); err != nil { if err := createParentDirectory(destFile); err != nil {
return err return err

View File

@ -30,6 +30,7 @@ import (
"testing" "testing"
"time" "time"
"github.com/GoogleContainerTools/kaniko/pkg/config"
"github.com/GoogleContainerTools/kaniko/pkg/mocks/go-containerregistry/mockv1" "github.com/GoogleContainerTools/kaniko/pkg/mocks/go-containerregistry/mockv1"
"github.com/GoogleContainerTools/kaniko/testutil" "github.com/GoogleContainerTools/kaniko/testutil"
"github.com/golang/mock/gomock" "github.com/golang/mock/gomock"
@ -157,11 +158,13 @@ func Test_ParentDirectories(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
path string path string
rootDir string
expected []string expected []string
}{ }{
{ {
name: "regular path", name: "regular path",
path: "/path/to/dir", path: "/path/to/dir",
rootDir: "/",
expected: []string{ expected: []string{
"/", "/",
"/path", "/path",
@ -169,17 +172,50 @@ func Test_ParentDirectories(t *testing.T) {
}, },
}, },
{ {
name: "current directory", name: "current directory",
path: ".", path: ".",
rootDir: "/",
expected: []string{ expected: []string{
"/", "/",
}, },
}, },
{
name: "non / root directory",
path: "/tmp/kaniko/test/another/dir",
rootDir: "/tmp/kaniko/",
expected: []string{
"/tmp/kaniko",
"/tmp/kaniko/test",
"/tmp/kaniko/test/another",
},
},
{
name: "non / root director same path",
path: "/tmp/123",
rootDir: "/tmp/123",
expected: []string{
"/tmp/123",
},
},
{
name: "non / root directory path",
path: "/tmp/120162240/kaniko",
rootDir: "/tmp/120162240",
expected: []string{
"/tmp/120162240",
},
},
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
original := config.RootDir
defer func() { config.RootDir = original }()
config.RootDir = tt.rootDir
actual := ParentDirectories(tt.path) actual := ParentDirectories(tt.path)
sort.Strings(actual)
sort.Strings(tt.expected)
testutil.CheckErrorAndDeepEqual(t, false, nil, tt.expected, actual) testutil.CheckErrorAndDeepEqual(t, false, nil, tt.expected, actual)
}) })
} }

View File

@ -28,6 +28,7 @@ import (
"strings" "strings"
"syscall" "syscall"
"github.com/GoogleContainerTools/kaniko/pkg/config"
"github.com/docker/docker/pkg/archive" "github.com/docker/docker/pkg/archive"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
@ -76,18 +77,17 @@ func (t *Tar) AddFileToTar(p string) error {
return err return err
} }
if p != "/" { if p == config.RootDir {
// Docker uses no leading / in the tarball
hdr.Name = strings.TrimLeft(p, "/")
} else {
// allow entry for / to preserve permission changes etc. (currently ignored anyway by Docker runtime) // allow entry for / to preserve permission changes etc. (currently ignored anyway by Docker runtime)
hdr.Name = p hdr.Name = "/"
} else {
// Docker uses no leading / in the tarball
hdr.Name = strings.TrimPrefix(p, config.RootDir)
hdr.Name = strings.TrimLeft(hdr.Name, "/")
} }
if hdr.Typeflag == tar.TypeDir && !strings.HasSuffix(hdr.Name, "/") { if hdr.Typeflag == tar.TypeDir && !strings.HasSuffix(hdr.Name, "/") {
hdr.Name = hdr.Name + "/" hdr.Name = hdr.Name + "/"
} }
// rootfs may not have been extracted when using cache, preventing uname/gname from resolving // rootfs may not have been extracted when using cache, preventing uname/gname from resolving
// this makes this layer unnecessarily differ from a cached layer which does contain this information // this makes this layer unnecessarily differ from a cached layer which does contain this information
hdr.Uname = "" hdr.Uname = ""