From b575a9ae9970bbdafe132f1ac73db1d0b7ee50ba Mon Sep 17 00:00:00 2001
From: DCCooper <1866858@gmail.com>
Date: Wed, 19 May 2021 09:36:12 +0800
Subject: [PATCH 4/5] hack: make isula-build binary static

Signed-off-by: DCCooper <1866858@gmail.com>
---
 Makefile                           |  5 +-
 builder/dockerfile/builder.go      | 12 ++---
 cmd/cli/build.go                   | 17 +++----
 cmd/cli/build_test.go              |  7 ++-
 cmd/cli/import.go                  | 10 +---
 cmd/cli/pull.go                    |  8 +---
 cmd/cli/pull_test.go               | 12 -----
 cmd/cli/push.go                    | 13 ++----
 cmd/cli/push_test.go               | 14 ------
 cmd/cli/save.go                    | 10 ++--
 constant.go                        | 14 ++++++
 daemon/import.go                   |  7 +++
 daemon/load.go                     | 10 ++--
 daemon/pull.go                     |  5 ++
 daemon/push.go                     | 13 ++++--
 daemon/save.go                     |  8 ++--
 exporter/common.go                 | 30 ++----------
 exporter/common_test.go            | 88 ++++-------------------------------
 exporter/docker/archive/archive.go |  3 +-
 exporter/docker/daemon/daemon.go   |  3 +-
 exporter/docker/docker.go          |  3 +-
 exporter/exporter.go               | 23 ----------
 exporter/isulad/isulad.go          |  2 +-
 exporter/manifest/manifest.go      |  3 +-
 exporter/oci/archive/archive.go    |  3 +-
 exporter/oci/oci.go                |  3 +-
 image/image.go                     | 14 +++---
 image/image_test.go                |  5 +-
 pkg/manifest/list.go               |  3 +-
 util/util.go                       | 49 ++++++++++++++++++++
 util/util_test.go                  | 94 ++++++++++++++++++++++++++++++++++++++
 31 files changed, 254 insertions(+), 237 deletions(-)

diff --git a/Makefile b/Makefile
index cbace59..e03254c 100644
--- a/Makefile
+++ b/Makefile
@@ -22,7 +22,8 @@ BUILDTAGS := seccomp
 BUILDFLAGS := -tags "$(BUILDTAGS)"
 TMPDIR := /tmp/isula_build_tmpdir
 BEFLAG := -tmpdir=${TMPDIR}
-SAFEBUILDFLAGS := -buildid=IdByIsula -buildmode=pie -extldflags=-ftrapv -extldflags=-static -extldflags=-zrelro -extldflags=-znow $(LDFLAGS) $(BEFLAG)
+SAFEBUILDFLAGS := -buildid=IdByIsula -buildmode=pie -extldflags=-ftrapv -extldflags=-zrelro -extldflags=-znow $(BEFLAG) $(LDFLAGS)
+STATIC_LDFLAGS := -linkmode=external -extldflags=-static
 
 IMAGE_BUILDARGS := $(if $(http_proxy), --build-arg http_proxy=$(http_proxy))
 IMAGE_BUILDARGS += $(if $(https_proxy), --build-arg https_proxy=$(https_proxy))
@@ -56,7 +57,7 @@ isula-builder: ./cmd/daemon
 safe:
 	@echo "Safe building isula-build..."
 	mkdir -p ${TMPDIR}
-	$(GO_BUILD) -ldflags '$(SAFEBUILDFLAGS)' -o bin/isula-build $(BUILDFLAGS) ./cmd/cli
+	$(GO_BUILD) -ldflags '$(SAFEBUILDFLAGS) $(STATIC_LDFLAGS)' -o bin/isula-build $(BUILDFLAGS) ./cmd/cli 2>/dev/null
 	$(GO_BUILD) -ldflags '$(SAFEBUILDFLAGS)' -o bin/isula-builder $(BUILDFLAGS) ./cmd/daemon
 	@echo "Safe build isula-build done!"
 
diff --git a/builder/dockerfile/builder.go b/builder/dockerfile/builder.go
index 4222974..cbd1e58 100644
--- a/builder/dockerfile/builder.go
+++ b/builder/dockerfile/builder.go
@@ -159,11 +159,11 @@ func NewBuilder(ctx context.Context, store *store.Store, req *pb.BuildRequest, r
 }
 
 func (b *Builder) parseFormat(format string) error {
-	if err := exporter.CheckImageFormat(format); err != nil {
+	if err := util.CheckImageFormat(format); err != nil {
 		return err
 	}
 
-	if format == exporter.OCITransport {
+	if format == constant.OCITransport {
 		b.manifestType = imgspecv1.MediaTypeImageManifest
 	}
 
@@ -183,12 +183,12 @@ func (b *Builder) parseOutputManifest(output []string) error {
 		}
 
 		transport := segments[0]
-		if transport == exporter.OCITransport {
+		if transport == constant.OCITransport {
 			// When transport is oci, still, we need to set b.buildOpts.Output[i] starting with prefix "docker://". We only need to set the related b.outputManifestType.
 			// As a result, we can push oci format image into registry. When with prefix "oci://", image is exported to local dir, which is not what we expect.
 			// See github.com/containers/image package for more information.
 			b.outputManifestType = append(b.outputManifestType, imgspecv1.MediaTypeImageManifest)
-			b.buildOpts.Output[i] = fmt.Sprintf("%s:%s", exporter.DockerTransport, segments[1])
+			b.buildOpts.Output[i] = fmt.Sprintf("%s:%s", constant.DockerTransport, segments[1])
 		}
 		b.outputManifestType = append(b.outputManifestType, manifest.DockerV2Schema2MediaType)
 	}
@@ -617,11 +617,11 @@ func parseOutputTag(output string) string {
 
 	var tag string
 	switch {
-	case (outputFields[0] == exporter.DockerDaemonTransport || outputFields[0] == exporter.IsuladTransport) && len(outputFields) > 1:
+	case (outputFields[0] == constant.DockerDaemonTransport || outputFields[0] == constant.IsuladTransport) && len(outputFields) > 1:
 		tag = strings.Join(outputFields[1:], ":")
 	case exporter.CheckArchiveFormat(outputFields[0]) == nil && len(outputFields) > archiveOutputWithoutTagLen:
 		tag = strings.Join(outputFields[archiveOutputWithoutTagLen:], ":")
-	case exporter.CheckImageFormat(outputFields[0]) == nil && len(outputFields) > 1:
+	case util.CheckImageFormat(outputFields[0]) == nil && len(outputFields) > 1:
 		repoAndTag := strings.Join(outputFields[1:], ":")
 		// repo format regexp, "//registry.example.com/" for example
 		repo := regexp.MustCompile(`^\/\/[\w\.\-\:]+\/`).FindString(repoAndTag)
diff --git a/cmd/cli/build.go b/cmd/cli/build.go
index decf285..3d9f549 100644
--- a/cmd/cli/build.go
+++ b/cmd/cli/build.go
@@ -25,7 +25,6 @@ import (
 	"strings"
 	"time"
 
-	"github.com/containers/storage/pkg/stringid"
 	"github.com/gogo/protobuf/types"
 	"github.com/opencontainers/go-digest"
 	"github.com/pkg/errors"
@@ -35,8 +34,6 @@ import (
 
 	constant "isula.org/isula-build"
 	pb "isula.org/isula-build/api/services"
-	"isula.org/isula-build/exporter"
-	_ "isula.org/isula-build/exporter/register"
 	"isula.org/isula-build/pkg/opts"
 	"isula.org/isula-build/util"
 )
@@ -107,7 +104,7 @@ func NewBuildCmd() *cobra.Command {
 	if util.CheckCliExperimentalEnabled() {
 		buildCmd.PersistentFlags().StringVar(&buildOpts.format, "format", "oci", "Image format of the built image")
 	} else {
-		buildOpts.format = exporter.DockerTransport
+		buildOpts.format = constant.DockerTransport
 	}
 	buildCmd.PersistentFlags().StringVarP(&buildOpts.output, "output", "o", "", "Destination of output images")
 	buildCmd.PersistentFlags().BoolVar(&buildOpts.proxyFlag, "proxy", true, "Inherit proxy environment variables from host")
@@ -161,7 +158,7 @@ func buildCommand(c *cobra.Command, args []string) error {
 
 func newBuildOptions(args []string) error {
 	// unique buildID for each build progress
-	buildOpts.buildID = stringid.GenerateNonCryptoID()[:constant.DefaultIDLen]
+	buildOpts.buildID = util.GenerateNonCryptoID()[:constant.DefaultIDLen]
 
 	if len(args) < 1 {
 		// use current working directory as default context directory
@@ -219,7 +216,7 @@ func checkOutput(output string) ([]string, error) {
 	if len(transport) == 0 {
 		return nil, errors.New("transport should not be empty")
 	}
-	if !exporter.IsSupport(transport) {
+	if !util.IsSupportExporter(transport) {
 		return nil, errors.Errorf("transport %q not support", transport)
 	}
 
@@ -248,12 +245,12 @@ func checkAbsPath(path string) (string, error) {
 func modifyLocalTransporter(transport string, absPath string, segments []string) error {
 	const validIsuladFieldsLen = 3
 	switch transport {
-	case exporter.DockerArchiveTransport, exporter.OCIArchiveTransport:
+	case constant.DockerArchiveTransport, constant.OCIArchiveTransport:
 		newSeg := util.CopyStrings(segments)
 		newSeg[1] = absPath
 		buildOpts.output = strings.Join(newSeg, ":")
 		return nil
-	case exporter.IsuladTransport:
+	case constant.IsuladTransport:
 		if len(segments) != validIsuladFieldsLen {
 			return errors.Errorf("invalid isulad output format: %v", buildOpts.output)
 		}
@@ -275,7 +272,7 @@ func checkAndProcessOutput() error {
 
 	transport := segments[0]
 	// just build, not need to export to any destination
-	if !exporter.IsClientExporter(transport) {
+	if !util.IsClientExporter(transport) {
 		return nil
 	}
 
@@ -325,7 +322,7 @@ func runBuild(ctx context.Context, cli Cli) (string, error) {
 		digest          string
 	)
 
-	if err = exporter.CheckImageFormat(buildOpts.format); err != nil {
+	if err = util.CheckImageFormat(buildOpts.format); err != nil {
 		return "", err
 	}
 	if err = checkAndProcessOutput(); err != nil {
diff --git a/cmd/cli/build_test.go b/cmd/cli/build_test.go
index fcdf6b4..a7fe64e 100644
--- a/cmd/cli/build_test.go
+++ b/cmd/cli/build_test.go
@@ -25,7 +25,6 @@ import (
 	"gotest.tools/v3/fs"
 
 	constant "isula.org/isula-build"
-	"isula.org/isula-build/exporter"
 	_ "isula.org/isula-build/exporter/register"
 	"isula.org/isula-build/util"
 )
@@ -175,7 +174,7 @@ func TestRunBuildWithNArchiveExporter(t *testing.T) {
 			format:   "docker",
 		},
 		{
-			exporter: exporter.OCIArchiveTransport,
+			exporter: constant.OCIArchiveTransport,
 			descSpec: "oci-archive:isula:latest",
 			format:   "oci",
 		},
@@ -222,12 +221,12 @@ func TestRunBuildWithArchiveExporter(t *testing.T) {
 
 	var testcases = []testcase{
 		{
-			exporter: exporter.DockerArchiveTransport,
+			exporter: constant.DockerArchiveTransport,
 			descSpec: "docker-archive:/tmp/image:isula:latest",
 			format:   "docker",
 		},
 		{
-			exporter: exporter.OCIArchiveTransport,
+			exporter: constant.OCIArchiveTransport,
 			descSpec: "oci-archive:/tmp/image:isula:latest",
 			format:   "oci",
 		},
diff --git a/cmd/cli/import.go b/cmd/cli/import.go
index 320197b..96263db 100644
--- a/cmd/cli/import.go
+++ b/cmd/cli/import.go
@@ -20,8 +20,6 @@ import (
 	"os"
 	"path/filepath"
 
-	dockerref "github.com/containers/image/v5/docker/reference"
-	"github.com/containers/storage/pkg/stringid"
 	"github.com/pkg/errors"
 	"github.com/spf13/cobra"
 
@@ -76,12 +74,6 @@ func importCommand(c *cobra.Command, args []string) error {
 }
 
 func runImport(ctx context.Context, cli Cli) error {
-	if importOpts.reference != "" {
-		if _, err := dockerref.Parse(importOpts.reference); err != nil {
-			return err
-		}
-	}
-
 	if !filepath.IsAbs(importOpts.source) {
 		pwd, err := os.Getwd()
 		if err != nil {
@@ -90,7 +82,7 @@ func runImport(ctx context.Context, cli Cli) error {
 		importOpts.source = util.MakeAbsolute(importOpts.source, pwd)
 	}
 
-	importOpts.importID = stringid.GenerateNonCryptoID()[:constant.DefaultIDLen]
+	importOpts.importID = util.GenerateNonCryptoID()[:constant.DefaultIDLen]
 
 	stream, err := cli.Client().Import(ctx, &pb.ImportRequest{
 		Source:    importOpts.source,
diff --git a/cmd/cli/pull.go b/cmd/cli/pull.go
index 316c548..02951ec 100644
--- a/cmd/cli/pull.go
+++ b/cmd/cli/pull.go
@@ -18,13 +18,12 @@ import (
 	"fmt"
 	"io"
 
-	dockerref "github.com/containers/image/v5/docker/reference"
-	"github.com/containers/storage/pkg/stringid"
 	"github.com/pkg/errors"
 	"github.com/spf13/cobra"
 
 	constant "isula.org/isula-build"
 	pb "isula.org/isula-build/api/services"
+	"isula.org/isula-build/util"
 )
 
 const (
@@ -46,9 +45,6 @@ func pullCommand(c *cobra.Command, args []string) error {
 	if len(args) != 1 {
 		return errors.New("pull requires exactly one argument")
 	}
-	if _, err := dockerref.Parse(args[0]); err != nil {
-		return err
-	}
 
 	ctx := context.TODO()
 	cli, err := NewClient(ctx)
@@ -60,7 +56,7 @@ func pullCommand(c *cobra.Command, args []string) error {
 }
 
 func runPull(ctx context.Context, cli Cli, imageName string) error {
-	pullID := stringid.GenerateNonCryptoID()[:constant.DefaultIDLen]
+	pullID := util.GenerateNonCryptoID()[:constant.DefaultIDLen]
 
 	pullStream, err := cli.Client().Pull(ctx, &pb.PullRequest{
 		PullID:    pullID,
diff --git a/cmd/cli/pull_test.go b/cmd/cli/pull_test.go
index a4dbd04..0a11b0b 100644
--- a/cmd/cli/pull_test.go
+++ b/cmd/cli/pull_test.go
@@ -40,18 +40,6 @@ func TestPullCommand(t *testing.T) {
 			wantErr:   true,
 			errString: "pull requires exactly one argument",
 		},
-		{
-			name:      "abnormal case with empty args",
-			args:      []string{""},
-			wantErr:   true,
-			errString: "repository name must have at least one component",
-		},
-		{
-			name:      "abnormal case with invalid args",
-			args:      []string{"busybox-:latest"},
-			wantErr:   true,
-			errString: "invalid reference format",
-		},
 	}
 
 	for _, tc := range testcases {
diff --git a/cmd/cli/push.go b/cmd/cli/push.go
index 7502abd..061c17b 100644
--- a/cmd/cli/push.go
+++ b/cmd/cli/push.go
@@ -18,14 +18,11 @@ import (
 	"fmt"
 	"io"
 
-	dockerref "github.com/containers/image/v5/docker/reference"
-	"github.com/containers/storage/pkg/stringid"
 	"github.com/pkg/errors"
 	"github.com/spf13/cobra"
 
 	constant "isula.org/isula-build"
 	pb "isula.org/isula-build/api/services"
-	"isula.org/isula-build/exporter"
 	"isula.org/isula-build/util"
 )
 
@@ -50,7 +47,7 @@ func NewPushCmd() *cobra.Command {
 	if util.CheckCliExperimentalEnabled() {
 		pushCmd.PersistentFlags().StringVarP(&pushOpts.format, "format", "f", "oci", "Format for image pushing to a registry")
 	} else {
-		pushOpts.format = exporter.DockerTransport
+		pushOpts.format = constant.DockerTransport
 	}
 	return pushCmd
 }
@@ -59,10 +56,8 @@ func pushCommand(c *cobra.Command, args []string) error {
 	if len(args) != 1 {
 		return errors.New("push requires exactly one argument")
 	}
-	if _, err := dockerref.Parse(args[0]); err != nil {
-		return err
-	}
-	if err := exporter.CheckImageFormat(pushOpts.format); err != nil {
+
+	if err := util.CheckImageFormat(pushOpts.format); err != nil {
 		return err
 	}
 
@@ -76,7 +71,7 @@ func pushCommand(c *cobra.Command, args []string) error {
 }
 
 func runPush(ctx context.Context, cli Cli, imageName string) error {
-	pushID := stringid.GenerateNonCryptoID()[:constant.DefaultIDLen]
+	pushID := util.GenerateNonCryptoID()[:constant.DefaultIDLen]
 
 	pushStream, err := cli.Client().Push(ctx, &pb.PushRequest{
 		PushID:    pushID,
diff --git a/cmd/cli/push_test.go b/cmd/cli/push_test.go
index 0f8db2e..27caef3 100644
--- a/cmd/cli/push_test.go
+++ b/cmd/cli/push_test.go
@@ -43,20 +43,6 @@ func TestPushCommand(t *testing.T) {
 			errString: "push requires exactly one argument",
 		},
 		{
-			name:      "abnormal case with empty args",
-			args:      []string{""},
-			format:    "docker",
-			wantErr:   true,
-			errString: "repository name must have at least one component",
-		},
-		{
-			name:      "abnormal case with invalid args",
-			args:      []string{"busybox-:latest"},
-			format:    "oci",
-			wantErr:   true,
-			errString: "invalid reference format",
-		},
-		{
 			name:      "normal case with image format oci",
 			args:      []string{"openeuler:latest"},
 			format:    "oci",
diff --git a/cmd/cli/save.go b/cmd/cli/save.go
index fe67673..cb78ecf 100644
--- a/cmd/cli/save.go
+++ b/cmd/cli/save.go
@@ -21,13 +21,11 @@ import (
 	"path/filepath"
 	"strings"
 
-	"github.com/containers/storage/pkg/stringid"
 	"github.com/pkg/errors"
 	"github.com/spf13/cobra"
 
 	constant "isula.org/isula-build"
 	pb "isula.org/isula-build/api/services"
-	"isula.org/isula-build/exporter"
 	"isula.org/isula-build/util"
 )
 
@@ -59,7 +57,7 @@ func NewSaveCmd() *cobra.Command {
 	if util.CheckCliExperimentalEnabled() {
 		saveCmd.PersistentFlags().StringVarP(&saveOpts.format, "format", "f", "oci", "Format of image saving to local tarball")
 	} else {
-		saveOpts.format = exporter.DockerTransport
+		saveOpts.format = constant.DockerTransport
 	}
 
 	return saveCmd
@@ -72,10 +70,10 @@ 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 {
+	if saveOpts.format == constant.OCITransport && len(args) >= 2 {
 		return errors.New("oci image format now only supports saving single image")
 	}
-	if err := exporter.CheckImageFormat(saveOpts.format); err != nil {
+	if err := util.CheckImageFormat(saveOpts.format); err != nil {
 		return err
 	}
 	if err := checkSavePath(); err != nil {
@@ -115,7 +113,7 @@ func checkSavePath() error {
 }
 
 func runSave(ctx context.Context, cli Cli, args []string) error {
-	saveOpts.saveID = stringid.GenerateNonCryptoID()[:constant.DefaultIDLen]
+	saveOpts.saveID = util.GenerateNonCryptoID()[:constant.DefaultIDLen]
 	saveOpts.images = args
 
 	saveStream, err := cli.Client().Save(ctx, &pb.SaveRequest{
diff --git a/constant.go b/constant.go
index 30c1653..9926728 100644
--- a/constant.go
+++ b/constant.go
@@ -75,6 +75,20 @@ const (
 	BuildContainerImageType = "ctr-img"
 	// BufferSize is default buffer size for file transportation
 	BufferSize = 32 * 1024
+	// DockerTransport used to export docker image format images to registry
+	DockerTransport = "docker"
+	// DockerArchiveTransport used to export docker image format images to local tarball
+	DockerArchiveTransport = "docker-archive"
+	// DockerDaemonTransport used to export images to docker daemon
+	DockerDaemonTransport = "docker-daemon"
+	// OCITransport used to export oci image format images to registry
+	OCITransport = "oci"
+	// OCIArchiveTransport used to export oci image format images to local tarball
+	OCIArchiveTransport = "oci-archive"
+	// IsuladTransport use to export images to isulad
+	IsuladTransport = "isulad"
+	// ManifestTransport used to export manifest list
+	ManifestTransport = "manifest"
 )
 
 var (
diff --git a/daemon/import.go b/daemon/import.go
index 3d7c0d0..40a0a92 100644
--- a/daemon/import.go
+++ b/daemon/import.go
@@ -18,6 +18,7 @@ import (
 	"path/filepath"
 
 	cp "github.com/containers/image/v5/copy"
+	dockerref "github.com/containers/image/v5/docker/reference"
 	is "github.com/containers/image/v5/storage"
 	"github.com/containers/image/v5/tarball"
 	"github.com/containers/image/v5/transports"
@@ -49,6 +50,12 @@ func (b *Backend) Import(req *pb.ImportRequest, stream pb.Control_ImportServer)
 	logEntry := logrus.WithFields(logrus.Fields{"ImportID": importID})
 	logEntry.Info("ImportRequest received")
 
+	if reference != "" {
+		if _, err := dockerref.Parse(reference); err != nil {
+			return err
+		}
+	}
+
 	tmpName := importID + "-import-tmp"
 	dstRef, err := is.Transport.ParseStoreReference(localStore, tmpName)
 	if err != nil {
diff --git a/daemon/load.go b/daemon/load.go
index b557d38..f2d818f 100644
--- a/daemon/load.go
+++ b/daemon/load.go
@@ -127,16 +127,16 @@ func tryToParseImageFormatFromTarball(dataRoot string, opts *loadOptions) ([][]s
 
 	allRepoTags, err = getDockerRepoTagFromImageTar(systemContext, opts.path)
 	if err == nil {
-		logrus.Infof("Parse image successful with %q format", exporter.DockerTransport)
-		opts.format = exporter.DockerArchiveTransport
+		logrus.Infof("Parse image successful with %q format", constant.DockerTransport)
+		opts.format = constant.DockerArchiveTransport
 		return allRepoTags, nil
 	}
 	logrus.Warnf("Try to Parse image of docker format failed with error: %v", err)
 
 	allRepoTags, err = getOCIRepoTagFromImageTar(systemContext, opts.path)
 	if err == nil {
-		logrus.Infof("Parse image successful with %q format", exporter.OCITransport)
-		opts.format = exporter.OCIArchiveTransport
+		logrus.Infof("Parse image successful with %q format", constant.OCITransport)
+		opts.format = constant.OCIArchiveTransport
 		return allRepoTags, nil
 	}
 	logrus.Warnf("Try to parse image of oci format failed with error: %v", err)
@@ -170,7 +170,7 @@ func getOCIRepoTagFromImageTar(systemContext *types.SystemContext, path string)
 		err error
 	)
 
-	srcRef, err := alltransports.ParseImageName(exporter.FormatTransport(exporter.OCIArchiveTransport, path))
+	srcRef, err := alltransports.ParseImageName(exporter.FormatTransport(constant.OCIArchiveTransport, path))
 	if err != nil {
 		return nil, errors.Wrapf(err, "failed to parse image name of oci image format")
 	}
diff --git a/daemon/pull.go b/daemon/pull.go
index 56be755..6d2e33d 100644
--- a/daemon/pull.go
+++ b/daemon/pull.go
@@ -16,6 +16,7 @@ package daemon
 import (
 	"context"
 
+	dockerref "github.com/containers/image/v5/docker/reference"
 	"github.com/containers/image/v5/types"
 	"github.com/pkg/errors"
 	"github.com/sirupsen/logrus"
@@ -53,6 +54,10 @@ func (b *Backend) Pull(req *pb.PullRequest, stream pb.Control_PullServer) error
 		imageName:  req.GetImageName(),
 	}
 
+	if _, err := dockerref.Parse(opt.imageName); err != nil {
+		return err
+	}
+
 	ctx := context.WithValue(stream.Context(), util.LogFieldKey(util.LogKeySessionID), req.GetPullID())
 	eg, egCtx := errgroup.WithContext(ctx)
 	eg.Go(pullHandler(egCtx, opt))
diff --git a/daemon/push.go b/daemon/push.go
index 4e3a6ed..e36198d 100644
--- a/daemon/push.go
+++ b/daemon/push.go
@@ -16,6 +16,7 @@ package daemon
 import (
 	"context"
 
+	dockerref "github.com/containers/image/v5/docker/reference"
 	"github.com/containers/image/v5/types"
 	"github.com/pkg/errors"
 	"github.com/sirupsen/logrus"
@@ -59,7 +60,11 @@ func (b *Backend) Push(req *pb.PushRequest, stream pb.Control_PushServer) error
 		format:     req.GetFormat(),
 	}
 
-	if err := exporter.CheckImageFormat(opt.format); err != nil {
+	if err := util.CheckImageFormat(opt.format); err != nil {
+		return err
+	}
+
+	if _, err := dockerref.Parse(opt.imageName); err != nil {
 		return err
 	}
 
@@ -111,11 +116,11 @@ func pushHandler(ctx context.Context, options pushOptions) func() error {
 			ManifestType:  options.manifestType,
 		}
 
-		if err := exporter.Export(options.imageName, exporter.FormatTransport(exporter.DockerTransport, options.imageName),
+		if err := exporter.Export(options.imageName, exporter.FormatTransport(constant.DockerTransport, options.imageName),
 			exOpts, options.localStore); err != nil {
 			logrus.WithField(util.LogKeySessionID, options.pushID).
-				Errorf("Push image %q of format %q failed with %v", options.imageName, exporter.DockerTransport, err)
-			return errors.Wrapf(err, "push image %q of format %q failed", options.imageName, exporter.DockerTransport)
+				Errorf("Push image %q of format %q failed with %v", options.imageName, constant.DockerTransport, err)
+			return errors.Wrapf(err, "push image %q of format %q failed", options.imageName, constant.DockerTransport)
 		}
 
 		return nil
diff --git a/daemon/save.go b/daemon/save.go
index fd6174b..de644c3 100644
--- a/daemon/save.go
+++ b/daemon/save.go
@@ -71,10 +71,10 @@ func (b *Backend) Save(req *pb.SaveRequest, stream pb.Control_SaveServer) error
 	opts := b.getSaveOptions(req)
 
 	switch opts.format {
-	case exporter.DockerTransport:
-		opts.format = exporter.DockerArchiveTransport
-	case exporter.OCITransport:
-		opts.format = exporter.OCIArchiveTransport
+	case constant.DockerTransport:
+		opts.format = constant.DockerArchiveTransport
+	case constant.OCITransport:
+		opts.format = constant.OCIArchiveTransport
 	default:
 		return errors.New("wrong image format provided")
 	}
diff --git a/exporter/common.go b/exporter/common.go
index 8f390ac..bded6ec 100644
--- a/exporter/common.go
+++ b/exporter/common.go
@@ -209,17 +209,7 @@ func NewPolicyContext(sc *types.SystemContext) (*signature.PolicyContext, error)
 // CheckArchiveFormat used to check if save or load image format is either docker-archive or oci-archive
 func CheckArchiveFormat(format string) error {
 	switch format {
-	case DockerArchiveTransport, OCIArchiveTransport:
-		return nil
-	default:
-		return errors.New("wrong image format provided")
-	}
-}
-
-// CheckImageFormat used to check if the image format is either docker or oci
-func CheckImageFormat(format string) error {
-	switch format {
-	case DockerTransport, OCITransport:
+	case constant.DockerArchiveTransport, constant.OCIArchiveTransport:
 		return nil
 	default:
 		return errors.New("wrong image format provided")
@@ -228,7 +218,7 @@ func CheckImageFormat(format string) error {
 
 // FormatTransport for formatting transport with corresponding path
 func FormatTransport(transport, path string) string {
-	if transport == DockerTransport {
+	if transport == constant.DockerTransport {
 		return fmt.Sprintf("%s://%s", transport, path)
 	}
 	return fmt.Sprintf("%s:%s", transport, path)
@@ -238,23 +228,13 @@ func FormatTransport(transport, path string) string {
 func GetManifestType(format string) (string, error) {
 	var manifestType string
 	switch format {
-	case OCITransport:
+	case constant.OCITransport:
 		manifestType = imgspecv1.MediaTypeImageManifest
-	case DockerTransport:
+	case constant.DockerTransport:
 		manifestType = manifest.DockerV2Schema2MediaType
 	default:
-		return "", errors.Errorf("unknown format %q. Choose one of the supported formats: %s,%s", format, DockerTransport, OCITransport)
+		return "", errors.Errorf("unknown format %q. Choose one of the supported formats: %s,%s", format, constant.DockerTransport, constant.OCITransport)
 	}
 	return manifestType, nil
 }
 
-// IsClientExporter used to determinate exporter whether need to send the image to client
-func IsClientExporter(exporter string) bool {
-	clientExporters := map[string]bool{
-		DockerArchiveTransport: true,
-		OCIArchiveTransport:    true,
-		IsuladTransport:        true,
-	}
-	_, ok := clientExporters[exporter]
-	return ok
-}
diff --git a/exporter/common_test.go b/exporter/common_test.go
index ca29296..7434d3b 100644
--- a/exporter/common_test.go
+++ b/exporter/common_test.go
@@ -21,6 +21,8 @@ import (
 	imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
 	"gotest.tools/v3/assert"
 	"gotest.tools/v3/fs"
+
+	"isula.org/isula-build"
 )
 
 func TestFormatTransport(t *testing.T) {
@@ -36,13 +38,13 @@ func TestFormatTransport(t *testing.T) {
 	}{
 		{
 			name:      "docker format transport",
-			transport: DockerTransport,
+			transport: constant.DockerTransport,
 			path:      "registry.example.com/library/image:test",
 			result:    "docker://registry.example.com/library/image:test",
 		},
 		{
 			name:      "oci-archive format transport",
-			transport: OCIArchiveTransport,
+			transport: constant.OCIArchiveTransport,
 			path:      ociArchiveFilePath,
 			result:    "oci-archive:",
 		},
@@ -59,43 +61,6 @@ func TestFormatTransport(t *testing.T) {
 	}
 }
 
-func TestCheckImageFormat(t *testing.T) {
-	testcases := []struct {
-		name      string
-		format    string
-		wantErr   bool
-		errString string
-	}{
-		{
-			name:    "docker image format",
-			format:  DockerTransport,
-			wantErr: false,
-		},
-		{
-			name:    "oci image format",
-			format:  OCITransport,
-			wantErr: false,
-		},
-		{
-			name:    "unknown image format",
-			format:  "you guess",
-			wantErr: true,
-		},
-	}
-	for _, tc := range testcases {
-		t.Run(tc.name, func(t *testing.T) {
-			err := CheckImageFormat(tc.format)
-			if tc.wantErr {
-				assert.Error(t, err, "wrong image format provided")
-				return
-			}
-			if !tc.wantErr {
-				assert.NilError(t, err)
-			}
-		})
-	}
-}
-
 func TestCheckArchiveFormat(t *testing.T) {
 	testcases := []struct {
 		name      string
@@ -105,12 +70,12 @@ func TestCheckArchiveFormat(t *testing.T) {
 	}{
 		{
 			name:    "docker-archive image format",
-			format:  DockerArchiveTransport,
+			format:  constant.DockerArchiveTransport,
 			wantErr: false,
 		},
 		{
 			name:    "oci-archive imagee format",
-			format:  OCIArchiveTransport,
+			format:  constant.OCIArchiveTransport,
 			wantErr: false,
 		},
 		{
@@ -143,13 +108,13 @@ func TestGetManifestType(t *testing.T) {
 	}{
 		{
 			name:     "docker format manifest type",
-			format:   DockerTransport,
+			format:   constant.DockerTransport,
 			manifest: manifest.DockerV2Schema2MediaType,
 			wantErr:  false,
 		},
 		{
 			name:     "oci format manifest type",
-			format:   OCITransport,
+			format:   constant.OCITransport,
 			manifest: imgspecv1.MediaTypeImageManifest,
 			wantErr:  false,
 		},
@@ -173,40 +138,3 @@ func TestGetManifestType(t *testing.T) {
 	}
 }
 
-func TestIsClientExporter(t *testing.T) {
-	testcases := []struct {
-		name       string
-		exporter   string
-		wantResult bool
-	}{
-		{
-			name:       "normal docker archive exporter",
-			exporter:   DockerArchiveTransport,
-			wantResult: true,
-		},
-		{
-			name:       "normal oci archive exporter",
-			exporter:   OCIArchiveTransport,
-			wantResult: true,
-		},
-		{
-			name:       "normal isulad exporter",
-			exporter:   IsuladTransport,
-			wantResult: true,
-		},
-		{
-			name:       "abnormal unkown",
-			exporter:   "unkown",
-			wantResult: false,
-		},
-	}
-
-	for _, tc := range testcases {
-		t.Run(tc.name, func(t *testing.T) {
-			isExporter := IsClientExporter(tc.exporter)
-			if isExporter != tc.wantResult {
-				t.Fatal("test client exporter failed")
-			}
-		})
-	}
-}
diff --git a/exporter/docker/archive/archive.go b/exporter/docker/archive/archive.go
index 5da3f53..04654cf 100644
--- a/exporter/docker/archive/archive.go
+++ b/exporter/docker/archive/archive.go
@@ -25,6 +25,7 @@ import (
 	"github.com/pkg/errors"
 	"github.com/sirupsen/logrus"
 
+	constant "isula.org/isula-build"
 	"isula.org/isula-build/exporter"
 	"isula.org/isula-build/image"
 	"isula.org/isula-build/store"
@@ -47,7 +48,7 @@ var DockerArchiveExporter = dockerArchiveExporter{
 }
 
 func (d *dockerArchiveExporter) Name() string {
-	return exporter.DockerArchiveTransport
+	return constant.DockerArchiveTransport
 }
 
 func (d *dockerArchiveExporter) Init(opts exporter.ExportOptions, src, destSpec string, localStore *store.Store) error {
diff --git a/exporter/docker/daemon/daemon.go b/exporter/docker/daemon/daemon.go
index c7e06b7..308495c 100644
--- a/exporter/docker/daemon/daemon.go
+++ b/exporter/docker/daemon/daemon.go
@@ -21,6 +21,7 @@ import (
 	"github.com/containers/image/v5/types"
 	"github.com/pkg/errors"
 
+	constant "isula.org/isula-build"
 	"isula.org/isula-build/exporter"
 	"isula.org/isula-build/image"
 	"isula.org/isula-build/store"
@@ -40,7 +41,7 @@ var _dockerDaemonExporter = dockerDaemonExporter{
 }
 
 func (d *dockerDaemonExporter) Name() string {
-	return exporter.DockerDaemonTransport
+	return constant.DockerDaemonTransport
 }
 
 func (d *dockerDaemonExporter) Init(opts exporter.ExportOptions, src, destSpec string, localStore *store.Store) error {
diff --git a/exporter/docker/docker.go b/exporter/docker/docker.go
index e830811..987ee94 100644
--- a/exporter/docker/docker.go
+++ b/exporter/docker/docker.go
@@ -21,6 +21,7 @@ import (
 	"github.com/containers/image/v5/types"
 	"github.com/pkg/errors"
 
+	constant "isula.org/isula-build"
 	"isula.org/isula-build/exporter"
 	"isula.org/isula-build/image"
 	"isula.org/isula-build/store"
@@ -41,7 +42,7 @@ var _dockerExporter = dockerExporter{
 }
 
 func (d *dockerExporter) Name() string {
-	return exporter.DockerTransport
+	return constant.DockerTransport
 }
 
 func (d *dockerExporter) Init(opts exporter.ExportOptions, src, destSpec string, localStore *store.Store) error {
diff --git a/exporter/exporter.go b/exporter/exporter.go
index af1148f..60af001 100644
--- a/exporter/exporter.go
+++ b/exporter/exporter.go
@@ -21,29 +21,6 @@ import (
 	"isula.org/isula-build/store"
 )
 
-const (
-	// DockerTransport used to export docker image format images to registry
-	DockerTransport = "docker"
-
-	// DockerArchiveTransport used to export docker image format images to local tarball
-	DockerArchiveTransport = "docker-archive"
-
-	// DockerDaemonTransport used to export images to docker daemon
-	DockerDaemonTransport = "docker-daemon"
-
-	// OCITransport used to export oci image format images to registry
-	OCITransport = "oci"
-
-	// OCIArchiveTransport used to export oci image format images to local tarball
-	OCIArchiveTransport = "oci-archive"
-
-	// IsuladTransport use to export images to isulad
-	IsuladTransport = "isulad"
-
-	// ManifestTransport used to export manifest list
-	ManifestTransport = "manifest"
-)
-
 type exportHub struct {
 	items map[string]Exporter
 	sync.RWMutex
diff --git a/exporter/isulad/isulad.go b/exporter/isulad/isulad.go
index dd41d2d..73b0496 100644
--- a/exporter/isulad/isulad.go
+++ b/exporter/isulad/isulad.go
@@ -46,7 +46,7 @@ var _isuladExporter = isuladExporter{
 }
 
 func (d *isuladExporter) Name() string {
-	return exporter.IsuladTransport
+	return constant.IsuladTransport
 }
 
 func (d *isuladExporter) Init(opts exporter.ExportOptions, src, destSpec string, localStore *store.Store) error {
diff --git a/exporter/manifest/manifest.go b/exporter/manifest/manifest.go
index b6b8d2a..1b06788 100644
--- a/exporter/manifest/manifest.go
+++ b/exporter/manifest/manifest.go
@@ -22,6 +22,7 @@ import (
 	"github.com/containers/image/v5/types"
 	"github.com/pkg/errors"
 
+	constant "isula.org/isula-build"
 	"isula.org/isula-build/exporter"
 	"isula.org/isula-build/pkg/manifest"
 	"isula.org/isula-build/store"
@@ -42,7 +43,7 @@ var _manifestExporter = manifestExporter{
 }
 
 func (d *manifestExporter) Name() string {
-	return exporter.ManifestTransport
+	return constant.ManifestTransport
 }
 
 func (d *manifestExporter) Init(opts exporter.ExportOptions, src, destSpec string, localStore *store.Store) error {
diff --git a/exporter/oci/archive/archive.go b/exporter/oci/archive/archive.go
index 03f5e4f..9c39df3 100644
--- a/exporter/oci/archive/archive.go
+++ b/exporter/oci/archive/archive.go
@@ -22,6 +22,7 @@ import (
 	"github.com/containers/image/v5/types"
 	"github.com/pkg/errors"
 
+	constant "isula.org/isula-build"
 	"isula.org/isula-build/exporter"
 	"isula.org/isula-build/image"
 	"isula.org/isula-build/store"
@@ -42,7 +43,7 @@ var _ociArchiveExporter = ociArchiveExporter{
 }
 
 func (o *ociArchiveExporter) Name() string {
-	return exporter.OCIArchiveTransport
+	return constant.OCIArchiveTransport
 }
 
 func (o *ociArchiveExporter) Init(opts exporter.ExportOptions, src, destSpec string, localStore *store.Store) error {
diff --git a/exporter/oci/oci.go b/exporter/oci/oci.go
index 2328a77..c0d703d 100644
--- a/exporter/oci/oci.go
+++ b/exporter/oci/oci.go
@@ -20,6 +20,7 @@ import (
 	"github.com/containers/image/v5/types"
 	"github.com/pkg/errors"
 
+	constant "isula.org/isula-build"
 	"isula.org/isula-build/exporter"
 	"isula.org/isula-build/image"
 	"isula.org/isula-build/store"
@@ -39,7 +40,7 @@ var _ociExporter = ociExporter{
 }
 
 func (o *ociExporter) Name() string {
-	return exporter.OCITransport
+	return constant.OCITransport
 }
 
 func (o *ociExporter) Init(opts exporter.ExportOptions, src, destSpec string, localStore *store.Store) error {
diff --git a/image/image.go b/image/image.go
index 1e48039..91ab720 100644
--- a/image/image.go
+++ b/image/image.go
@@ -152,7 +152,7 @@ func PullAndGetImageInfo(opt *PrepareImageOptions) (types.ImageReference, *stora
 		)
 
 		imageName := exporter.FormatTransport(transport, strImage)
-		if transport == exporter.DockerArchiveTransport {
+		if transport == constant.DockerArchiveTransport {
 			srcRef, pErr = alltransports.ParseImageName(imageName + ":@" + strconv.Itoa(opt.ManifestIndex))
 		} else {
 			srcRef, pErr = alltransports.ParseImageName(imageName)
@@ -255,7 +255,7 @@ func getLocalImageNameFromRef(store storage.Store, srcRef types.ImageReference)
 		return stringid.GenerateRandomID() + ":" + stringid.GenerateRandomID(), nil
 	}
 
-	if srcRef.Transport().Name() != exporter.DockerTransport {
+	if srcRef.Transport().Name() != constant.DockerTransport {
 		return "", errors.Errorf("the %s transport is not supported yet", srcRef.Transport().Name())
 	}
 
@@ -612,11 +612,11 @@ func tryResolveNameWithTransport(name string) (string, string) {
 	if len(splits) == 2 {
 		if trans := transports.Get(splits[0]); trans != nil {
 			switch trans.Name() {
-			case exporter.DockerTransport:
+			case constant.DockerTransport:
 				// trim prefix if dest like docker://registry.example.com format
 				dest := strings.TrimPrefix(splits[1], "//")
 				return dest, trans.Name()
-			case exporter.DockerArchiveTransport, exporter.OCIArchiveTransport:
+			case constant.DockerArchiveTransport, constant.OCIArchiveTransport:
 				dest := strings.TrimSpace(splits[1])
 				return dest, trans.Name()
 			}
@@ -632,7 +632,7 @@ func tryResolveNameWithDockerReference(name string) (string, string, error) {
 		return "", "", errors.Wrapf(err, "error parsing image name %q", name)
 	}
 	if named.String() == name {
-		return name, exporter.DockerTransport, nil
+		return name, constant.DockerTransport, nil
 	}
 
 	domain := reference.Domain(named)
@@ -648,7 +648,7 @@ func tryResolveNameWithDockerReference(name string) (string, string, error) {
 		}
 		defaultPrefix := pathPrefix + string(os.PathSeparator)
 		if strings.HasPrefix(repoPath, defaultPrefix) && path.Join(domain, repoPath[len(defaultPrefix):])+tag+digest == name {
-			return name, exporter.DockerTransport, nil
+			return name, constant.DockerTransport, nil
 		}
 	}
 
@@ -687,7 +687,7 @@ func tryResolveNameInRegistries(name string, sc *types.SystemContext) ([]string,
 		candidate := path.Join(registry, middle, name)
 		candidates = append(candidates, candidate)
 	}
-	return candidates, exporter.DockerTransport
+	return candidates, constant.DockerTransport
 }
 
 // CheckAndAddDefaultTag checks if src is format of repository[:tag], add default tag if src without tag
diff --git a/image/image_test.go b/image/image_test.go
index 17176d4..c698b4d 100644
--- a/image/image_test.go
+++ b/image/image_test.go
@@ -25,7 +25,6 @@ import (
 	"gotest.tools/v3/fs"
 
 	constant "isula.org/isula-build"
-	"isula.org/isula-build/exporter"
 	"isula.org/isula-build/store"
 )
 
@@ -65,7 +64,7 @@ func TestTryResolveNameWithDockerReference(t *testing.T) {
 	var testcases = []testcase{
 		{
 			name:        "docker.io/library/busybox:latest",
-			expectTrans: exporter.DockerTransport,
+			expectTrans: constant.DockerTransport,
 			errStr:      "",
 		}, {
 			name:        "busybox:latest",
@@ -122,5 +121,5 @@ registries = []
 	name := "busybox:latest"
 	candidates, transport := tryResolveNameInRegistries(name, nil)
 	assert.Assert(t, cmp.Contains(candidates, "localhost/busybox:latest"))
-	assert.Equal(t, transport, exporter.DockerTransport)
+	assert.Equal(t, transport, constant.DockerTransport)
 }
diff --git a/pkg/manifest/list.go b/pkg/manifest/list.go
index 381746f..bc6037f 100644
--- a/pkg/manifest/list.go
+++ b/pkg/manifest/list.go
@@ -24,6 +24,7 @@ import (
 	"github.com/pkg/errors"
 	"github.com/sirupsen/logrus"
 
+	constant "isula.org/isula-build"
 	pb "isula.org/isula-build/api/services"
 	"isula.org/isula-build/builder/dockerfile/container"
 	"isula.org/isula-build/exporter"
@@ -60,7 +61,7 @@ func NewManifestList() *List {
 func (l *List) AddImage(ctx context.Context, store *store.Store, imageSpec string) (digest.Digest, error) {
 	img, _, err := image.ResolveFromImage(&image.PrepareImageOptions{
 		Ctx:           ctx,
-		FromImage:     exporter.FormatTransport(exporter.DockerTransport, imageSpec),
+		FromImage:     exporter.FormatTransport(constant.DockerTransport, imageSpec),
 		SystemContext: image.GetSystemContext(),
 		Store:         store,
 	})
diff --git a/util/util.go b/util/util.go
index 3f46d79..f527608 100644
--- a/util/util.go
+++ b/util/util.go
@@ -315,3 +315,52 @@ func ChangeGroup(path, g string) error {
 	}
 	return nil
 }
+
+// GenerateNonCryptoID generate none crypto id with length 32
+func GenerateNonCryptoID() string {
+	b := make([]byte, 32)
+	_, err := rand.Read(b)
+	if err != nil {
+		panic(err) // This shouldn't happen
+	}
+	id := fmt.Sprintf("%x", b)
+
+	return id
+}
+
+// IsSupportExporter returns true when the specific exporter is supported
+func IsSupportExporter(name string) bool {
+	exporters := map[string]bool{
+		constant.DockerTransport:        true,
+		constant.DockerArchiveTransport: true,
+		constant.DockerDaemonTransport:  true,
+		constant.OCITransport:           true,
+		constant.OCIArchiveTransport:    true,
+		constant.IsuladTransport:        true,
+		constant.ManifestTransport:      true,
+	}
+	_, ok := exporters[name]
+
+	return ok
+}
+
+// CheckImageFormat used to check if the image format is either docker or oci
+func CheckImageFormat(format string) error {
+	switch format {
+	case constant.DockerTransport, constant.OCITransport:
+		return nil
+	default:
+		return errors.New("wrong image format provided")
+	}
+}
+
+// IsClientExporter used to determinate exporter whether need to send the image to client
+func IsClientExporter(exporter string) bool {
+	clientExporters := map[string]bool{
+		constant.DockerArchiveTransport: true,
+		constant.OCIArchiveTransport:    true,
+		constant.IsuladTransport:        true,
+	}
+	_, ok := clientExporters[exporter]
+	return ok
+}
diff --git a/util/util_test.go b/util/util_test.go
index 722c2a3..db57393 100644
--- a/util/util_test.go
+++ b/util/util_test.go
@@ -315,3 +315,97 @@ func TestSetDaemonLock(t *testing.T) {
 	_, err = SetDaemonLock(root, name)
 	assert.ErrorContains(t, err, "check if there is another daemon running")
 }
+
+func TestGenerateNonCryptoID(t *testing.T) {
+	tests := []struct {
+		name string
+		want int
+	}{
+		{
+			name: "TC1 - generate id",
+			want:64,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if got := GenerateNonCryptoID(); len(got) != tt.want {
+				t.Errorf("GenerateNonCryptoID() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func TestCheckImageFormat(t *testing.T) {
+	testcases := []struct {
+		name      string
+		format    string
+		wantErr   bool
+		errString string
+	}{
+		{
+			name:    "docker image format",
+			format:  constant.DockerTransport,
+			wantErr: false,
+		},
+		{
+			name:    "oci image format",
+			format:  constant.OCITransport,
+			wantErr: false,
+		},
+		{
+			name:    "unknown image format",
+			format:  "you guess",
+			wantErr: true,
+		},
+	}
+	for _, tc := range testcases {
+		t.Run(tc.name, func(t *testing.T) {
+			err := CheckImageFormat(tc.format)
+			if tc.wantErr {
+				assert.Error(t, err, "wrong image format provided")
+				return
+			}
+			if !tc.wantErr {
+				assert.NilError(t, err)
+			}
+		})
+	}
+}
+
+func TestIsClientExporter(t *testing.T) {
+	testcases := []struct {
+		name       string
+		exporter   string
+		wantResult bool
+	}{
+		{
+			name:       "normal docker archive exporter",
+			exporter:   constant.DockerArchiveTransport,
+			wantResult: true,
+		},
+		{
+			name:       "normal oci archive exporter",
+			exporter:   constant.OCIArchiveTransport,
+			wantResult: true,
+		},
+		{
+			name:       "normal isulad exporter",
+			exporter:   constant.IsuladTransport,
+			wantResult: true,
+		},
+		{
+			name:       "abnormal unkown",
+			exporter:   "unkown",
+			wantResult: false,
+		},
+	}
+
+	for _, tc := range testcases {
+		t.Run(tc.name, func(t *testing.T) {
+			isExporter := IsClientExporter(tc.exporter)
+			if isExporter != tc.wantResult {
+				t.Fatal("test client exporter failed")
+			}
+		})
+	}
+}
-- 
1.8.3.1

