Merge branch 'master' into registry-mirror

This commit is contained in:
Tejal Desai
2020-01-29 11:42:06 -08:00
committed by GitHub
1221 changed files with 110154 additions and 38757 deletions
+17 -12
View File
@@ -164,20 +164,25 @@ func IsDestDir(path string) bool {
// If dest is a dir, copy it to /dest/relpath
// If dest is a file, copy directly to dest
// If source is a dir:
// Assume dest is also a dir, and copy to dest/relpath
// Assume dest is also a dir, and copy to dest/
// If dest is not an absolute filepath, add /cwd to the beginning
func DestinationFilepath(src, dest, cwd string) (string, error) {
if IsDestDir(dest) {
destPath := filepath.Join(dest, filepath.Base(src))
if filepath.IsAbs(dest) {
return destPath, nil
}
return filepath.Join(cwd, destPath), nil
_, srcFileName := filepath.Split(src)
newDest := dest
if IsDestDir(newDest) {
newDest = filepath.Join(newDest, srcFileName)
}
if filepath.IsAbs(dest) {
return dest, nil
if !filepath.IsAbs(newDest) {
newDest = filepath.Join(cwd, newDest)
}
return filepath.Join(cwd, dest), nil
if len(srcFileName) <= 0 && !strings.HasSuffix(newDest, "/") {
newDest += "/"
}
return newDest, nil
}
// URLDestinationFilepath gives the destination a file from a remote URL should be saved to
@@ -208,7 +213,7 @@ func IsSrcsValid(srcsAndDest instructions.SourcesAndDest, resolvedSources []stri
if !ContainsWildcards(srcs) {
totalSrcs := 0
for _, src := range srcs {
if excludeFile(src, root) {
if ExcludeFile(src, root) {
continue
}
totalSrcs++
@@ -245,7 +250,7 @@ func IsSrcsValid(srcsAndDest instructions.SourcesAndDest, resolvedSources []stri
return errors.Wrap(err, "failed to get relative files")
}
for _, file := range files {
if excludeFile(file, root) {
if ExcludeFile(file, root) {
continue
}
totalFiles++
+3 -3
View File
@@ -153,13 +153,13 @@ var destinationFilepathTests = []struct {
src: "context/bar/",
cwd: "/",
dest: "pkg/",
expectedFilepath: "/pkg/bar",
expectedFilepath: "/pkg/",
},
{
src: "context/bar/",
cwd: "/newdir",
dest: "pkg/",
expectedFilepath: "/newdir/pkg/bar",
expectedFilepath: "/newdir/pkg/",
},
{
src: "./context/empty",
@@ -177,7 +177,7 @@ var destinationFilepathTests = []struct {
src: "./",
cwd: "/",
dest: "/dir",
expectedFilepath: "/dir",
expectedFilepath: "/dir/",
},
{
src: "context/foo",
+158 -36
View File
@@ -30,6 +30,8 @@ import (
"syscall"
"time"
otiai10Cpy "github.com/otiai10/copy"
"github.com/GoogleContainerTools/kaniko/pkg/constants"
"github.com/docker/docker/builder/dockerignore"
"github.com/docker/docker/pkg/fileutils"
@@ -48,13 +50,6 @@ var initialWhitelist = []WhitelistEntry{
Path: "/kaniko",
PrefixMatchOnly: false,
},
{
// /var/run is a special case. It's common to mount in /var/run/docker.sock or something similar
// which leads to a special mount on the /var/run/docker.sock file itself, but the directory to exist
// in the image with no way to tell if it came from the base image or not.
Path: "/var/run",
PrefixMatchOnly: false,
},
{
// similarly, we whitelist /etc/mtab, since there is no way to know if the file was mounted or came
// from the base image
@@ -71,25 +66,58 @@ var excluded []string
type ExtractFunction func(string, *tar.Header, io.Reader) error
type FSConfig struct {
includeWhiteout bool
extractFunc ExtractFunction
}
type FSOpt func(*FSConfig)
func IncludeWhiteout() FSOpt {
return func(opts *FSConfig) {
opts.includeWhiteout = true
}
}
func ExtractFunc(extractFunc ExtractFunction) FSOpt {
return func(opts *FSConfig) {
opts.extractFunc = extractFunc
}
}
// GetFSFromImage extracts the layers of img to root
// It returns a list of all files extracted
func GetFSFromImage(root string, img v1.Image, extract ExtractFunction) ([]string, error) {
if extract == nil {
return nil, errors.New("must supply an extract function")
}
if img == nil {
return nil, errors.New("image cannot be nil")
}
if err := DetectFilesystemWhitelist(constants.WhitelistPath); err != nil {
return nil, err
}
logrus.Debugf("Mounted directories: %v", whitelist)
layers, err := img.Layers()
if err != nil {
return nil, err
}
extractedFiles := []string{}
return GetFSFromLayers(root, layers, ExtractFunc(extract))
}
func GetFSFromLayers(root string, layers []v1.Layer, opts ...FSOpt) ([]string, error) {
cfg := new(FSConfig)
for _, opt := range opts {
opt(cfg)
}
if cfg.extractFunc == nil {
return nil, errors.New("must supply an extract function")
}
if err := DetectFilesystemWhitelist(constants.WhitelistPath); err != nil {
return nil, err
}
logrus.Debugf("Mounted directories: %v", whitelist)
extractedFiles := []string{}
for i, l := range layers {
if mediaType, err := l.MediaType(); err == nil {
logrus.Tracef("Extracting layer %d of media type %s", i, mediaType)
@@ -102,29 +130,41 @@ func GetFSFromImage(root string, img v1.Image, extract ExtractFunction) ([]strin
return nil, err
}
defer r.Close()
tr := tar.NewReader(r)
for {
hdr, err := tr.Next()
if err == io.EOF {
break
}
if err != nil {
return nil, errors.Wrap(err, fmt.Sprintf("error reading tar %d", i))
}
path := filepath.Join(root, filepath.Clean(hdr.Name))
base := filepath.Base(path)
dir := filepath.Dir(path)
if strings.HasPrefix(base, ".wh.") {
logrus.Debugf("Whiting out %s", path)
name := strings.TrimPrefix(base, ".wh.")
if err := os.RemoveAll(filepath.Join(dir, name)); err != nil {
return nil, errors.Wrapf(err, "removing whiteout %s", hdr.Name)
}
continue
if !cfg.includeWhiteout {
logrus.Debug("not including whiteout files")
continue
}
}
if err := extract(root, hdr, tr); err != nil {
if err := cfg.extractFunc(root, hdr, tr); err != nil {
return nil, err
}
extractedFiles = append(extractedFiles, filepath.Join(root, filepath.Clean(hdr.Name)))
}
}
@@ -190,7 +230,7 @@ func unTar(r io.Reader, dest string) ([]string, error) {
if err := ExtractFile(dest, hdr, tr); err != nil {
return nil, err
}
extractedFiles = append(extractedFiles, dest)
extractedFiles = append(extractedFiles, filepath.Join(dest, filepath.Clean(hdr.Name)))
}
return extractedFiles, nil
}
@@ -215,6 +255,7 @@ func ExtractFile(dest string, hdr *tar.Header, tr io.Reader) error {
switch hdr.Typeflag {
case tar.TypeReg:
logrus.Tracef("creating file %s", path)
// It's possible a file is in the tar before its directory,
// or a file was copied over a directory prior to now
fi, err := os.Stat(dir)
@@ -225,6 +266,7 @@ func ExtractFile(dest string, hdr *tar.Header, tr io.Reader) error {
return err
}
}
// Check if something already exists at path (symlinks etc.)
// If so, delete it
if FilepathExists(path) {
@@ -232,16 +274,26 @@ func ExtractFile(dest string, hdr *tar.Header, tr io.Reader) error {
return errors.Wrapf(err, "error removing %s to make way for new file.", path)
}
}
currFile, err := os.Create(path)
if err != nil {
return err
}
if _, err = io.Copy(currFile, tr); err != nil {
return err
}
if err = setFilePermissions(path, mode, uid, gid); err != nil {
return err
}
// We set AccessTime because its a required arg but we only care about
// ModTime. The file will get accessed again so AccessTime will change.
if err := os.Chtimes(path, hdr.AccessTime, hdr.ModTime); err != nil {
return err
}
currFile.Close()
case tar.TypeDir:
logrus.Tracef("creating dir %s", path)
@@ -431,18 +483,8 @@ func FilepathExists(path string) bool {
// CreateFile creates a file at path and copies over contents from the reader
func CreateFile(path string, reader io.Reader, perm os.FileMode, uid uint32, gid uint32) error {
// Create directory path if it doesn't exist
baseDir := filepath.Dir(path)
if info, err := os.Lstat(baseDir); os.IsNotExist(err) {
logrus.Tracef("baseDir %s for file %s does not exist. Creating.", baseDir, path)
if err := os.MkdirAll(baseDir, 0755); err != nil {
return err
}
} else {
switch mode := info.Mode(); {
case mode&os.ModeSymlink != 0:
logrus.Infof("destination cannot be a symlink %v", baseDir)
return errors.New("destination cannot be a symlink")
}
if err := createParentDirectory(path); err != nil {
return err
}
dest, err := os.Create(path)
if err != nil {
@@ -502,9 +544,10 @@ func CopyDir(src, dest, buildcontext string) ([]string, error) {
fullPath := filepath.Join(src, file)
fi, err := os.Lstat(fullPath)
if err != nil {
fmt.Println(" i am returning from here this", err)
return nil, err
}
if excludeFile(fullPath, buildcontext) {
if ExcludeFile(fullPath, buildcontext) {
logrus.Debugf("%s found in .dockerignore, ignoring", src)
continue
}
@@ -519,7 +562,7 @@ func CopyDir(src, dest, buildcontext string) ([]string, error) {
if err := mkdirAllWithPermissions(destPath, mode, uid, gid); err != nil {
return nil, err
}
} else if fi.Mode()&os.ModeSymlink != 0 {
} else if IsSymlink(fi) {
// If file is a symlink, we want to create the same relative symlink
if _, err := CopySymlink(fullPath, destPath, buildcontext); err != nil {
return nil, err
@@ -537,7 +580,7 @@ func CopyDir(src, dest, buildcontext string) ([]string, error) {
// CopySymlink copies the symlink at src to dest
func CopySymlink(src, dest, buildcontext string) (bool, error) {
if excludeFile(src, buildcontext) {
if ExcludeFile(src, buildcontext) {
logrus.Debugf("%s found in .dockerignore, ignoring", src)
return true, nil
}
@@ -550,12 +593,15 @@ func CopySymlink(src, dest, buildcontext string) (bool, error) {
return false, err
}
}
if err := createParentDirectory(dest); err != nil {
return false, err
}
return false, os.Symlink(link, dest)
}
// CopyFile copies the file at src to dest
func CopyFile(src, dest, buildcontext string) (bool, error) {
if excludeFile(src, buildcontext) {
if ExcludeFile(src, buildcontext) {
logrus.Debugf("%s found in .dockerignore, ignoring", src)
return true, nil
}
@@ -599,8 +645,8 @@ func GetExcludedFiles(dockerfilepath string, buildcontext string) error {
return err
}
// excludeFile returns true if the .dockerignore specified this file should be ignored
func excludeFile(path, buildcontext string) bool {
// ExcludeFile returns true if the .dockerignore specified this file should be ignored
func ExcludeFile(path, buildcontext string) bool {
if HasFilepathPrefix(path, buildcontext, false) {
var err error
path, err = filepath.Rel(buildcontext, path)
@@ -647,6 +693,7 @@ func mkdirAllWithPermissions(path string, mode os.FileMode, uid, gid int) error
if err := os.MkdirAll(path, mode); err != nil {
return err
}
if err := os.Chown(path, uid, gid); err != nil {
return err
}
@@ -677,3 +724,78 @@ func CreateTargetTarfile(tarpath string) (*os.File, error) {
return os.Create(tarpath)
}
// Returns true if a file is a symlink
func IsSymlink(fi os.FileInfo) bool {
return fi.Mode()&os.ModeSymlink != 0
}
var ErrNotSymLink = fmt.Errorf("not a symlink")
func GetSymLink(path string) (string, error) {
if err := getSymlink(path); err != nil {
return "", err
}
return os.Readlink(path)
}
func EvalSymLink(path string) (string, error) {
if err := getSymlink(path); err != nil {
return "", err
}
return filepath.EvalSymlinks(path)
}
func getSymlink(path string) error {
fi, err := os.Lstat(path)
if err != nil {
return err
}
if !IsSymlink(fi) {
return ErrNotSymLink
}
return nil
}
// 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
// result in a dead link
func CopyFileOrSymlink(src string, destDir string) error {
destFile := filepath.Join(destDir, src)
if fi, _ := os.Lstat(src); IsSymlink(fi) {
link, err := os.Readlink(src)
if err != nil {
return err
}
return os.Symlink(link, destFile)
}
return otiai10Cpy.Copy(src, destFile)
}
func createParentDirectory(path string) error {
baseDir := filepath.Dir(path)
if info, err := os.Lstat(baseDir); os.IsNotExist(err) {
logrus.Tracef("baseDir %s for file %s does not exist. Creating.", baseDir, path)
if err := os.MkdirAll(baseDir, 0755); err != nil {
return err
}
} else if IsSymlink(info) {
logrus.Infof("destination cannot be a symlink %v", baseDir)
return errors.New("destination cannot be a symlink")
}
return nil
}
// UpdateInitialWhitelist will add /var/run to whitelisted paths if
func UpdateWhitelist(whitelistVarRun bool) {
if !whitelistVarRun {
return
}
whitelist = append(initialWhitelist, WhitelistEntry{
// /var/run is a special case. It's common to mount in /var/run/docker.sock or something similar
// which leads to a special mount on the /var/run/docker.sock file itself, but the directory to exist
// in the image with no way to tell if it came from the base image or not.
Path: "/var/run",
PrefixMatchOnly: false,
})
}
+448 -16
View File
@@ -20,6 +20,7 @@ import (
"archive/tar"
"bytes"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
@@ -27,8 +28,13 @@ import (
"sort"
"strings"
"testing"
"time"
"github.com/GoogleContainerTools/kaniko/pkg/mocks/go-containerregistry/mockv1"
"github.com/GoogleContainerTools/kaniko/testutil"
"github.com/golang/mock/gomock"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/types"
)
func Test_DetectFilesystemWhitelist(t *testing.T) {
@@ -58,7 +64,6 @@ func Test_DetectFilesystemWhitelist(t *testing.T) {
{"/dev", false},
{"/dev/pts", false},
{"/sys", false},
{"/var/run", false},
{"/etc/mtab", false},
}
actualWhitelist := whitelist
@@ -445,6 +450,19 @@ func fileMatches(p string, c []byte) checker {
}
}
func timesMatch(p string, fTime time.Time) checker {
return func(root string, t *testing.T) {
fi, err := os.Stat(filepath.Join(root, p))
if err != nil {
t.Fatalf("error statting file %s", p)
}
if fi.ModTime().UTC() != fTime.UTC() {
t.Errorf("Expected modtime to equal %v but was %v", fTime, fi.ModTime())
}
}
}
func permissionsMatch(p string, perms os.FileMode) checker {
return func(root string, t *testing.T) {
fi, err := os.Stat(filepath.Join(root, p))
@@ -488,14 +506,16 @@ func filesAreHardlinks(first, second string) checker {
}
}
func fileHeader(name string, contents string, mode int64) *tar.Header {
func fileHeader(name string, contents string, mode int64, fTime time.Time) *tar.Header {
return &tar.Header{
Name: name,
Size: int64(len(contents)),
Mode: mode,
Typeflag: tar.TypeReg,
Uid: os.Getuid(),
Gid: os.Getgid(),
Name: name,
Size: int64(len(contents)),
Mode: mode,
Typeflag: tar.TypeReg,
Uid: os.Getuid(),
Gid: os.Getgid(),
AccessTime: fTime,
ModTime: fTime,
}
}
@@ -528,6 +548,87 @@ func dirHeader(name string, mode int64) *tar.Header {
}
}
func createUncompressedTar(fileContents map[string]string, tarFileName, testDir string) error {
if err := testutil.SetupFiles(testDir, fileContents); err != nil {
return err
}
tarFile, err := os.Create(filepath.Join(testDir, tarFileName))
if err != nil {
return err
}
t := NewTar(tarFile)
defer t.Close()
for file := range fileContents {
filePath := filepath.Join(testDir, file)
if err := t.AddFileToTar(filePath); err != nil {
return err
}
}
return nil
}
func Test_unTar(t *testing.T) {
tcs := []struct {
name string
setupTarContents map[string]string
tarFileName string
destination string
expectedFileList []string
errorExpected bool
}{
{
name: "multfile tar",
setupTarContents: map[string]string{
"foo/file1": "hello World",
"bar/file1": "hello World",
"bar/file2": "hello World",
"file1": "hello World",
},
tarFileName: "test.tar",
destination: "/",
expectedFileList: []string{"foo/file1", "bar/file1", "bar/file2", "file1"},
errorExpected: false,
},
{
name: "empty tar",
setupTarContents: map[string]string{},
tarFileName: "test.tar",
destination: "/",
expectedFileList: nil,
errorExpected: false,
},
}
for _, tc := range tcs {
t.Run(tc.name, func(t *testing.T) {
testDir, err := ioutil.TempDir("", "")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(testDir)
if err := createUncompressedTar(tc.setupTarContents, tc.tarFileName, testDir); err != nil {
t.Fatal(err)
}
file, err := os.Open(filepath.Join(testDir, tc.tarFileName))
if err != nil {
t.Fatal(err)
}
fileList, err := unTar(file, tc.destination)
if err != nil {
t.Fatal(err)
}
// update expectedFileList to take into factor temp directory
for i, file := range tc.expectedFileList {
tc.expectedFileList[i] = filepath.Join(testDir, file)
}
// sort both slices to ensure objects are in the same order for deep equals
sort.Strings(tc.expectedFileList)
sort.Strings(fileList)
testutil.CheckErrorAndDeepEqual(t, tc.errorExpected, err, tc.expectedFileList, fileList)
})
}
}
func TestExtractFile(t *testing.T) {
type tc struct {
name string
@@ -537,21 +638,27 @@ func TestExtractFile(t *testing.T) {
checkers []checker
}
defaultTestTime, err := time.Parse(time.RFC3339, "1912-06-23T00:00:00Z")
if err != nil {
t.Fatal(err)
}
tcs := []tc{
{
name: "normal file",
contents: []byte("helloworld"),
hdrs: []*tar.Header{fileHeader("./bar", "helloworld", 0644)},
hdrs: []*tar.Header{fileHeader("./bar", "helloworld", 0644, defaultTestTime)},
checkers: []checker{
fileExists("/bar"),
fileMatches("/bar", []byte("helloworld")),
permissionsMatch("/bar", 0644),
timesMatch("/bar", defaultTestTime),
},
},
{
name: "normal file, directory does not exist",
contents: []byte("helloworld"),
hdrs: []*tar.Header{fileHeader("./foo/bar", "helloworld", 0644)},
hdrs: []*tar.Header{fileHeader("./foo/bar", "helloworld", 0644, defaultTestTime)},
checkers: []checker{
fileExists("/foo/bar"),
fileMatches("/foo/bar", []byte("helloworld")),
@@ -563,7 +670,7 @@ func TestExtractFile(t *testing.T) {
name: "normal file, directory is created after",
contents: []byte("helloworld"),
hdrs: []*tar.Header{
fileHeader("./foo/bar", "helloworld", 0644),
fileHeader("./foo/bar", "helloworld", 0644, defaultTestTime),
dirHeader("./foo", 0722),
},
checkers: []checker{
@@ -607,7 +714,7 @@ func TestExtractFile(t *testing.T) {
name: "hardlink",
tmpdir: "/tmp/hardlink",
hdrs: []*tar.Header{
fileHeader("/bin/gzip", "gzip-binary", 0751),
fileHeader("/bin/gzip", "gzip-binary", 0751, defaultTestTime),
hardlinkHeader("/bin/uncompress", "/bin/gzip"),
},
checkers: []checker{
@@ -618,7 +725,7 @@ func TestExtractFile(t *testing.T) {
{
name: "file with setuid bit",
contents: []byte("helloworld"),
hdrs: []*tar.Header{fileHeader("./bar", "helloworld", 04644)},
hdrs: []*tar.Header{fileHeader("./bar", "helloworld", 04644, defaultTestTime)},
checkers: []checker{
fileExists("/bar"),
fileMatches("/bar", []byte("helloworld")),
@@ -630,7 +737,7 @@ func TestExtractFile(t *testing.T) {
contents: []byte("helloworld"),
hdrs: []*tar.Header{
dirHeader("./foo", 01755),
fileHeader("./foo/bar", "helloworld", 0644),
fileHeader("./foo/bar", "helloworld", 0644, defaultTestTime),
},
checkers: []checker{
fileExists("/foo/bar"),
@@ -698,6 +805,9 @@ func TestCopySymlink(t *testing.T) {
tc := tc
t.Parallel()
r, err := ioutil.TempDir("", "")
os.MkdirAll(filepath.Join(r, filepath.Dir(tc.linkTarget)), 0777)
tc.linkTarget = filepath.Join(r, tc.linkTarget)
ioutil.WriteFile(tc.linkTarget, nil, 0644)
if err != nil {
t.Fatal(err)
}
@@ -811,14 +921,14 @@ func Test_correctDockerignoreFileIsUsed(t *testing.T) {
}
for _, excl := range tt.args.excluded {
t.Run(tt.name+" to exclude "+excl, func(t *testing.T) {
if !excludeFile(excl, tt.args.buildcontext) {
if !ExcludeFile(excl, tt.args.buildcontext) {
t.Errorf("'%v' not excluded", excl)
}
})
}
for _, incl := range tt.args.included {
t.Run(tt.name+" to include "+incl, func(t *testing.T) {
if excludeFile(incl, tt.args.buildcontext) {
if ExcludeFile(incl, tt.args.buildcontext) {
t.Errorf("'%v' not included", incl)
}
})
@@ -863,3 +973,325 @@ func Test_CopyFile_skips_self(t *testing.T) {
t.Fatalf("expected file contents to be %q, but got %q", expected, actual)
}
}
func fakeExtract(dest string, hdr *tar.Header, tr io.Reader) error {
return nil
}
func Test_GetFSFromLayers_with_whiteouts_include_whiteout_enabled(t *testing.T) {
ctrl := gomock.NewController(t)
root, err := ioutil.TempDir("", "layers-test")
if err != nil {
t.Fatal(err)
}
defer os.Remove(root)
opts := []FSOpt{
// I'd rather use the real func (util.ExtractFile)
// but you have to be root to chown
ExtractFunc(fakeExtract),
IncludeWhiteout(),
}
expectErr := false
f := func(expectedFiles []string, tw *tar.Writer) {
for _, f := range expectedFiles {
f := strings.TrimPrefix(strings.TrimPrefix(f, root), "/")
hdr := &tar.Header{
Name: f,
Mode: 0644,
Size: int64(len("Hello World\n")),
}
if err := tw.WriteHeader(hdr); err != nil {
t.Fatal(err)
}
if _, err := tw.Write([]byte("Hello World\n")); err != nil {
t.Fatal(err)
}
}
if err := tw.Close(); err != nil {
t.Fatal(err)
}
}
expectedFiles := []string{
filepath.Join(root, "foobar"),
}
buf := new(bytes.Buffer)
tw := tar.NewWriter(buf)
f(expectedFiles, tw)
mockLayer := mockv1.NewMockLayer(ctrl)
mockLayer.EXPECT().MediaType().Return(types.OCILayer, nil)
rc := ioutil.NopCloser(buf)
mockLayer.EXPECT().Uncompressed().Return(rc, nil)
secondLayerFiles := []string{
filepath.Join(root, ".wh.foobar"),
}
buf = new(bytes.Buffer)
tw = tar.NewWriter(buf)
f(secondLayerFiles, tw)
mockLayer2 := mockv1.NewMockLayer(ctrl)
mockLayer2.EXPECT().MediaType().Return(types.OCILayer, nil)
rc = ioutil.NopCloser(buf)
mockLayer2.EXPECT().Uncompressed().Return(rc, nil)
layers := []v1.Layer{
mockLayer,
mockLayer2,
}
expectedFiles = append(expectedFiles, secondLayerFiles...)
actualFiles, err := GetFSFromLayers(root, layers, opts...)
assertGetFSFromLayers(
t,
actualFiles,
expectedFiles,
err,
expectErr,
)
}
func Test_GetFSFromLayers_with_whiteouts_include_whiteout_disabled(t *testing.T) {
ctrl := gomock.NewController(t)
root, err := ioutil.TempDir("", "layers-test")
if err != nil {
t.Fatal(err)
}
defer os.Remove(root)
opts := []FSOpt{
// I'd rather use the real func (util.ExtractFile)
// but you have to be root to chown
ExtractFunc(fakeExtract),
}
expectErr := false
f := func(expectedFiles []string, tw *tar.Writer) {
for _, f := range expectedFiles {
f := strings.TrimPrefix(strings.TrimPrefix(f, root), "/")
hdr := &tar.Header{
Name: f,
Mode: 0644,
Size: int64(len("Hello world\n")),
}
if err := tw.WriteHeader(hdr); err != nil {
t.Fatal(err)
}
if _, err := tw.Write([]byte("Hello world\n")); err != nil {
t.Fatal(err)
}
}
if err := tw.Close(); err != nil {
t.Fatal(err)
}
}
expectedFiles := []string{
filepath.Join(root, "foobar"),
}
buf := new(bytes.Buffer)
tw := tar.NewWriter(buf)
f(expectedFiles, tw)
mockLayer := mockv1.NewMockLayer(ctrl)
mockLayer.EXPECT().MediaType().Return(types.OCILayer, nil)
rc := ioutil.NopCloser(buf)
mockLayer.EXPECT().Uncompressed().Return(rc, nil)
secondLayerFiles := []string{
filepath.Join(root, ".wh.foobar"),
}
buf = new(bytes.Buffer)
tw = tar.NewWriter(buf)
f(secondLayerFiles, tw)
mockLayer2 := mockv1.NewMockLayer(ctrl)
mockLayer2.EXPECT().MediaType().Return(types.OCILayer, nil)
rc = ioutil.NopCloser(buf)
mockLayer2.EXPECT().Uncompressed().Return(rc, nil)
layers := []v1.Layer{
mockLayer,
mockLayer2,
}
actualFiles, err := GetFSFromLayers(root, layers, opts...)
assertGetFSFromLayers(
t,
actualFiles,
expectedFiles,
err,
expectErr,
)
}
func Test_GetFSFromLayers(t *testing.T) {
ctrl := gomock.NewController(t)
root, err := ioutil.TempDir("", "layers-test")
if err != nil {
t.Fatal(err)
}
defer os.Remove(root)
opts := []FSOpt{
// I'd rather use the real func (util.ExtractFile)
// but you have to be root to chown
ExtractFunc(fakeExtract),
}
expectErr := false
expectedFiles := []string{
filepath.Join(root, "foobar"),
}
buf := new(bytes.Buffer)
tw := tar.NewWriter(buf)
for _, f := range expectedFiles {
f := strings.TrimPrefix(strings.TrimPrefix(f, root), "/")
hdr := &tar.Header{
Name: f,
Mode: 0644,
Size: int64(len("Hello world\n")),
}
if err := tw.WriteHeader(hdr); err != nil {
t.Fatal(err)
}
if _, err := tw.Write([]byte("Hello world\n")); err != nil {
t.Fatal(err)
}
}
if err := tw.Close(); err != nil {
t.Fatal(err)
}
mockLayer := mockv1.NewMockLayer(ctrl)
mockLayer.EXPECT().MediaType().Return(types.OCILayer, nil)
rc := ioutil.NopCloser(buf)
mockLayer.EXPECT().Uncompressed().Return(rc, nil)
layers := []v1.Layer{
mockLayer,
}
actualFiles, err := GetFSFromLayers(root, layers, opts...)
assertGetFSFromLayers(
t,
actualFiles,
expectedFiles,
err,
expectErr,
)
}
func assertGetFSFromLayers(
t *testing.T,
actualFiles []string,
expectedFiles []string,
err error,
expectErr bool,
) {
if !expectErr && err != nil {
t.Error(err)
t.FailNow()
} else if expectErr && err == nil {
t.Error("expected err to not be nil")
t.FailNow()
}
if len(actualFiles) != len(expectedFiles) {
t.Errorf("expected %s to equal %s", actualFiles, expectedFiles)
t.FailNow()
}
for i := range expectedFiles {
if actualFiles[i] != expectedFiles[i] {
t.Errorf("expected %s to equal %s", actualFiles[i], expectedFiles[i])
}
}
}
func TestUpdateWhitelist(t *testing.T) {
tests := []struct {
name string
whitelistVarRun bool
expected []WhitelistEntry
}{
{
name: "var/run whitelisted",
whitelistVarRun: true,
expected: []WhitelistEntry{
{
Path: "/kaniko",
PrefixMatchOnly: false,
},
{
Path: "/etc/mtab",
PrefixMatchOnly: false,
},
{
Path: "/var/run",
PrefixMatchOnly: false,
},
},
},
{
name: "var/run not whitelisted",
expected: []WhitelistEntry{
{
Path: "/kaniko",
PrefixMatchOnly: false,
},
{
Path: "/etc/mtab",
PrefixMatchOnly: false,
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
whitelist = initialWhitelist
defer func() { whitelist = initialWhitelist }()
UpdateWhitelist(tt.whitelistVarRun)
testutil.CheckDeepEqual(t, tt.expected, whitelist)
})
}
}
+8 -5
View File
@@ -49,12 +49,12 @@ var (
func RetrieveSourceImage(stage config.KanikoStage, opts *config.KanikoOptions) (v1.Image, error) {
t := timing.Start("Retrieving Source Image")
defer timing.DefaultRun.Stop(t)
buildArgs := opts.BuildArgs
var metaArgsString []string
var buildArgs []string
for _, arg := range stage.MetaArgs {
metaArgsString = append(metaArgsString, fmt.Sprintf("%s=%s", arg.Key, arg.ValueString()))
buildArgs = append(buildArgs, fmt.Sprintf("%s=%s", arg.Key, arg.ValueString()))
}
buildArgs = append(buildArgs, metaArgsString...)
buildArgs = append(buildArgs, opts.BuildArgs...)
currentBaseName, err := ResolveEnvironmentReplacement(stage.BaseName, buildArgs, false)
if err != nil {
return nil, err
@@ -148,7 +148,10 @@ func remoteOptions(registryName string, opts *config.KanikoOptions) []remote.Opt
}
}
return []remote.Option{remote.WithTransport(tr), remote.WithAuthFromKeychain(creds.GetKeychain())}
// on which v1.Platform is this currently running?
platform := currentPlatform()
return []remote.Option{remote.WithTransport(tr), remote.WithAuthFromKeychain(creds.GetKeychain()), remote.WithPlatform(platform)}
}
func cachedImage(opts *config.KanikoOptions, image string) (v1.Image, error) {
+11
View File
@@ -22,6 +22,7 @@ import (
"encoding/hex"
"io"
"os"
"runtime"
"strconv"
"sync"
"syscall"
@@ -29,6 +30,8 @@ import (
"github.com/minio/highwayhash"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
v1 "github.com/google/go-containerregistry/pkg/v1"
)
// ConfigureLogging sets the logrus logging level and forces logs to be colorful (!)
@@ -138,3 +141,11 @@ func SHA256(r io.Reader) (string, error) {
}
return hex.EncodeToString(hasher.Sum(make([]byte, 0, hasher.Size()))), nil
}
// CurrentPlatform returns the v1.Platform on which the code runs
func currentPlatform() v1.Platform {
return v1.Platform{
OS: runtime.GOOS,
Architecture: runtime.GOARCH,
}
}