306 lines
10 KiB
Diff
306 lines
10 KiB
Diff
|
|
From 2b845fdb3e3c9d23b0fec856bcd5ce8ced868683 Mon Sep 17 00:00:00 2001
|
||
|
|
From: DCCooper <1866858@gmail.com>
|
||
|
|
Date: Thu, 4 Nov 2021 14:38:20 +0800
|
||
|
|
Subject: [PATCH] isula-build:fix panic when using image ID to save separated
|
||
|
|
image
|
||
|
|
|
||
|
|
Signed-off-by: DCCooper <1866858@gmail.com>
|
||
|
|
---
|
||
|
|
daemon/save.go | 120 +++++++++++++--------
|
||
|
|
.../src/cover_test_save_separated_image_failed.sh | 28 +++++
|
||
|
|
.../src/cover_test_save_separated_image_success.sh | 24 ++++-
|
||
|
|
3 files changed, 127 insertions(+), 45 deletions(-)
|
||
|
|
|
||
|
|
diff --git a/daemon/save.go b/daemon/save.go
|
||
|
|
index 9ad4e03..9c5e563 100644
|
||
|
|
--- a/daemon/save.go
|
||
|
|
+++ b/daemon/save.go
|
||
|
|
@@ -83,6 +83,7 @@ type separatorSave struct {
|
||
|
|
base string
|
||
|
|
lib string
|
||
|
|
dest string
|
||
|
|
+ renameFile string
|
||
|
|
enabled bool
|
||
|
|
}
|
||
|
|
|
||
|
|
@@ -141,15 +142,7 @@ type tarballInfo struct {
|
||
|
|
BaseLayers []string `json:"baseLayer"`
|
||
|
|
}
|
||
|
|
|
||
|
|
-func (b *Backend) getSaveOptions(req *pb.SaveRequest) (saveOptions, error) {
|
||
|
|
- var sep = separatorSave{
|
||
|
|
- base: req.GetSep().GetBase(),
|
||
|
|
- lib: req.GetSep().GetLib(),
|
||
|
|
- dest: req.GetSep().GetDest(),
|
||
|
|
- log: logrus.WithFields(logrus.Fields{"SaveID": req.GetSaveID()}),
|
||
|
|
- enabled: req.GetSep().GetEnabled(),
|
||
|
|
- }
|
||
|
|
-
|
||
|
|
+func (b *Backend) getSaveOptions(req *pb.SaveRequest) saveOptions {
|
||
|
|
var opt = saveOptions{
|
||
|
|
sysCtx: image.GetSystemContext(),
|
||
|
|
localStore: b.daemon.localStore,
|
||
|
|
@@ -161,11 +154,19 @@ func (b *Backend) getSaveOptions(req *pb.SaveRequest) (saveOptions, error) {
|
||
|
|
outputPath: req.GetPath(),
|
||
|
|
logger: logger.NewCliLogger(constant.CliLogBufferLen),
|
||
|
|
logEntry: logrus.WithFields(logrus.Fields{"SaveID": req.GetSaveID(), "Format": req.GetFormat()}),
|
||
|
|
- sep: sep,
|
||
|
|
}
|
||
|
|
// normal save
|
||
|
|
- if !sep.enabled {
|
||
|
|
- return opt, nil
|
||
|
|
+ if !req.GetSep().GetEnabled() {
|
||
|
|
+ return opt
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ opt.sep = separatorSave{
|
||
|
|
+ base: req.GetSep().GetBase(),
|
||
|
|
+ lib: req.GetSep().GetLib(),
|
||
|
|
+ dest: req.GetSep().GetDest(),
|
||
|
|
+ log: logrus.WithFields(logrus.Fields{"SaveID": req.GetSaveID()}),
|
||
|
|
+ enabled: req.GetSep().GetEnabled(),
|
||
|
|
+ renameFile: req.GetSep().GetRename(),
|
||
|
|
}
|
||
|
|
|
||
|
|
// save separated image
|
||
|
|
@@ -175,44 +176,22 @@ func (b *Backend) getSaveOptions(req *pb.SaveRequest) (saveOptions, error) {
|
||
|
|
baseDir := filepath.Join(tmpRoot, baseUntarTempDirName)
|
||
|
|
libDir := filepath.Join(tmpRoot, libUntarTempDirName)
|
||
|
|
|
||
|
|
- opt.sep.tmpDir = imageTmpDir{
|
||
|
|
- app: appDir,
|
||
|
|
- base: baseDir,
|
||
|
|
- lib: libDir,
|
||
|
|
- untar: untar,
|
||
|
|
- root: tmpRoot,
|
||
|
|
- }
|
||
|
|
+ opt.sep.tmpDir = imageTmpDir{app: appDir, base: baseDir, lib: libDir, untar: untar, root: tmpRoot}
|
||
|
|
opt.outputPath = filepath.Join(untar, unionTarName)
|
||
|
|
- renameFile := req.GetSep().GetRename()
|
||
|
|
- if len(renameFile) != 0 {
|
||
|
|
- var reName []renames
|
||
|
|
- if err := util.LoadJSONFile(renameFile, &reName); err != nil {
|
||
|
|
- return saveOptions{}, err
|
||
|
|
- }
|
||
|
|
- opt.sep.renameData = reName
|
||
|
|
- }
|
||
|
|
|
||
|
|
- return opt, nil
|
||
|
|
+ return opt
|
||
|
|
}
|
||
|
|
|
||
|
|
// Save receives a save request and save the image(s) into tarball
|
||
|
|
-func (b *Backend) Save(req *pb.SaveRequest, stream pb.Control_SaveServer) error {
|
||
|
|
+func (b *Backend) Save(req *pb.SaveRequest, stream pb.Control_SaveServer) (err error) {
|
||
|
|
logrus.WithFields(logrus.Fields{
|
||
|
|
"SaveID": req.GetSaveID(),
|
||
|
|
"Format": req.GetFormat(),
|
||
|
|
}).Info("SaveRequest received")
|
||
|
|
|
||
|
|
- var err error
|
||
|
|
- opts, err := b.getSaveOptions(req)
|
||
|
|
- if err != nil {
|
||
|
|
- return errors.Wrap(err, "process save options failed")
|
||
|
|
- }
|
||
|
|
-
|
||
|
|
- if err = checkFormat(&opts); err != nil {
|
||
|
|
- return err
|
||
|
|
- }
|
||
|
|
- if err = filterImageName(&opts); err != nil {
|
||
|
|
- return err
|
||
|
|
+ opts := b.getSaveOptions(req)
|
||
|
|
+ if err = opts.check(); err != nil {
|
||
|
|
+ return errors.Wrap(err, "check save options failed")
|
||
|
|
}
|
||
|
|
|
||
|
|
defer func() {
|
||
|
|
@@ -299,7 +278,47 @@ func messageHandler(stream pb.Control_SaveServer, cliLogger *logger.Logger) func
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
-func checkFormat(opts *saveOptions) error {
|
||
|
|
+func (opts *saveOptions) check() error {
|
||
|
|
+ if err := opts.checkImageNameIsID(); err != nil {
|
||
|
|
+ return err
|
||
|
|
+ }
|
||
|
|
+ if err := opts.checkFormat(); err != nil {
|
||
|
|
+ return err
|
||
|
|
+ }
|
||
|
|
+ if err := opts.filterImageName(); err != nil {
|
||
|
|
+ return err
|
||
|
|
+ }
|
||
|
|
+ if err := opts.checkRenameFile(); err != nil {
|
||
|
|
+ return err
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ return nil
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+func (opts *saveOptions) checkImageNameIsID() error {
|
||
|
|
+ imageNames := opts.oriImgList
|
||
|
|
+ if opts.sep.enabled {
|
||
|
|
+ if len(opts.sep.base) != 0 {
|
||
|
|
+ imageNames = append(imageNames, opts.sep.base)
|
||
|
|
+ }
|
||
|
|
+ if len(opts.sep.lib) != 0 {
|
||
|
|
+ imageNames = append(imageNames, opts.sep.lib)
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ for _, name := range imageNames {
|
||
|
|
+ _, img, err := image.FindImage(opts.localStore, name)
|
||
|
|
+ if err != nil {
|
||
|
|
+ return errors.Wrapf(err, "check image name failed when finding image name %q", name)
|
||
|
|
+ }
|
||
|
|
+ if strings.HasPrefix(img.ID, name) && opts.sep.enabled {
|
||
|
|
+ return errors.Errorf("using image ID %q as image name to save separated image is not allowed", name)
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ return nil
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+func (opts *saveOptions) checkFormat() error {
|
||
|
|
switch opts.format {
|
||
|
|
case constant.DockerTransport:
|
||
|
|
opts.format = constant.DockerArchiveTransport
|
||
|
|
@@ -312,7 +331,7 @@ func checkFormat(opts *saveOptions) error {
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
-func filterImageName(opts *saveOptions) error {
|
||
|
|
+func (opts *saveOptions) filterImageName() error {
|
||
|
|
if opts.format == constant.OCIArchiveTransport {
|
||
|
|
opts.finalImageOrdered = opts.oriImgList
|
||
|
|
return nil
|
||
|
|
@@ -350,6 +369,18 @@ func filterImageName(opts *saveOptions) error {
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
+func (opts *saveOptions) checkRenameFile() error {
|
||
|
|
+ if len(opts.sep.renameFile) != 0 {
|
||
|
|
+ var reName []renames
|
||
|
|
+ if err := util.LoadJSONFile(opts.sep.renameFile, &reName); err != nil {
|
||
|
|
+ return errors.Wrap(err, "check rename file failed")
|
||
|
|
+ }
|
||
|
|
+ opts.sep.renameData = reName
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ return nil
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
func getLayerHashFromStorage(store *store.Store, name string) ([]string, error) {
|
||
|
|
if len(name) == 0 {
|
||
|
|
return nil, nil
|
||
|
|
@@ -770,6 +801,11 @@ func getLayersID(layer []string) []string {
|
||
|
|
|
||
|
|
func (s *separatorSave) constructSingleImgInfo(mani imageManifest, store *store.Store) (imageInfo, error) {
|
||
|
|
var libLayers, appLayers []string
|
||
|
|
+ // image name should not be empty here
|
||
|
|
+ if len(mani.RepoTags) == 0 {
|
||
|
|
+ return imageInfo{}, errors.New("image name and tag is empty")
|
||
|
|
+ }
|
||
|
|
+ // if there is more than one repoTag, will use first one as image name
|
||
|
|
imageRepoFields := strings.Split(mani.RepoTags[0], ":")
|
||
|
|
imageLayers := getLayersID(mani.Layers)
|
||
|
|
|
||
|
|
diff --git a/tests/src/cover_test_save_separated_image_failed.sh b/tests/src/cover_test_save_separated_image_failed.sh
|
||
|
|
index c64dcf5..66db580 100644
|
||
|
|
--- a/tests/src/cover_test_save_separated_image_failed.sh
|
||
|
|
+++ b/tests/src/cover_test_save_separated_image_failed.sh
|
||
|
|
@@ -89,6 +89,33 @@ function test_run6() {
|
||
|
|
rm -rf "${workspace}"/Images
|
||
|
|
}
|
||
|
|
|
||
|
|
+# using image id to save
|
||
|
|
+function test_run7() {
|
||
|
|
+ base_image_id=$(isula-build ctr-img images ${base_image_name} | tail -n 2 | head -n 1 | awk '{print $3}')
|
||
|
|
+ lib_image_id=$(isula-build ctr-img images ${lib_image_name} | tail -n 2 | head -n 1 | awk '{print $3}')
|
||
|
|
+ app_image_id=$(isula-build ctr-img images ${app1_image_name} | tail -n 2 | head -n 1 | awk '{print $3}')
|
||
|
|
+ app1_image_id=$(isula-build ctr-img images ${app2_image_name} | tail -n 2 | head -n 1 | awk '{print $3}')
|
||
|
|
+ # all name is image id
|
||
|
|
+ isula-build ctr-img save -b "${base_image_id}" -l "${lib_image_id}" -d "${workspace}"/Images "${app1_image_id}" "${app2_image_id}"
|
||
|
|
+ check_result_not_equal $? 0
|
||
|
|
+ rm -rf "${workspace}"/Images
|
||
|
|
+
|
||
|
|
+ # app name is image id
|
||
|
|
+ isula-build ctr-img save -b "${base_image_name}" -l "${lib_image_name}" -d "${workspace}"/Images "${app1_image_id}" "${app2_image_name}"
|
||
|
|
+ check_result_not_equal $? 0
|
||
|
|
+ rm -rf "${workspace}"/Images
|
||
|
|
+
|
||
|
|
+ # lib name is image id
|
||
|
|
+ isula-build ctr-img save -b "${base_image_name}" -l "${lib_image_id}" -d "${workspace}"/Images "${app1_image_name}" "${app2_image_name}"
|
||
|
|
+ check_result_not_equal $? 0
|
||
|
|
+ rm -rf "${workspace}"/Images
|
||
|
|
+
|
||
|
|
+ # base name is image id
|
||
|
|
+ isula-build ctr-img save -b "${base_image_id}" -l "${lib_image_name}" -d "${workspace}"/Images "${app1_image_name}" "${app2_image_name}"
|
||
|
|
+ check_result_not_equal $? 0
|
||
|
|
+ rm -rf "${workspace}"/Images
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
function cleanup() {
|
||
|
|
rm -rf "${workspace}"
|
||
|
|
isula-build ctr-img rm "${bad_lib_image_name}" "${bad_app1_image_name}" "${bad_app2_image_name}" "${lib_image_name}" "${app1_image_name}" "${app2_image_name}"
|
||
|
|
@@ -102,6 +129,7 @@ test_run3
|
||
|
|
test_run4
|
||
|
|
test_run5
|
||
|
|
test_run6
|
||
|
|
+test_run7
|
||
|
|
cleanup
|
||
|
|
# shellcheck disable=SC2154
|
||
|
|
exit "${exit_flag}"
|
||
|
|
diff --git a/tests/src/cover_test_save_separated_image_success.sh b/tests/src/cover_test_save_separated_image_success.sh
|
||
|
|
index 2095bd3..68d2cae 100644
|
||
|
|
--- a/tests/src/cover_test_save_separated_image_success.sh
|
||
|
|
+++ b/tests/src/cover_test_save_separated_image_success.sh
|
||
|
|
@@ -26,6 +26,11 @@ function pre_run() {
|
||
|
|
lib_image_name="lib:latest"
|
||
|
|
app1_image_name="app1:latest"
|
||
|
|
app2_image_name="app2:latest"
|
||
|
|
+ base_image_short_name="b:latest"
|
||
|
|
+ lib_image_short_name="l:latest"
|
||
|
|
+ app1_image_short_name="a:latest"
|
||
|
|
+ app2_image_short_name="c:latest"
|
||
|
|
+
|
||
|
|
lib_layer_number=5
|
||
|
|
app1_layer_number=4
|
||
|
|
app2_layer_number=3
|
||
|
|
@@ -37,18 +42,31 @@ function pre_run() {
|
||
|
|
build_image "${app2_image_name}" "${workspace}"
|
||
|
|
}
|
||
|
|
|
||
|
|
-function test_run() {
|
||
|
|
+function test_run1() {
|
||
|
|
isula-build ctr-img save -b "${base_image_name}" -l "${lib_image_name}" -d "${workspace}"/Images "${app1_image_name}" "${app2_image_name}"
|
||
|
|
check_result_equal $? 0
|
||
|
|
+ rm -rf "${workspace}"
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+# use short image name
|
||
|
|
+function test_run2() {
|
||
|
|
+ isula-build ctr-img tag "${base_image_name}" "${base_image_short_name}"
|
||
|
|
+ isula-build ctr-img tag "${lib_image_name}" "${lib_image_short_name}"
|
||
|
|
+ isula-build ctr-img tag "${app1_image_name}" "${app1_image_short_name}"
|
||
|
|
+ isula-build ctr-img tag "${app2_image_name}" "${app2_image_short_name}"
|
||
|
|
+ isula-build ctr-img save -b "${base_image_short_name}" -l "${lib_image_short_name}" -d "${workspace}"/Images "${app1_image_short_name}" "${app2_image_short_name}"
|
||
|
|
+ check_result_equal $? 0
|
||
|
|
+ rm -rf "${workspace}"
|
||
|
|
}
|
||
|
|
|
||
|
|
function cleanup() {
|
||
|
|
rm -rf "${workspace}"
|
||
|
|
- isula-build ctr-img rm "${lib_image_name}" "${app1_image_name}" "${app2_image_name}"
|
||
|
|
+ isula-build ctr-img rm "${lib_image_name}" "${app1_image_name}" "${app2_image_name}" "${base_image_short_name}" "${lib_image_short_name}" "${app1_image_short_name}" "${app2_image_short_name}"
|
||
|
|
}
|
||
|
|
|
||
|
|
pre_run
|
||
|
|
-test_run
|
||
|
|
+test_run1
|
||
|
|
+test_run2
|
||
|
|
cleanup
|
||
|
|
# shellcheck disable=SC2154
|
||
|
|
exit "${exit_flag}"
|
||
|
|
--
|
||
|
|
1.8.3.1
|
||
|
|
|