Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

package_test.go - Support OCI Image Layout #37727

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 54 additions & 15 deletions dev-tools/packaging/package_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ import (
"flag"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"regexp"
"slices"
"strings"
"testing"

Expand Down Expand Up @@ -106,6 +106,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 @@ -713,13 +714,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)

Expand All @@ -740,22 +747,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):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't in 8.12 yet since it is still at Go 1.20, so is 7.17 but we plan to change that with #37694 since 7.17.18 will be after the Go 1.22 release.

I don't think we can put it into 8.12 since Go 1.21 modifies our support matrix by dropping Windows 8.1

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When we do the backport for 8.12 we can substitute in golang.org/x/exp/slices or a helper function or a map.

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 @@ -769,10 +771,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 @@ -798,14 +799,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 @@ -833,7 +872,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
Loading