Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix snapshotter ignore list; do not attempt to delete whiteouts of ignored paths #1652

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions cmd/executor/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,19 @@ var RootCmd = &cobra.Command{
return errors.New("You must provide --destination if setting ImageNameTagDigestFile")
}
// Update ignored paths
util.UpdateInitialIgnoreList(opts.IgnoreVarRun)
if opts.IgnoreVarRun {
// /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.
logrus.Trace("Adding /var/run to default ignore list")
util.AddToDefaultIgnoreList(util.IgnoreListEntry{
Path: "/var/run",
PrefixMatchOnly: false,
})
}
for _, p := range opts.IgnorePaths {
util.AddToBaseIgnoreList(util.IgnoreListEntry{
util.AddToDefaultIgnoreList(util.IgnoreListEntry{
Path: p,
PrefixMatchOnly: false,
})
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
FROM alpine@sha256:def822f9851ca422481ec6fee59a9966f12b351c62ccb9aca841526ffaa9f748
RUN ln -s /dev/null /hello
37 changes: 29 additions & 8 deletions integration/images.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,17 +75,38 @@ var additionalDockerFlagsMap = map[string][]string{

// Arguments to build Dockerfiles with when building with kaniko
var additionalKanikoFlagsMap = map[string][]string{
"Dockerfile_test_add": {"--single-snapshot"},
"Dockerfile_test_run_new": {"--use-new-run=true"},
"Dockerfile_test_run_redo": {"--snapshotMode=redo"},
"Dockerfile_test_scratch": {"--single-snapshot"},
"Dockerfile_test_maintainer": {"--single-snapshot"},
"Dockerfile_test_target": {"--target=second"},
"Dockerfile_test_add": {"--single-snapshot"},
"Dockerfile_test_run_new": {"--use-new-run=true"},
"Dockerfile_test_run_redo": {"--snapshotMode=redo"},
"Dockerfile_test_scratch": {"--single-snapshot"},
"Dockerfile_test_maintainer": {"--single-snapshot"},
"Dockerfile_test_target": {"--target=second"},
"Dockerfile_test_snapshotter_ignorelist": {"--use-new-run=true", "-v=debug"},
}

// output check to do when building with kaniko
var outputChecks = map[string]func(string, []byte) error{
"Dockerfile_test_arg_secret": checkArgsNotPrinted,
"Dockerfile_test_snapshotter_ignorelist": func(_ string, out []byte) error {
for _, s := range []string{
"Adding whiteout for /dev",
} {
if strings.Contains(string(out), s) {
return fmt.Errorf("output must not contain %s", s)
}
}

for _, s := range []string{
"resolved symlink /hello to /dev/null",
"path /dev/null is ignored, ignoring it",
} {
if !strings.Contains(string(out), s) {
return fmt.Errorf("output must contain %s", s)
}
}

return nil
},
}

// Checks if argument are not printed in output.
Expand Down Expand Up @@ -450,11 +471,11 @@ func buildKanikoImage(

out, err := RunCommandWithoutTest(kanikoCmd)
if err != nil {
return "", fmt.Errorf("Failed to build image %s with kaniko command \"%s\": %s %s", kanikoImage, kanikoCmd.Args, err, string(out))
return "", fmt.Errorf("Failed to build image %s with kaniko command \"%s\": %s\n%s", kanikoImage, kanikoCmd.Args, err, string(out))
}
if outputCheck := outputChecks[dockerfile]; outputCheck != nil {
if err := outputCheck(dockerfile, out); err != nil {
return "", fmt.Errorf("Output check failed for image %s with kaniko command : %s %s", kanikoImage, err, string(out))
return "", fmt.Errorf("Output check failed for image %s with kaniko command : %s\n%s", kanikoImage, err, string(out))
}
}
return benchmarkDir, nil
Expand Down
9 changes: 5 additions & 4 deletions pkg/executor/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,11 @@ func newStageBuilder(opts *config.KanikoOptions, stage config.KanikoStage, cross
return nil, err
}

err = util.InitIgnoreList(true)
if err != nil {
return nil, errors.Wrap(err, "failed to initialize ignore list")
}

hasher, err := getHasher(opts.SnapshotMode)
if err != nil {
return nil, err
Expand Down Expand Up @@ -311,10 +316,6 @@ func (s *stageBuilder) build() error {
logrus.Info("Skipping unpacking as no commands require it.")
}

if err := util.DetectFilesystemIgnoreList(config.IgnoreListPath); err != nil {
return errors.Wrap(err, "failed to check filesystem mount paths")
}

initSnapshotTaken := false
if s.opts.SingleSnapshot || s.opts.RunV2 {
if err := s.initSnapshotWithTimings(); err != nil {
Expand Down
5 changes: 4 additions & 1 deletion pkg/filesystem/resolve.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,13 @@ func ResolvePaths(paths []string, wl []util.IgnoreListEntry) (pathsToAdd []strin
logrus.Debugf("symlink path %s, target does not exist", f)
continue
}
if f != evaled {
logrus.Debugf("resolved symlink %s to %s", f, evaled)
}

// If the given path is a symlink and the target is part of the ignorelist
// ignore the target
if util.IsInProvidedIgnoreList(evaled, wl) {
if util.CheckProvidedIgnoreList(evaled, wl) {
logrus.Debugf("path %s is ignored, ignoring it", evaled)
continue
}
Expand Down
80 changes: 47 additions & 33 deletions pkg/util/fs_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,7 @@ var defaultIgnoreList = []IgnoreListEntry{
},
}

var baseIgnoreList = defaultIgnoreList
var ignorelist = baseIgnoreList
var ignorelist = append([]IgnoreListEntry{}, defaultIgnoreList...)

var volumes = []string{}

Expand All @@ -101,8 +100,8 @@ func AddToIgnoreList(entry IgnoreListEntry) {
ignorelist = append(ignorelist, entry)
}

func AddToBaseIgnoreList(entry IgnoreListEntry) {
baseIgnoreList = append(baseIgnoreList, entry)
func AddToDefaultIgnoreList(entry IgnoreListEntry) {
defaultIgnoreList = append(defaultIgnoreList, entry)
}

func IncludeWhiteout() FSOpt {
Expand Down Expand Up @@ -133,7 +132,12 @@ func GetFSFromImage(root string, img v1.Image, extract ExtractFunction) ([]strin
}

func GetFSFromLayers(root string, layers []v1.Layer, opts ...FSOpt) ([]string, error) {
volumes = []string{}
cfg := new(FSConfig)
if err := InitIgnoreList(true); err != nil {
return nil, errors.Wrap(err, "initializing filesystem ignore list")
}
logrus.Debugf("Ignore list: %v", ignorelist)

for _, opt := range opts {
opt(cfg)
Expand All @@ -143,12 +147,6 @@ func GetFSFromLayers(root string, layers []v1.Layer, opts ...FSOpt) ([]string, e
return nil, errors.New("must supply an extract function")
}

if err := DetectFilesystemIgnoreList(config.IgnoreListPath); err != nil {
return nil, err
}

logrus.Debugf("Mounted directories: %v", ignorelist)

extractedFiles := []string{}
for i, l := range layers {
if mediaType, err := l.MediaType(); err == nil {
Expand Down Expand Up @@ -182,7 +180,18 @@ func GetFSFromLayers(root string, layers []v1.Layer, opts ...FSOpt) ([]string, e
logrus.Debugf("Whiting out %s", path)

name := strings.TrimPrefix(base, ".wh.")
if err := os.RemoveAll(filepath.Join(dir, name)); err != nil {
path := filepath.Join(dir, name)

if CheckIgnoreList(path) {
logrus.Debugf("Not deleting %s, as it's ignored", path)
continue
}
if childDirInIgnoreList(path) {
logrus.Debugf("Not deleting %s, as it contains a ignored path", path)
continue
}

if err := os.RemoveAll(path); err != nil {
return nil, errors.Wrapf(err, "removing whiteout %s", hdr.Name)
}

Expand Down Expand Up @@ -382,20 +391,21 @@ func ExtractFile(dest string, hdr *tar.Header, tr io.Reader) error {
return nil
}

func IsInIgnoreList(path string) bool {
return IsInProvidedIgnoreList(path, ignorelist)
}

func IsInProvidedIgnoreList(path string, wl []IgnoreListEntry) bool {
for _, entry := range wl {
if !entry.PrefixMatchOnly && path == entry.Path {
return true
}
}

return false
}

func CheckIgnoreList(path string) bool {
func IsInIgnoreList(path string) bool {
return IsInProvidedIgnoreList(path, ignorelist)
}

func CheckProvidedIgnoreList(path string, wl []IgnoreListEntry) bool {
for _, wl := range ignorelist {
if HasFilepathPrefix(path, wl.Path, wl.PrefixMatchOnly) {
return true
Expand All @@ -405,6 +415,10 @@ func CheckIgnoreList(path string) bool {
return false
}

func CheckIgnoreList(path string) bool {
return CheckProvidedIgnoreList(path, ignorelist)
}

func checkIgnoreListRoot(root string) bool {
if root == config.RootDir {
return false
Expand All @@ -419,8 +433,7 @@ func checkIgnoreListRoot(root string) bool {
// Where (5) is the mount point relative to the process's root
// From: https://www.kernel.org/doc/Documentation/filesystems/proc.txt
func DetectFilesystemIgnoreList(path string) error {
ignorelist = baseIgnoreList
volumes = []string{}
logrus.Trace("Detecting filesystem ignore list")
f, err := os.Open(path)
if err != nil {
return err
Expand All @@ -442,7 +455,7 @@ func DetectFilesystemIgnoreList(path string) error {
continue
}
if lineArr[4] != config.RootDir {
logrus.Tracef("Appending %s from line: %s", lineArr[4], line)
logrus.Tracef("Adding ignore list entry %s from line: %s", lineArr[4], line)
ignorelist = append(ignorelist, IgnoreListEntry{
Path: lineArr[4],
PrefixMatchOnly: false,
Expand Down Expand Up @@ -898,19 +911,20 @@ func createParentDirectory(path string) error {
return nil
}

// UpdateInitialIgnoreList will add /var/run to ignored paths if
func UpdateInitialIgnoreList(ignoreVarRun bool) {
if !ignoreVarRun {
return
}
logrus.Trace("Adding /var/run to initialIgnoreList ")
baseIgnoreList = append(baseIgnoreList, IgnoreListEntry{
// /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,
})
// InitIgnoreList will initialize the ignore list using:
// - defaultIgnoreList
// - mounted paths via DetectFilesystemIgnoreList()
func InitIgnoreList(detectFilesystem bool) error {
logrus.Trace("Initializing ignore list")
ignorelist = append([]IgnoreListEntry{}, defaultIgnoreList...)

if detectFilesystem {
if err := DetectFilesystemIgnoreList(config.IgnoreListPath); err != nil {
return errors.Wrap(err, "checking filesystem mount paths for ignore list")
}
}

return nil
}

type walkFSResult struct {
Expand Down Expand Up @@ -985,7 +999,7 @@ func GetFSInfoMap(dir string, existing map[string]os.FileInfo) (map[string]os.Fi
timer := timing.Start("Walking filesystem with Stat")
godirwalk.Walk(dir, &godirwalk.Options{
Callback: func(path string, ent *godirwalk.Dirent) error {
if IsInIgnoreList(path) {
if CheckIgnoreList(path) {
if IsDestDir(path) {
logrus.Tracef("Skipping paths under %s, as it is a ignored directory", path)
return filepath.SkipDir
Expand Down
Loading