diff --git a/executor/cmd/root.go b/executor/cmd/root.go index 509e53870..14a1c68e8 100644 --- a/executor/cmd/root.go +++ b/executor/cmd/root.go @@ -17,6 +17,7 @@ limitations under the License. package cmd import ( + "fmt" "github.com/GoogleCloudPlatform/k8s-container-builder/pkg/commands" "github.com/GoogleCloudPlatform/k8s-container-builder/pkg/constants" "github.com/GoogleCloudPlatform/k8s-container-builder/pkg/dockerfile" @@ -37,6 +38,7 @@ var ( dockerfilePath string destination string srcContext string + snapshotMode string bucket string logLevel string ) @@ -46,6 +48,7 @@ func init() { RootCmd.PersistentFlags().StringVarP(&srcContext, "context", "c", "", "Path to the dockerfile build context.") RootCmd.PersistentFlags().StringVarP(&bucket, "bucket", "b", "", "Name of the GCS bucket from which to access build context as tarball.") RootCmd.PersistentFlags().StringVarP(&destination, "destination", "d", "", "Registry the final image should be pushed to (ex: gcr.io/test/example:latest)") + RootCmd.PersistentFlags().StringVarP(&snapshotMode, "snapshotMode", "", "full", "Set this flag to change the file attributes inspected during snapshotting") RootCmd.PersistentFlags().StringVarP(&logLevel, "verbosity", "v", constants.DefaultLogLevel, "Log level (debug, info, warn, error, fatal, panic") } @@ -121,7 +124,11 @@ func execute() error { return err } - l := snapshot.NewLayeredMap(util.Hasher()) + hasher, err := getHasher() + if err != nil { + return err + } + l := snapshot.NewLayeredMap(hasher) snapshotter := snapshot.NewSnapshotter(l, constants.RootDir) // Take initial snapshot @@ -179,6 +186,17 @@ func execute() error { return image.PushImage(sourceImage, destination) } +func getHasher() (func(string) (string, error), error) { + if snapshotMode == constants.SnapshotModeTime { + logrus.Info("Only file modification time will be considered when snapshotting") + return util.MtimeHasher(), nil + } + if snapshotMode == constants.SnapshotModeFull { + return util.Hasher(), nil + } + return nil, fmt.Errorf("%s is not a valid snapshot mode", snapshotMode) +} + func resolveOnBuild(stage *instructions.Stage, config *manifest.Schema2Config) error { if config.OnBuild == nil { return nil diff --git a/integration_tests/integration_test_yaml.go b/integration_tests/integration_test_yaml.go index a543eb963..bf7716004 100644 --- a/integration_tests/integration_test_yaml.go +++ b/integration_tests/integration_test_yaml.go @@ -45,6 +45,7 @@ var fileTests = []struct { kanikoContext string kanikoContextBucket bool repo string + snapshotMode string }{ { description: "test extract filesystem", @@ -53,6 +54,7 @@ var fileTests = []struct { dockerContext: dockerfilesPath, kanikoContext: dockerfilesPath, repo: "extract-filesystem", + snapshotMode: "time", }, { description: "test run", @@ -69,6 +71,7 @@ var fileTests = []struct { dockerContext: dockerfilesPath, kanikoContext: dockerfilesPath, repo: "test-run-2", + snapshotMode: "time", }, { description: "test copy", @@ -77,6 +80,7 @@ var fileTests = []struct { dockerContext: buildcontextPath, kanikoContext: buildcontextPath, repo: "test-copy", + snapshotMode: "time", }, { description: "test bucket build context", @@ -231,13 +235,17 @@ func main() { // Then, buld the image with kaniko kanikoImage := testRepo + kanikoPrefix + test.repo + snapshotMode := "" + if test.snapshotMode != "" { + snapshotMode = "--snapshotMode=" + test.snapshotMode + } contextFlag := "--context" if test.kanikoContextBucket { contextFlag = "--bucket" } kaniko := step{ Name: executorImage, - Args: []string{"--destination", kanikoImage, "--dockerfile", test.dockerfilePath, contextFlag, test.kanikoContext}, + Args: []string{"--destination", kanikoImage, "--dockerfile", test.dockerfilePath, contextFlag, test.kanikoContext, snapshotMode}, } // Pull the kaniko image diff --git a/pkg/constants/constants.go b/pkg/constants/constants.go index 004bb3c89..2a3845c53 100644 --- a/pkg/constants/constants.go +++ b/pkg/constants/constants.go @@ -39,4 +39,8 @@ const ( // BuildContextDir is the directory a build context will be unpacked into, // for example, a tarball from a GCS bucket will be unpacked here BuildContextDir = "/kaniko/buildcontext/" + + // Various snapshot modes: + SnapshotModeTime = "time" + SnapshotModeFull = "full" ) diff --git a/pkg/util/util.go b/pkg/util/util.go index f27ebba5a..2e4a08851 100644 --- a/pkg/util/util.go +++ b/pkg/util/util.go @@ -61,3 +61,17 @@ func Hasher() func(string) (string, error) { } return hasher } + +// Hasher returns a hash function, which only looks at mtime to determine if a file has changed +func MtimeHasher() 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.ModTime().String())) + return hex.EncodeToString(h.Sum(nil)), nil + } + return hasher +}