refactor to add unit tests

This commit is contained in:
Tejal Desai 2020-03-19 13:22:24 -07:00
parent 9f4fead7b5
commit ffc372a63b
14 changed files with 362 additions and 72 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

@ -97,7 +97,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 {
@ -298,7 +298,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")
} }
@ -307,7 +307,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")
} }
@ -524,7 +524,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:
@ -629,20 +628,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))
} }
} }
@ -653,17 +655,15 @@ func DoBuild(opts *config.KanikoOptions) (v1.Image, error) {
// If a file is a symlink, it also returns the target file. // If a file is a symlink, it also returns the target file.
func filesToSave(deps []string) ([]string, error) { func filesToSave(deps []string) ([]string, error) {
srcFiles := []string{} srcFiles := []string{}
for _, src := range deps { srcs, err := util.ResolveSources(deps, config.RootDir)
srcs, err := filepath.Glob(src) if err != nil {
if err != nil { return nil, errors.Wrap(err, "resolving sources to save")
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 { srcFiles = append(srcFiles, link)
srcFiles = append(srcFiles, link)
}
srcFiles = append(srcFiles, f)
} }
srcFiles = append(srcFiles, f)
} }
return srcFiles, nil return srcFiles, nil
} }
@ -717,7 +717,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

@ -1129,9 +1129,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 +1141,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,186 @@
/*
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)
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

@ -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
@ -145,7 +146,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
} }
@ -188,7 +188,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
@ -209,7 +209,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)
@ -388,7 +388,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)
@ -423,7 +423,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],
@ -463,16 +463,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
} }
@ -484,7 +486,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
@ -824,12 +826,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,14 +77,14 @@ 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, "/")
} }
// 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 = ""