196 lines
5.3 KiB
Go
196 lines
5.3 KiB
Go
|
package storage
|
||
|
|
||
|
import (
|
||
|
"github.com/containers/image/copy"
|
||
|
"github.com/containers/image/signature"
|
||
|
istorage "github.com/containers/image/storage"
|
||
|
"github.com/containers/image/transports"
|
||
|
"github.com/containers/image/types"
|
||
|
"github.com/containers/storage/storage"
|
||
|
)
|
||
|
|
||
|
// ImageResult wraps a subset of information about an image: its ID, its names,
|
||
|
// and the size, if known, or nil if it isn't.
|
||
|
type ImageResult struct {
|
||
|
ID string
|
||
|
Names []string
|
||
|
Size *uint64
|
||
|
}
|
||
|
|
||
|
type imageService struct {
|
||
|
store storage.Store
|
||
|
defaultTransport string
|
||
|
}
|
||
|
|
||
|
// ImageServer wraps up various CRI-related activities into a reusable
|
||
|
// implementation.
|
||
|
type ImageServer interface {
|
||
|
// ListImages returns list of all images which match the filter.
|
||
|
ListImages(filter string) ([]ImageResult, error)
|
||
|
// ImageStatus returns status of an image which matches the filter.
|
||
|
ImageStatus(systemContext *types.SystemContext, filter string) (*ImageResult, error)
|
||
|
// PullImage imports an image from the specified location.
|
||
|
PullImage(systemContext *types.SystemContext, imageName string, options *copy.Options) (types.ImageReference, error)
|
||
|
// RemoveImage deletes the specified image.
|
||
|
RemoveImage(systemContext *types.SystemContext, imageName string) error
|
||
|
// GetStore returns the reference to the storage library Store which
|
||
|
// the image server uses to hold images, and is the destination used
|
||
|
// when it's asked to pull an image.
|
||
|
GetStore() storage.Store
|
||
|
}
|
||
|
|
||
|
func (svc *imageService) ListImages(filter string) ([]ImageResult, error) {
|
||
|
results := []ImageResult{}
|
||
|
if filter != "" {
|
||
|
if image, err := svc.store.GetImage(filter); err == nil {
|
||
|
results = append(results, ImageResult{
|
||
|
ID: image.ID,
|
||
|
Names: image.Names,
|
||
|
})
|
||
|
}
|
||
|
} else {
|
||
|
images, err := svc.store.Images()
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
for _, image := range images {
|
||
|
results = append(results, ImageResult{
|
||
|
ID: image.ID,
|
||
|
Names: image.Names,
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
return results, nil
|
||
|
}
|
||
|
|
||
|
func (svc *imageService) ImageStatus(systemContext *types.SystemContext, nameOrID string) (*ImageResult, error) {
|
||
|
ref, err := transports.ParseImageName(nameOrID)
|
||
|
if err != nil {
|
||
|
ref2, err2 := istorage.Transport.ParseStoreReference(svc.store, "@"+nameOrID)
|
||
|
if err2 != nil {
|
||
|
ref3, err3 := istorage.Transport.ParseStoreReference(svc.store, nameOrID)
|
||
|
if err3 != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
ref2 = ref3
|
||
|
}
|
||
|
ref = ref2
|
||
|
}
|
||
|
image, err := istorage.Transport.GetStoreImage(svc.store, ref)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
img, err := ref.NewImage(systemContext)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
size := imageSize(img)
|
||
|
img.Close()
|
||
|
|
||
|
return &ImageResult{
|
||
|
ID: image.ID,
|
||
|
Names: image.Names,
|
||
|
Size: size,
|
||
|
}, nil
|
||
|
}
|
||
|
|
||
|
func imageSize(img types.Image) *uint64 {
|
||
|
if sum, err := img.Size(); err == nil {
|
||
|
usum := uint64(sum)
|
||
|
return &usum
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (svc *imageService) PullImage(systemContext *types.SystemContext, imageName string, options *copy.Options) (types.ImageReference, error) {
|
||
|
policy, err := signature.DefaultPolicy(systemContext)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
policyContext, err := signature.NewPolicyContext(policy)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
if imageName == "" {
|
||
|
return nil, storage.ErrNotAnImage
|
||
|
}
|
||
|
if options == nil {
|
||
|
options = ©.Options{}
|
||
|
}
|
||
|
srcRef, err := transports.ParseImageName(imageName)
|
||
|
if err != nil {
|
||
|
if svc.defaultTransport == "" {
|
||
|
return nil, err
|
||
|
}
|
||
|
srcRef2, err2 := transports.ParseImageName(svc.defaultTransport + imageName)
|
||
|
if err2 != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
srcRef = srcRef2
|
||
|
}
|
||
|
dest := imageName
|
||
|
if srcRef.DockerReference() != nil {
|
||
|
dest = srcRef.DockerReference().FullName()
|
||
|
}
|
||
|
destRef, err := istorage.Transport.ParseStoreReference(svc.store, dest)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
err = copy.Image(policyContext, destRef, srcRef, options)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
// Go find the image, and attach the requested name to it, so that we
|
||
|
// can more easily find it later, even if the destination reference
|
||
|
// looks different.
|
||
|
destImage, err := istorage.Transport.GetStoreImage(svc.store, destRef)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
names := append(destImage.Names, imageName, dest)
|
||
|
err = svc.store.SetNames(destImage.ID, names)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
return destRef, nil
|
||
|
}
|
||
|
|
||
|
func (svc *imageService) RemoveImage(systemContext *types.SystemContext, nameOrID string) error {
|
||
|
ref, err := transports.ParseImageName(nameOrID)
|
||
|
if err != nil {
|
||
|
ref2, err2 := istorage.Transport.ParseStoreReference(svc.store, "@"+nameOrID)
|
||
|
if err2 != nil {
|
||
|
ref3, err3 := istorage.Transport.ParseStoreReference(svc.store, nameOrID)
|
||
|
if err3 != nil {
|
||
|
return err
|
||
|
}
|
||
|
ref2 = ref3
|
||
|
}
|
||
|
ref = ref2
|
||
|
}
|
||
|
return ref.DeleteImage(systemContext)
|
||
|
}
|
||
|
|
||
|
func (svc *imageService) GetStore() storage.Store {
|
||
|
return svc.store
|
||
|
}
|
||
|
|
||
|
// GetImageService returns an ImageServer that uses the passed-in store, and
|
||
|
// which will prepend the passed-in defaultTransport value to an image name if
|
||
|
// a name that's passed to its PullImage() method can't be resolved to an image
|
||
|
// in the store and can't be resolved to a source on its own.
|
||
|
func GetImageService(store storage.Store, defaultTransport string) (ImageServer, error) {
|
||
|
if store == nil {
|
||
|
var err error
|
||
|
store, err = storage.GetStore(storage.DefaultStoreOptions)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
}
|
||
|
return &imageService{
|
||
|
store: store,
|
||
|
defaultTransport: defaultTransport,
|
||
|
}, nil
|
||
|
}
|