From 62055bb9f767b71440ef52bf19c4db0593d1559a Mon Sep 17 00:00:00 2001 From: wrfly Date: Tue, 29 May 2018 09:34:41 +0800 Subject: [PATCH] bugfix: pull image before run and upgrade (#1419) bugfix: pull image before run and upgrade --- apis/server/image_bridge.go | 2 +- cli/pull.go | 60 +++++++++++++++++++++++-------------- cli/run.go | 5 ++++ cli/upgrade.go | 43 ++++---------------------- client/request.go | 5 ++++ 5 files changed, 55 insertions(+), 60 deletions(-) diff --git a/apis/server/image_bridge.go b/apis/server/image_bridge.go index 4caa99fbd..6211fdd2b 100644 --- a/apis/server/image_bridge.go +++ b/apis/server/image_bridge.go @@ -48,7 +48,7 @@ func (s *Server) pullImage(ctx context.Context, rw http.ResponseWriter, req *htt } // Error information has be sent to client, so no need call resp.Write if err := s.ImageMgr.PullImage(ctx, image, &authConfig, rw); err != nil { - logrus.Errorf("failed to pull image %s:%s: %v", image, tag, err) + logrus.Errorf("failed to pull image %s: %v", image, err) return nil } return nil diff --git a/cli/pull.go b/cli/pull.go index dd1d05fe7..1b1114e38 100644 --- a/cli/pull.go +++ b/cli/pull.go @@ -7,11 +7,13 @@ import ( "encoding/json" "fmt" "io" + "net/http" "os" "text/tabwriter" "time" "github.com/alibaba/pouch/apis/types" + "github.com/alibaba/pouch/client" "github.com/alibaba/pouch/credential" "github.com/alibaba/pouch/ctrd" "github.com/alibaba/pouch/pkg/reference" @@ -55,28 +57,7 @@ func (p *PullCommand) addFlags() { // runPull is the entry of pull command. func (p *PullCommand) runPull(args []string) error { - namedRef, err := reference.Parse(args[0]) - if err != nil { - return fmt.Errorf("failed to pull image: %v", err) - } - namedRef = reference.TrimTagForDigest(reference.WithDefaultTagIfMissing(namedRef)) - - var name, tag string - if reference.IsNameTagged(namedRef) { - name, tag = namedRef.Name(), namedRef.(reference.Tagged).Tag() - } else { - name = namedRef.String() - } - - ctx := context.Background() - apiClient := p.cli.Client() - responseBody, err := apiClient.ImagePull(ctx, name, tag, fetchRegistryAuth(namedRef.Name())) - if err != nil { - return fmt.Errorf("failed to pull image: %v", err) - } - defer responseBody.Close() - - return showProgress(responseBody) + return pullMissingImage(context.Background(), p.cli.Client(), args[0], true) } func fetchRegistryAuth(serverAddress string) string { @@ -228,3 +209,38 @@ IMAGE ID IMAGE NAME SIZE bbc3a0323522 docker.io/library/busybox:latest 703.14 KB 0153c5db97e5 docker.io/library/redis:alpine 9.63 MB` } + +// pullMissingImage pull the image if it doesn't exist. +// When `force` is true, always pull the latest image instead of +// using the local version +func pullMissingImage(ctx context.Context, apiClient client.CommonAPIClient, image string, force bool) error { + if !force { + _, inspectError := apiClient.ImageInspect(ctx, image) + if inspectError == nil { + return nil + } + if err, ok := inspectError.(client.RespError); !ok { + return inspectError + } else if err.Code() != http.StatusNotFound { + return inspectError + } + } + + namedRef, _ := reference.Parse(image) + namedRef = reference.TrimTagForDigest(reference.WithDefaultTagIfMissing(namedRef)) + + var name, tag string + if reference.IsNameTagged(namedRef) { + name, tag = namedRef.Name(), namedRef.(reference.Tagged).Tag() + } else { + name = namedRef.String() + } + + responseBody, err := apiClient.ImagePull(ctx, name, tag, fetchRegistryAuth(namedRef.Name())) + if err != nil { + return fmt.Errorf("failed to pull image: %v", err) + } + defer responseBody.Close() + + return showProgress(responseBody) +} diff --git a/cli/run.go b/cli/run.go index 35165fad2..b0f290599 100644 --- a/cli/run.go +++ b/cli/run.go @@ -74,6 +74,11 @@ func (rc *RunCommand) runRun(args []string) error { ctx := context.Background() apiClient := rc.cli.Client() + + if err := pullMissingImage(ctx, apiClient, config.Image, false); err != nil { + return err + } + result, err := apiClient.ContainerCreate(ctx, config.ContainerConfig, config.HostConfig, config.NetworkingConfig, containerName) if err != nil { return fmt.Errorf("failed to run container: %v", err) diff --git a/cli/upgrade.go b/cli/upgrade.go index 2d8245a97..21ee49cb1 100644 --- a/cli/upgrade.go +++ b/cli/upgrade.go @@ -4,9 +4,6 @@ import ( "context" "fmt" - "github.com/alibaba/pouch/pkg/errtypes" - "github.com/alibaba/pouch/pkg/reference" - "github.com/spf13/cobra" ) @@ -56,46 +53,18 @@ func (ug *UpgradeCommand) runUpgrade(args []string) error { config.Cmd = args[1:] } + containerName := ug.name + if containerName == "" { + return fmt.Errorf("failed to upgrade container: must specify container name") + } + ctx := context.Background() apiClient := ug.cli.Client() - // Check whether the image has been pulled - _, err = apiClient.ImageInspect(ctx, config.Image) - if err != nil && errtypes.IsNotfound(err) { - fmt.Printf("Image %s not found, try to pull it...\n", config.Image) - - namedRef, err := reference.Parse(config.Image) - if err != nil { - return fmt.Errorf("failed to pull image: %v", err) - } - namedRef = reference.TrimTagForDigest(reference.WithDefaultTagIfMissing(namedRef)) - - var name, tag string - if reference.IsNameTagged(namedRef) { - name, tag = namedRef.Name(), namedRef.(reference.Tagged).Tag() - } else { - name = namedRef.String() - } - - responseBody, err := apiClient.ImagePull(ctx, name, tag, fetchRegistryAuth(namedRef.Name())) - if err != nil { - return fmt.Errorf("failed to pull image: %v", err) - } - defer responseBody.Close() - - if err := showProgress(responseBody); err != nil { - return err - } - } else if err != nil { + if err := pullMissingImage(ctx, apiClient, config.Image, false); err != nil { return err } - containerName := ug.name - if containerName == "" { - return fmt.Errorf("failed to upgrade container: must specify container name") - } - - // TODO if error is image not found, we can pull image, and retry upgrade err = apiClient.ContainerUpgrade(ctx, containerName, config.ContainerConfig, config.HostConfig) if err == nil { fmt.Println(containerName) diff --git a/client/request.go b/client/request.go index 71dbed405..e362c1985 100644 --- a/client/request.go +++ b/client/request.go @@ -25,6 +25,11 @@ func (e RespError) Error() string { return e.msg } +// Code returns the response code +func (e RespError) Code() int { + return e.code +} + // Response wraps the http.Response and other states. type Response struct { StatusCode int