diff --git a/integration-test.sh b/integration-test.sh index 722a85ac4..0463fb89c 100755 --- a/integration-test.sh +++ b/integration-test.sh @@ -18,6 +18,8 @@ set -ex GCS_BUCKET="${GCS_BUCKET:-gs://kaniko-test-bucket}" IMAGE_REPO="${IMAGE_REPO:-gcr.io/kaniko-test}" +docker version + # Sets up a kokoro (Google internal integration testing tool) environment if [ -f "$KOKORO_GFILE_DIR"/common.sh ]; then echo "Installing dependencies..." diff --git a/integration/images.go b/integration/images.go index 0ddc8fd8f..f98a716d4 100644 --- a/integration/images.go +++ b/integration/images.go @@ -154,7 +154,8 @@ func addServiceAccountFlags(flags []string, serviceAccount string) []string { // BuildImage will build dockerfile (located at dockerfilesPath) using both kaniko and docker. // The resulting image will be tagged with imageRepo. If the dockerfile will be built with // context (i.e. it is in `buildContextTests`) the context will be pulled from gcsBucket. -func (d *DockerFileBuilder) BuildImage(imageRepo, gcsBucket, dockerfilesPath, dockerfile, serviceAccount string) error { +func (d *DockerFileBuilder) BuildImage(config *gcpConfig, dockerfilesPath, dockerfile string) error { + gcsBucket, serviceAccount, imageRepo := config.gcsBucket, config.serviceAccount, config.imageRepo _, ex, _, _ := runtime.Caller(0) cwd := filepath.Dir(ex) @@ -268,7 +269,8 @@ func populateVolumeCache() error { } // buildCachedImages builds the images for testing caching via kaniko where version is the nth time this image has been built -func (d *DockerFileBuilder) buildCachedImages(imageRepo, cacheRepo, dockerfilesPath, serviceAccount string, version int) error { +func (d *DockerFileBuilder) buildCachedImages(config *gcpConfig, cacheRepo, dockerfilesPath string, version int) error { + imageRepo, serviceAccount := config.imageRepo, config.serviceAccount _, ex, _, _ := runtime.Caller(0) cwd := filepath.Dir(ex) diff --git a/integration/integration_test.go b/integration/integration_test.go index b23e37b13..43b51fbe7 100644 --- a/integration/integration_test.go +++ b/integration/integration_test.go @@ -67,12 +67,27 @@ const ( ]` ) +func getDockerMajorVersion() int { + out, err := exec.Command("docker", "version", "--format", "{{.Server.Version}}").Output() + if err != nil { + log.Fatal("Error getting docker version of server:", err) + } + versionArr := strings.Split(string(out), ".") + + ver, err := strconv.Atoi(versionArr[0]) + if err != nil { + log.Fatal("Error getting docker version of server during parsing version string:", err) + } + return ver +} + func TestMain(m *testing.M) { if !meetsRequirements() { fmt.Println("Missing required tools") os.Exit(1) } config = initGCPConfig() + contextFile, err := CreateIntegrationTarball() if err != nil { fmt.Println("Failed to create tarball of integration files for build context", err) @@ -307,9 +322,7 @@ func buildImage(t *testing.T, dockerfile string, imageBuilder *DockerFileBuilder return } - if err := imageBuilder.BuildImage( - config.imageRepo, config.gcsBucket, dockerfilesPath, dockerfile, config.serviceAccount, - ); err != nil { + if err := imageBuilder.BuildImage(config, dockerfilesPath, dockerfile); err != nil { t.Errorf("Error building image: %s", err) t.FailNow() } @@ -324,13 +337,14 @@ func TestCache(t *testing.T) { t.Run("test_cache_"+dockerfile, func(t *testing.T) { dockerfile := dockerfile t.Parallel() + cache := filepath.Join(config.imageRepo, "cache", fmt.Sprintf("%v", time.Now().UnixNano())) // Build the initial image which will cache layers - if err := imageBuilder.buildCachedImages(config.imageRepo, cache, dockerfilesPath, config.serviceAccount, 0); err != nil { + if err := imageBuilder.buildCachedImages(config, cache, dockerfilesPath, 0); err != nil { t.Fatalf("error building cached image for the first time: %v", err) } // Build the second image which should pull from the cache - if err := imageBuilder.buildCachedImages(config.imageRepo, cache, dockerfilesPath, config.serviceAccount, 1); err != nil { + if err := imageBuilder.buildCachedImages(config, cache, dockerfilesPath, 1); err != nil { t.Fatalf("error building cached image for the first time: %v", err) } // Make sure both images are the same @@ -384,14 +398,46 @@ type fileDiff struct { Size int } +type fileDiffResult struct { + Adds []fileDiff + Dels []fileDiff +} + +type metaDiffResult struct { + Adds []string + Dels []string +} + type diffOutput struct { Image1 string Image2 string DiffType string - Diff struct { - Adds []fileDiff - Dels []fileDiff + Diff interface{} +} + +func (diff *diffOutput) UnmarshalJSON(data []byte) error { + type Alias diffOutput + aux := &struct{ *Alias }{Alias: (*Alias)(diff)} + var rawJSON json.RawMessage + aux.Diff = &rawJSON + err := json.Unmarshal(data, &aux) + if err != nil { + return err } + switch diff.DiffType { + case "File": + var dst fileDiffResult + err = json.Unmarshal(rawJSON, &dst) + diff.Diff = &dst + case "Metadata": + var dst metaDiffResult + err = json.Unmarshal(rawJSON, &dst) + diff.Diff = &dst + } + if err != nil { + return err + } + return err } var allowedDiffPaths = []string{"/sys"} @@ -415,13 +461,35 @@ func checkContainerDiffOutput(t *testing.T, diff []byte, expected string) { } // Some differences (whitelisted paths, etc.) are known and expected. - diffInt[0].Diff.Adds = filterDiff(diffInt[0].Diff.Adds) - diffInt[0].Diff.Dels = filterDiff(diffInt[0].Diff.Dels) + fdr := diffInt[0].Diff.(*fileDiffResult) + fdr.Adds = filterFileDiff(fdr.Adds) + fdr.Dels = filterFileDiff(fdr.Dels) + // Remove some of the meta diffs that shouldn't be checked + mdr := diffInt[1].Diff.(*metaDiffResult) + mdr.Adds = filterMetaDiff(mdr.Adds) + mdr.Dels = filterMetaDiff(mdr.Dels) testutil.CheckErrorAndDeepEqual(t, false, nil, expectedInt, diffInt) } -func filterDiff(f []fileDiff) []fileDiff { +func filterMetaDiff(metaDiff []string) []string { + // TODO remove this once we agree testing shouldn't run on docker 18.xx + // currently docker 18.xx will build an image with Metadata set + // ArgsEscaped: true, however Docker 19.xx will build an image and have + // ArgsEscaped: false + if config.dockerMajorVersion == 19 { + return metaDiff + } + newDiffs := []string{} + for _, meta := range metaDiff { + if !strings.HasPrefix(meta, "ArgsEscaped") { + newDiffs = append(newDiffs, meta) + } + } + return newDiffs +} + +func filterFileDiff(f []fileDiff) []fileDiff { var newDiffs []fileDiff for _, diff := range f { isWhitelisted := false @@ -493,11 +561,12 @@ func logBenchmarks(benchmark string) error { } type gcpConfig struct { - gcsBucket string - imageRepo string - onbuildBaseImage string - hardlinkBaseImage string - serviceAccount string + gcsBucket string + imageRepo string + onbuildBaseImage string + hardlinkBaseImage string + serviceAccount string + dockerMajorVersion int } type imageDetails struct { @@ -535,6 +604,7 @@ func initGCPConfig() *gcpConfig { if !strings.HasSuffix(c.imageRepo, "/") { c.imageRepo = c.imageRepo + "/" } + c.dockerMajorVersion = getDockerMajorVersion() c.onbuildBaseImage = c.imageRepo + "onbuild-base:latest" c.hardlinkBaseImage = c.imageRepo + "hardlink-base:latest" return &c diff --git a/pkg/commands/cmd.go b/pkg/commands/cmd.go index ff94de509..e3788d9a7 100644 --- a/pkg/commands/cmd.go +++ b/pkg/commands/cmd.go @@ -49,7 +49,8 @@ func (c *CmdCommand) ExecuteCommand(config *v1.Config, buildArgs *dockerfile.Bui } config.Cmd = newCommand - config.ArgsEscaped = true + // ArgsEscaped is only used in windows environments + config.ArgsEscaped = false return nil }