From 6769ceec290bacfa6efec15abf02301c146b759c Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Wed, 24 Jan 2024 19:10:49 -0500 Subject: [PATCH] [8.12](backport #37727) package_test.go - Support OCI Image Layout (#37730) * package_test.go - Support OCI Image Layout (#37727) Modify TestDocker such that is can read both the original docker image layout and the OCI Image Layout. This works by reading the config and layer file names from the manifest.yml instead of assuming their names. Fixes #37726 (cherry picked from commit ebd85124f0a7b98604cc3380a52d269d59150216) * Replace slices.Contains usage with helper func The 8.12 branch is not yet on Go 1.21 so the slices package isn't available. --- dev-tools/packaging/package_test.go | 77 +++++++++++++++++++++++------ 1 file changed, 62 insertions(+), 15 deletions(-) diff --git a/dev-tools/packaging/package_test.go b/dev-tools/packaging/package_test.go index 363e6d904d4..8c51d5cf405 100644 --- a/dev-tools/packaging/package_test.go +++ b/dev-tools/packaging/package_test.go @@ -30,7 +30,6 @@ import ( "flag" "fmt" "io" - "io/ioutil" "os" "path/filepath" "regexp" @@ -106,6 +105,7 @@ func TestZip(t *testing.T) { func TestDocker(t *testing.T) { dockers := getFiles(t, regexp.MustCompile(`\.docker\.tar\.gz$`)) for _, docker := range dockers { + t.Log(docker) checkDocker(t, docker) } } @@ -713,13 +713,19 @@ func readZip(t *testing.T, zipFile string, inspectors ...inspector) (*packageFil } func readDocker(dockerFile string) (*packageFile, *dockerInfo, error) { + // Read the manifest file first so that the config file and layer + // names are known in advance. + manifest, err := getDockerManifest(dockerFile) + if err != nil { + return nil, nil, err + } + file, err := os.Open(dockerFile) if err != nil { return nil, nil, err } defer file.Close() - var manifest *dockerManifest var info *dockerInfo layers := make(map[string]*packageFile) @@ -740,22 +746,17 @@ func readDocker(dockerFile string) (*packageFile, *dockerInfo, error) { } switch { - case header.Name == "manifest.json": - manifest, err = readDockerManifest(tarReader) - if err != nil { - return nil, nil, err - } - case strings.HasSuffix(header.Name, ".json") && header.Name != "manifest.json": + case header.Name == manifest.Config: info, err = readDockerInfo(tarReader) if err != nil { return nil, nil, err } - case strings.HasSuffix(header.Name, "/layer.tar"): + case sliceContains(manifest.Layers, header.Name): layer, err := readTarContents(header.Name, tarReader) if err != nil { return nil, nil, err } - layers[filepath.Dir(header.Name)] = layer + layers[header.Name] = layer } } @@ -769,10 +770,9 @@ func readDocker(dockerFile string) (*packageFile, *dockerInfo, error) { // Read layers in order and for each file keep only the entry seen in the later layer p := &packageFile{Name: filepath.Base(dockerFile), Contents: map[string]packageEntry{}} for _, layer := range manifest.Layers { - layerID := filepath.Dir(layer) - layerFile, found := layers[layerID] + layerFile, found := layers[layer] if !found { - return nil, nil, fmt.Errorf("layer not found: %s", layerID) + return nil, nil, fmt.Errorf("layer not found: %s", layer) } for name, entry := range layerFile.Contents { // Check only files in working dir and entrypoint @@ -798,6 +798,44 @@ func readDocker(dockerFile string) (*packageFile, *dockerInfo, error) { return p, info, nil } +// getDockerManifest opens a gzipped tar file to read the Docker manifest.json +// that it is expected to contain. +func getDockerManifest(file string) (*dockerManifest, error) { + f, err := os.Open(file) + if err != nil { + return nil, err + } + defer f.Close() + + gzipReader, err := gzip.NewReader(f) + if err != nil { + return nil, err + } + defer gzipReader.Close() + + var manifest *dockerManifest + tarReader := tar.NewReader(gzipReader) + for { + header, err := tarReader.Next() + if err != nil { + if errors.Is(err, io.EOF) { + break + } + return nil, err + } + + if header.Name == "manifest.json" { + manifest, err = readDockerManifest(tarReader) + if err != nil { + return nil, err + } + break + } + } + + return manifest, nil +} + type dockerManifest struct { Config string RepoTags []string @@ -805,7 +843,7 @@ type dockerManifest struct { } func readDockerManifest(r io.Reader) (*dockerManifest, error) { - data, err := ioutil.ReadAll(r) + data, err := io.ReadAll(r) if err != nil { return nil, err } @@ -833,7 +871,7 @@ type dockerInfo struct { } func readDockerInfo(r io.Reader) (*dockerInfo, error) { - data, err := ioutil.ReadAll(r) + data, err := io.ReadAll(r) if err != nil { return nil, err } @@ -846,3 +884,12 @@ func readDockerInfo(r io.Reader) (*dockerInfo, error) { return &info, nil } + +func sliceContains(s []string, e string) bool { + for _, v := range s { + if e == v { + return true + } + } + return false +}