diff --git a/storage/cmd/containers-storage/image.go b/storage/cmd/containers-storage/image.go index 8819cb5cca..abfd7bc5cc 100644 --- a/storage/cmd/containers-storage/image.go +++ b/storage/cmd/containers-storage/image.go @@ -8,6 +8,7 @@ import ( "github.com/containers/storage" "github.com/containers/storage/pkg/mflag" + digest "github.com/opencontainers/go-digest" ) var ( @@ -95,6 +96,10 @@ func getImageBigData(flags *mflag.FlagSet, action string, m storage.Store, args return 0 } +func wrongManifestDigest(b []byte) (digest.Digest, error) { + return digest.Canonical.FromBytes(b), nil +} + func getImageBigDataSize(flags *mflag.FlagSet, action string, m storage.Store, args []string) int { image, err := m.Image(args[0]) if err != nil { @@ -149,7 +154,7 @@ func setImageBigData(flags *mflag.FlagSet, action string, m storage.Store, args fmt.Fprintf(os.Stderr, "%v\n", err) return 1 } - err = m.SetImageBigData(image.ID, args[1], b) + err = m.SetImageBigData(image.ID, args[1], b, wrongManifestDigest) if err != nil { fmt.Fprintf(os.Stderr, "%v\n", err) return 1 @@ -207,7 +212,7 @@ func init() { command{ names: []string{"set-image-data", "setimagedata"}, optionsHelp: "[options [...]] imageNameOrID dataName", - usage: "Set data that is attached to an image", + usage: "Set data that is attached to an image (with sometimes wrong digest)", action: setImageBigData, minArgs: 2, addFlags: func(flags *mflag.FlagSet, cmd *command) { diff --git a/storage/containers.go b/storage/containers.go index 10d628dbe5..bbac78b60b 100644 --- a/storage/containers.go +++ b/storage/containers.go @@ -71,7 +71,7 @@ type Container struct { type ContainerStore interface { FileBasedStore MetadataStore - BigDataStore + ContainerBigDataStore FlaggableStore // Create creates a container that has a specified ID (or generates a @@ -456,7 +456,7 @@ func (r *containerStore) BigDataSize(id, key string) (int64, error) { return size, nil } if data, err := r.BigData(id, key); err == nil && data != nil { - if r.SetBigData(id, key, data) == nil { + if err = r.SetBigData(id, key, data); err == nil { c, ok := r.lookup(id) if !ok { return -1, ErrContainerUnknown @@ -464,6 +464,8 @@ func (r *containerStore) BigDataSize(id, key string) (int64, error) { if size, ok := c.BigDataSizes[key]; ok { return size, nil } + } else { + return -1, err } } return -1, ErrSizeUnknown @@ -484,7 +486,7 @@ func (r *containerStore) BigDataDigest(id, key string) (digest.Digest, error) { return d, nil } if data, err := r.BigData(id, key); err == nil && data != nil { - if r.SetBigData(id, key, data) == nil { + if err = r.SetBigData(id, key, data); err == nil { c, ok := r.lookup(id) if !ok { return "", ErrContainerUnknown @@ -492,6 +494,8 @@ func (r *containerStore) BigDataDigest(id, key string) (digest.Digest, error) { if d, ok := c.BigDataDigests[key]; ok { return d, nil } + } else { + return "", err } } return "", ErrDigestUnknown diff --git a/storage/images.go b/storage/images.go index 7dc4972e67..38b5a3ef3b 100644 --- a/storage/images.go +++ b/storage/images.go @@ -8,7 +8,6 @@ import ( "strings" "time" - "github.com/containers/image/manifest" "github.com/containers/storage/pkg/ioutils" "github.com/containers/storage/pkg/stringid" "github.com/containers/storage/pkg/truncindex" @@ -117,7 +116,7 @@ type ImageStore interface { ROImageStore RWFileBasedStore RWMetadataStore - RWBigDataStore + RWImageBigDataStore FlaggableStore // Create creates an image that has a specified ID (or a random one) and @@ -636,7 +635,7 @@ func imageSliceWithoutValue(slice []*Image, value *Image) []*Image { return modified } -func (r *imageStore) SetBigData(id, key string, data []byte) error { +func (r *imageStore) SetBigData(id, key string, data []byte, digestManifest func([]byte) (digest.Digest, error)) error { if key == "" { return errors.Wrapf(ErrInvalidBigDataName, "can't set empty name for image big data item") } @@ -653,7 +652,10 @@ func (r *imageStore) SetBigData(id, key string, data []byte) error { } var newDigest digest.Digest if bigDataNameIsManifest(key) { - if newDigest, err = manifest.Digest(data); err != nil { + if digestManifest == nil { + return errors.Wrapf(ErrDigestUnknown, "error digesting manifest: no manifest digest callback provided") + } + if newDigest, err = digestManifest(data); err != nil { return errors.Wrapf(err, "error digesting manifest") } } else { diff --git a/storage/store.go b/storage/store.go index 8237ae7957..57be441b04 100644 --- a/storage/store.go +++ b/storage/store.go @@ -102,19 +102,21 @@ type ROBigDataStore interface { BigDataNames(id string) ([]string, error) } -// A RWBigDataStore wraps up the read-write big-data related methods of the -// various types of file-based lookaside stores that we implement. -type RWBigDataStore interface { - // SetBigData stores a (potentially large) piece of data associated with this - // ID. - SetBigData(id, key string, data []byte) error +// A RWImageBigDataStore wraps up how we store big-data associated with images. +type RWImageBigDataStore interface { + // SetBigData stores a (potentially large) piece of data associated + // with this ID. + // Pass github.com/containers/image/manifest.Digest as digestManifest + // to allow ByDigest to find images by their correct digests. + SetBigData(id, key string, data []byte, digestManifest func([]byte) (digest.Digest, error)) error } -// A BigDataStore wraps up the most common big-data related methods of the -// various types of file-based lookaside stores that we implement. -type BigDataStore interface { +// A ContainerBigDataStore wraps up how we store big-data associated with containers. +type ContainerBigDataStore interface { ROBigDataStore - RWBigDataStore + // SetBigData stores a (potentially large) piece of data associated + // with this ID. + SetBigData(id, key string, data []byte) error } // A FlaggableStore can have flags set and cleared on items which it manages. @@ -352,9 +354,11 @@ type Store interface { // of named data associated with an image. ImageBigDataDigest(id, key string) (digest.Digest, error) - // SetImageBigData stores a (possibly large) chunk of named data associated - // with an image. - SetImageBigData(id, key string, data []byte) error + // SetImageBigData stores a (possibly large) chunk of named data + // associated with an image. Pass + // github.com/containers/image/manifest.Digest as digestManifest to + // allow ImagesByDigest to find images by their correct digests. + SetImageBigData(id, key string, data []byte, digestManifest func([]byte) (digest.Digest, error)) error // ImageSize computes the size of the image's layers and ancillary data. ImageSize(id string) (int64, error) @@ -1485,7 +1489,7 @@ func (s *store) ImageBigData(id, key string) ([]byte, error) { return nil, ErrImageUnknown } -func (s *store) SetImageBigData(id, key string, data []byte) error { +func (s *store) SetImageBigData(id, key string, data []byte, digestManifest func([]byte) (digest.Digest, error)) error { ristore, err := s.ImageStore() if err != nil { return err @@ -1499,7 +1503,7 @@ func (s *store) SetImageBigData(id, key string, data []byte) error { } } - return ristore.SetBigData(id, key, data) + return ristore.SetBigData(id, key, data, digestManifest) } func (s *store) ImageSize(id string) (int64, error) { diff --git a/storage/tests/bigdata.bats b/storage/tests/bigdata.bats index e0c05a878d..9b8383c869 100644 --- a/storage/tests/bigdata.bats +++ b/storage/tests/bigdata.bats @@ -131,6 +131,7 @@ load helpers run storage get-container-data-size $container no-such-item [ "$status" -ne 0 ] run storage --debug=false get-container-data-size $container big-item-1 + echo "$output" [ "$status" -eq 0 ] [ "$output" -eq 1234 ] run storage --debug=false get-container-data-size $container big-item-2