image_pull: check image already pulled
This is an optimization of our image pull code path. It's basically how docker handles pulls as well. Let's be smart and check the image in pull code path as well. This also matches docker behavior which first checks whether we're allowed to actually pull an image before looking into local storage. Signed-off-by: Antonio Murdaca <runcom@redhat.com>
This commit is contained in:
parent
cb4c6004fc
commit
3b545abf12
2 changed files with 52 additions and 3 deletions
|
@ -3,6 +3,7 @@ package storage
|
||||||
import (
|
import (
|
||||||
"github.com/containers/image/copy"
|
"github.com/containers/image/copy"
|
||||||
"github.com/containers/image/docker/reference"
|
"github.com/containers/image/docker/reference"
|
||||||
|
"github.com/containers/image/image"
|
||||||
"github.com/containers/image/signature"
|
"github.com/containers/image/signature"
|
||||||
istorage "github.com/containers/image/storage"
|
istorage "github.com/containers/image/storage"
|
||||||
"github.com/containers/image/transports/alltransports"
|
"github.com/containers/image/transports/alltransports"
|
||||||
|
@ -38,6 +39,8 @@ type ImageServer interface {
|
||||||
// the image server uses to hold images, and is the destination used
|
// the image server uses to hold images, and is the destination used
|
||||||
// when it's asked to pull an image.
|
// when it's asked to pull an image.
|
||||||
GetStore() storage.Store
|
GetStore() storage.Store
|
||||||
|
// CanPull preliminary checks whether we're allowed to pull an image
|
||||||
|
CanPull(imageName string, sourceCtx *types.SystemContext) (bool, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (svc *imageService) ListImages(filter string) ([]ImageResult, error) {
|
func (svc *imageService) ListImages(filter string) ([]ImageResult, error) {
|
||||||
|
@ -116,6 +119,35 @@ func imageSize(img types.Image) *uint64 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (svc *imageService) CanPull(imageName string, sourceCtx *types.SystemContext) (bool, error) {
|
||||||
|
if imageName == "" {
|
||||||
|
return false, storage.ErrNotAnImage
|
||||||
|
}
|
||||||
|
srcRef, err := alltransports.ParseImageName(imageName)
|
||||||
|
if err != nil {
|
||||||
|
if svc.defaultTransport == "" {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
srcRef2, err2 := alltransports.ParseImageName(svc.defaultTransport + imageName)
|
||||||
|
if err2 != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
srcRef = srcRef2
|
||||||
|
}
|
||||||
|
rawSource, err := srcRef.NewImageSource(sourceCtx, nil)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
unparsedImage := image.UnparsedFromSource(rawSource)
|
||||||
|
defer unparsedImage.Close()
|
||||||
|
src, err := image.FromUnparsedImage(unparsedImage)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
src.Close()
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (svc *imageService) PullImage(systemContext *types.SystemContext, imageName string, options *copy.Options) (types.ImageReference, error) {
|
func (svc *imageService) PullImage(systemContext *types.SystemContext, imageName string, options *copy.Options) (types.ImageReference, error) {
|
||||||
policy, err := signature.DefaultPolicy(systemContext)
|
policy, err := signature.DefaultPolicy(systemContext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -21,6 +21,7 @@ func (s *Server) PullImage(ctx context.Context, req *pb.PullImageRequest) (*pb.P
|
||||||
if img != nil {
|
if img != nil {
|
||||||
image = img.Image
|
image = img.Image
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
username string
|
username string
|
||||||
password string
|
password string
|
||||||
|
@ -36,7 +37,11 @@ func (s *Server) PullImage(ctx context.Context, req *pb.PullImageRequest) (*pb.P
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
options := ©.Options{}
|
options := ©.Options{
|
||||||
|
// TODO: we need a way to specify insecure registries like docker
|
||||||
|
//DockerInsecureSkipTLSVerify: true,
|
||||||
|
SourceCtx: &types.SystemContext{},
|
||||||
|
}
|
||||||
// a not empty username should be sufficient to decide whether to send auth
|
// a not empty username should be sufficient to decide whether to send auth
|
||||||
// or not I guess
|
// or not I guess
|
||||||
if username != "" {
|
if username != "" {
|
||||||
|
@ -47,8 +52,20 @@ func (s *Server) PullImage(ctx context.Context, req *pb.PullImageRequest) (*pb.P
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_, err := s.storageImageServer.PullImage(s.imageContext, image, options)
|
|
||||||
if err != nil {
|
canPull, err := s.storageImageServer.CanPull(image, options.SourceCtx)
|
||||||
|
if err != nil && !canPull {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// let's be smart, docker doesn't repull if image already exists.
|
||||||
|
if _, err := s.storageImageServer.ImageStatus(s.imageContext, image); err == nil {
|
||||||
|
return &pb.PullImageResponse{
|
||||||
|
ImageRef: image,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := s.storageImageServer.PullImage(s.imageContext, image, options); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
resp := &pb.PullImageResponse{
|
resp := &pb.PullImageResponse{
|
||||||
|
|
Loading…
Reference in a new issue