Skip to content

Commit

Permalink
package_test.go - Support OCI Image Layout (#37727)
Browse files Browse the repository at this point in the history
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 ebd8512)
  • Loading branch information
andrewkroh authored and mergify[bot] committed Jan 24, 2024
1 parent c298cea commit bbc8563
Showing 1 changed file with 54 additions and 15 deletions.
69 changes: 54 additions & 15 deletions dev-tools/packaging/package_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ import (
"flag"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"regexp"
"slices"
"strings"
"testing"

Expand Down Expand Up @@ -105,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)
}
}
Expand Down Expand Up @@ -655,13 +656,19 @@ func readZip(zipFile string) (*packageFile, error) {
}

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)

Expand All @@ -682,22 +689,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 slices.Contains(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
}
}

Expand All @@ -711,10 +713,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
Expand All @@ -740,14 +741,52 @@ 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
Layers []string
}

func readDockerManifest(r io.Reader) (*dockerManifest, error) {
data, err := ioutil.ReadAll(r)
data, err := io.ReadAll(r)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -776,7 +815,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
}
Expand Down

0 comments on commit bbc8563

Please sign in to comment.