341 lines
10 KiB
Diff
341 lines
10 KiB
Diff
|
|
From 947fc1ef0c103f687e195c467ddabd3cf0aa746f Mon Sep 17 00:00:00 2001
|
||
|
|
From: meilier <xingweizheng@huawei.com>
|
||
|
|
Date: Sat, 20 Feb 2021 00:42:55 +0800
|
||
|
|
Subject: [PATCH 06/10] fix load oci image panic
|
||
|
|
|
||
|
|
---
|
||
|
|
cmd/cli/save.go | 3 +
|
||
|
|
cmd/cli/save_test.go | 18 +++++
|
||
|
|
daemon/load.go | 11 +--
|
||
|
|
daemon/load_test.go | 188 +++++++++++++++++++++++++++++++++++--------
|
||
|
|
4 files changed, 181 insertions(+), 39 deletions(-)
|
||
|
|
|
||
|
|
diff --git a/cmd/cli/save.go b/cmd/cli/save.go
|
||
|
|
index 64dc8acc..fe676731 100644
|
||
|
|
--- a/cmd/cli/save.go
|
||
|
|
+++ b/cmd/cli/save.go
|
||
|
|
@@ -72,6 +72,9 @@ func saveCommand(cmd *cobra.Command, args []string) error {
|
||
|
|
if len(args) == 0 {
|
||
|
|
return errors.New("save accepts at least one image")
|
||
|
|
}
|
||
|
|
+ if saveOpts.format == exporter.OCITransport && len(args) >= 2 {
|
||
|
|
+ return errors.New("oci image format now only supports saving single image")
|
||
|
|
+ }
|
||
|
|
if err := exporter.CheckImageFormat(saveOpts.format); err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
diff --git a/cmd/cli/save_test.go b/cmd/cli/save_test.go
|
||
|
|
index 4183aa8b..3fe6bf81 100644
|
||
|
|
--- a/cmd/cli/save_test.go
|
||
|
|
+++ b/cmd/cli/save_test.go
|
||
|
|
@@ -38,6 +38,8 @@ func TestSaveCommand(t *testing.T) {
|
||
|
|
wantErr bool
|
||
|
|
}
|
||
|
|
|
||
|
|
+ // For normal cases, default err is "invalid socket path: unix:///var/run/isula_build.sock".
|
||
|
|
+ // As daemon is not running as we run unit test.
|
||
|
|
var testcases = []testcase{
|
||
|
|
{
|
||
|
|
name: "TC1 - normal case with format docker",
|
||
|
|
@@ -103,6 +105,22 @@ func TestSaveCommand(t *testing.T) {
|
||
|
|
errString: "colon in path",
|
||
|
|
format: "docker",
|
||
|
|
},
|
||
|
|
+ {
|
||
|
|
+ name: "TC9 - normal case save multiple images with format docker",
|
||
|
|
+ path: tmpDir.Join("test9"),
|
||
|
|
+ args: []string{"testImage1", "testImage2"},
|
||
|
|
+ wantErr: true,
|
||
|
|
+ errString: "isula_build.sock",
|
||
|
|
+ format: "docker",
|
||
|
|
+ },
|
||
|
|
+ {
|
||
|
|
+ name: "TC10 - abnormal case save multiple images with format oci",
|
||
|
|
+ path: tmpDir.Join("test10"),
|
||
|
|
+ args: []string{"testImage1", "testImage2"},
|
||
|
|
+ wantErr: true,
|
||
|
|
+ errString: "oci image format now only supports saving single image",
|
||
|
|
+ format: "oci",
|
||
|
|
+ },
|
||
|
|
}
|
||
|
|
|
||
|
|
for _, tc := range testcases {
|
||
|
|
diff --git a/daemon/load.go b/daemon/load.go
|
||
|
|
index d756f9ed..b557d386 100644
|
||
|
|
--- a/daemon/load.go
|
||
|
|
+++ b/daemon/load.go
|
||
|
|
@@ -147,7 +147,6 @@ func tryToParseImageFormatFromTarball(dataRoot string, opts *loadOptions) ([][]s
|
||
|
|
|
||
|
|
func getDockerRepoTagFromImageTar(systemContext *types.SystemContext, path string) ([][]string, error) {
|
||
|
|
// tmp dir will be removed after NewSourceFromFileWithContext
|
||
|
|
-
|
||
|
|
tarfileSource, err := tarfile.NewSourceFromFileWithContext(systemContext, path)
|
||
|
|
if err != nil {
|
||
|
|
return nil, errors.Wrapf(err, "failed to get the source of loading tar file")
|
||
|
|
@@ -168,8 +167,7 @@ func getDockerRepoTagFromImageTar(systemContext *types.SystemContext, path strin
|
||
|
|
|
||
|
|
func getOCIRepoTagFromImageTar(systemContext *types.SystemContext, path string) ([][]string, error) {
|
||
|
|
var (
|
||
|
|
- allRepoTags [][]string
|
||
|
|
- err error
|
||
|
|
+ err error
|
||
|
|
)
|
||
|
|
|
||
|
|
srcRef, err := alltransports.ParseImageName(exporter.FormatTransport(exporter.OCIArchiveTransport, path))
|
||
|
|
@@ -179,14 +177,13 @@ func getOCIRepoTagFromImageTar(systemContext *types.SystemContext, path string)
|
||
|
|
|
||
|
|
tarManifest, err := ociarchive.LoadManifestDescriptorWithContext(systemContext, srcRef)
|
||
|
|
if err != nil {
|
||
|
|
- return nil, errors.Wrapf(err, "failed to loadmanifest descriptor of oci image format")
|
||
|
|
+ return nil, errors.Wrapf(err, "failed to load manifest descriptor of oci image format")
|
||
|
|
}
|
||
|
|
|
||
|
|
- // If index.json has no reference name, compute the image digest instead
|
||
|
|
// For now, we only support load single image in archive file
|
||
|
|
if _, ok := tarManifest.Annotations[imgspecv1.AnnotationRefName]; ok {
|
||
|
|
- allRepoTags = [][]string{{tarManifest.Annotations[imgspecv1.AnnotationRefName]}}
|
||
|
|
+ return [][]string{{tarManifest.Annotations[imgspecv1.AnnotationRefName]}}, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
- return allRepoTags, nil
|
||
|
|
+ return [][]string{{}}, nil
|
||
|
|
}
|
||
|
|
diff --git a/daemon/load_test.go b/daemon/load_test.go
|
||
|
|
index 0513a889..cbcb5d8f 100644
|
||
|
|
--- a/daemon/load_test.go
|
||
|
|
+++ b/daemon/load_test.go
|
||
|
|
@@ -30,6 +30,12 @@ import (
|
||
|
|
"isula.org/isula-build/store"
|
||
|
|
)
|
||
|
|
|
||
|
|
+const (
|
||
|
|
+ loadedTarFile = "load.tar"
|
||
|
|
+ manifestJSONFile = "manifest.json"
|
||
|
|
+ indexJSONFile = "index.json"
|
||
|
|
+)
|
||
|
|
+
|
||
|
|
var (
|
||
|
|
localStore store.Store
|
||
|
|
daemon *Daemon
|
||
|
|
@@ -51,10 +57,10 @@ func (x *controlLoadServer) Context() context.Context {
|
||
|
|
return context.Background()
|
||
|
|
}
|
||
|
|
|
||
|
|
-func prepareLoadTar(dir *fs.Dir) error {
|
||
|
|
- manifest := dir.Join("manifest.json")
|
||
|
|
+func prepareLoadTar(dir *fs.Dir, jsonFile string) error {
|
||
|
|
+ manifest := dir.Join(jsonFile)
|
||
|
|
|
||
|
|
- fi, err := os.Create(dir.Join("load.tar"))
|
||
|
|
+ fi, err := os.Create(dir.Join(loadedTarFile))
|
||
|
|
if err != nil {
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
@@ -88,9 +94,9 @@ func prepareLoadTar(dir *fs.Dir) error {
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
-func prepareForLoad(t *testing.T, manifest string) *fs.Dir {
|
||
|
|
- tmpDir := fs.NewDir(t, t.Name(), fs.WithFile("manifest.json", manifest))
|
||
|
|
- if err := prepareLoadTar(tmpDir); err != nil {
|
||
|
|
+func prepareForLoad(t *testing.T, jsonFile, manifest string) *fs.Dir {
|
||
|
|
+ tmpDir := fs.NewDir(t, t.Name(), fs.WithFile(jsonFile, manifest))
|
||
|
|
+ if err := prepareLoadTar(tmpDir, jsonFile); err != nil {
|
||
|
|
tmpDir.Remove()
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
@@ -119,34 +125,152 @@ func clean(dir *fs.Dir) {
|
||
|
|
dir.Remove()
|
||
|
|
}
|
||
|
|
|
||
|
|
-func TestLoad(t *testing.T) {
|
||
|
|
- manifestJSON :=
|
||
|
|
- `[
|
||
|
|
- {
|
||
|
|
- "Config":"76a4dd2d5d6a18323ac8d90f959c3c8562bf592e2a559bab9b462ab600e9e5fc.json",
|
||
|
|
- "RepoTags":[
|
||
|
|
- "hello:latest"
|
||
|
|
- ],
|
||
|
|
- "Layers":[
|
||
|
|
- "6eb4c21cc3fcb729a9df230ae522c1d3708ca66e5cf531713dbfa679837aa287.tar",
|
||
|
|
- "37841116ad3b1eeea972c75ab8bad05f48f721a7431924bc547fc91c9076c1c8.tar"
|
||
|
|
- ]
|
||
|
|
+func TestLoadSingleImage(t *testing.T) {
|
||
|
|
+ testcases := []struct {
|
||
|
|
+ name string
|
||
|
|
+ manifest string
|
||
|
|
+ format string
|
||
|
|
+ tarPath string
|
||
|
|
+ withTag bool
|
||
|
|
+ wantErr bool
|
||
|
|
+ errString string
|
||
|
|
+ }{
|
||
|
|
+ {
|
||
|
|
+ name: "TC1 normal case load docker tar",
|
||
|
|
+ manifest: `[
|
||
|
|
+ {
|
||
|
|
+ "Config":"76a4dd2d5d6a18323ac8d90f959c3c8562bf592e2a559bab9b462ab600e9e5fc.json",
|
||
|
|
+ "RepoTags":[
|
||
|
|
+ "hello:latest"
|
||
|
|
+ ],
|
||
|
|
+ "Layers":[
|
||
|
|
+ "6eb4c21cc3fcb729a9df230ae522c1d3708ca66e5cf531713dbfa679837aa287.tar",
|
||
|
|
+ "37841116ad3b1eeea972c75ab8bad05f48f721a7431924bc547fc91c9076c1c8.tar"
|
||
|
|
+ ]
|
||
|
|
+ }
|
||
|
|
+ ]`,
|
||
|
|
+ format: "docker",
|
||
|
|
+ withTag: true,
|
||
|
|
+ },
|
||
|
|
+ {
|
||
|
|
+ name: "TC2 normal case load oci tar",
|
||
|
|
+ manifest: `{
|
||
|
|
+ "schemaVersion": 2,
|
||
|
|
+ "manifests": [
|
||
|
|
+ {
|
||
|
|
+ "mediaType": "application/vnd.oci.image.manifest.v1+json",
|
||
|
|
+ "digest": "sha256:a65db259a719d915df30c82ce554ab3880ea567e2150d6288580408c2629b802",
|
||
|
|
+ "size": 347,
|
||
|
|
+ "annotations": {
|
||
|
|
+ "org.opencontainers.image.ref.name": "hello:latest"
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ ]
|
||
|
|
+ }`,
|
||
|
|
+ format: "oci",
|
||
|
|
+ withTag: true,
|
||
|
|
+ },
|
||
|
|
+ {
|
||
|
|
+ name: "TC3 normal case load docker tar with no RepoTags",
|
||
|
|
+ manifest: `[
|
||
|
|
+ {
|
||
|
|
+ "Config":"76a4dd2d5d6a18323ac8d90f959c3c8562bf592e2a559bab9b462ab600e9e5fc.json",
|
||
|
|
+ "RepoTags":[],
|
||
|
|
+ "Layers":[
|
||
|
|
+ "6eb4c21cc3fcb729a9df230ae522c1d3708ca66e5cf531713dbfa679837aa287.tar",
|
||
|
|
+ "37841116ad3b1eeea972c75ab8bad05f48f721a7431924bc547fc91c9076c1c8.tar"
|
||
|
|
+ ]
|
||
|
|
+ }
|
||
|
|
+ ]`,
|
||
|
|
+ format: "docker",
|
||
|
|
+ withTag: false,
|
||
|
|
+ },
|
||
|
|
+ {
|
||
|
|
+ name: "TC4 normal case load oci tar with no annotations",
|
||
|
|
+ manifest: `{
|
||
|
|
+ "schemaVersion": 2,
|
||
|
|
+ "manifests": [
|
||
|
|
+ {
|
||
|
|
+ "mediaType": "application/vnd.oci.image.manifest.v1+json",
|
||
|
|
+ "digest": "sha256:a65db259a719d915df30c82ce554ab3880ea567e2150d6288580408c2629b802",
|
||
|
|
+ "size": 347
|
||
|
|
+ }
|
||
|
|
+ ]
|
||
|
|
+ }`,
|
||
|
|
+ format: "oci",
|
||
|
|
+ withTag: false,
|
||
|
|
+ },
|
||
|
|
+ {
|
||
|
|
+ name: "TC5 abnormal case load docker tar with wrong manifestJSON",
|
||
|
|
+ manifest: `[
|
||
|
|
+ {
|
||
|
|
+ :"76a4dd2d5d6a18323ac8d90f959c3c8562bf592e2a559bab9b462ab600e9e5fc.json",
|
||
|
|
+ "RepoTags":[
|
||
|
|
+ "hello:latest"
|
||
|
|
+ ],
|
||
|
|
+ "Layers":[
|
||
|
|
+ "6eb4c21cc3fcb729a9df230ae522c1d3708ca66e5cf531713dbfa679837aa287.tar",
|
||
|
|
+ "37841116ad3b1eeea972c75ab8bad05f48f721a7431924bc547fc91c9076c1c8.tar"
|
||
|
|
+ ]
|
||
|
|
+ }
|
||
|
|
+ ]`,
|
||
|
|
+ format: "docker",
|
||
|
|
+ withTag: true,
|
||
|
|
+ wantErr: true,
|
||
|
|
+ errString: "error loading index",
|
||
|
|
+ },
|
||
|
|
+ {
|
||
|
|
+ name: "TC6 abnormal case with wrong tar path",
|
||
|
|
+ manifest: `[
|
||
|
|
+ {
|
||
|
|
+ "Config":"76a4dd2d5d6a18323ac8d90f959c3c8562bf592e2a559bab9b462ab600e9e5fc.json",
|
||
|
|
+ "RepoTags":[
|
||
|
|
+ "hello:latest"
|
||
|
|
+ ],
|
||
|
|
+ "Layers":[
|
||
|
|
+ "6eb4c21cc3fcb729a9df230ae522c1d3708ca66e5cf531713dbfa679837aa287.tar",
|
||
|
|
+ "37841116ad3b1eeea972c75ab8bad05f48f721a7431924bc547fc91c9076c1c8.tar"
|
||
|
|
+ ]
|
||
|
|
+ }
|
||
|
|
+ ]`,
|
||
|
|
+
|
||
|
|
+ tarPath: "/path/that/not/exist/load.tar",
|
||
|
|
+ format: "docker",
|
||
|
|
+ withTag: true,
|
||
|
|
+ wantErr: true,
|
||
|
|
+ errString: "no such file or directory",
|
||
|
|
+ },
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ for _, tc := range testcases {
|
||
|
|
+ t.Run(tc.name, func(t *testing.T) {
|
||
|
|
+ var jsonFile string
|
||
|
|
+ if tc.format == "docker" {
|
||
|
|
+ jsonFile = manifestJSONFile
|
||
|
|
}
|
||
|
|
- ]`
|
||
|
|
- dir := prepareForLoad(t, manifestJSON)
|
||
|
|
- assert.Equal(t, dir != nil, true)
|
||
|
|
- defer clean(dir)
|
||
|
|
+ if tc.format == "oci" {
|
||
|
|
+ jsonFile = indexJSONFile
|
||
|
|
+ }
|
||
|
|
+ dir := prepareForLoad(t, jsonFile, tc.manifest)
|
||
|
|
+ assert.Equal(t, dir != nil, true)
|
||
|
|
+ defer clean(dir)
|
||
|
|
|
||
|
|
- path := dir.Join("load.tar")
|
||
|
|
- repoTags, err := tryToParseImageFormatFromTarball(daemon.opts.DataRoot, &loadOptions{path: path})
|
||
|
|
- assert.NilError(t, err)
|
||
|
|
- assert.Equal(t, repoTags[0][0], "hello:latest")
|
||
|
|
+ path := dir.Join(loadedTarFile)
|
||
|
|
+ if tc.tarPath == "" {
|
||
|
|
+ tc.tarPath = path
|
||
|
|
+ }
|
||
|
|
+ req := &pb.LoadRequest{Path: tc.tarPath}
|
||
|
|
+ stream := &controlLoadServer{}
|
||
|
|
|
||
|
|
- req := &pb.LoadRequest{Path: path}
|
||
|
|
- stream := &controlLoadServer{}
|
||
|
|
+ err := daemon.backend.Load(req, stream)
|
||
|
|
+ if tc.wantErr {
|
||
|
|
+ assert.ErrorContains(t, err, tc.errString)
|
||
|
|
+ return
|
||
|
|
+ }
|
||
|
|
+ assert.ErrorContains(t, err, "failed to get the image")
|
||
|
|
+ })
|
||
|
|
+ }
|
||
|
|
|
||
|
|
- err = daemon.backend.Load(req, stream)
|
||
|
|
- assert.ErrorContains(t, err, "failed to get the image")
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestLoadMultipleImages(t *testing.T) {
|
||
|
|
@@ -181,11 +305,11 @@ func TestLoadMultipleImages(t *testing.T) {
|
||
|
|
]
|
||
|
|
}
|
||
|
|
]`
|
||
|
|
- dir := prepareForLoad(t, manifestJSON)
|
||
|
|
+ dir := prepareForLoad(t, manifestJSONFile, manifestJSON)
|
||
|
|
assert.Equal(t, dir != nil, true)
|
||
|
|
defer clean(dir)
|
||
|
|
|
||
|
|
- path := dir.Join("load.tar")
|
||
|
|
+ path := dir.Join(loadedTarFile)
|
||
|
|
repoTags, err := tryToParseImageFormatFromTarball(daemon.opts.DataRoot, &loadOptions{path: path})
|
||
|
|
assert.NilError(t, err)
|
||
|
|
assert.Equal(t, repoTags[0][0], "registry.example.com/sayhello:first")
|
||
|
|
--
|
||
|
|
2.27.0
|
||
|
|
|