merge
This commit is contained in:
		
						commit
						4ac51ef515
					
				|  | @ -0,0 +1,26 @@ | ||||||
|  | # Copyright 2020 Google, Inc. All rights reserved. | ||||||
|  | # | ||||||
|  | # 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. | ||||||
|  | 
 | ||||||
|  | FROM debian:9.11 | ||||||
|  | RUN echo "hey" > /etc/foo | ||||||
|  | RUN echo "baz" > /etc/baz | ||||||
|  | RUN cp /etc/baz /etc/bar | ||||||
|  | RUN rm /etc/baz | ||||||
|  | 
 | ||||||
|  | # Test with ARG | ||||||
|  | ARG file | ||||||
|  | RUN echo "run" > $file | ||||||
|  | 
 | ||||||
|  | RUN echo "test home" > $HOME/file | ||||||
|  | COPY context/foo $HOME/foo | ||||||
|  | @ -49,6 +49,7 @@ const ( | ||||||
| var argsMap = map[string][]string{ | var argsMap = map[string][]string{ | ||||||
| 	"Dockerfile_test_run":        {"file=/file"}, | 	"Dockerfile_test_run":        {"file=/file"}, | ||||||
| 	"Dockerfile_test_run_new":    {"file=/file"}, | 	"Dockerfile_test_run_new":    {"file=/file"}, | ||||||
|  | 	"Dockerfile_test_run_redo":   {"file=/file"}, | ||||||
| 	"Dockerfile_test_workdir":    {"workdir=/arg/workdir"}, | 	"Dockerfile_test_workdir":    {"workdir=/arg/workdir"}, | ||||||
| 	"Dockerfile_test_add":        {"file=context/foo"}, | 	"Dockerfile_test_add":        {"file=context/foo"}, | ||||||
| 	"Dockerfile_test_arg_secret": {"SSH_PRIVATE_KEY", "SSH_PUBLIC_KEY=Pµbl1cK€Y"}, | 	"Dockerfile_test_arg_secret": {"SSH_PRIVATE_KEY", "SSH_PUBLIC_KEY=Pµbl1cK€Y"}, | ||||||
|  | @ -76,6 +77,7 @@ var additionalDockerFlagsMap = map[string][]string{ | ||||||
| var additionalKanikoFlagsMap = map[string][]string{ | var additionalKanikoFlagsMap = map[string][]string{ | ||||||
| 	"Dockerfile_test_add":        {"--single-snapshot"}, | 	"Dockerfile_test_add":        {"--single-snapshot"}, | ||||||
| 	"Dockerfile_test_run_new":    {"--use-new-run=true"}, | 	"Dockerfile_test_run_new":    {"--use-new-run=true"}, | ||||||
|  | 	"Dockerfile_test_run_redo":   {"--snapshotMode=redo"}, | ||||||
| 	"Dockerfile_test_scratch":    {"--single-snapshot"}, | 	"Dockerfile_test_scratch":    {"--single-snapshot"}, | ||||||
| 	"Dockerfile_test_maintainer": {"--single-snapshot"}, | 	"Dockerfile_test_maintainer": {"--single-snapshot"}, | ||||||
| 	"Dockerfile_test_target":     {"--target=second"}, | 	"Dockerfile_test_target":     {"--target=second"}, | ||||||
|  |  | ||||||
|  | @ -60,7 +60,7 @@ func (r *RunMarkerCommand) ExecuteCommand(config *v1.Config, buildArgs *dockerfi | ||||||
| 		} | 		} | ||||||
| 		return fi.ModTime().After(markerInfo.ModTime()), nil | 		return fi.ModTime().After(markerInfo.ModTime()), nil | ||||||
| 	} | 	} | ||||||
| 	r.Files = util.WalkFS("/", isNewer) | 	r.Files, _ = util.WalkFS("/", map[string]struct{}{}, isNewer) | ||||||
| 	logrus.Debugf("files changed %s", r.Files) | 	logrus.Debugf("files changed %s", r.Files) | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -47,6 +47,7 @@ const ( | ||||||
| 	// Various snapshot modes:
 | 	// Various snapshot modes:
 | ||||||
| 	SnapshotModeTime = "time" | 	SnapshotModeTime = "time" | ||||||
| 	SnapshotModeFull = "full" | 	SnapshotModeFull = "full" | ||||||
|  | 	SnapshotModeRedo = "redo" | ||||||
| 
 | 
 | ||||||
| 	// NoBaseImage is the scratch image
 | 	// NoBaseImage is the scratch image
 | ||||||
| 	NoBaseImage = "scratch" | 	NoBaseImage = "scratch" | ||||||
|  |  | ||||||
|  | @ -799,14 +799,17 @@ func saveStageAsTarball(path string, image v1.Image) error { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func getHasher(snapshotMode string) (func(string) (string, error), error) { | func getHasher(snapshotMode string) (func(string) (string, error), error) { | ||||||
| 	if snapshotMode == constants.SnapshotModeTime { | 	switch snapshotMode { | ||||||
|  | 	case constants.SnapshotModeTime: | ||||||
| 		logrus.Info("Only file modification time will be considered when snapshotting") | 		logrus.Info("Only file modification time will be considered when snapshotting") | ||||||
| 		return util.MtimeHasher(), nil | 		return util.MtimeHasher(), nil | ||||||
| 	} | 	case constants.SnapshotModeFull: | ||||||
| 	if snapshotMode == constants.SnapshotModeFull { |  | ||||||
| 		return util.Hasher(), nil | 		return util.Hasher(), nil | ||||||
|  | 	case constants.SnapshotModeRedo: | ||||||
|  | 		return util.RedoHasher(), nil | ||||||
|  | 	default: | ||||||
|  | 		return nil, fmt.Errorf("%s is not a valid snapshot mode", snapshotMode) | ||||||
| 	} | 	} | ||||||
| 	return nil, fmt.Errorf("%s is not a valid snapshot mode", snapshotMode) |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func resolveOnBuild(stage *config.KanikoStage, config *v1.Config, stageNameToIdx map[string]string) error { | func resolveOnBuild(stage *config.KanikoStage, config *v1.Config, stageNameToIdx map[string]string) error { | ||||||
|  |  | ||||||
|  | @ -30,9 +30,10 @@ import ( | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| type LayeredMap struct { | type LayeredMap struct { | ||||||
| 	layers    []map[string]string | 	layers         []map[string]string | ||||||
| 	whiteouts []map[string]struct{} | 	whiteouts      []map[string]struct{} | ||||||
| 	hasher    func(string) (string, error) | 	layerHashCache map[string]string | ||||||
|  | 	hasher         func(string) (string, error) | ||||||
| 	// cacheHasher doesn't include mtime in it's hash so that filesystem cache keys are stable
 | 	// cacheHasher doesn't include mtime in it's hash so that filesystem cache keys are stable
 | ||||||
| 	cacheHasher func(string) (string, error) | 	cacheHasher func(string) (string, error) | ||||||
| } | } | ||||||
|  | @ -43,6 +44,7 @@ func NewLayeredMap(h func(string) (string, error), c func(string) (string, error | ||||||
| 		cacheHasher: c, | 		cacheHasher: c, | ||||||
| 	} | 	} | ||||||
| 	l.layers = []map[string]string{} | 	l.layers = []map[string]string{} | ||||||
|  | 	l.layerHashCache = map[string]string{} | ||||||
| 	return &l | 	return &l | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -103,7 +105,14 @@ func (l *LayeredMap) MaybeAddWhiteout(s string) bool { | ||||||
| // Add will add the specified file s to the layered map.
 | // Add will add the specified file s to the layered map.
 | ||||||
| func (l *LayeredMap) Add(s string) error { | func (l *LayeredMap) Add(s string) error { | ||||||
| 	// Use hash function and add to layers
 | 	// Use hash function and add to layers
 | ||||||
| 	newV, err := l.hasher(s) | 	newV, err := func(s string) (string, error) { | ||||||
|  | 		if v, ok := l.layerHashCache[s]; ok { | ||||||
|  | 			// clear it cache for next layer.
 | ||||||
|  | 			delete(l.layerHashCache, s) | ||||||
|  | 			return v, nil | ||||||
|  | 		} | ||||||
|  | 		return l.hasher(s) | ||||||
|  | 	}(s) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return fmt.Errorf("error creating hash for %s: %v", s, err) | 		return fmt.Errorf("error creating hash for %s: %v", s, err) | ||||||
| 	} | 	} | ||||||
|  | @ -126,6 +135,7 @@ func (l *LayeredMap) CheckFileChange(s string) (bool, error) { | ||||||
| 		} | 		} | ||||||
| 		return false, err | 		return false, err | ||||||
| 	} | 	} | ||||||
|  | 	l.layerHashCache[s] = newV | ||||||
| 	oldV, ok := l.Get(s) | 	oldV, ok := l.Get(s) | ||||||
| 	if ok && newV == oldV { | 	if ok && newV == oldV { | ||||||
| 		return false, nil | 		return false, nil | ||||||
|  |  | ||||||
|  | @ -34,7 +34,6 @@ import ( | ||||||
| 
 | 
 | ||||||
| // For testing
 | // For testing
 | ||||||
| var snapshotPathPrefix = config.KanikoDir | var snapshotPathPrefix = config.KanikoDir | ||||||
| var allPass = func(s string) (bool, error) { return true, nil } |  | ||||||
| 
 | 
 | ||||||
| // 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 { | ||||||
|  | @ -94,16 +93,14 @@ func (s *Snapshotter) TakeSnapshot(files []string, shdCheckDelete bool) (string, | ||||||
| 	// Get whiteout paths
 | 	// Get whiteout paths
 | ||||||
| 	filesToWhiteout := []string{} | 	filesToWhiteout := []string{} | ||||||
| 	if shdCheckDelete { | 	if shdCheckDelete { | ||||||
| 		existingPaths := s.l.getFlattenedPathsForWhiteOut() | 		_, deletedFiles := util.WalkFS(s.directory, s.l.getFlattenedPathsForWhiteOut(), func(s string) (bool, error) { | ||||||
| 		foundFiles := util.WalkFS(s.directory, allPass) | 			return true, nil | ||||||
| 		for _, file := range foundFiles { | 		}) | ||||||
| 			delete(existingPaths, file) |  | ||||||
| 		} |  | ||||||
| 		// The paths left here are the ones that have been deleted in this layer.
 | 		// The paths left here are the ones that have been deleted in this layer.
 | ||||||
| 		for path := range existingPaths { | 		for path := range deletedFiles { | ||||||
| 			// Only add the whiteout if the directory for the file still exists.
 | 			// Only add the whiteout if the directory for the file still exists.
 | ||||||
| 			dir := filepath.Dir(path) | 			dir := filepath.Dir(path) | ||||||
| 			if _, ok := existingPaths[dir]; !ok { | 			if _, ok := deletedFiles[dir]; !ok { | ||||||
| 				if s.l.MaybeAddWhiteout(path) { | 				if s.l.MaybeAddWhiteout(path) { | ||||||
| 					logrus.Debugf("Adding whiteout for %s", path) | 					logrus.Debugf("Adding whiteout for %s", path) | ||||||
| 					filesToWhiteout = append(filesToWhiteout, path) | 					filesToWhiteout = append(filesToWhiteout, path) | ||||||
|  | @ -152,48 +149,28 @@ func (s *Snapshotter) scanFullFilesystem() ([]string, []string, error) { | ||||||
| 
 | 
 | ||||||
| 	s.l.Snapshot() | 	s.l.Snapshot() | ||||||
| 
 | 
 | ||||||
| 	foundPaths := util.WalkFS(s.directory, allPass) | 	changedPaths, deletedPaths := util.WalkFS(s.directory, s.l.getFlattenedPathsForWhiteOut(), s.l.CheckFileChange) | ||||||
| 	timer := timing.Start("Resolving Paths") | 	timer := timing.Start("Resolving Paths") | ||||||
| 	// First handle whiteouts
 |  | ||||||
| 	//   Get a list of all the files that existed before this layer
 |  | ||||||
| 	existingPaths := s.l.getFlattenedPathsForWhiteOut() |  | ||||||
| 
 | 
 | ||||||
| 	filesToAdd := []string{} | 	filesToAdd := []string{} | ||||||
| 	resolvedMemFs := make(map[string]bool) | 	resolvedFiles, err := filesystem.ResolvePaths(changedPaths, s.ignorelist) | ||||||
| 
 | 	if err != nil { | ||||||
| 	for _, path := range foundPaths { | 		return nil, nil, err | ||||||
| 		delete(existingPaths, path) | 	} | ||||||
| 		resolvedFiles, err := filesystem.ResolvePaths([]string{path}, s.ignorelist) | 	for _, path := range resolvedFiles { | ||||||
| 		if err != nil { | 		if util.CheckIgnoreList(path) { | ||||||
| 			return nil, nil, err | 			logrus.Tracef("Not adding %s to layer, as it's whitelisted", path) | ||||||
| 		} | 			continue | ||||||
| 		for _, path := range resolvedFiles { |  | ||||||
| 			// Continue if this path is already processed
 |  | ||||||
| 			if _, ok := resolvedMemFs[path]; ok { |  | ||||||
| 				continue |  | ||||||
| 			} |  | ||||||
| 			if util.CheckIgnoreList(path) { |  | ||||||
| 				logrus.Tracef("Not adding %s to layer, as it's whitelisted", path) |  | ||||||
| 				continue |  | ||||||
| 			} |  | ||||||
| 			// Only add changed files.
 |  | ||||||
| 			fileChanged, err := s.l.CheckFileChange(path) |  | ||||||
| 			if err != nil { |  | ||||||
| 				return nil, nil, fmt.Errorf("could not check if file has changed %s %s", path, err) |  | ||||||
| 			} |  | ||||||
| 			if fileChanged { |  | ||||||
| 				logrus.Tracef("Adding file %s to layer, because it was changed.", path) |  | ||||||
| 				filesToAdd = append(filesToAdd, path) |  | ||||||
| 			} |  | ||||||
| 		} | 		} | ||||||
|  | 		filesToAdd = append(filesToAdd, path) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// The paths left here are the ones that have been deleted in this layer.
 | 	// The paths left here are the ones that have been deleted in this layer.
 | ||||||
| 	filesToWhiteOut := []string{} | 	filesToWhiteOut := []string{} | ||||||
| 	for path := range existingPaths { | 	for path := range deletedPaths { | ||||||
| 		// Only add the whiteout if the directory for the file still exists.
 | 		// Only add the whiteout if the directory for the file still exists.
 | ||||||
| 		dir := filepath.Dir(path) | 		dir := filepath.Dir(path) | ||||||
| 		if _, ok := existingPaths[dir]; !ok { | 		if _, ok := deletedPaths[dir]; !ok { | ||||||
| 			if s.l.MaybeAddWhiteout(path) { | 			if s.l.MaybeAddWhiteout(path) { | ||||||
| 				logrus.Debugf("Adding whiteout for %s", path) | 				logrus.Debugf("Adding whiteout for %s", path) | ||||||
| 				filesToWhiteOut = append(filesToWhiteOut, path) | 				filesToWhiteOut = append(filesToWhiteOut, path) | ||||||
|  |  | ||||||
|  | @ -66,6 +66,7 @@ func TestSnapshotFSFileChange(t *testing.T) { | ||||||
| 	} | 	} | ||||||
| 	for _, path := range util.ParentDirectoriesWithoutLeadingSlash(batPath) { | 	for _, path := range util.ParentDirectoriesWithoutLeadingSlash(batPath) { | ||||||
| 		if path == "/" { | 		if path == "/" { | ||||||
|  | 			snapshotFiles["/"] = "" | ||||||
| 			continue | 			continue | ||||||
| 		} | 		} | ||||||
| 		snapshotFiles[path+"/"] = "" | 		snapshotFiles[path+"/"] = "" | ||||||
|  | @ -164,6 +165,7 @@ func TestSnapshotFSChangePermissions(t *testing.T) { | ||||||
| 	} | 	} | ||||||
| 	for _, path := range util.ParentDirectoriesWithoutLeadingSlash(batPathWithoutLeadingSlash) { | 	for _, path := range util.ParentDirectoriesWithoutLeadingSlash(batPathWithoutLeadingSlash) { | ||||||
| 		if path == "/" { | 		if path == "/" { | ||||||
|  | 			snapshotFiles["/"] = "" | ||||||
| 			continue | 			continue | ||||||
| 		} | 		} | ||||||
| 		snapshotFiles[path+"/"] = "" | 		snapshotFiles[path+"/"] = "" | ||||||
|  |  | ||||||
|  | @ -878,7 +878,7 @@ func UpdateInitialIgnoreList(ignoreVarRun bool) { | ||||||
| 	}) | 	}) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func WalkFS(dir string, f func(string) (bool, error)) []string { | func WalkFS(dir string, existingPaths map[string]struct{}, f func(string) (bool, error)) ([]string, map[string]struct{}) { | ||||||
| 	foundPaths := make([]string, 0) | 	foundPaths := make([]string, 0) | ||||||
| 	timer := timing.Start("Walking filesystem") | 	timer := timing.Start("Walking filesystem") | ||||||
| 	godirwalk.Walk(dir, &godirwalk.Options{ | 	godirwalk.Walk(dir, &godirwalk.Options{ | ||||||
|  | @ -891,6 +891,7 @@ func WalkFS(dir string, f func(string) (bool, error)) []string { | ||||||
| 
 | 
 | ||||||
| 				return nil | 				return nil | ||||||
| 			} | 			} | ||||||
|  | 			delete(existingPaths, path) | ||||||
| 			if t, err := f(path); err != nil { | 			if t, err := f(path); err != nil { | ||||||
| 				return err | 				return err | ||||||
| 			} else if t { | 			} else if t { | ||||||
|  | @ -902,5 +903,5 @@ func WalkFS(dir string, f func(string) (bool, error)) []string { | ||||||
| 	}, | 	}, | ||||||
| 	) | 	) | ||||||
| 	timing.DefaultRun.Stop(timer) | 	timing.DefaultRun.Stop(timer) | ||||||
| 	return foundPaths | 	return foundPaths, existingPaths | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -115,6 +115,27 @@ func MtimeHasher() func(string) (string, error) { | ||||||
| 	return hasher | 	return hasher | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // RedoHasher returns a hash function, which looks at mtime, size, filemode, owner uid and gid
 | ||||||
|  | // Note that the mtime can lag, so it's possible that a file will have changed but the mtime may look the same.
 | ||||||
|  | func RedoHasher() func(string) (string, error) { | ||||||
|  | 	hasher := func(p string) (string, error) { | ||||||
|  | 		h := md5.New() | ||||||
|  | 		fi, err := os.Lstat(p) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return "", err | ||||||
|  | 		} | ||||||
|  | 		h.Write([]byte(fi.Mode().String())) | ||||||
|  | 		h.Write([]byte(fi.ModTime().String())) | ||||||
|  | 		h.Write([]byte(strconv.FormatInt(fi.Size(), 16))) | ||||||
|  | 		h.Write([]byte(strconv.FormatUint(uint64(fi.Sys().(*syscall.Stat_t).Uid), 36))) | ||||||
|  | 		h.Write([]byte(",")) | ||||||
|  | 		h.Write([]byte(strconv.FormatUint(uint64(fi.Sys().(*syscall.Stat_t).Gid), 36))) | ||||||
|  | 
 | ||||||
|  | 		return hex.EncodeToString(h.Sum(nil)), nil | ||||||
|  | 	} | ||||||
|  | 	return hasher | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // SHA256 returns the shasum of the contents of r
 | // SHA256 returns the shasum of the contents of r
 | ||||||
| func SHA256(r io.Reader) (string, error) { | func SHA256(r io.Reader) (string, error) { | ||||||
| 	hasher := sha256.New() | 	hasher := sha256.New() | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue