From ad72036e58081edbc21b2aecea530402e324d71b Mon Sep 17 00:00:00 2001 From: Derek McGowan Date: Fri, 28 Jul 2017 15:48:02 -0700 Subject: [PATCH 1/6] Refactor common boltdb fields to subpackage Moves label and timestamp bolt functions to subpackage for use outside the metadata package without importing metadata package. Signed-off-by: Derek McGowan --- metadata/{ => boltutil}/helpers.go | 39 +++++++++++++++++++++++------- metadata/buckets.go | 3 --- metadata/containers.go | 32 ++++++++++-------------- metadata/content.go | 33 ++++++++++--------------- metadata/images.go | 17 ++++++------- 5 files changed, 64 insertions(+), 60 deletions(-) rename metadata/{ => boltutil}/helpers.go (58%) diff --git a/metadata/helpers.go b/metadata/boltutil/helpers.go similarity index 58% rename from metadata/helpers.go rename to metadata/boltutil/helpers.go index 063a0a54b..b713132dc 100644 --- a/metadata/helpers.go +++ b/metadata/boltutil/helpers.go @@ -1,4 +1,4 @@ -package metadata +package boltutil import ( "time" @@ -7,19 +7,36 @@ import ( "github.com/pkg/errors" ) -func readLabels(m map[string]string, bkt *bolt.Bucket) error { - return bkt.ForEach(func(k, v []byte) error { - m[string(k)] = string(v) +var ( + bucketKeyLabels = []byte("labels") + bucketKeyCreatedAt = []byte("createdat") + bucketKeyUpdatedAt = []byte("updatedat") +) + +// ReadLabels reads the labels key from the bucket +// Uses the key "labels" +func ReadLabels(bkt *bolt.Bucket) (map[string]string, error) { + lbkt := bkt.Bucket(bucketKeyLabels) + if lbkt == nil { + return nil, nil + } + labels := map[string]string{} + if err := lbkt.ForEach(func(k, v []byte) error { + labels[string(k)] = string(v) return nil - }) + }); err != nil { + return nil, err + } + return labels, nil } -// writeLabels will write a new labels bucket to the provided bucket at key +// WriteLabels will write a new labels bucket to the provided bucket at key // bucketKeyLabels, replacing the contents of the bucket with the provided map. // // The provide map labels will be modified to have the final contents of the // bucket. Typically, this removes zero-value entries. -func writeLabels(bkt *bolt.Bucket, labels map[string]string) error { +// Uses the key "labels" +func WriteLabels(bkt *bolt.Bucket, labels map[string]string) error { // Remove existing labels to keep from merging if lbkt := bkt.Bucket(bucketKeyLabels); lbkt != nil { if err := bkt.DeleteBucket(bucketKeyLabels); err != nil { @@ -50,7 +67,9 @@ func writeLabels(bkt *bolt.Bucket, labels map[string]string) error { return nil } -func readTimestamps(created, updated *time.Time, bkt *bolt.Bucket) error { +// ReadTimestamps reads created and updated timestamps from a bucket. +// Uses keys "createdat" and "updatedat" +func ReadTimestamps(bkt *bolt.Bucket, created, updated *time.Time) error { for _, f := range []struct { b []byte t *time.Time @@ -68,7 +87,9 @@ func readTimestamps(created, updated *time.Time, bkt *bolt.Bucket) error { return nil } -func writeTimestamps(bkt *bolt.Bucket, created, updated time.Time) error { +// WriteTimestamps writes created and updated timestamps to a bucket. +// Uses keys "createdat" and "updatedat" +func WriteTimestamps(bkt *bolt.Bucket, created, updated time.Time) error { createdAt, err := created.MarshalBinary() if err != nil { return err diff --git a/metadata/buckets.go b/metadata/buckets.go index 0ba3126bb..4bbcbe043 100644 --- a/metadata/buckets.go +++ b/metadata/buckets.go @@ -41,7 +41,6 @@ var ( bucketKeyDigest = []byte("digest") bucketKeyMediaType = []byte("mediatype") bucketKeySize = []byte("size") - bucketKeyLabels = []byte("labels") bucketKeyImage = []byte("image") bucketKeyRuntime = []byte("runtime") bucketKeyName = []byte("name") @@ -49,8 +48,6 @@ var ( bucketKeySpec = []byte("spec") bucketKeyRootFS = []byte("rootfs") bucketKeyTarget = []byte("target") - bucketKeyCreatedAt = []byte("createdat") - bucketKeyUpdatedAt = []byte("updatedat") ) func getBucket(tx *bolt.Tx, keys ...[]byte) *bolt.Bucket { diff --git a/metadata/containers.go b/metadata/containers.go index a951066ba..6061cd48f 100644 --- a/metadata/containers.go +++ b/metadata/containers.go @@ -10,6 +10,7 @@ import ( "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/filters" "github.com/containerd/containerd/identifiers" + "github.com/containerd/containerd/metadata/boltutil" "github.com/containerd/containerd/namespaces" "github.com/gogo/protobuf/proto" "github.com/gogo/protobuf/types" @@ -206,6 +207,16 @@ func (s *containerStore) Delete(ctx context.Context, id string) error { } func readContainer(container *containers.Container, bkt *bolt.Bucket) error { + labels, err := boltutil.ReadLabels(bkt) + if err != nil { + return err + } + container.Labels = labels + + if err := boltutil.ReadTimestamps(bkt, &container.CreatedAt, &container.UpdatedAt); err != nil { + return err + } + return bkt.ForEach(func(k, v []byte) error { switch string(k) { case string(bucketKeyImage): @@ -239,24 +250,7 @@ func readContainer(container *containers.Container, bkt *bolt.Bucket) error { container.Spec = &any case string(bucketKeyRootFS): container.RootFS = string(v) - case string(bucketKeyCreatedAt): - if err := container.CreatedAt.UnmarshalBinary(v); err != nil { - return err - } - case string(bucketKeyUpdatedAt): - if err := container.UpdatedAt.UnmarshalBinary(v); err != nil { - return err - } - case string(bucketKeyLabels): - lbkt := bkt.Bucket(bucketKeyLabels) - if lbkt == nil { - return nil - } - container.Labels = map[string]string{} - if err := readLabels(container.Labels, lbkt); err != nil { - return err - } } return nil @@ -264,7 +258,7 @@ func readContainer(container *containers.Container, bkt *bolt.Bucket) error { } func writeContainer(bkt *bolt.Bucket, container *containers.Container) error { - if err := writeTimestamps(bkt, container.CreatedAt, container.UpdatedAt); err != nil { + if err := boltutil.WriteTimestamps(bkt, container.CreatedAt, container.UpdatedAt); err != nil { return err } @@ -314,5 +308,5 @@ func writeContainer(bkt *bolt.Bucket, container *containers.Container) error { } } - return writeLabels(bkt, container.Labels) + return boltutil.WriteLabels(bkt, container.Labels) } diff --git a/metadata/content.go b/metadata/content.go index 811a91912..24b69d090 100644 --- a/metadata/content.go +++ b/metadata/content.go @@ -11,6 +11,7 @@ import ( "github.com/containerd/containerd/content" "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/filters" + "github.com/containerd/containerd/metadata/boltutil" "github.com/containerd/containerd/namespaces" digest "github.com/opencontainers/go-digest" "github.com/pkg/errors" @@ -390,24 +391,18 @@ func (nw *namespacedWriter) commit(tx *bolt.Tx, size int64, expected digest.Dige return err } + commitTime := time.Now().UTC() + sizeEncoded, err := encodeSize(size) if err != nil { return err } - timeEncoded, err := time.Now().UTC().MarshalBinary() - if err != nil { + if err := boltutil.WriteTimestamps(bkt, commitTime, commitTime); err != nil { return err } - - for _, v := range [][2][]byte{ - {bucketKeyCreatedAt, timeEncoded}, - {bucketKeyUpdatedAt, timeEncoded}, - {bucketKeySize, sizeEncoded}, - } { - if err := bkt.Put(v[0], v[1]); err != nil { - return err - } + if err := bkt.Put(bucketKeySize, sizeEncoded); err != nil { + return err } return nil @@ -451,17 +446,15 @@ func (cs *contentStore) checkAccess(ctx context.Context, dgst digest.Digest) err } func readInfo(info *content.Info, bkt *bolt.Bucket) error { - if err := readTimestamps(&info.CreatedAt, &info.UpdatedAt, bkt); err != nil { + if err := boltutil.ReadTimestamps(bkt, &info.CreatedAt, &info.UpdatedAt); err != nil { return err } - lbkt := bkt.Bucket(bucketKeyLabels) - if lbkt != nil { - info.Labels = map[string]string{} - if err := readLabels(info.Labels, lbkt); err != nil { - return err - } + labels, err := boltutil.ReadLabels(bkt) + if err != nil { + return err } + info.Labels = labels if v := bkt.Get(bucketKeySize); len(v) > 0 { info.Size, _ = binary.Varint(v) @@ -471,11 +464,11 @@ func readInfo(info *content.Info, bkt *bolt.Bucket) error { } func writeInfo(info *content.Info, bkt *bolt.Bucket) error { - if err := writeTimestamps(bkt, info.CreatedAt, info.UpdatedAt); err != nil { + if err := boltutil.WriteTimestamps(bkt, info.CreatedAt, info.UpdatedAt); err != nil { return err } - if err := writeLabels(bkt, info.Labels); err != nil { + if err := boltutil.WriteLabels(bkt, info.Labels); err != nil { return errors.Wrapf(err, "writing labels for info %v", info.Digest) } diff --git a/metadata/images.go b/metadata/images.go index 1815af396..a44b3a7f4 100644 --- a/metadata/images.go +++ b/metadata/images.go @@ -11,6 +11,7 @@ import ( "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/filters" "github.com/containerd/containerd/images" + "github.com/containerd/containerd/metadata/boltutil" "github.com/containerd/containerd/namespaces" digest "github.com/opencontainers/go-digest" "github.com/pkg/errors" @@ -191,17 +192,15 @@ func (s *imageStore) Delete(ctx context.Context, name string) error { } func readImage(image *images.Image, bkt *bolt.Bucket) error { - if err := readTimestamps(&image.CreatedAt, &image.UpdatedAt, bkt); err != nil { + if err := boltutil.ReadTimestamps(bkt, &image.CreatedAt, &image.UpdatedAt); err != nil { return err } - lbkt := bkt.Bucket(bucketKeyLabels) - if lbkt != nil { - image.Labels = map[string]string{} - if err := readLabels(image.Labels, lbkt); err != nil { - return err - } + labels, err := boltutil.ReadLabels(bkt) + if err != nil { + return err } + image.Labels = labels tbkt := bkt.Bucket(bucketKeyTarget) if tbkt == nil { @@ -228,11 +227,11 @@ func readImage(image *images.Image, bkt *bolt.Bucket) error { } func writeImage(bkt *bolt.Bucket, image *images.Image) error { - if err := writeTimestamps(bkt, image.CreatedAt, image.UpdatedAt); err != nil { + if err := boltutil.WriteTimestamps(bkt, image.CreatedAt, image.UpdatedAt); err != nil { return err } - if err := writeLabels(bkt, image.Labels); err != nil { + if err := boltutil.WriteLabels(bkt, image.Labels); err != nil { return errors.Wrapf(err, "writing labels for image %v", image.Name) } From 7d3a1e77376c612a4d0b9a06d1efa97d3b957e54 Mon Sep 17 00:00:00 2001 From: Derek McGowan Date: Fri, 28 Jul 2017 15:48:17 -0700 Subject: [PATCH 2/6] Add snapshot labels Update snapshot storage to use boltdb keys instead of protobuf. Add update function to snapshotter to allow updating labels. Add option type for creating snapshots to allow setting labels. Signed-off-by: Derek McGowan --- snapshot/btrfs/btrfs.go | 35 +- snapshot/naive/naive.go | 35 +- snapshot/overlay/overlay.go | 35 +- snapshot/snapshotter.go | 34 +- snapshot/storage/bolt.go | 448 +++++++++++++++++------- snapshot/storage/bolt_test.go | 31 +- snapshot/storage/metastore_test.go | 92 +++++ snapshot/storage/proto/record.pb.go | 506 ---------------------------- snapshot/storage/proto/record.proto | 34 -- 9 files changed, 527 insertions(+), 723 deletions(-) delete mode 100644 snapshot/storage/proto/record.pb.go delete mode 100644 snapshot/storage/proto/record.proto diff --git a/snapshot/btrfs/btrfs.go b/snapshot/btrfs/btrfs.go index e9f963b07..e58edb301 100644 --- a/snapshot/btrfs/btrfs.go +++ b/snapshot/btrfs/btrfs.go @@ -103,6 +103,25 @@ func (b *snapshotter) Stat(ctx context.Context, key string) (snapshot.Info, erro return info, nil } +func (o *snapshotter) Update(ctx context.Context, info snapshot.Info, fieldpaths ...string) (snapshot.Info, error) { + ctx, t, err := o.ms.TransactionContext(ctx, true) + if err != nil { + return snapshot.Info{}, err + } + + info, err = storage.UpdateInfo(ctx, info, fieldpaths...) + if err != nil { + t.Rollback() + return snapshot.Info{}, err + } + + if err := t.Commit(); err != nil { + return snapshot.Info{}, err + } + + return info, nil +} + // Usage retrieves the disk usage of the top-level snapshot. func (b *snapshotter) Usage(ctx context.Context, key string) (snapshot.Usage, error) { panic("not implemented") @@ -129,15 +148,15 @@ func (b *snapshotter) Walk(ctx context.Context, fn func(context.Context, snapsho return storage.WalkInfo(ctx, fn) } -func (b *snapshotter) Prepare(ctx context.Context, key, parent string) ([]mount.Mount, error) { - return b.makeSnapshot(ctx, snapshot.KindActive, key, parent) +func (b *snapshotter) Prepare(ctx context.Context, key, parent string, opts ...snapshot.Opt) ([]mount.Mount, error) { + return b.makeSnapshot(ctx, snapshot.KindActive, key, parent, opts) } -func (b *snapshotter) View(ctx context.Context, key, parent string) ([]mount.Mount, error) { - return b.makeSnapshot(ctx, snapshot.KindView, key, parent) +func (b *snapshotter) View(ctx context.Context, key, parent string, opts ...snapshot.Opt) ([]mount.Mount, error) { + return b.makeSnapshot(ctx, snapshot.KindView, key, parent, opts) } -func (b *snapshotter) makeSnapshot(ctx context.Context, kind snapshot.Kind, key, parent string) ([]mount.Mount, error) { +func (b *snapshotter) makeSnapshot(ctx context.Context, kind snapshot.Kind, key, parent string, opts []snapshot.Opt) ([]mount.Mount, error) { ctx, t, err := b.ms.TransactionContext(ctx, true) if err != nil { return nil, err @@ -150,7 +169,7 @@ func (b *snapshotter) makeSnapshot(ctx context.Context, kind snapshot.Kind, key, } }() - s, err := storage.CreateSnapshot(ctx, kind, key, parent) + s, err := storage.CreateSnapshot(ctx, kind, key, parent, opts...) if err != nil { return nil, err } @@ -214,7 +233,7 @@ func (b *snapshotter) mounts(dir string) ([]mount.Mount, error) { }, nil } -func (b *snapshotter) Commit(ctx context.Context, name, key string) (err error) { +func (b *snapshotter) Commit(ctx context.Context, name, key string, opts ...snapshot.Opt) (err error) { ctx, t, err := b.ms.TransactionContext(ctx, true) if err != nil { return err @@ -227,7 +246,7 @@ func (b *snapshotter) Commit(ctx context.Context, name, key string) (err error) } }() - id, err := storage.CommitActive(ctx, key, name, snapshot.Usage{}) // TODO(stevvooe): Resolve a usage value for btrfs + id, err := storage.CommitActive(ctx, key, name, snapshot.Usage{}, opts...) // TODO(stevvooe): Resolve a usage value for btrfs if err != nil { return errors.Wrap(err, "failed to commit") } diff --git a/snapshot/naive/naive.go b/snapshot/naive/naive.go index a78a76145..f2f849cc1 100644 --- a/snapshot/naive/naive.go +++ b/snapshot/naive/naive.go @@ -70,6 +70,25 @@ func (o *snapshotter) Stat(ctx context.Context, key string) (snapshot.Info, erro return info, nil } +func (o *snapshotter) Update(ctx context.Context, info snapshot.Info, fieldpaths ...string) (snapshot.Info, error) { + ctx, t, err := o.ms.TransactionContext(ctx, true) + if err != nil { + return snapshot.Info{}, err + } + + info, err = storage.UpdateInfo(ctx, info, fieldpaths...) + if err != nil { + t.Rollback() + return snapshot.Info{}, err + } + + if err := t.Commit(); err != nil { + return snapshot.Info{}, err + } + + return info, nil +} + func (o *snapshotter) Usage(ctx context.Context, key string) (snapshot.Usage, error) { ctx, t, err := o.ms.TransactionContext(ctx, false) if err != nil { @@ -93,12 +112,12 @@ func (o *snapshotter) Usage(ctx context.Context, key string) (snapshot.Usage, er return usage, nil } -func (o *snapshotter) Prepare(ctx context.Context, key, parent string) ([]mount.Mount, error) { - return o.createSnapshot(ctx, snapshot.KindActive, key, parent) +func (o *snapshotter) Prepare(ctx context.Context, key, parent string, opts ...snapshot.Opt) ([]mount.Mount, error) { + return o.createSnapshot(ctx, snapshot.KindActive, key, parent, opts) } -func (o *snapshotter) View(ctx context.Context, key, parent string) ([]mount.Mount, error) { - return o.createSnapshot(ctx, snapshot.KindView, key, parent) +func (o *snapshotter) View(ctx context.Context, key, parent string, opts ...snapshot.Opt) ([]mount.Mount, error) { + return o.createSnapshot(ctx, snapshot.KindView, key, parent, opts) } // Mounts returns the mounts for the transaction identified by key. Can be @@ -118,7 +137,7 @@ func (o *snapshotter) Mounts(ctx context.Context, key string) ([]mount.Mount, er return o.mounts(s), nil } -func (o *snapshotter) Commit(ctx context.Context, name, key string) error { +func (o *snapshotter) Commit(ctx context.Context, name, key string, opts ...snapshot.Opt) error { ctx, t, err := o.ms.TransactionContext(ctx, true) if err != nil { return err @@ -134,7 +153,7 @@ func (o *snapshotter) Commit(ctx context.Context, name, key string) error { return err } - if _, err := storage.CommitActive(ctx, key, name, snapshot.Usage(usage)); err != nil { + if _, err := storage.CommitActive(ctx, key, name, snapshot.Usage(usage), opts...); err != nil { if rerr := t.Rollback(); rerr != nil { log.G(ctx).WithError(rerr).Warn("Failure rolling back transaction") } @@ -203,7 +222,7 @@ func (o *snapshotter) Walk(ctx context.Context, fn func(context.Context, snapsho return storage.WalkInfo(ctx, fn) } -func (o *snapshotter) createSnapshot(ctx context.Context, kind snapshot.Kind, key, parent string) ([]mount.Mount, error) { +func (o *snapshotter) createSnapshot(ctx context.Context, kind snapshot.Kind, key, parent string, opts []snapshot.Opt) ([]mount.Mount, error) { var ( err error path, td string @@ -235,7 +254,7 @@ func (o *snapshotter) createSnapshot(ctx context.Context, kind snapshot.Kind, ke return nil, err } - s, err := storage.CreateSnapshot(ctx, kind, key, parent) + s, err := storage.CreateSnapshot(ctx, kind, key, parent, opts...) if err != nil { if rerr := t.Rollback(); rerr != nil { log.G(ctx).WithError(rerr).Warn("Failure rolling back transaction") diff --git a/snapshot/overlay/overlay.go b/snapshot/overlay/overlay.go index 7d1616bc6..35644b07a 100644 --- a/snapshot/overlay/overlay.go +++ b/snapshot/overlay/overlay.go @@ -89,6 +89,25 @@ func (o *snapshotter) Stat(ctx context.Context, key string) (snapshot.Info, erro return info, nil } +func (o *snapshotter) Update(ctx context.Context, info snapshot.Info, fieldpaths ...string) (snapshot.Info, error) { + ctx, t, err := o.ms.TransactionContext(ctx, true) + if err != nil { + return snapshot.Info{}, err + } + + info, err = storage.UpdateInfo(ctx, info, fieldpaths...) + if err != nil { + t.Rollback() + return snapshot.Info{}, err + } + + if err := t.Commit(); err != nil { + return snapshot.Info{}, err + } + + return info, nil +} + // Usage returns the resources taken by the snapshot identified by key. // // For active snapshots, this will scan the usage of the overlay "diff" (aka @@ -121,12 +140,12 @@ func (o *snapshotter) Usage(ctx context.Context, key string) (snapshot.Usage, er return usage, nil } -func (o *snapshotter) Prepare(ctx context.Context, key, parent string) ([]mount.Mount, error) { - return o.createSnapshot(ctx, snapshot.KindActive, key, parent) +func (o *snapshotter) Prepare(ctx context.Context, key, parent string, opts ...snapshot.Opt) ([]mount.Mount, error) { + return o.createSnapshot(ctx, snapshot.KindActive, key, parent, opts) } -func (o *snapshotter) View(ctx context.Context, key, parent string) ([]mount.Mount, error) { - return o.createSnapshot(ctx, snapshot.KindView, key, parent) +func (o *snapshotter) View(ctx context.Context, key, parent string, opts ...snapshot.Opt) ([]mount.Mount, error) { + return o.createSnapshot(ctx, snapshot.KindView, key, parent, opts) } // Mounts returns the mounts for the transaction identified by key. Can be @@ -146,7 +165,7 @@ func (o *snapshotter) Mounts(ctx context.Context, key string) ([]mount.Mount, er return o.mounts(s), nil } -func (o *snapshotter) Commit(ctx context.Context, name, key string) error { +func (o *snapshotter) Commit(ctx context.Context, name, key string, opts ...snapshot.Opt) error { ctx, t, err := o.ms.TransactionContext(ctx, true) if err != nil { return err @@ -171,7 +190,7 @@ func (o *snapshotter) Commit(ctx context.Context, name, key string) error { return err } - if _, err = storage.CommitActive(ctx, key, name, snapshot.Usage(usage)); err != nil { + if _, err = storage.CommitActive(ctx, key, name, snapshot.Usage(usage), opts...); err != nil { return errors.Wrap(err, "failed to commit snapshot") } return t.Commit() @@ -230,7 +249,7 @@ func (o *snapshotter) Walk(ctx context.Context, fn func(context.Context, snapsho return storage.WalkInfo(ctx, fn) } -func (o *snapshotter) createSnapshot(ctx context.Context, kind snapshot.Kind, key, parent string) ([]mount.Mount, error) { +func (o *snapshotter) createSnapshot(ctx context.Context, kind snapshot.Kind, key, parent string, opts []snapshot.Opt) ([]mount.Mount, error) { var ( path string snapshotDir = filepath.Join(o.root, "snapshots") @@ -270,7 +289,7 @@ func (o *snapshotter) createSnapshot(ctx context.Context, kind snapshot.Kind, ke return nil, err } - s, err := storage.CreateSnapshot(ctx, kind, key, parent) + s, err := storage.CreateSnapshot(ctx, kind, key, parent, opts...) if err != nil { if rerr := t.Rollback(); rerr != nil { log.G(ctx).WithError(rerr).Warn("Failure rolling back transaction") diff --git a/snapshot/snapshotter.go b/snapshot/snapshotter.go index c2cd73fc8..35d645000 100644 --- a/snapshot/snapshotter.go +++ b/snapshot/snapshotter.go @@ -2,12 +2,13 @@ package snapshot import ( "context" + "time" "github.com/containerd/containerd/mount" ) // Kind identifies the kind of snapshot. -type Kind int +type Kind uint8 // definitions of snapshot kinds const ( @@ -31,9 +32,12 @@ func (k Kind) String() string { // Info provides information about a particular snapshot. type Info struct { - Kind Kind // active or committed snapshot - Name string // name or key of snapshot - Parent string // name of parent snapshot + Kind Kind // active or committed snapshot + Name string // name or key of snapshot + Parent string // name of parent snapshot + Labels map[string]string // Labels for snapshot + Created time.Time // Created time + Updated time.Time // Last update time } // Usage defines statistics for disk resources consumed by the snapshot. @@ -177,6 +181,11 @@ type Snapshotter interface { // the kind of snapshot. Stat(ctx context.Context, key string) (Info, error) + // Update updates the infor for a snapshot. + // + // Only mutable properties of a snapshot may be updated. + Update(ctx context.Context, info Info, fieldpaths ...string) (Info, error) + // Usage returns the resource usage of an active or committed snapshot // excluding the usage of parent snapshots. // @@ -208,7 +217,7 @@ type Snapshotter interface { // one is done with the transaction, Remove should be called on the key. // // Multiple calls to Prepare or View with the same key should fail. - Prepare(ctx context.Context, key, parent string) ([]mount.Mount, error) + Prepare(ctx context.Context, key, parent string, opts ...Opt) ([]mount.Mount, error) // View behaves identically to Prepare except the result may not be // committed back to the snapshot snapshotter. View returns a readonly view on @@ -223,7 +232,7 @@ type Snapshotter interface { // Commit may not be called on the provided key and will return an error. // To collect the resources associated with key, Remove must be called with // key as the argument. - View(ctx context.Context, key, parent string) ([]mount.Mount, error) + View(ctx context.Context, key, parent string, opts ...Opt) ([]mount.Mount, error) // Commit captures the changes between key and its parent into a snapshot // identified by name. The name can then be used with the snapshotter's other @@ -235,7 +244,7 @@ type Snapshotter interface { // Commit may be called multiple times on the same key. Snapshots created // in this manner will all reference the parent used to start the // transaction. - Commit(ctx context.Context, name, key string) error + Commit(ctx context.Context, name, key string, opts ...Opt) error // Remove the committed or active snapshot by the provided key. // @@ -249,3 +258,14 @@ type Snapshotter interface { // snapshotter, the function will be called. Walk(ctx context.Context, fn func(context.Context, Info) error) error } + +// Opt allows setting mutable snapshot properties on creation +type Opt func(info *Info) error + +// WithLabels adds labels to a created snapshot +func WithLabels(labels map[string]string) Opt { + return func(info *Info) error { + info.Labels = labels + return nil + } +} diff --git a/snapshot/storage/bolt.go b/snapshot/storage/bolt.go index abe997c29..4f0c677ce 100644 --- a/snapshot/storage/bolt.go +++ b/snapshot/storage/bolt.go @@ -4,12 +4,13 @@ import ( "context" "encoding/binary" "fmt" + "strings" + "time" "github.com/boltdb/bolt" "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/metadata/boltutil" "github.com/containerd/containerd/snapshot" - db "github.com/containerd/containerd/snapshot/storage/proto" - "github.com/gogo/protobuf/proto" "github.com/pkg/errors" ) @@ -18,6 +19,12 @@ var ( bucketKeySnapshot = []byte("snapshots") bucketKeyParents = []byte("parents") + bucketKeyID = []byte("id") + bucketKeyParent = []byte("parent") + bucketKeyKind = []byte("kind") + bucketKeyInodes = []byte("inodes") + bucketKeySize = []byte("size") + // ErrNoTransaction is returned when an operation is attempted with // a context which is not inside of a transaction. ErrNoTransaction = errors.New("no transaction in context") @@ -65,24 +72,75 @@ func getParentPrefix(b []byte) uint64 { // GetInfo returns the snapshot Info directly from the metadata. Requires a // context with a storage transaction. func GetInfo(ctx context.Context, key string) (string, snapshot.Info, snapshot.Usage, error) { - var ss db.Snapshot - err := withBucket(ctx, func(ctx context.Context, bkt, pbkt *bolt.Bucket) error { - return getSnapshot(bkt, key, &ss) + var ( + id uint64 + su snapshot.Usage + si = snapshot.Info{ + Name: key, + } + ) + err := withSnapshotBucket(ctx, key, func(ctx context.Context, bkt, pbkt *bolt.Bucket) error { + getUsage(bkt, &su) + return readSnapshot(bkt, &id, &si) }) if err != nil { return "", snapshot.Info{}, snapshot.Usage{}, err } - usage := snapshot.Usage{ - Inodes: ss.Inodes, - Size: ss.Size_, - } + return fmt.Sprintf("%d", id), si, su, nil +} - return fmt.Sprint(ss.ID), snapshot.Info{ - Name: key, - Parent: ss.Parent, - Kind: snapshot.Kind(ss.Kind), - }, usage, nil +func UpdateInfo(ctx context.Context, info snapshot.Info, fieldpaths ...string) (snapshot.Info, error) { + updated := snapshot.Info{ + Name: info.Name, + } + err := withBucket(ctx, func(ctx context.Context, bkt, pbkt *bolt.Bucket) error { + sbkt := bkt.Bucket([]byte(info.Name)) + if sbkt == nil { + return errors.Wrap(errdefs.ErrNotFound, "snapshot does not exist") + } + if err := readSnapshot(sbkt, nil, &updated); err != nil { + return err + } + + if len(fieldpaths) > 0 { + for _, path := range fieldpaths { + if strings.HasPrefix(path, "labels.") { + if updated.Labels == nil { + updated.Labels = map[string]string{} + } + + key := strings.TrimPrefix(path, "labels.") + updated.Labels[key] = info.Labels[key] + continue + } + + switch path { + case "labels": + updated.Labels = info.Labels + default: + return errors.Wrapf(errdefs.ErrInvalidArgument, "cannot update %q field on snapshot %q", path, info.Name) + } + } + } else { + // Set mutable fields + updated.Labels = info.Labels + } + updated.Updated = time.Now().UTC() + if err := boltutil.WriteTimestamps(sbkt, updated.Created, updated.Updated); err != nil { + return err + } + + if err := boltutil.WriteLabels(sbkt, updated.Labels); err != nil { + return err + } + + return nil + }) + if err != nil { + return snapshot.Info{}, err + } + return updated, nil } // WalkInfo iterates through all metadata Info for the stored snapshots and @@ -91,21 +149,21 @@ func GetInfo(ctx context.Context, key string) (string, snapshot.Info, snapshot.U func WalkInfo(ctx context.Context, fn func(context.Context, snapshot.Info) error) error { return withBucket(ctx, func(ctx context.Context, bkt, pbkt *bolt.Bucket) error { return bkt.ForEach(func(k, v []byte) error { - // skip nested buckets - if v == nil { + // skip non buckets + if v != nil { return nil } - var ss db.Snapshot - if err := proto.Unmarshal(v, &ss); err != nil { - return errors.Wrap(err, "failed to unmarshal snapshot") + var ( + sbkt = bkt.Bucket(k) + si = snapshot.Info{ + Name: string(k), + } + ) + if err := readSnapshot(sbkt, nil, &si); err != nil { + return err } - info := snapshot.Info{ - Name: string(k), - Parent: ss.Parent, - Kind: snapshot.Kind(ss.Kind), - } - return fn(ctx, info) + return fn(ctx, si) }) }) } @@ -114,30 +172,25 @@ func WalkInfo(ctx context.Context, fn func(context.Context, snapshot.Info) error // referenced by the given key. Requires a context with a storage transaction. func GetSnapshot(ctx context.Context, key string) (s Snapshot, err error) { err = withBucket(ctx, func(ctx context.Context, bkt, pbkt *bolt.Bucket) error { - b := bkt.Get([]byte(key)) - if len(b) == 0 { - return errors.Wrapf(errdefs.ErrNotFound, "snapshot %v", key) + sbkt := bkt.Bucket([]byte(key)) + if sbkt == nil { + return errors.Wrap(errdefs.ErrNotFound, "snapshot does not exist") } - var ss db.Snapshot - if err := proto.Unmarshal(b, &ss); err != nil { - return errors.Wrap(err, "failed to unmarshal snapshot") - } + s.ID = fmt.Sprintf("%d", readID(sbkt)) + s.Kind = readKind(sbkt) - if ss.Kind != db.KindActive && ss.Kind != db.KindView { + if s.Kind != snapshot.KindActive && s.Kind != snapshot.KindView { return errors.Wrapf(errdefs.ErrFailedPrecondition, "requested snapshot %v not active or view", key) } - s.ID = fmt.Sprintf("%d", ss.ID) - s.Kind = snapshot.Kind(ss.Kind) - - if ss.Parent != "" { - var parent db.Snapshot - if err := getSnapshot(bkt, ss.Parent, &parent); err != nil { - return errors.Wrap(err, "failed to get parent snapshot") + if parentKey := sbkt.Get(bucketKeyParent); len(parentKey) > 0 { + spbkt := bkt.Bucket(parentKey) + if spbkt == nil { + return errors.Wrap(errdefs.ErrNotFound, "parent does not exist") } - s.ParentIDs, err = parents(bkt, &parent) + s.ParentIDs, err = parents(bkt, spbkt, readID(spbkt)) if err != nil { return errors.Wrap(err, "failed to get parent chain") } @@ -152,30 +205,39 @@ func GetSnapshot(ctx context.Context, key string) (s Snapshot, err error) { } // CreateSnapshot inserts a record for an active or view snapshot with the provided parent. -func CreateSnapshot(ctx context.Context, kind snapshot.Kind, key, parent string) (s Snapshot, err error) { +func CreateSnapshot(ctx context.Context, kind snapshot.Kind, key, parent string, opts ...snapshot.Opt) (s Snapshot, err error) { switch kind { case snapshot.KindActive, snapshot.KindView: default: return Snapshot{}, errors.Wrapf(errdefs.ErrInvalidArgument, "snapshot type %v invalid; only snapshots of type Active or View can be created", kind) } + var base snapshot.Info + for _, opt := range opts { + if err := opt(&base); err != nil { + return Snapshot{}, err + } + } err = createBucketIfNotExists(ctx, func(ctx context.Context, bkt, pbkt *bolt.Bucket) error { var ( - parentS *db.Snapshot + spbkt *bolt.Bucket ) if parent != "" { - parentS = new(db.Snapshot) - if err := getSnapshot(bkt, parent, parentS); err != nil { - return errors.Wrap(err, "failed to get parent snapshot") + spbkt = bkt.Bucket([]byte(parent)) + if spbkt == nil { + return errors.Wrap(errdefs.ErrNotFound, "missing parent bucket") } - if parentS.Kind != db.KindCommitted { + if readKind(spbkt) != snapshot.KindCommitted { return errors.Wrap(errdefs.ErrInvalidArgument, "parent is not committed snapshot") } } - b := bkt.Get([]byte(key)) - if len(b) != 0 { - return errors.Wrapf(errdefs.ErrAlreadyExists, "snapshot %v", key) + sbkt, err := bkt.CreateBucket([]byte(key)) + if err != nil { + if err == bolt.ErrBucketExists { + err = errors.Wrapf(errdefs.ErrAlreadyExists, "snapshot %v", key) + } + return err } id, err := bkt.NextSequence() @@ -183,23 +245,28 @@ func CreateSnapshot(ctx context.Context, kind snapshot.Kind, key, parent string) return errors.Wrap(err, "unable to get identifier") } - ss := db.Snapshot{ - ID: id, - Parent: parent, - Kind: db.Kind(kind), + t := time.Now().UTC() + si := snapshot.Info{ + Parent: parent, + Kind: kind, + Labels: base.Labels, + Created: t, + Updated: t, } - if err := putSnapshot(bkt, key, &ss); err != nil { + if err := putSnapshot(sbkt, id, si); err != nil { return err } - if parentS != nil { + if spbkt != nil { + pid := readID(spbkt) + // Store a backlink from the key to the parent. Store the snapshot name // as the value to allow following the backlink to the snapshot value. - if err := pbkt.Put(parentKey(parentS.ID, ss.ID), []byte(key)); err != nil { + if err := pbkt.Put(parentKey(pid, id), []byte(key)); err != nil { return errors.Wrap(err, "failed to write parent link") } - s.ParentIDs, err = parents(bkt, parentS) + s.ParentIDs, err = parents(bkt, spbkt, pid) if err != nil { return errors.Wrap(err, "failed to get parent chain") } @@ -219,47 +286,50 @@ func CreateSnapshot(ctx context.Context, kind snapshot.Kind, key, parent string) // Remove removes a snapshot from the metastore. The string identifier for the // snapshot is returned as well as the kind. The provided context must contain a // writable transaction. -func Remove(ctx context.Context, key string) (id string, k snapshot.Kind, err error) { - err = withBucket(ctx, func(ctx context.Context, bkt, pbkt *bolt.Bucket) error { - var ss db.Snapshot - b := bkt.Get([]byte(key)) - if len(b) == 0 { +func Remove(ctx context.Context, key string) (string, snapshot.Kind, error) { + var ( + id uint64 + si snapshot.Info + ) + + if err := withBucket(ctx, func(ctx context.Context, bkt, pbkt *bolt.Bucket) error { + sbkt := bkt.Bucket([]byte(key)) + if sbkt == nil { return errors.Wrapf(errdefs.ErrNotFound, "snapshot %v", key) } - if err := proto.Unmarshal(b, &ss); err != nil { - return errors.Wrap(err, "failed to unmarshal snapshot") + if err := readSnapshot(sbkt, &id, &si); err != nil { + errors.Wrapf(err, "failed to read snapshot %s", key) } if pbkt != nil { - k, _ := pbkt.Cursor().Seek(parentPrefixKey(ss.ID)) - if getParentPrefix(k) == ss.ID { + k, _ := pbkt.Cursor().Seek(parentPrefixKey(id)) + if getParentPrefix(k) == id { return errors.Errorf("cannot remove snapshot with child") } - if ss.Parent != "" { - var ps db.Snapshot - if err := getSnapshot(bkt, ss.Parent, &ps); err != nil { - return errors.Wrap(err, "failed to get parent snapshot") + if si.Parent != "" { + spbkt := bkt.Bucket([]byte(si.Parent)) + if spbkt == nil { + return errors.Wrapf(errdefs.ErrNotFound, "snapshot %v", key) } - if err := pbkt.Delete(parentKey(ps.ID, ss.ID)); err != nil { - return errors.Wrap(err, "failed to delte parent link") + if err := pbkt.Delete(parentKey(readID(spbkt), id)); err != nil { + return errors.Wrap(err, "failed to delete parent link") } } } - if err := bkt.Delete([]byte(key)); err != nil { + if err := bkt.DeleteBucket([]byte(key)); err != nil { return errors.Wrap(err, "failed to delete snapshot") } - id = fmt.Sprintf("%d", ss.ID) - k = snapshot.Kind(ss.Kind) - return nil - }) + }); err != nil { + return "", 0, err + } - return + return fmt.Sprintf("%d", id), si.Kind, nil } // CommitActive renames the active snapshot transaction referenced by `key` @@ -268,52 +338,94 @@ func Remove(ctx context.Context, key string) (id string, k snapshot.Kind, err er // lookup or removal. The returned string identifier for the committed snapshot // is the same identifier of the original active snapshot. The provided context // must contain a writable transaction. -func CommitActive(ctx context.Context, key, name string, usage snapshot.Usage) (id string, err error) { - err = withBucket(ctx, func(ctx context.Context, bkt, pbkt *bolt.Bucket) error { - b := bkt.Get([]byte(name)) - if len(b) != 0 { - return errors.Wrapf(errdefs.ErrAlreadyExists, "committed snapshot %v", name) +func CommitActive(ctx context.Context, key, name string, usage snapshot.Usage, opts ...snapshot.Opt) (string, error) { + var ( + id uint64 + base snapshot.Info + ) + for _, opt := range opts { + if err := opt(&base); err != nil { + return "", err + } + } + + if err := withBucket(ctx, func(ctx context.Context, bkt, pbkt *bolt.Bucket) error { + dbkt, err := bkt.CreateBucket([]byte(name)) + if err != nil { + if err == bolt.ErrBucketExists { + err = errdefs.ErrAlreadyExists + } + return errors.Wrapf(err, "committed snapshot %v", name) + } + sbkt := bkt.Bucket([]byte(key)) + if sbkt == nil { + return errors.Wrap(errdefs.ErrNotFound, "failed to get active snapshot") } - var ss db.Snapshot - if err := getSnapshot(bkt, key, &ss); err != nil { - return errors.Wrap(err, "failed to get active snapshot") + var si snapshot.Info + if err := readSnapshot(sbkt, &id, &si); err != nil { + return errors.Wrap(err, "failed to read snapshot") } - if ss.Kind != db.KindActive { + + if si.Kind != snapshot.KindActive { return errors.Wrapf(errdefs.ErrFailedPrecondition, "snapshot %v is not active", name) } + si.Kind = snapshot.KindCommitted + si.Created = time.Now().UTC() + si.Updated = si.Created - ss.Kind = db.KindCommitted - ss.Inodes = usage.Inodes - ss.Size_ = usage.Size + // Replace labels, do not inherit + si.Labels = base.Labels - if err := putSnapshot(bkt, name, &ss); err != nil { + if err := putSnapshot(dbkt, id, si); err != nil { return err } - if err := bkt.Delete([]byte(key)); err != nil { + if err := putUsage(dbkt, usage); err != nil { + return err + } + if err := bkt.DeleteBucket([]byte(key)); err != nil { return errors.Wrap(err, "failed to delete active") } - if ss.Parent != "" { - var ps db.Snapshot - if err := getSnapshot(bkt, ss.Parent, &ps); err != nil { - return errors.Wrap(err, "failed to get parent snapshot") + if si.Parent != "" { + spbkt := bkt.Bucket([]byte(si.Parent)) + if spbkt == nil { + return errors.Wrap(errdefs.ErrNotFound, "missing parent") } + pid := readID(spbkt) // Updates parent back link to use new key - if err := pbkt.Put(parentKey(ps.ID, ss.ID), []byte(name)); err != nil { + if err := pbkt.Put(parentKey(pid, id), []byte(name)); err != nil { return errors.Wrap(err, "failed to update parent link") } } - id = fmt.Sprintf("%d", ss.ID) - return nil - }) - if err != nil { + }); err != nil { return "", err } - return + return fmt.Sprintf("%d", id), nil +} + +func withSnapshotBucket(ctx context.Context, key string, fn func(context.Context, *bolt.Bucket, *bolt.Bucket) error) error { + t, ok := ctx.Value(transactionKey{}).(*boltFileTransactor) + if !ok { + return ErrNoTransaction + } + bkt := t.tx.Bucket(bucketKeyStorageVersion) + if bkt == nil { + return errors.Wrap(errdefs.ErrNotFound, "bucket does not exist") + } + bkt = bkt.Bucket(bucketKeySnapshot) + if bkt == nil { + return errors.Wrap(errdefs.ErrNotFound, "snapshots bucket does not exist") + } + bkt = bkt.Bucket([]byte(key)) + if bkt == nil { + return errors.Wrap(errdefs.ErrNotFound, "snapshot does not exist") + } + + return fn(ctx, bkt, bkt.Bucket(bucketKeyParents)) } func withBucket(ctx context.Context, fn func(context.Context, *bolt.Bucket, *bolt.Bucket) error) error { @@ -349,41 +461,133 @@ func createBucketIfNotExists(ctx context.Context, fn func(context.Context, *bolt return fn(ctx, sbkt, pbkt) } -func parents(bkt *bolt.Bucket, parent *db.Snapshot) (parents []string, err error) { +func parents(bkt, pbkt *bolt.Bucket, parent uint64) (parents []string, err error) { for { - parents = append(parents, fmt.Sprintf("%d", parent.ID)) + parents = append(parents, fmt.Sprintf("%d", parent)) - if parent.Parent == "" { + parentKey := pbkt.Get(bucketKeyParent) + if len(parentKey) == 0 { return } - - var ps db.Snapshot - if err := getSnapshot(bkt, parent.Parent, &ps); err != nil { - return nil, errors.Wrap(err, "failed to get parent snapshot") + pbkt = bkt.Bucket(parentKey) + if pbkt == nil { + return nil, errors.Wrap(errdefs.ErrNotFound, "missing parent") } - parent = &ps + + parent = readID(pbkt) } } -func getSnapshot(bkt *bolt.Bucket, key string, ss *db.Snapshot) error { - b := bkt.Get([]byte(key)) - if len(b) == 0 { - return errors.Wrapf(errdefs.ErrNotFound, "snapshot %v", key) +func readKind(bkt *bolt.Bucket) (k snapshot.Kind) { + kind := bkt.Get(bucketKeyKind) + if len(kind) == 1 { + k = snapshot.Kind(kind[0]) } - if err := proto.Unmarshal(b, ss); err != nil { - return errors.Wrap(err, "failed to unmarshal snapshot") + return +} + +func readID(bkt *bolt.Bucket) uint64 { + id, _ := binary.Uvarint(bkt.Get(bucketKeyID)) + return id +} + +func readSnapshot(bkt *bolt.Bucket, id *uint64, si *snapshot.Info) error { + if id != nil { + *id = readID(bkt) } + if si != nil { + si.Kind = readKind(bkt) + si.Parent = string(bkt.Get(bucketKeyParent)) + + if err := boltutil.ReadTimestamps(bkt, &si.Created, &si.Updated); err != nil { + return err + } + + labels, err := boltutil.ReadLabels(bkt) + if err != nil { + return err + } + si.Labels = labels + } + return nil } -func putSnapshot(bkt *bolt.Bucket, key string, ss *db.Snapshot) error { - b, err := proto.Marshal(ss) +func putSnapshot(bkt *bolt.Bucket, id uint64, si snapshot.Info) error { + idEncoded, err := encodeID(id) if err != nil { - return errors.Wrap(err, "failed to marshal snapshot") + return err } - if err := bkt.Put([]byte(key), b); err != nil { - return errors.Wrap(err, "failed to save snapshot") + updates := [][2][]byte{ + {bucketKeyID, idEncoded}, + {bucketKeyKind, []byte{byte(si.Kind)}}, + } + if si.Parent != "" { + updates = append(updates, [2][]byte{bucketKeyParent, []byte(si.Parent)}) + } + for _, v := range updates { + if err := bkt.Put(v[0], v[1]); err != nil { + return err + } + } + if err := boltutil.WriteTimestamps(bkt, si.Created, si.Updated); err != nil { + return err + } + + if err := boltutil.WriteLabels(bkt, si.Labels); err != nil { + return err + } + + return nil +} + +func getUsage(bkt *bolt.Bucket, usage *snapshot.Usage) { + usage.Inodes, _ = binary.Varint(bkt.Get(bucketKeyInodes)) + usage.Size, _ = binary.Varint(bkt.Get(bucketKeySize)) +} + +func putUsage(bkt *bolt.Bucket, usage snapshot.Usage) error { + for _, v := range []struct { + key []byte + value int64 + }{ + {bucketKeyInodes, usage.Inodes}, + {bucketKeySize, usage.Size}, + } { + e, err := encodeSize(v.value) + if err != nil { + return err + } + if err := bkt.Put(v.key, e); err != nil { + return err + } } return nil } + +func encodeSize(size int64) ([]byte, error) { + var ( + buf [binary.MaxVarintLen64]byte + sizeEncoded []byte = buf[:] + ) + sizeEncoded = sizeEncoded[:binary.PutVarint(sizeEncoded, size)] + + if len(sizeEncoded) == 0 { + return nil, fmt.Errorf("failed encoding size = %v", size) + } + return sizeEncoded, nil +} + +func encodeID(id uint64) ([]byte, error) { + var ( + buf [binary.MaxVarintLen64]byte + idEncoded []byte = buf[:] + ) + idEncoded = idEncoded[:binary.PutUvarint(idEncoded, id)] + + if len(idEncoded) == 0 { + return nil, fmt.Errorf("failed encoding id = %v", id) + } + return idEncoded, nil +} diff --git a/snapshot/storage/bolt_test.go b/snapshot/storage/bolt_test.go index cacbab270..a3e73a6d5 100644 --- a/snapshot/storage/bolt_test.go +++ b/snapshot/storage/bolt_test.go @@ -5,8 +5,7 @@ import ( "testing" // Does not require root but flag must be defined for snapshot tests - "github.com/containerd/containerd/snapshot" - "github.com/containerd/containerd/snapshot/storage/proto" + _ "github.com/containerd/containerd/testutil" ) @@ -16,34 +15,6 @@ func TestMetastore(t *testing.T) { }) } -// TestKidnConversion ensures we can blindly cast from protobuf types. -func TestKindConversion(t *testing.T) { - for _, testcase := range []struct { - s snapshot.Kind - p proto.Kind - }{ - { - s: snapshot.KindView, - p: proto.KindView, - }, - { - s: snapshot.KindActive, - p: proto.KindActive, - }, - { - s: snapshot.KindCommitted, - p: proto.KindCommitted, - }, - } { - if testcase.s != snapshot.Kind(testcase.p) { - t.Fatalf("snapshot kind value cast failed: %v != %v", testcase.s, testcase.p) - } - if testcase.p != proto.Kind(testcase.s) { - t.Fatalf("proto kind value cast failed: %v != %v", testcase.s, testcase.p) - } - } -} - func BenchmarkSuite(b *testing.B) { Benchmarks(b, "BoltDBBench", func(root string) (*MetaStore, error) { return NewMetaStore(filepath.Join(root, "metadata.db")) diff --git a/snapshot/storage/metastore_test.go b/snapshot/storage/metastore_test.go index 9aa164f66..91455a295 100644 --- a/snapshot/storage/metastore_test.go +++ b/snapshot/storage/metastore_test.go @@ -2,9 +2,11 @@ package storage import ( "context" + "fmt" "io/ioutil" "os" "testing" + "time" "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/snapshot" @@ -40,6 +42,7 @@ func MetaStoreSuite(t *testing.T, name string, meta func(root string) (*MetaStor t.Run("Remove", makeTest(t, name, meta, inWriteTransaction(testRemove))) t.Run("RemoveNotExist", makeTest(t, name, meta, inWriteTransaction(testRemoveNotExist))) t.Run("RemoveWithChildren", makeTest(t, name, meta, inWriteTransaction(testRemoveWithChildren))) + t.Run("ParentIDs", makeTest(t, name, meta, inWriteTransaction(testParents))) } // makeTest creates a testsuite with a writable transaction @@ -236,6 +239,9 @@ func testGetInfo(ctx context.Context, t *testing.T, ms *MetaStore) { if err != nil { t.Fatalf("GetInfo on %v failed: %+v", key, err) } + // TODO: Check timestamp range + info.Created = time.Time{} + info.Updated = time.Time{} assert.Equal(t, expected, info) } } @@ -251,6 +257,9 @@ func testWalk(ctx context.Context, t *testing.T, ms *MetaStore) { if _, ok := found[info.Name]; ok { return errors.Errorf("entry already encountered") } + // TODO: Check time range + info.Created = time.Time{} + info.Updated = time.Time{} found[info.Name] = info return nil }) @@ -545,3 +554,86 @@ func testRemoveNotExist(ctx context.Context, t *testing.T, ms *MetaStore) { _, _, err := Remove(ctx, "does-not-exist") assertNotExist(t, err) } + +func testParents(ctx context.Context, t *testing.T, ms *MetaStore) { + if err := basePopulate(ctx, ms); err != nil { + t.Fatalf("Populate failed: %+v", err) + } + + testcases := []struct { + Name string + Parents int + }{ + {"committed-1", 0}, + {"committed-2", 1}, + {"active-1", 0}, + {"active-2", 1}, + {"active-3", 2}, + {"view-1", 0}, + {"view-2", 2}, + } + + for _, tc := range testcases { + name := tc.Name + expectedID := "" + expectedParents := []string{} + for i := tc.Parents; i >= 0; i-- { + sid, info, _, err := GetInfo(ctx, name) + if err != nil { + t.Fatalf("Failed to get snapshot %s: %v", tc.Name, err) + } + var ( + id string + parents []string + ) + if info.Kind == snapshot.KindCommitted { + // When commited, create view and resolve from view + nid := fmt.Sprintf("test-%s-%d", tc.Name, i) + s, err := CreateSnapshot(ctx, snapshot.KindView, nid, name) + if err != nil { + t.Fatalf("Failed to get snapshot %s: %v", tc.Name, err) + } + if len(s.ParentIDs) != i+1 { + t.Fatalf("Unexpected number of parents for view of %s: %d, expected %d", name, len(s.ParentIDs), i+1) + } + id = s.ParentIDs[0] + parents = s.ParentIDs[1:] + } else { + s, err := GetSnapshot(ctx, name) + if err != nil { + t.Fatalf("Failed to get snapshot %s: %v", tc.Name, err) + } + if len(s.ParentIDs) != i { + t.Fatalf("Unexpected number of parents for %s: %d, expected %d", name, len(s.ParentIDs), i) + } + + id = s.ID + parents = s.ParentIDs + } + if sid != id { + t.Fatalf("Info ID mismatched resolved snapshot ID for %s, %s vs %s", name, sid, id) + } + + if expectedID != "" { + if id != expectedID { + t.Errorf("Unexpected ID of parent: %s, expected %s", id, expectedID) + } + } + + if len(expectedParents) > 0 { + for j := range expectedParents { + if parents[j] != expectedParents[j] { + t.Errorf("Unexpected ID in parent array at %d: %s, expected %s", j, parents[j], expectedParents[j]) + } + } + } + + if i > 0 { + name = info.Parent + expectedID = parents[0] + expectedParents = parents[1:] + } + + } + } +} diff --git a/snapshot/storage/proto/record.pb.go b/snapshot/storage/proto/record.pb.go deleted file mode 100644 index bfaa67d0b..000000000 --- a/snapshot/storage/proto/record.pb.go +++ /dev/null @@ -1,506 +0,0 @@ -// Code generated by protoc-gen-gogo. -// source: github.com/containerd/containerd/snapshot/storage/proto/record.proto -// DO NOT EDIT! - -/* - Package proto is a generated protocol buffer package. - - It is generated from these files: - github.com/containerd/containerd/snapshot/storage/proto/record.proto - - It has these top-level messages: - Snapshot -*/ -package proto - -import proto1 "github.com/gogo/protobuf/proto" -import fmt "fmt" -import math "math" -import _ "github.com/gogo/protobuf/gogoproto" - -import strings "strings" -import reflect "reflect" - -import io "io" - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto1.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto1.GoGoProtoPackageIsVersion2 // please upgrade the proto package - -type Kind int32 - -const ( - KindUnknown Kind = 0 - KindView Kind = 1 - KindActive Kind = 2 - KindCommitted Kind = 3 -) - -var Kind_name = map[int32]string{ - 0: "UNKNOWN", - 1: "VIEW", - 2: "ACTIVE", - 3: "COMMITTED", -} -var Kind_value = map[string]int32{ - "UNKNOWN": 0, - "VIEW": 1, - "ACTIVE": 2, - "COMMITTED": 3, -} - -func (x Kind) String() string { - return proto1.EnumName(Kind_name, int32(x)) -} -func (Kind) EnumDescriptor() ([]byte, []int) { return fileDescriptorRecord, []int{0} } - -// Snapshot defines the storage type for a snapshot in the -// metadata store. -type Snapshot struct { - ID uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` - Parent string `protobuf:"bytes,2,opt,name=parent,proto3" json:"parent,omitempty"` - Kind Kind `protobuf:"varint,4,opt,name=kind,proto3,enum=containerd.snapshot.v1.Kind" json:"kind,omitempty"` - // inodes stores the number inodes in use for the snapshot. - // - // Only valid for committed snapshots. - Inodes int64 `protobuf:"varint,6,opt,name=inodes,proto3" json:"inodes,omitempty"` - // Size reports the disk used by the snapshot, excluding the parents. - // - // Only valid for committed snapshots, active snapshots must read the - // current usage from the disk. - Size_ int64 `protobuf:"varint,7,opt,name=size,proto3" json:"size,omitempty"` -} - -func (m *Snapshot) Reset() { *m = Snapshot{} } -func (*Snapshot) ProtoMessage() {} -func (*Snapshot) Descriptor() ([]byte, []int) { return fileDescriptorRecord, []int{0} } - -func init() { - proto1.RegisterType((*Snapshot)(nil), "containerd.snapshot.v1.Snapshot") - proto1.RegisterEnum("containerd.snapshot.v1.Kind", Kind_name, Kind_value) -} -func (m *Snapshot) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *Snapshot) MarshalTo(dAtA []byte) (int, error) { - var i int - _ = i - var l int - _ = l - if m.ID != 0 { - dAtA[i] = 0x8 - i++ - i = encodeVarintRecord(dAtA, i, uint64(m.ID)) - } - if len(m.Parent) > 0 { - dAtA[i] = 0x12 - i++ - i = encodeVarintRecord(dAtA, i, uint64(len(m.Parent))) - i += copy(dAtA[i:], m.Parent) - } - if m.Kind != 0 { - dAtA[i] = 0x20 - i++ - i = encodeVarintRecord(dAtA, i, uint64(m.Kind)) - } - if m.Inodes != 0 { - dAtA[i] = 0x30 - i++ - i = encodeVarintRecord(dAtA, i, uint64(m.Inodes)) - } - if m.Size_ != 0 { - dAtA[i] = 0x38 - i++ - i = encodeVarintRecord(dAtA, i, uint64(m.Size_)) - } - return i, nil -} - -func encodeFixed64Record(dAtA []byte, offset int, v uint64) int { - dAtA[offset] = uint8(v) - dAtA[offset+1] = uint8(v >> 8) - dAtA[offset+2] = uint8(v >> 16) - dAtA[offset+3] = uint8(v >> 24) - dAtA[offset+4] = uint8(v >> 32) - dAtA[offset+5] = uint8(v >> 40) - dAtA[offset+6] = uint8(v >> 48) - dAtA[offset+7] = uint8(v >> 56) - return offset + 8 -} -func encodeFixed32Record(dAtA []byte, offset int, v uint32) int { - dAtA[offset] = uint8(v) - dAtA[offset+1] = uint8(v >> 8) - dAtA[offset+2] = uint8(v >> 16) - dAtA[offset+3] = uint8(v >> 24) - return offset + 4 -} -func encodeVarintRecord(dAtA []byte, offset int, v uint64) int { - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ - } - dAtA[offset] = uint8(v) - return offset + 1 -} -func (m *Snapshot) Size() (n int) { - var l int - _ = l - if m.ID != 0 { - n += 1 + sovRecord(uint64(m.ID)) - } - l = len(m.Parent) - if l > 0 { - n += 1 + l + sovRecord(uint64(l)) - } - if m.Kind != 0 { - n += 1 + sovRecord(uint64(m.Kind)) - } - if m.Inodes != 0 { - n += 1 + sovRecord(uint64(m.Inodes)) - } - if m.Size_ != 0 { - n += 1 + sovRecord(uint64(m.Size_)) - } - return n -} - -func sovRecord(x uint64) (n int) { - for { - n++ - x >>= 7 - if x == 0 { - break - } - } - return n -} -func sozRecord(x uint64) (n int) { - return sovRecord(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} -func (this *Snapshot) String() string { - if this == nil { - return "nil" - } - s := strings.Join([]string{`&Snapshot{`, - `ID:` + fmt.Sprintf("%v", this.ID) + `,`, - `Parent:` + fmt.Sprintf("%v", this.Parent) + `,`, - `Kind:` + fmt.Sprintf("%v", this.Kind) + `,`, - `Inodes:` + fmt.Sprintf("%v", this.Inodes) + `,`, - `Size_:` + fmt.Sprintf("%v", this.Size_) + `,`, - `}`, - }, "") - return s -} -func valueToStringRecord(v interface{}) string { - rv := reflect.ValueOf(v) - if rv.IsNil() { - return "nil" - } - pv := reflect.Indirect(rv).Interface() - return fmt.Sprintf("*%v", pv) -} -func (m *Snapshot) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowRecord - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: Snapshot: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: Snapshot: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field ID", wireType) - } - m.ID = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowRecord - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.ID |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Parent", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowRecord - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthRecord - } - postIndex := iNdEx + intStringLen - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Parent = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 4: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Kind", wireType) - } - m.Kind = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowRecord - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Kind |= (Kind(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 6: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Inodes", wireType) - } - m.Inodes = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowRecord - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Inodes |= (int64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - case 7: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Size_", wireType) - } - m.Size_ = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowRecord - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Size_ |= (int64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - default: - iNdEx = preIndex - skippy, err := skipRecord(dAtA[iNdEx:]) - if err != nil { - return err - } - if skippy < 0 { - return ErrInvalidLengthRecord - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func skipRecord(dAtA []byte) (n int, err error) { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowRecord - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - wireType := int(wire & 0x7) - switch wireType { - case 0: - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowRecord - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - iNdEx++ - if dAtA[iNdEx-1] < 0x80 { - break - } - } - return iNdEx, nil - case 1: - iNdEx += 8 - return iNdEx, nil - case 2: - var length int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowRecord - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - length |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - iNdEx += length - if length < 0 { - return 0, ErrInvalidLengthRecord - } - return iNdEx, nil - case 3: - for { - var innerWire uint64 - var start int = iNdEx - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowRecord - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - innerWire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - innerWireType := int(innerWire & 0x7) - if innerWireType == 4 { - break - } - next, err := skipRecord(dAtA[start:]) - if err != nil { - return 0, err - } - iNdEx = start + next - } - return iNdEx, nil - case 4: - return iNdEx, nil - case 5: - iNdEx += 4 - return iNdEx, nil - default: - return 0, fmt.Errorf("proto: illegal wireType %d", wireType) - } - } - panic("unreachable") -} - -var ( - ErrInvalidLengthRecord = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowRecord = fmt.Errorf("proto: integer overflow") -) - -func init() { - proto1.RegisterFile("github.com/containerd/containerd/snapshot/storage/proto/record.proto", fileDescriptorRecord) -} - -var fileDescriptorRecord = []byte{ - // 364 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x90, 0xbb, 0xae, 0xd3, 0x30, - 0x18, 0xc7, 0xe3, 0x9c, 0x28, 0xe7, 0xd4, 0x94, 0x12, 0x2c, 0x14, 0x45, 0x51, 0x65, 0x2c, 0xa6, - 0x88, 0x21, 0xe1, 0xf2, 0x04, 0xbd, 0x0d, 0x51, 0xd5, 0x56, 0x0a, 0xbd, 0xcc, 0x69, 0x6c, 0xa5, - 0x56, 0x55, 0xbb, 0x4a, 0x4c, 0x2b, 0x31, 0x31, 0x56, 0x79, 0x02, 0x96, 0x4c, 0xf0, 0x14, 0x3c, - 0x41, 0x47, 0x46, 0x26, 0x44, 0xf3, 0x24, 0x28, 0x69, 0x11, 0x0c, 0x67, 0xfb, 0x5f, 0x7e, 0xf6, - 0xf7, 0xe9, 0x83, 0xc3, 0x94, 0xab, 0xcd, 0xc7, 0xb5, 0x9f, 0xc8, 0x5d, 0x90, 0x48, 0xa1, 0x62, - 0x2e, 0x58, 0x46, 0xff, 0x97, 0xb9, 0x88, 0xf7, 0xf9, 0x46, 0xaa, 0x20, 0x57, 0x32, 0x8b, 0x53, - 0x16, 0xec, 0x33, 0xa9, 0x64, 0x90, 0xb1, 0x44, 0x66, 0xd4, 0x6f, 0x0c, 0xb2, 0xff, 0xf1, 0xfe, - 0x5f, 0xde, 0x3f, 0xbc, 0x75, 0x5f, 0xa4, 0x32, 0x95, 0x57, 0xbe, 0x56, 0x57, 0xfa, 0xd5, 0x17, - 0x00, 0x1f, 0x3e, 0xdc, 0x28, 0x64, 0x43, 0x9d, 0x53, 0x07, 0x10, 0xe0, 0x19, 0x7d, 0xb3, 0xfa, - 0xf5, 0x52, 0x0f, 0x87, 0x91, 0xce, 0x29, 0xb2, 0xa1, 0xb9, 0x8f, 0x33, 0x26, 0x94, 0xa3, 0x13, - 0xe0, 0xb5, 0xa2, 0x9b, 0x43, 0x6f, 0xa0, 0xb1, 0xe5, 0x82, 0x3a, 0x06, 0x01, 0x5e, 0xe7, 0x5d, - 0xd7, 0x7f, 0x7c, 0xb2, 0x3f, 0xe6, 0x82, 0x46, 0x0d, 0x59, 0xff, 0xc4, 0x85, 0xa4, 0x2c, 0x77, - 0x4c, 0x02, 0xbc, 0xbb, 0xe8, 0xe6, 0x10, 0x82, 0x46, 0xce, 0x3f, 0x31, 0xe7, 0xbe, 0x49, 0x1b, - 0xfd, 0xfa, 0x04, 0xa0, 0x51, 0x3f, 0x45, 0x5d, 0x78, 0xbf, 0x98, 0x8e, 0xa7, 0xb3, 0xd5, 0xd4, - 0xd2, 0xdc, 0x67, 0x45, 0x49, 0x9e, 0xd4, 0xf1, 0x42, 0x6c, 0x85, 0x3c, 0x0a, 0x64, 0x43, 0x63, - 0x19, 0x8e, 0x56, 0x16, 0x70, 0xdb, 0x45, 0x49, 0x1e, 0xea, 0x6a, 0xc9, 0xd9, 0x11, 0xb9, 0xd0, - 0xec, 0x0d, 0xe6, 0xe1, 0x72, 0x64, 0xe9, 0x6e, 0xa7, 0x28, 0x09, 0xac, 0x9b, 0x5e, 0xa2, 0xf8, - 0x81, 0x21, 0x02, 0x5b, 0x83, 0xd9, 0x64, 0x12, 0xce, 0xe7, 0xa3, 0xa1, 0x75, 0xe7, 0x3e, 0x2f, - 0x4a, 0xf2, 0xb4, 0xae, 0x07, 0x72, 0xb7, 0xe3, 0x4a, 0x31, 0xea, 0xb6, 0x4f, 0x5f, 0xb1, 0xf6, - 0xfd, 0x1b, 0x6e, 0x36, 0xe8, 0x3b, 0xe7, 0x0b, 0xd6, 0x7e, 0x5e, 0xb0, 0xf6, 0xb9, 0xc2, 0xe0, - 0x5c, 0x61, 0xf0, 0xa3, 0xc2, 0xe0, 0x77, 0x85, 0xc1, 0xda, 0x6c, 0xce, 0xf8, 0xfe, 0x4f, 0x00, - 0x00, 0x00, 0xff, 0xff, 0x61, 0xef, 0x92, 0x3d, 0xbc, 0x01, 0x00, 0x00, -} diff --git a/snapshot/storage/proto/record.proto b/snapshot/storage/proto/record.proto deleted file mode 100644 index 50a462a07..000000000 --- a/snapshot/storage/proto/record.proto +++ /dev/null @@ -1,34 +0,0 @@ -syntax = "proto3"; - -package containerd.snapshot.v1; - -import "gogoproto/gogo.proto"; - -enum Kind { - option (gogoproto.goproto_enum_prefix) = false; - option (gogoproto.enum_customname) = "Kind"; - - UNKNOWN = 0 [(gogoproto.enumvalue_customname) = "KindUnknown"]; - VIEW = 1 [(gogoproto.enumvalue_customname) = "KindView"]; - ACTIVE = 2 [(gogoproto.enumvalue_customname) = "KindActive"]; - COMMITTED = 3 [(gogoproto.enumvalue_customname) = "KindCommitted"]; -} - -// Snapshot defines the storage type for a snapshot in the -// metadata store. -message Snapshot { - uint64 id = 1; - string parent = 2; - Kind kind = 4; - - // inodes stores the number inodes in use for the snapshot. - // - // Only valid for committed snapshots. - int64 inodes = 6; - - // Size reports the disk used by the snapshot, excluding the parents. - // - // Only valid for committed snapshots, active snapshots must read the - // current usage from the disk. - int64 size = 7; -} From 55c3711fab69460465dce75c1fbfe59d55978825 Mon Sep 17 00:00:00 2001 From: Derek McGowan Date: Tue, 1 Aug 2017 16:12:45 -0700 Subject: [PATCH 3/6] Update snapshot metadata to support labels Updates structure of snapshot metadata to add labels and updates. Signed-off-by: Derek McGowan --- metadata/buckets.go | 1 + metadata/snapshot.go | 343 ++++++++++++++++++++++++++++++++++++------- 2 files changed, 287 insertions(+), 57 deletions(-) diff --git a/metadata/buckets.go b/metadata/buckets.go index 4bbcbe043..4bcfb203c 100644 --- a/metadata/buckets.go +++ b/metadata/buckets.go @@ -44,6 +44,7 @@ var ( bucketKeyImage = []byte("image") bucketKeyRuntime = []byte("runtime") bucketKeyName = []byte("name") + bucketKeyParent = []byte("parent") bucketKeyOptions = []byte("options") bucketKeySpec = []byte("spec") bucketKeyRootFS = []byte("rootfs") diff --git a/metadata/snapshot.go b/metadata/snapshot.go index f2267ec53..708843fa0 100644 --- a/metadata/snapshot.go +++ b/metadata/snapshot.go @@ -4,9 +4,11 @@ import ( "context" "fmt" "strings" + "time" "github.com/boltdb/bolt" "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/metadata/boltutil" "github.com/containerd/containerd/mount" "github.com/containerd/containerd/namespaces" "github.com/containerd/containerd/snapshot" @@ -46,7 +48,11 @@ func getKey(tx *bolt.Tx, ns, name, key string) string { if bkt == nil { return "" } - v := bkt.Get([]byte(key)) + bkt = bkt.Bucket([]byte(key)) + if bkt == nil { + return "" + } + v := bkt.Get(bucketKeyName) if len(v) == 0 { return "" } @@ -74,20 +80,144 @@ func (s *snapshotter) resolveKey(ctx context.Context, key string) (string, error } func (s *snapshotter) Stat(ctx context.Context, key string) (snapshot.Info, error) { - bkey, err := s.resolveKey(ctx, key) + ns, err := namespaces.NamespaceRequired(ctx) if err != nil { return snapshot.Info{}, err } + + var ( + bkey string + local = snapshot.Info{ + Name: key, + } + ) + if err := view(ctx, s.db, func(tx *bolt.Tx) error { + bkt := getSnapshotterBucket(tx, ns, s.name) + if bkt == nil { + return errors.Wrapf(errdefs.ErrNotFound, "snapshot %v does not exist", key) + } + sbkt := bkt.Bucket([]byte(key)) + if sbkt == nil { + return errors.Wrapf(errdefs.ErrNotFound, "snapshot %v does not exist", key) + } + local.Labels, err = boltutil.ReadLabels(sbkt) + if err != nil { + return errors.Wrap(err, "failed to read labels") + } + if err := boltutil.ReadTimestamps(sbkt, &local.Created, &local.Updated); err != nil { + return errors.Wrap(err, "failed to read timestamps") + } + bkey = string(sbkt.Get(bucketKeyName)) + local.Parent = string(sbkt.Get(bucketKeyParent)) + + return nil + }); err != nil { + return snapshot.Info{}, err + } + info, err := s.Snapshotter.Stat(ctx, bkey) if err != nil { return snapshot.Info{}, err } - info.Name = trimKey(info.Name) - if info.Parent != "" { - info.Parent = trimKey(info.Parent) + + return overlayInfo(info, local), nil +} + +func (s *snapshotter) Update(ctx context.Context, info snapshot.Info, fieldpaths ...string) (snapshot.Info, error) { + ns, err := namespaces.NamespaceRequired(ctx) + if err != nil { + return snapshot.Info{}, err } - return info, nil + if info.Name == "" { + return snapshot.Info{}, errors.Wrap(errdefs.ErrInvalidArgument, "") + } + + var ( + bkey string + local = snapshot.Info{ + Name: info.Name, + } + ) + if err := update(ctx, s.db, func(tx *bolt.Tx) error { + bkt := getSnapshotterBucket(tx, ns, s.name) + if bkt == nil { + return errors.Wrapf(errdefs.ErrNotFound, "snapshot %v does not exist", info.Name) + } + sbkt := bkt.Bucket([]byte(info.Name)) + if sbkt == nil { + return errors.Wrapf(errdefs.ErrNotFound, "snapshot %v does not exist", info.Name) + } + + local.Labels, err = boltutil.ReadLabels(sbkt) + if err != nil { + return errors.Wrap(err, "failed to read labels") + } + if err := boltutil.ReadTimestamps(sbkt, &local.Created, &local.Updated); err != nil { + return errors.Wrap(err, "failed to read timestamps") + } + + // Handle field updates + if len(fieldpaths) > 0 { + for _, path := range fieldpaths { + if strings.HasPrefix(path, "labels.") { + if local.Labels == nil { + local.Labels = map[string]string{} + } + + key := strings.TrimPrefix(path, "labels.") + local.Labels[key] = info.Labels[key] + continue + } + + switch path { + case "labels": + local.Labels = info.Labels + default: + return errors.Wrapf(errdefs.ErrInvalidArgument, "cannot update %q field on snapshot %q", path, info.Name) + } + } + } else { + local.Labels = info.Labels + } + local.Updated = time.Now().UTC() + + if err := boltutil.WriteTimestamps(sbkt, local.Created, local.Updated); err != nil { + return errors.Wrap(err, "failed to read timestamps") + } + if err := boltutil.WriteLabels(sbkt, local.Labels); err != nil { + return errors.Wrap(err, "failed to read labels") + } + bkey = string(sbkt.Get(bucketKeyName)) + local.Parent = string(sbkt.Get(bucketKeyParent)) + + return nil + }); err != nil { + return snapshot.Info{}, err + } + + info, err = s.Snapshotter.Stat(ctx, bkey) + if err != nil { + return snapshot.Info{}, err + } + + return overlayInfo(info, local), nil +} + +func overlayInfo(info, overlay snapshot.Info) snapshot.Info { + // Merge info + info.Name = overlay.Name + info.Created = overlay.Created + info.Updated = overlay.Updated + info.Parent = overlay.Parent + if info.Labels == nil { + info.Labels = overlay.Labels + } else { + for k, v := range overlay.Labels { + overlay.Labels[k] = v + } + } + return info } func (s *snapshotter) Usage(ctx context.Context, key string) (snapshot.Usage, error) { @@ -106,20 +236,27 @@ func (s *snapshotter) Mounts(ctx context.Context, key string) ([]mount.Mount, er return s.Snapshotter.Mounts(ctx, bkey) } -func (s *snapshotter) Prepare(ctx context.Context, key, parent string) ([]mount.Mount, error) { - return s.createSnapshot(ctx, key, parent, false) +func (s *snapshotter) Prepare(ctx context.Context, key, parent string, opts ...snapshot.Opt) ([]mount.Mount, error) { + return s.createSnapshot(ctx, key, parent, false, opts) } -func (s *snapshotter) View(ctx context.Context, key, parent string) ([]mount.Mount, error) { - return s.createSnapshot(ctx, key, parent, true) +func (s *snapshotter) View(ctx context.Context, key, parent string, opts ...snapshot.Opt) ([]mount.Mount, error) { + return s.createSnapshot(ctx, key, parent, true, opts) } -func (s *snapshotter) createSnapshot(ctx context.Context, key, parent string, readonly bool) ([]mount.Mount, error) { +func (s *snapshotter) createSnapshot(ctx context.Context, key, parent string, readonly bool, opts []snapshot.Opt) ([]mount.Mount, error) { ns, err := namespaces.NamespaceRequired(ctx) if err != nil { return nil, err } + var base snapshot.Info + for _, opt := range opts { + if err := opt(&base); err != nil { + return nil, err + } + } + var m []mount.Mount if err := update(ctx, s.db, func(tx *bolt.Tx) error { bkt, err := createSnapshotterBucket(tx, ns, s.name) @@ -127,24 +264,40 @@ func (s *snapshotter) createSnapshot(ctx context.Context, key, parent string, re return err } - bkey := string(bkt.Get([]byte(key))) - if bkey != "" { - return errors.Wrapf(errdefs.ErrAlreadyExists, "snapshot %v already exists", key) + bbkt, err := bkt.CreateBucket([]byte(key)) + if err != nil { + if err == bolt.ErrBucketExists { + err = errors.Wrapf(errdefs.ErrAlreadyExists, "snapshot %v already exists", key) + } + return err } var bparent string if parent != "" { - bparent = string(bkt.Get([]byte(parent))) - if bparent == "" { + pbkt := bkt.Bucket([]byte(parent)) + if pbkt == nil { return errors.Wrapf(errdefs.ErrNotFound, "snapshot %v does not exist", parent) } + bparent = string(pbkt.Get(bucketKeyName)) + + if err := bbkt.Put(bucketKeyParent, []byte(parent)); err != nil { + return err + } } sid, err := bkt.NextSequence() if err != nil { return err } - bkey = createKey(sid, ns, key) - if err := bkt.Put([]byte(key), []byte(bkey)); err != nil { + bkey := createKey(sid, ns, key) + if err := bbkt.Put(bucketKeyName, []byte(bkey)); err != nil { + return err + } + + ts := time.Now().UTC() + if err := boltutil.WriteTimestamps(bbkt, ts, ts); err != nil { + return err + } + if err := boltutil.WriteLabels(bbkt, base.Labels); err != nil { return err } @@ -162,37 +315,62 @@ func (s *snapshotter) createSnapshot(ctx context.Context, key, parent string, re return m, nil } -func (s *snapshotter) Commit(ctx context.Context, name, key string) error { +func (s *snapshotter) Commit(ctx context.Context, name, key string, opts ...snapshot.Opt) error { ns, err := namespaces.NamespaceRequired(ctx) if err != nil { return err } + var base snapshot.Info + for _, opt := range opts { + if err := opt(&base); err != nil { + return err + } + } + return update(ctx, s.db, func(tx *bolt.Tx) error { bkt := getSnapshotterBucket(tx, ns, s.name) if bkt == nil { return errors.Wrapf(errdefs.ErrNotFound, "snapshot %v does not exist", key) } - nameKey := string(bkt.Get([]byte(name))) - if nameKey != "" { - return errors.Wrapf(errdefs.ErrAlreadyExists, "snapshot %v already exists", name) + bbkt, err := bkt.CreateBucket([]byte(name)) + if err != nil { + if err == bolt.ErrBucketExists { + err = errors.Wrapf(errdefs.ErrAlreadyExists, "snapshot %v already exists", name) + } + return err } - bkey := string(bkt.Get([]byte(key))) - if bkey == "" { + obkt := bkt.Bucket([]byte(key)) + if obkt == nil { return errors.Wrapf(errdefs.ErrNotFound, "snapshot %v does not exist", key) } + bkey := string(obkt.Get(bucketKeyName)) + parent := string(obkt.Get(bucketKeyParent)) + sid, err := bkt.NextSequence() if err != nil { return err } - nameKey = createKey(sid, ns, name) - if err := bkt.Put([]byte(name), []byte(nameKey)); err != nil { + + nameKey := createKey(sid, ns, name) + + if err := bbkt.Put(bucketKeyName, []byte(nameKey)); err != nil { return err } - if err := bkt.Delete([]byte(key)); err != nil { + if err := bbkt.Put(bucketKeyParent, []byte(parent)); err != nil { + return err + } + ts := time.Now().UTC() + if err := boltutil.WriteTimestamps(bbkt, ts, ts); err != nil { + return err + } + if err := boltutil.WriteLabels(bbkt, base.Labels); err != nil { + return err + } + if err := bkt.DeleteBucket([]byte(key)); err != nil { return err } @@ -210,16 +388,19 @@ func (s *snapshotter) Remove(ctx context.Context, key string) error { } return update(ctx, s.db, func(tx *bolt.Tx) error { + var bkey string bkt := getSnapshotterBucket(tx, ns, s.name) - if bkt == nil { - return errors.Wrapf(errdefs.ErrNotFound, "snapshot %v does not exist", key) + if bkt != nil { + sbkt := bkt.Bucket([]byte(key)) + if sbkt != nil { + bkey = string(sbkt.Get(bucketKeyName)) + } } - - bkey := string(bkt.Get([]byte(key))) if bkey == "" { return errors.Wrapf(errdefs.ErrNotFound, "snapshot %v does not exist", key) } - if err := bkt.Delete([]byte(key)); err != nil { + + if err := bkt.DeleteBucket([]byte(key)); err != nil { return err } @@ -227,45 +408,93 @@ func (s *snapshotter) Remove(ctx context.Context, key string) error { }) } +type infoPair struct { + bkey string + info snapshot.Info +} + func (s *snapshotter) Walk(ctx context.Context, fn func(context.Context, snapshot.Info) error) error { ns, err := namespaces.NamespaceRequired(ctx) if err != nil { return err } - var keys []string + var ( + batchSize = 100 + pairs = []infoPair{} + lastKey string + ) - if err := view(ctx, s.db, func(tx *bolt.Tx) error { - bkt := getSnapshotterBucket(tx, ns, s.name) - if bkt == nil { - return nil - } - - bkt.ForEach(func(k, v []byte) error { - if len(v) > 0 { - keys = append(keys, string(v)) + for { + if err := view(ctx, s.db, func(tx *bolt.Tx) error { + bkt := getSnapshotterBucket(tx, ns, s.name) + if bkt == nil { + return nil } + + c := bkt.Cursor() + + var k, v []byte + if lastKey == "" { + k, v = c.First() + } else { + k, v = c.Seek([]byte(lastKey)) + } + + for k != nil { + if v == nil { + if len(pairs) >= batchSize { + break + } + sbkt := bkt.Bucket(k) + + pair := infoPair{ + bkey: string(sbkt.Get(bucketKeyName)), + info: snapshot.Info{ + Name: string(k), + Parent: string(sbkt.Get(bucketKeyParent)), + }, + } + + err := boltutil.ReadTimestamps(sbkt, &pair.info.Created, &pair.info.Updated) + if err != nil { + return err + } + pair.info.Labels, err = boltutil.ReadLabels(sbkt) + if err != nil { + return err + } + + pairs = append(pairs, pair) + } + + k, v = c.Next() + } + + lastKey = string(k) + return nil - }) - - return nil - }); err != nil { - return err - } - - for _, k := range keys { - info, err := s.Snapshotter.Stat(ctx, k) - if err != nil { + }); err != nil { return err } - info.Name = trimKey(info.Name) - if info.Parent != "" { - info.Parent = trimKey(info.Parent) + for _, pair := range pairs { + info, err := s.Snapshotter.Stat(ctx, pair.bkey) + if err != nil { + return err + } + + if err := fn(ctx, overlayInfo(info, pair.info)); err != nil { + return err + } } - if err := fn(ctx, info); err != nil { - return err + + if lastKey == "" { + break } + + pairs = pairs[:0] + } return nil From efca0c5347612c3338405e028ff4b67a6017c482 Mon Sep 17 00:00:00 2001 From: Derek McGowan Date: Tue, 1 Aug 2017 17:15:39 -0700 Subject: [PATCH 4/6] Update GRPC api to support labels and snapshot updates Signed-off-by: Derek McGowan --- api/services/snapshot/v1/snapshots.pb.go | 1232 +++++++++++++++++++++- api/services/snapshot/v1/snapshots.proto | 38 + services/snapshot/client.go | 55 +- services/snapshot/service.go | 65 +- 4 files changed, 1310 insertions(+), 80 deletions(-) diff --git a/api/services/snapshot/v1/snapshots.pb.go b/api/services/snapshot/v1/snapshots.pb.go index 5770792ca..2758bf490 100644 --- a/api/services/snapshot/v1/snapshots.pb.go +++ b/api/services/snapshot/v1/snapshots.pb.go @@ -20,6 +20,8 @@ StatSnapshotRequest Info StatSnapshotResponse + UpdateSnapshotRequest + UpdateSnapshotResponse ListSnapshotsRequest ListSnapshotsResponse UsageRequest @@ -32,15 +34,22 @@ import fmt "fmt" import math "math" import _ "github.com/gogo/protobuf/gogoproto" import google_protobuf1 "github.com/golang/protobuf/ptypes/empty" +import google_protobuf2 "github.com/gogo/protobuf/types" +import _ "github.com/gogo/protobuf/types" import containerd_types "github.com/containerd/containerd/api/types" +import time "time" + import ( context "golang.org/x/net/context" grpc "google.golang.org/grpc" ) +import github_com_gogo_protobuf_types "github.com/gogo/protobuf/types" + import strings "strings" import reflect "reflect" +import github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys" import io "io" @@ -48,6 +57,7 @@ import io "io" var _ = proto.Marshal var _ = fmt.Errorf var _ = math.Inf +var _ = time.Kitchen // This is a compile-time assertion to ensure that this generated file // is compatible with the proto package it is being compiled against. @@ -86,6 +96,8 @@ type PrepareSnapshotRequest struct { Snapshotter string `protobuf:"bytes,1,opt,name=snapshotter,proto3" json:"snapshotter,omitempty"` Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"` Parent string `protobuf:"bytes,3,opt,name=parent,proto3" json:"parent,omitempty"` + // Labels are arbitrary data on snapshots. + Labels map[string]string `protobuf:"bytes,4,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } func (m *PrepareSnapshotRequest) Reset() { *m = PrepareSnapshotRequest{} } @@ -104,6 +116,8 @@ type ViewSnapshotRequest struct { Snapshotter string `protobuf:"bytes,1,opt,name=snapshotter,proto3" json:"snapshotter,omitempty"` Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"` Parent string `protobuf:"bytes,3,opt,name=parent,proto3" json:"parent,omitempty"` + // Labels are arbitrary data on snapshots. + Labels map[string]string `protobuf:"bytes,4,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } func (m *ViewSnapshotRequest) Reset() { *m = ViewSnapshotRequest{} } @@ -148,6 +162,8 @@ type CommitSnapshotRequest struct { Snapshotter string `protobuf:"bytes,1,opt,name=snapshotter,proto3" json:"snapshotter,omitempty"` Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` Key string `protobuf:"bytes,3,opt,name=key,proto3" json:"key,omitempty"` + // Labels are arbitrary data on snapshots. + Labels map[string]string `protobuf:"bytes,4,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } func (m *CommitSnapshotRequest) Reset() { *m = CommitSnapshotRequest{} } @@ -167,6 +183,12 @@ type Info struct { Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` Parent string `protobuf:"bytes,2,opt,name=parent,proto3" json:"parent,omitempty"` Kind Kind `protobuf:"varint,3,opt,name=kind,proto3,enum=containerd.services.snapshots.v1.Kind" json:"kind,omitempty"` + // CreatedAt provides the time at which the snapshot was created. + CreatedAt time.Time `protobuf:"bytes,4,opt,name=created_at,json=createdAt,stdtime" json:"created_at"` + // UpdatedAt provides the time the info was last updated. + UpdatedAt time.Time `protobuf:"bytes,5,opt,name=updated_at,json=updatedAt,stdtime" json:"updated_at"` + // Labels are arbitrary data on snapshots. + Labels map[string]string `protobuf:"bytes,6,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } func (m *Info) Reset() { *m = Info{} } @@ -181,13 +203,37 @@ func (m *StatSnapshotResponse) Reset() { *m = StatSnapshotRes func (*StatSnapshotResponse) ProtoMessage() {} func (*StatSnapshotResponse) Descriptor() ([]byte, []int) { return fileDescriptorSnapshots, []int{10} } +type UpdateSnapshotRequest struct { + Snapshotter string `protobuf:"bytes,1,opt,name=snapshotter,proto3" json:"snapshotter,omitempty"` + Info Info `protobuf:"bytes,2,opt,name=info" json:"info"` + // UpdateMask specifies which fields to perform the update on. If empty, + // the operation applies to all fields. + // + // In info, Name, Parent, Kind, Created are immutable, + // other field may be updated using this mask. + // If no mask is provided, all mutable field are updated. + UpdateMask *google_protobuf2.FieldMask `protobuf:"bytes,3,opt,name=update_mask,json=updateMask" json:"update_mask,omitempty"` +} + +func (m *UpdateSnapshotRequest) Reset() { *m = UpdateSnapshotRequest{} } +func (*UpdateSnapshotRequest) ProtoMessage() {} +func (*UpdateSnapshotRequest) Descriptor() ([]byte, []int) { return fileDescriptorSnapshots, []int{11} } + +type UpdateSnapshotResponse struct { + Info Info `protobuf:"bytes,1,opt,name=info" json:"info"` +} + +func (m *UpdateSnapshotResponse) Reset() { *m = UpdateSnapshotResponse{} } +func (*UpdateSnapshotResponse) ProtoMessage() {} +func (*UpdateSnapshotResponse) Descriptor() ([]byte, []int) { return fileDescriptorSnapshots, []int{12} } + type ListSnapshotsRequest struct { Snapshotter string `protobuf:"bytes,1,opt,name=snapshotter,proto3" json:"snapshotter,omitempty"` } func (m *ListSnapshotsRequest) Reset() { *m = ListSnapshotsRequest{} } func (*ListSnapshotsRequest) ProtoMessage() {} -func (*ListSnapshotsRequest) Descriptor() ([]byte, []int) { return fileDescriptorSnapshots, []int{11} } +func (*ListSnapshotsRequest) Descriptor() ([]byte, []int) { return fileDescriptorSnapshots, []int{13} } type ListSnapshotsResponse struct { Info []Info `protobuf:"bytes,1,rep,name=info" json:"info"` @@ -195,7 +241,7 @@ type ListSnapshotsResponse struct { func (m *ListSnapshotsResponse) Reset() { *m = ListSnapshotsResponse{} } func (*ListSnapshotsResponse) ProtoMessage() {} -func (*ListSnapshotsResponse) Descriptor() ([]byte, []int) { return fileDescriptorSnapshots, []int{12} } +func (*ListSnapshotsResponse) Descriptor() ([]byte, []int) { return fileDescriptorSnapshots, []int{14} } type UsageRequest struct { Snapshotter string `protobuf:"bytes,1,opt,name=snapshotter,proto3" json:"snapshotter,omitempty"` @@ -204,7 +250,7 @@ type UsageRequest struct { func (m *UsageRequest) Reset() { *m = UsageRequest{} } func (*UsageRequest) ProtoMessage() {} -func (*UsageRequest) Descriptor() ([]byte, []int) { return fileDescriptorSnapshots, []int{13} } +func (*UsageRequest) Descriptor() ([]byte, []int) { return fileDescriptorSnapshots, []int{15} } type UsageResponse struct { Size_ int64 `protobuf:"varint,1,opt,name=size,proto3" json:"size,omitempty"` @@ -213,7 +259,7 @@ type UsageResponse struct { func (m *UsageResponse) Reset() { *m = UsageResponse{} } func (*UsageResponse) ProtoMessage() {} -func (*UsageResponse) Descriptor() ([]byte, []int) { return fileDescriptorSnapshots, []int{14} } +func (*UsageResponse) Descriptor() ([]byte, []int) { return fileDescriptorSnapshots, []int{16} } func init() { proto.RegisterType((*PrepareSnapshotRequest)(nil), "containerd.services.snapshots.v1.PrepareSnapshotRequest") @@ -227,6 +273,8 @@ func init() { proto.RegisterType((*StatSnapshotRequest)(nil), "containerd.services.snapshots.v1.StatSnapshotRequest") proto.RegisterType((*Info)(nil), "containerd.services.snapshots.v1.Info") proto.RegisterType((*StatSnapshotResponse)(nil), "containerd.services.snapshots.v1.StatSnapshotResponse") + proto.RegisterType((*UpdateSnapshotRequest)(nil), "containerd.services.snapshots.v1.UpdateSnapshotRequest") + proto.RegisterType((*UpdateSnapshotResponse)(nil), "containerd.services.snapshots.v1.UpdateSnapshotResponse") proto.RegisterType((*ListSnapshotsRequest)(nil), "containerd.services.snapshots.v1.ListSnapshotsRequest") proto.RegisterType((*ListSnapshotsResponse)(nil), "containerd.services.snapshots.v1.ListSnapshotsResponse") proto.RegisterType((*UsageRequest)(nil), "containerd.services.snapshots.v1.UsageRequest") @@ -251,6 +299,7 @@ type SnapshotsClient interface { Commit(ctx context.Context, in *CommitSnapshotRequest, opts ...grpc.CallOption) (*google_protobuf1.Empty, error) Remove(ctx context.Context, in *RemoveSnapshotRequest, opts ...grpc.CallOption) (*google_protobuf1.Empty, error) Stat(ctx context.Context, in *StatSnapshotRequest, opts ...grpc.CallOption) (*StatSnapshotResponse, error) + Update(ctx context.Context, in *UpdateSnapshotRequest, opts ...grpc.CallOption) (*UpdateSnapshotResponse, error) List(ctx context.Context, in *ListSnapshotsRequest, opts ...grpc.CallOption) (Snapshots_ListClient, error) Usage(ctx context.Context, in *UsageRequest, opts ...grpc.CallOption) (*UsageResponse, error) } @@ -317,6 +366,15 @@ func (c *snapshotsClient) Stat(ctx context.Context, in *StatSnapshotRequest, opt return out, nil } +func (c *snapshotsClient) Update(ctx context.Context, in *UpdateSnapshotRequest, opts ...grpc.CallOption) (*UpdateSnapshotResponse, error) { + out := new(UpdateSnapshotResponse) + err := grpc.Invoke(ctx, "/containerd.services.snapshots.v1.Snapshots/Update", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *snapshotsClient) List(ctx context.Context, in *ListSnapshotsRequest, opts ...grpc.CallOption) (Snapshots_ListClient, error) { stream, err := grpc.NewClientStream(ctx, &_Snapshots_serviceDesc.Streams[0], c.cc, "/containerd.services.snapshots.v1.Snapshots/List", opts...) if err != nil { @@ -367,6 +425,7 @@ type SnapshotsServer interface { Commit(context.Context, *CommitSnapshotRequest) (*google_protobuf1.Empty, error) Remove(context.Context, *RemoveSnapshotRequest) (*google_protobuf1.Empty, error) Stat(context.Context, *StatSnapshotRequest) (*StatSnapshotResponse, error) + Update(context.Context, *UpdateSnapshotRequest) (*UpdateSnapshotResponse, error) List(*ListSnapshotsRequest, Snapshots_ListServer) error Usage(context.Context, *UsageRequest) (*UsageResponse, error) } @@ -483,6 +542,24 @@ func _Snapshots_Stat_Handler(srv interface{}, ctx context.Context, dec func(inte return interceptor(ctx, in, info, handler) } +func _Snapshots_Update_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateSnapshotRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SnapshotsServer).Update(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/containerd.services.snapshots.v1.Snapshots/Update", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SnapshotsServer).Update(ctx, req.(*UpdateSnapshotRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _Snapshots_List_Handler(srv interface{}, stream grpc.ServerStream) error { m := new(ListSnapshotsRequest) if err := stream.RecvMsg(m); err != nil { @@ -550,6 +627,10 @@ var _Snapshots_serviceDesc = grpc.ServiceDesc{ MethodName: "Stat", Handler: _Snapshots_Stat_Handler, }, + { + MethodName: "Update", + Handler: _Snapshots_Update_Handler, + }, { MethodName: "Usage", Handler: _Snapshots_Usage_Handler, @@ -598,6 +679,23 @@ func (m *PrepareSnapshotRequest) MarshalTo(dAtA []byte) (int, error) { i = encodeVarintSnapshots(dAtA, i, uint64(len(m.Parent))) i += copy(dAtA[i:], m.Parent) } + if len(m.Labels) > 0 { + for k, _ := range m.Labels { + dAtA[i] = 0x22 + i++ + v := m.Labels[k] + mapSize := 1 + len(k) + sovSnapshots(uint64(len(k))) + 1 + len(v) + sovSnapshots(uint64(len(v))) + i = encodeVarintSnapshots(dAtA, i, uint64(mapSize)) + dAtA[i] = 0xa + i++ + i = encodeVarintSnapshots(dAtA, i, uint64(len(k))) + i += copy(dAtA[i:], k) + dAtA[i] = 0x12 + i++ + i = encodeVarintSnapshots(dAtA, i, uint64(len(v))) + i += copy(dAtA[i:], v) + } + } return i, nil } @@ -664,6 +762,23 @@ func (m *ViewSnapshotRequest) MarshalTo(dAtA []byte) (int, error) { i = encodeVarintSnapshots(dAtA, i, uint64(len(m.Parent))) i += copy(dAtA[i:], m.Parent) } + if len(m.Labels) > 0 { + for k, _ := range m.Labels { + dAtA[i] = 0x22 + i++ + v := m.Labels[k] + mapSize := 1 + len(k) + sovSnapshots(uint64(len(k))) + 1 + len(v) + sovSnapshots(uint64(len(v))) + i = encodeVarintSnapshots(dAtA, i, uint64(mapSize)) + dAtA[i] = 0xa + i++ + i = encodeVarintSnapshots(dAtA, i, uint64(len(k))) + i += copy(dAtA[i:], k) + dAtA[i] = 0x12 + i++ + i = encodeVarintSnapshots(dAtA, i, uint64(len(v))) + i += copy(dAtA[i:], v) + } + } return i, nil } @@ -820,6 +935,23 @@ func (m *CommitSnapshotRequest) MarshalTo(dAtA []byte) (int, error) { i = encodeVarintSnapshots(dAtA, i, uint64(len(m.Key))) i += copy(dAtA[i:], m.Key) } + if len(m.Labels) > 0 { + for k, _ := range m.Labels { + dAtA[i] = 0x22 + i++ + v := m.Labels[k] + mapSize := 1 + len(k) + sovSnapshots(uint64(len(k))) + 1 + len(v) + sovSnapshots(uint64(len(v))) + i = encodeVarintSnapshots(dAtA, i, uint64(mapSize)) + dAtA[i] = 0xa + i++ + i = encodeVarintSnapshots(dAtA, i, uint64(len(k))) + i += copy(dAtA[i:], k) + dAtA[i] = 0x12 + i++ + i = encodeVarintSnapshots(dAtA, i, uint64(len(v))) + i += copy(dAtA[i:], v) + } + } return i, nil } @@ -885,6 +1017,39 @@ func (m *Info) MarshalTo(dAtA []byte) (int, error) { i++ i = encodeVarintSnapshots(dAtA, i, uint64(m.Kind)) } + dAtA[i] = 0x22 + i++ + i = encodeVarintSnapshots(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.CreatedAt))) + n1, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.CreatedAt, dAtA[i:]) + if err != nil { + return 0, err + } + i += n1 + dAtA[i] = 0x2a + i++ + i = encodeVarintSnapshots(dAtA, i, uint64(github_com_gogo_protobuf_types.SizeOfStdTime(m.UpdatedAt))) + n2, err := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.UpdatedAt, dAtA[i:]) + if err != nil { + return 0, err + } + i += n2 + if len(m.Labels) > 0 { + for k, _ := range m.Labels { + dAtA[i] = 0x32 + i++ + v := m.Labels[k] + mapSize := 1 + len(k) + sovSnapshots(uint64(len(k))) + 1 + len(v) + sovSnapshots(uint64(len(v))) + i = encodeVarintSnapshots(dAtA, i, uint64(mapSize)) + dAtA[i] = 0xa + i++ + i = encodeVarintSnapshots(dAtA, i, uint64(len(k))) + i += copy(dAtA[i:], k) + dAtA[i] = 0x12 + i++ + i = encodeVarintSnapshots(dAtA, i, uint64(len(v))) + i += copy(dAtA[i:], v) + } + } return i, nil } @@ -906,11 +1071,79 @@ func (m *StatSnapshotResponse) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0xa i++ i = encodeVarintSnapshots(dAtA, i, uint64(m.Info.Size())) - n1, err := m.Info.MarshalTo(dAtA[i:]) + n3, err := m.Info.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n1 + i += n3 + return i, nil +} + +func (m *UpdateSnapshotRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *UpdateSnapshotRequest) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if len(m.Snapshotter) > 0 { + dAtA[i] = 0xa + i++ + i = encodeVarintSnapshots(dAtA, i, uint64(len(m.Snapshotter))) + i += copy(dAtA[i:], m.Snapshotter) + } + dAtA[i] = 0x12 + i++ + i = encodeVarintSnapshots(dAtA, i, uint64(m.Info.Size())) + n4, err := m.Info.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n4 + if m.UpdateMask != nil { + dAtA[i] = 0x1a + i++ + i = encodeVarintSnapshots(dAtA, i, uint64(m.UpdateMask.Size())) + n5, err := m.UpdateMask.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n5 + } + return i, nil +} + +func (m *UpdateSnapshotResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *UpdateSnapshotResponse) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + dAtA[i] = 0xa + i++ + i = encodeVarintSnapshots(dAtA, i, uint64(m.Info.Size())) + n6, err := m.Info.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n6 return i, nil } @@ -1068,6 +1301,14 @@ func (m *PrepareSnapshotRequest) Size() (n int) { if l > 0 { n += 1 + l + sovSnapshots(uint64(l)) } + if len(m.Labels) > 0 { + for k, v := range m.Labels { + _ = k + _ = v + mapEntrySize := 1 + len(k) + sovSnapshots(uint64(len(k))) + 1 + len(v) + sovSnapshots(uint64(len(v))) + n += mapEntrySize + 1 + sovSnapshots(uint64(mapEntrySize)) + } + } return n } @@ -1098,6 +1339,14 @@ func (m *ViewSnapshotRequest) Size() (n int) { if l > 0 { n += 1 + l + sovSnapshots(uint64(l)) } + if len(m.Labels) > 0 { + for k, v := range m.Labels { + _ = k + _ = v + mapEntrySize := 1 + len(k) + sovSnapshots(uint64(len(k))) + 1 + len(v) + sovSnapshots(uint64(len(v))) + n += mapEntrySize + 1 + sovSnapshots(uint64(mapEntrySize)) + } + } return n } @@ -1168,6 +1417,14 @@ func (m *CommitSnapshotRequest) Size() (n int) { if l > 0 { n += 1 + l + sovSnapshots(uint64(l)) } + if len(m.Labels) > 0 { + for k, v := range m.Labels { + _ = k + _ = v + mapEntrySize := 1 + len(k) + sovSnapshots(uint64(len(k))) + 1 + len(v) + sovSnapshots(uint64(len(v))) + n += mapEntrySize + 1 + sovSnapshots(uint64(mapEntrySize)) + } + } return n } @@ -1199,6 +1456,18 @@ func (m *Info) Size() (n int) { if m.Kind != 0 { n += 1 + sovSnapshots(uint64(m.Kind)) } + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.CreatedAt) + n += 1 + l + sovSnapshots(uint64(l)) + l = github_com_gogo_protobuf_types.SizeOfStdTime(m.UpdatedAt) + n += 1 + l + sovSnapshots(uint64(l)) + if len(m.Labels) > 0 { + for k, v := range m.Labels { + _ = k + _ = v + mapEntrySize := 1 + len(k) + sovSnapshots(uint64(len(k))) + 1 + len(v) + sovSnapshots(uint64(len(v))) + n += mapEntrySize + 1 + sovSnapshots(uint64(mapEntrySize)) + } + } return n } @@ -1210,6 +1479,30 @@ func (m *StatSnapshotResponse) Size() (n int) { return n } +func (m *UpdateSnapshotRequest) Size() (n int) { + var l int + _ = l + l = len(m.Snapshotter) + if l > 0 { + n += 1 + l + sovSnapshots(uint64(l)) + } + l = m.Info.Size() + n += 1 + l + sovSnapshots(uint64(l)) + if m.UpdateMask != nil { + l = m.UpdateMask.Size() + n += 1 + l + sovSnapshots(uint64(l)) + } + return n +} + +func (m *UpdateSnapshotResponse) Size() (n int) { + var l int + _ = l + l = m.Info.Size() + n += 1 + l + sovSnapshots(uint64(l)) + return n +} + func (m *ListSnapshotsRequest) Size() (n int) { var l int _ = l @@ -1275,10 +1568,21 @@ func (this *PrepareSnapshotRequest) String() string { if this == nil { return "nil" } + keysForLabels := make([]string, 0, len(this.Labels)) + for k, _ := range this.Labels { + keysForLabels = append(keysForLabels, k) + } + github_com_gogo_protobuf_sortkeys.Strings(keysForLabels) + mapStringForLabels := "map[string]string{" + for _, k := range keysForLabels { + mapStringForLabels += fmt.Sprintf("%v: %v,", k, this.Labels[k]) + } + mapStringForLabels += "}" s := strings.Join([]string{`&PrepareSnapshotRequest{`, `Snapshotter:` + fmt.Sprintf("%v", this.Snapshotter) + `,`, `Key:` + fmt.Sprintf("%v", this.Key) + `,`, `Parent:` + fmt.Sprintf("%v", this.Parent) + `,`, + `Labels:` + mapStringForLabels + `,`, `}`, }, "") return s @@ -1297,10 +1601,21 @@ func (this *ViewSnapshotRequest) String() string { if this == nil { return "nil" } + keysForLabels := make([]string, 0, len(this.Labels)) + for k, _ := range this.Labels { + keysForLabels = append(keysForLabels, k) + } + github_com_gogo_protobuf_sortkeys.Strings(keysForLabels) + mapStringForLabels := "map[string]string{" + for _, k := range keysForLabels { + mapStringForLabels += fmt.Sprintf("%v: %v,", k, this.Labels[k]) + } + mapStringForLabels += "}" s := strings.Join([]string{`&ViewSnapshotRequest{`, `Snapshotter:` + fmt.Sprintf("%v", this.Snapshotter) + `,`, `Key:` + fmt.Sprintf("%v", this.Key) + `,`, `Parent:` + fmt.Sprintf("%v", this.Parent) + `,`, + `Labels:` + mapStringForLabels + `,`, `}`, }, "") return s @@ -1351,10 +1666,21 @@ func (this *CommitSnapshotRequest) String() string { if this == nil { return "nil" } + keysForLabels := make([]string, 0, len(this.Labels)) + for k, _ := range this.Labels { + keysForLabels = append(keysForLabels, k) + } + github_com_gogo_protobuf_sortkeys.Strings(keysForLabels) + mapStringForLabels := "map[string]string{" + for _, k := range keysForLabels { + mapStringForLabels += fmt.Sprintf("%v: %v,", k, this.Labels[k]) + } + mapStringForLabels += "}" s := strings.Join([]string{`&CommitSnapshotRequest{`, `Snapshotter:` + fmt.Sprintf("%v", this.Snapshotter) + `,`, `Name:` + fmt.Sprintf("%v", this.Name) + `,`, `Key:` + fmt.Sprintf("%v", this.Key) + `,`, + `Labels:` + mapStringForLabels + `,`, `}`, }, "") return s @@ -1374,10 +1700,23 @@ func (this *Info) String() string { if this == nil { return "nil" } + keysForLabels := make([]string, 0, len(this.Labels)) + for k, _ := range this.Labels { + keysForLabels = append(keysForLabels, k) + } + github_com_gogo_protobuf_sortkeys.Strings(keysForLabels) + mapStringForLabels := "map[string]string{" + for _, k := range keysForLabels { + mapStringForLabels += fmt.Sprintf("%v: %v,", k, this.Labels[k]) + } + mapStringForLabels += "}" s := strings.Join([]string{`&Info{`, `Name:` + fmt.Sprintf("%v", this.Name) + `,`, `Parent:` + fmt.Sprintf("%v", this.Parent) + `,`, `Kind:` + fmt.Sprintf("%v", this.Kind) + `,`, + `CreatedAt:` + strings.Replace(strings.Replace(this.CreatedAt.String(), "Timestamp", "google_protobuf3.Timestamp", 1), `&`, ``, 1) + `,`, + `UpdatedAt:` + strings.Replace(strings.Replace(this.UpdatedAt.String(), "Timestamp", "google_protobuf3.Timestamp", 1), `&`, ``, 1) + `,`, + `Labels:` + mapStringForLabels + `,`, `}`, }, "") return s @@ -1392,6 +1731,28 @@ func (this *StatSnapshotResponse) String() string { }, "") return s } +func (this *UpdateSnapshotRequest) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&UpdateSnapshotRequest{`, + `Snapshotter:` + fmt.Sprintf("%v", this.Snapshotter) + `,`, + `Info:` + strings.Replace(strings.Replace(this.Info.String(), "Info", "Info", 1), `&`, ``, 1) + `,`, + `UpdateMask:` + strings.Replace(fmt.Sprintf("%v", this.UpdateMask), "FieldMask", "google_protobuf2.FieldMask", 1) + `,`, + `}`, + }, "") + return s +} +func (this *UpdateSnapshotResponse) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&UpdateSnapshotResponse{`, + `Info:` + strings.Replace(strings.Replace(this.Info.String(), "Info", "Info", 1), `&`, ``, 1) + `,`, + `}`, + }, "") + return s +} func (this *ListSnapshotsRequest) String() string { if this == nil { return "nil" @@ -1558,6 +1919,122 @@ func (m *PrepareSnapshotRequest) Unmarshal(dAtA []byte) error { } m.Parent = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Labels", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSnapshots + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSnapshots + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + var keykey uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSnapshots + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + keykey |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + var stringLenmapkey uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSnapshots + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapkey |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapkey := int(stringLenmapkey) + if intStringLenmapkey < 0 { + return ErrInvalidLengthSnapshots + } + postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey > l { + return io.ErrUnexpectedEOF + } + mapkey := string(dAtA[iNdEx:postStringIndexmapkey]) + iNdEx = postStringIndexmapkey + if m.Labels == nil { + m.Labels = make(map[string]string) + } + if iNdEx < postIndex { + var valuekey uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSnapshots + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + valuekey |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + var stringLenmapvalue uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSnapshots + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapvalue |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapvalue := int(stringLenmapvalue) + if intStringLenmapvalue < 0 { + return ErrInvalidLengthSnapshots + } + postStringIndexmapvalue := iNdEx + intStringLenmapvalue + if postStringIndexmapvalue > l { + return io.ErrUnexpectedEOF + } + mapvalue := string(dAtA[iNdEx:postStringIndexmapvalue]) + iNdEx = postStringIndexmapvalue + m.Labels[mapkey] = mapvalue + } else { + var mapvalue string + m.Labels[mapkey] = mapvalue + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipSnapshots(dAtA[iNdEx:]) @@ -1776,6 +2253,122 @@ func (m *ViewSnapshotRequest) Unmarshal(dAtA []byte) error { } m.Parent = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Labels", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSnapshots + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSnapshots + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + var keykey uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSnapshots + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + keykey |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + var stringLenmapkey uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSnapshots + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapkey |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapkey := int(stringLenmapkey) + if intStringLenmapkey < 0 { + return ErrInvalidLengthSnapshots + } + postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey > l { + return io.ErrUnexpectedEOF + } + mapkey := string(dAtA[iNdEx:postStringIndexmapkey]) + iNdEx = postStringIndexmapkey + if m.Labels == nil { + m.Labels = make(map[string]string) + } + if iNdEx < postIndex { + var valuekey uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSnapshots + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + valuekey |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + var stringLenmapvalue uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSnapshots + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapvalue |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapvalue := int(stringLenmapvalue) + if intStringLenmapvalue < 0 { + return ErrInvalidLengthSnapshots + } + postStringIndexmapvalue := iNdEx + intStringLenmapvalue + if postStringIndexmapvalue > l { + return io.ErrUnexpectedEOF + } + mapvalue := string(dAtA[iNdEx:postStringIndexmapvalue]) + iNdEx = postStringIndexmapvalue + m.Labels[mapkey] = mapvalue + } else { + var mapvalue string + m.Labels[mapkey] = mapvalue + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipSnapshots(dAtA[iNdEx:]) @@ -2291,6 +2884,122 @@ func (m *CommitSnapshotRequest) Unmarshal(dAtA []byte) error { } m.Key = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Labels", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSnapshots + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSnapshots + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + var keykey uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSnapshots + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + keykey |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + var stringLenmapkey uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSnapshots + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapkey |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapkey := int(stringLenmapkey) + if intStringLenmapkey < 0 { + return ErrInvalidLengthSnapshots + } + postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey > l { + return io.ErrUnexpectedEOF + } + mapkey := string(dAtA[iNdEx:postStringIndexmapkey]) + iNdEx = postStringIndexmapkey + if m.Labels == nil { + m.Labels = make(map[string]string) + } + if iNdEx < postIndex { + var valuekey uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSnapshots + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + valuekey |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + var stringLenmapvalue uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSnapshots + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapvalue |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapvalue := int(stringLenmapvalue) + if intStringLenmapvalue < 0 { + return ErrInvalidLengthSnapshots + } + postStringIndexmapvalue := iNdEx + intStringLenmapvalue + if postStringIndexmapvalue > l { + return io.ErrUnexpectedEOF + } + mapvalue := string(dAtA[iNdEx:postStringIndexmapvalue]) + iNdEx = postStringIndexmapvalue + m.Labels[mapkey] = mapvalue + } else { + var mapvalue string + m.Labels[mapkey] = mapvalue + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipSnapshots(dAtA[iNdEx:]) @@ -2526,6 +3235,182 @@ func (m *Info) Unmarshal(dAtA []byte) error { break } } + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CreatedAt", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSnapshots + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSnapshots + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.CreatedAt, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UpdatedAt", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSnapshots + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSnapshots + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := github_com_gogo_protobuf_types.StdTimeUnmarshal(&m.UpdatedAt, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Labels", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSnapshots + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSnapshots + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + var keykey uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSnapshots + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + keykey |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + var stringLenmapkey uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSnapshots + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapkey |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapkey := int(stringLenmapkey) + if intStringLenmapkey < 0 { + return ErrInvalidLengthSnapshots + } + postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey > l { + return io.ErrUnexpectedEOF + } + mapkey := string(dAtA[iNdEx:postStringIndexmapkey]) + iNdEx = postStringIndexmapkey + if m.Labels == nil { + m.Labels = make(map[string]string) + } + if iNdEx < postIndex { + var valuekey uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSnapshots + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + valuekey |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + var stringLenmapvalue uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSnapshots + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapvalue |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapvalue := int(stringLenmapvalue) + if intStringLenmapvalue < 0 { + return ErrInvalidLengthSnapshots + } + postStringIndexmapvalue := iNdEx + intStringLenmapvalue + if postStringIndexmapvalue > l { + return io.ErrUnexpectedEOF + } + mapvalue := string(dAtA[iNdEx:postStringIndexmapvalue]) + iNdEx = postStringIndexmapvalue + m.Labels[mapkey] = mapvalue + } else { + var mapvalue string + m.Labels[mapkey] = mapvalue + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipSnapshots(dAtA[iNdEx:]) @@ -2627,6 +3512,228 @@ func (m *StatSnapshotResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *UpdateSnapshotRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSnapshots + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: UpdateSnapshotRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: UpdateSnapshotRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Snapshotter", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSnapshots + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthSnapshots + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Snapshotter = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Info", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSnapshots + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSnapshots + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Info.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UpdateMask", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSnapshots + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSnapshots + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.UpdateMask == nil { + m.UpdateMask = &google_protobuf2.FieldMask{} + } + if err := m.UpdateMask.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipSnapshots(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthSnapshots + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *UpdateSnapshotResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSnapshots + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: UpdateSnapshotResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: UpdateSnapshotResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Info", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSnapshots + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSnapshots + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Info.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipSnapshots(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthSnapshots + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *ListSnapshotsRequest) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -3093,53 +4200,68 @@ func init() { } var fileDescriptorSnapshots = []byte{ - // 766 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x56, 0xcd, 0x4e, 0xdb, 0x4a, - 0x18, 0x8d, 0xb1, 0x6f, 0xb8, 0x7c, 0x01, 0x6e, 0xee, 0x10, 0x42, 0xe4, 0x7b, 0xe5, 0x6b, 0x79, - 0x71, 0x85, 0xba, 0xb0, 0x81, 0xaa, 0x40, 0xcb, 0xa6, 0x24, 0x8d, 0xaa, 0x94, 0x02, 0x95, 0xf9, - 0x2b, 0x55, 0xa5, 0xca, 0x24, 0x43, 0xb0, 0xd2, 0xcc, 0xa4, 0xf1, 0x24, 0x28, 0x5d, 0x54, 0xed, - 0x0e, 0xe5, 0x1d, 0xb2, 0x6a, 0x9f, 0xa2, 0x4f, 0xc0, 0xb2, 0xcb, 0xae, 0xaa, 0x92, 0x27, 0xa9, - 0x66, 0xec, 0xfc, 0x50, 0x52, 0xc5, 0x04, 0xba, 0xfb, 0x3c, 0xdf, 0x9c, 0xf3, 0x9d, 0xcc, 0xb1, - 0xcf, 0x04, 0x72, 0x45, 0x97, 0x9d, 0xd4, 0x8e, 0xcc, 0x3c, 0x2d, 0x5b, 0x79, 0x4a, 0x98, 0xe3, - 0x12, 0x5c, 0x2d, 0xf4, 0x97, 0x4e, 0xc5, 0xb5, 0x3c, 0x5c, 0xad, 0xbb, 0x79, 0xec, 0x59, 0x1e, - 0x71, 0x2a, 0xde, 0x09, 0x65, 0x56, 0x7d, 0xb1, 0x5b, 0x7b, 0x66, 0xa5, 0x4a, 0x19, 0x45, 0x7a, - 0x0f, 0x64, 0x76, 0x00, 0x66, 0x6f, 0x53, 0x7d, 0x51, 0x4d, 0x14, 0x69, 0x91, 0x8a, 0xcd, 0x16, - 0xaf, 0x7c, 0x9c, 0xfa, 0x4f, 0x91, 0xd2, 0xe2, 0x6b, 0x6c, 0x89, 0xa7, 0xa3, 0xda, 0xb1, 0x85, - 0xcb, 0x15, 0xd6, 0x08, 0x9a, 0xcb, 0xa1, 0xf4, 0xb1, 0x46, 0x05, 0x7b, 0x56, 0x99, 0xd6, 0x08, - 0xf3, 0x71, 0x46, 0x01, 0x92, 0xcf, 0xaa, 0xb8, 0xe2, 0x54, 0xf1, 0x4e, 0xa0, 0xc0, 0xc6, 0x6f, - 0x6a, 0xd8, 0x63, 0x48, 0x87, 0x58, 0x47, 0x14, 0xc3, 0xd5, 0x94, 0xa4, 0x4b, 0xf3, 0x13, 0x76, - 0xff, 0x12, 0x8a, 0x83, 0x5c, 0xc2, 0x8d, 0xd4, 0x98, 0xe8, 0xf0, 0x12, 0x25, 0x21, 0xca, 0xa9, - 0x08, 0x4b, 0xc9, 0x62, 0x31, 0x78, 0x32, 0x9e, 0xc0, 0xdc, 0x95, 0x29, 0x5e, 0x85, 0x12, 0x0f, - 0x23, 0x0b, 0xa2, 0x42, 0x8f, 0x97, 0x92, 0x74, 0x79, 0x3e, 0xb6, 0x34, 0x67, 0xf6, 0x1d, 0x8f, - 0xd0, 0x6b, 0x6e, 0xf2, 0xbe, 0x1d, 0x6c, 0x33, 0x1c, 0x98, 0xd9, 0x77, 0xf1, 0xe9, 0xef, 0x94, - 0xfb, 0x18, 0x12, 0x97, 0x47, 0x8c, 0xaa, 0x35, 0x03, 0x53, 0x62, 0xc1, 0xbb, 0x81, 0x4a, 0x63, - 0x1d, 0xa6, 0x3b, 0x24, 0xa3, 0xea, 0xd8, 0x80, 0x59, 0x1b, 0x97, 0x69, 0xfd, 0x36, 0x4c, 0x36, - 0x5e, 0xc1, 0x6c, 0x86, 0x96, 0xcb, 0x2e, 0xbb, 0x3e, 0x19, 0x02, 0x85, 0x38, 0x65, 0x1c, 0xb0, - 0x89, 0xba, 0x33, 0x40, 0xee, 0x0d, 0xc8, 0xc1, 0xcc, 0x0e, 0x73, 0xd8, 0x6d, 0x68, 0x25, 0xa0, - 0xe4, 0xc8, 0x31, 0xed, 0x0e, 0x96, 0xfa, 0x06, 0xf7, 0xdc, 0x1f, 0xeb, 0x77, 0x1f, 0x3d, 0x00, - 0xa5, 0xe4, 0x92, 0x82, 0x50, 0x34, 0xbd, 0xf4, 0xbf, 0x39, 0xec, 0x73, 0x35, 0x37, 0x5c, 0x52, - 0xb0, 0x05, 0xc6, 0x78, 0x0e, 0x89, 0xcb, 0xd2, 0x03, 0xc7, 0x1e, 0x82, 0xe2, 0x92, 0x63, 0x2a, - 0xe6, 0xc7, 0xc2, 0x70, 0x72, 0xd5, 0x69, 0xe5, 0xfc, 0xdb, 0x7f, 0x11, 0x5b, 0x20, 0x8d, 0x55, - 0x48, 0x3c, 0x75, 0xbd, 0x2e, 0x73, 0xf8, 0x37, 0xca, 0x38, 0x84, 0xd9, 0x9f, 0x90, 0x57, 0x44, - 0xc9, 0x23, 0x8a, 0x4a, 0xc3, 0xe4, 0x9e, 0xe7, 0x14, 0xf1, 0x4d, 0x2c, 0x5a, 0x83, 0xa9, 0x80, - 0x23, 0x90, 0x85, 0x40, 0xf1, 0xdc, 0xb7, 0xbe, 0x57, 0xb2, 0x2d, 0x6a, 0xee, 0x95, 0x4b, 0x68, - 0x01, 0x7b, 0x02, 0x29, 0xdb, 0xc1, 0xd3, 0x9d, 0x33, 0x09, 0x14, 0x7e, 0xfc, 0xe8, 0x5f, 0x18, - 0xdf, 0xdb, 0xda, 0xd8, 0xda, 0x3e, 0xd8, 0x8a, 0x47, 0xd4, 0xbf, 0x9a, 0x2d, 0x3d, 0xc6, 0x97, - 0xf7, 0x48, 0x89, 0xd0, 0x53, 0x82, 0x92, 0xa0, 0xec, 0xe7, 0xb2, 0x07, 0x71, 0x49, 0x9d, 0x6c, - 0xb6, 0xf4, 0x3f, 0x79, 0x8b, 0x7f, 0xe0, 0x48, 0x85, 0xe8, 0x7a, 0x66, 0x37, 0xb7, 0x9f, 0x8d, - 0x8f, 0xa9, 0xd3, 0xcd, 0x96, 0x0e, 0xbc, 0xb3, 0x9e, 0x67, 0x6e, 0x1d, 0x23, 0x1d, 0x26, 0x32, - 0xdb, 0x9b, 0x9b, 0xb9, 0xdd, 0xdd, 0xec, 0xa3, 0xb8, 0xac, 0xfe, 0xdd, 0x6c, 0xe9, 0x53, 0xbc, - 0xed, 0xbf, 0xfb, 0x0c, 0x17, 0xd4, 0xc9, 0xb3, 0x8f, 0x5a, 0xe4, 0xf3, 0x27, 0x4d, 0x28, 0x58, - 0xfa, 0x30, 0x0e, 0x13, 0xdd, 0x33, 0x46, 0xef, 0x60, 0x3c, 0x48, 0x3c, 0xb4, 0x3a, 0xfc, 0x60, - 0x07, 0x47, 0xb0, 0x7a, 0x7f, 0x04, 0x64, 0x70, 0x88, 0x35, 0x50, 0xc4, 0x2f, 0xbc, 0x37, 0x9c, - 0x62, 0x40, 0x9a, 0xaa, 0xcb, 0xd7, 0x85, 0x05, 0x63, 0x4b, 0x10, 0xf5, 0xb3, 0x0a, 0x59, 0xc3, - 0x19, 0x2e, 0x45, 0xa3, 0xba, 0x10, 0x1e, 0x10, 0x0c, 0x3b, 0x84, 0xa8, 0x6f, 0x06, 0x5a, 0x19, - 0x8e, 0x1d, 0x18, 0x59, 0x6a, 0xd2, 0xf4, 0x2f, 0x55, 0xb3, 0x73, 0xa9, 0x9a, 0x59, 0x7e, 0xa9, - 0x72, 0x6a, 0x3f, 0x30, 0xc3, 0x50, 0x0f, 0x8c, 0xd6, 0x5f, 0x52, 0xd7, 0x40, 0xe1, 0x11, 0x11, - 0xc6, 0x99, 0x01, 0x29, 0x18, 0xc6, 0x99, 0x81, 0x09, 0xd4, 0x00, 0x85, 0xa7, 0x00, 0x0a, 0x81, - 0x1f, 0x94, 0x33, 0xea, 0xca, 0xb5, 0x71, 0xfe, 0xe0, 0x05, 0x09, 0x9d, 0xc0, 0x1f, 0xe2, 0x0b, - 0x47, 0xe6, 0x70, 0x8e, 0xfe, 0x38, 0x51, 0xad, 0xd0, 0xfb, 0xfd, 0x59, 0xe9, 0x97, 0xe7, 0x17, - 0x5a, 0xe4, 0xeb, 0x85, 0x16, 0x79, 0xdf, 0xd6, 0xa4, 0xf3, 0xb6, 0x26, 0x7d, 0x69, 0x6b, 0xd2, - 0xf7, 0xb6, 0x26, 0xbd, 0x48, 0x8f, 0xfc, 0xff, 0x6d, 0xad, 0x53, 0x1f, 0x45, 0x85, 0x93, 0x77, - 0x7f, 0x04, 0x00, 0x00, 0xff, 0xff, 0x51, 0x4b, 0x27, 0x3b, 0x0c, 0x0a, 0x00, 0x00, + // 1004 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x57, 0x4f, 0x6f, 0x1a, 0x47, + 0x14, 0xf7, 0xc0, 0x1a, 0xc7, 0x0f, 0xdb, 0xa5, 0x13, 0x4c, 0xd0, 0xb6, 0xc2, 0x2b, 0x0e, 0x95, + 0xd5, 0xc3, 0x6e, 0x42, 0xd5, 0xc4, 0x89, 0x2f, 0x05, 0x42, 0x2b, 0xe2, 0xd8, 0xa9, 0x36, 0xb6, + 0x53, 0xa7, 0x91, 0xa2, 0x35, 0x8c, 0xf1, 0x0a, 0x76, 0x97, 0x32, 0x03, 0x11, 0xad, 0x54, 0xf5, + 0x18, 0xf9, 0xd4, 0x2f, 0xe0, 0x53, 0xfb, 0x21, 0xaa, 0x7e, 0x02, 0x1f, 0x7b, 0xec, 0xa9, 0x6d, + 0xfc, 0x25, 0x7a, 0xea, 0x1f, 0xcd, 0xec, 0x2c, 0x60, 0x4c, 0xc5, 0xb2, 0xa1, 0xb7, 0xb7, 0x33, + 0xf3, 0xde, 0xfb, 0xbd, 0xdf, 0x9b, 0xf7, 0xde, 0x2c, 0x54, 0x1b, 0x36, 0x3b, 0xed, 0x1e, 0xeb, + 0x35, 0xcf, 0x31, 0x6a, 0x9e, 0xcb, 0x2c, 0xdb, 0x25, 0x9d, 0xfa, 0xa8, 0x68, 0xb5, 0x6d, 0x83, + 0x92, 0x4e, 0xcf, 0xae, 0x11, 0x6a, 0x50, 0xd7, 0x6a, 0xd3, 0x53, 0x8f, 0x19, 0xbd, 0x3b, 0x03, + 0x99, 0xea, 0xed, 0x8e, 0xc7, 0x3c, 0xac, 0x0d, 0x95, 0xf4, 0x40, 0x41, 0x1f, 0x1e, 0xea, 0xdd, + 0x51, 0xd3, 0x0d, 0xaf, 0xe1, 0x89, 0xc3, 0x06, 0x97, 0x7c, 0x3d, 0xf5, 0xbd, 0x86, 0xe7, 0x35, + 0x5a, 0xc4, 0x10, 0x5f, 0xc7, 0xdd, 0x13, 0x83, 0x38, 0x6d, 0xd6, 0x97, 0x9b, 0xda, 0xf8, 0xe6, + 0x89, 0x4d, 0x5a, 0xf5, 0x97, 0x8e, 0x45, 0x9b, 0xf2, 0xc4, 0xc6, 0xf8, 0x09, 0x66, 0x3b, 0x84, + 0x32, 0xcb, 0x69, 0xcb, 0x03, 0x77, 0x43, 0x85, 0xc8, 0xfa, 0x6d, 0x42, 0x0d, 0xc7, 0xeb, 0xba, + 0xcc, 0xd7, 0xcb, 0xff, 0x85, 0x20, 0xf3, 0x79, 0x87, 0xb4, 0xad, 0x0e, 0x79, 0x2a, 0xa3, 0x30, + 0xc9, 0x57, 0x5d, 0x42, 0x19, 0xd6, 0x20, 0x19, 0x04, 0xc6, 0x48, 0x27, 0x8b, 0x34, 0xb4, 0xb9, + 0x6c, 0x8e, 0x2e, 0xe1, 0x14, 0xc4, 0x9b, 0xa4, 0x9f, 0x8d, 0x89, 0x1d, 0x2e, 0xe2, 0x0c, 0x24, + 0xb8, 0x29, 0x97, 0x65, 0xe3, 0x62, 0x51, 0x7e, 0xe1, 0x17, 0x90, 0x68, 0x59, 0xc7, 0xa4, 0x45, + 0xb3, 0x8a, 0x16, 0xdf, 0x4c, 0x16, 0x1e, 0xea, 0xd3, 0x78, 0xd4, 0x27, 0xa3, 0xd2, 0x1f, 0x0b, + 0x33, 0x15, 0x97, 0x75, 0xfa, 0xa6, 0xb4, 0xa9, 0xde, 0x87, 0xe4, 0xc8, 0x72, 0x00, 0x0b, 0x0d, + 0x61, 0xa5, 0x61, 0xb1, 0x67, 0xb5, 0xba, 0x44, 0x42, 0xf5, 0x3f, 0x1e, 0xc4, 0xb6, 0x50, 0xfe, + 0x11, 0xdc, 0xba, 0xe6, 0x88, 0xb6, 0x3d, 0x97, 0x12, 0x6c, 0x40, 0x42, 0x30, 0x45, 0xb3, 0x48, + 0x60, 0xbe, 0x35, 0x8a, 0x59, 0x30, 0xa9, 0xef, 0xf2, 0x7d, 0x53, 0x1e, 0xcb, 0xff, 0x89, 0xe0, + 0xe6, 0xa1, 0x4d, 0x5e, 0xfd, 0x9f, 0x44, 0x1e, 0x8d, 0x11, 0x59, 0x9c, 0x4e, 0xe4, 0x04, 0x48, + 0xf3, 0x66, 0xf1, 0x33, 0x48, 0x5f, 0xf5, 0x12, 0x95, 0xc2, 0x32, 0xac, 0x8a, 0x05, 0xfa, 0x16, + 0xdc, 0xe5, 0x8b, 0xb0, 0x16, 0x18, 0x89, 0x8a, 0x63, 0x07, 0xd6, 0x4d, 0xe2, 0x78, 0xbd, 0x79, + 0x14, 0x05, 0xbf, 0x17, 0xeb, 0x65, 0xcf, 0x71, 0x6c, 0x36, 0xbb, 0x35, 0x0c, 0x8a, 0x6b, 0x39, + 0x01, 0xe5, 0x42, 0x0e, 0x3c, 0xc4, 0x87, 0x99, 0xf9, 0x72, 0xec, 0x56, 0x94, 0xa7, 0xdf, 0x8a, + 0x89, 0x80, 0xe6, 0x7d, 0x2f, 0xaa, 0x70, 0xf3, 0x29, 0xb3, 0xd8, 0x3c, 0x48, 0xfc, 0x27, 0x06, + 0x4a, 0xd5, 0x3d, 0xf1, 0x06, 0x8c, 0xa0, 0x11, 0x46, 0x86, 0xd5, 0x12, 0xbb, 0x52, 0x2d, 0x0f, + 0x40, 0x69, 0xda, 0x6e, 0x5d, 0x50, 0xb5, 0x56, 0xf8, 0x60, 0x3a, 0x2b, 0x3b, 0xb6, 0x5b, 0x37, + 0x85, 0x0e, 0x2e, 0x03, 0xd4, 0x3a, 0xc4, 0x62, 0xa4, 0xfe, 0xd2, 0x62, 0x59, 0x45, 0x43, 0x9b, + 0xc9, 0x82, 0xaa, 0xfb, 0x7d, 0x58, 0x0f, 0xfa, 0xb0, 0xbe, 0x1f, 0xf4, 0xe1, 0xd2, 0x8d, 0x8b, + 0xdf, 0x36, 0x16, 0xbe, 0xff, 0x7d, 0x03, 0x99, 0xcb, 0x52, 0xaf, 0xc8, 0xb8, 0x91, 0x6e, 0xbb, + 0x1e, 0x18, 0x59, 0x9c, 0xc5, 0x88, 0xd4, 0x2b, 0x32, 0xfc, 0x68, 0x90, 0xdd, 0x84, 0xc8, 0x6e, + 0x61, 0x7a, 0x1c, 0x9c, 0xa9, 0x79, 0x27, 0xf3, 0x0b, 0x48, 0x5f, 0x4d, 0xa6, 0x2c, 0xae, 0x4f, + 0x40, 0xb1, 0xdd, 0x13, 0x4f, 0x18, 0x49, 0x86, 0x21, 0x99, 0x83, 0x2b, 0x29, 0x3c, 0x52, 0x53, + 0x68, 0xe6, 0x7f, 0x42, 0xb0, 0x7e, 0x20, 0xc2, 0x9d, 0xfd, 0xa6, 0x04, 0xde, 0x63, 0x51, 0xbd, + 0xe3, 0x6d, 0x48, 0xfa, 0x5c, 0x8b, 0x81, 0x2b, 0xee, 0xca, 0xa4, 0x24, 0x7d, 0xca, 0x67, 0xf2, + 0xae, 0x45, 0x9b, 0xa6, 0x4c, 0x29, 0x97, 0xf3, 0xcf, 0x21, 0x33, 0x8e, 0x7c, 0x6e, 0xb4, 0x6c, + 0x41, 0xfa, 0xb1, 0x4d, 0x07, 0x84, 0x87, 0xef, 0x89, 0xf9, 0x23, 0x58, 0x1f, 0xd3, 0xbc, 0x06, + 0x2a, 0x1e, 0x11, 0x54, 0x09, 0x56, 0x0e, 0xa8, 0xd5, 0x20, 0x6f, 0x53, 0xcb, 0xdb, 0xb0, 0x2a, + 0x6d, 0x48, 0x58, 0x18, 0x14, 0x6a, 0x7f, 0xed, 0xd7, 0x74, 0xdc, 0x14, 0x32, 0xaf, 0x69, 0xdb, + 0xf5, 0xea, 0x84, 0x0a, 0xcd, 0xb8, 0x29, 0xbf, 0x3e, 0x7c, 0x8d, 0x40, 0xe1, 0x65, 0x8a, 0xdf, + 0x87, 0xa5, 0x83, 0xbd, 0x9d, 0xbd, 0x27, 0xcf, 0xf6, 0x52, 0x0b, 0xea, 0x3b, 0x67, 0xe7, 0x5a, + 0x92, 0x2f, 0x1f, 0xb8, 0x4d, 0xd7, 0x7b, 0xe5, 0xe2, 0x0c, 0x28, 0x87, 0xd5, 0xca, 0xb3, 0x14, + 0x52, 0x57, 0xce, 0xce, 0xb5, 0x1b, 0x7c, 0x8b, 0x8f, 0x28, 0xac, 0x42, 0xa2, 0x58, 0xde, 0xaf, + 0x1e, 0x56, 0x52, 0x31, 0x75, 0xed, 0xec, 0x5c, 0x03, 0xbe, 0x53, 0xac, 0x31, 0xbb, 0x47, 0xb0, + 0x06, 0xcb, 0xe5, 0x27, 0xbb, 0xbb, 0xd5, 0xfd, 0xfd, 0xca, 0xc3, 0x54, 0x5c, 0x7d, 0xf7, 0xec, + 0x5c, 0x5b, 0xe5, 0xdb, 0x7e, 0xaf, 0x64, 0xa4, 0xae, 0xae, 0xbc, 0xfe, 0x21, 0xb7, 0xf0, 0xf3, + 0x8f, 0x39, 0x81, 0xa0, 0xf0, 0xf7, 0x12, 0x2c, 0x0f, 0x38, 0xc6, 0xdf, 0xc2, 0x92, 0x7c, 0x4a, + 0xe0, 0xad, 0xa8, 0xcf, 0x1b, 0xf5, 0x7e, 0x04, 0x4d, 0x49, 0x62, 0x17, 0x14, 0x11, 0xe1, 0xc7, + 0x91, 0x9e, 0x04, 0xea, 0xdd, 0x59, 0xd5, 0xa4, 0xdb, 0x26, 0x24, 0xfc, 0x69, 0x8b, 0x8d, 0xe9, + 0x16, 0xae, 0x0c, 0x77, 0xf5, 0x76, 0x78, 0x05, 0xe9, 0xec, 0x08, 0x12, 0x7e, 0x32, 0xf0, 0xbd, + 0x88, 0x23, 0x4e, 0xcd, 0x5c, 0xab, 0xec, 0x0a, 0x7f, 0x8a, 0x73, 0xd3, 0xfe, 0xc8, 0x0f, 0x63, + 0x7a, 0xe2, 0xe3, 0xe0, 0x3f, 0x4d, 0x77, 0x41, 0xe1, 0x9d, 0x33, 0x4c, 0x66, 0x26, 0x8c, 0xcb, + 0x30, 0x99, 0x99, 0xd8, 0x98, 0xbf, 0x81, 0x84, 0xdf, 0x9b, 0xc2, 0x44, 0x34, 0xb1, 0xff, 0xaa, + 0x5b, 0xb3, 0x2b, 0x4a, 0xe7, 0x7d, 0x50, 0x78, 0x0b, 0xc2, 0x21, 0xc0, 0x4f, 0x6a, 0x72, 0xea, + 0xbd, 0x99, 0xf5, 0x7c, 0xc7, 0xb7, 0x11, 0x3e, 0x85, 0x45, 0xd1, 0x5e, 0xb0, 0x1e, 0x02, 0xfd, + 0x48, 0x2f, 0x53, 0x8d, 0xd0, 0xe7, 0x7d, 0x5f, 0xa5, 0x17, 0x17, 0x6f, 0x72, 0x0b, 0xbf, 0xbe, + 0xc9, 0x2d, 0x7c, 0x77, 0x99, 0x43, 0x17, 0x97, 0x39, 0xf4, 0xcb, 0x65, 0x0e, 0xfd, 0x71, 0x99, + 0x43, 0xcf, 0x4b, 0x91, 0x7f, 0x39, 0xb7, 0x03, 0xf9, 0x38, 0x21, 0xae, 0xd1, 0x47, 0xff, 0x06, + 0x00, 0x00, 0xff, 0xff, 0x55, 0xaa, 0x35, 0xc8, 0xbf, 0x0e, 0x00, 0x00, } diff --git a/api/services/snapshot/v1/snapshots.proto b/api/services/snapshot/v1/snapshots.proto index 3f5180dc1..af3930ffb 100644 --- a/api/services/snapshot/v1/snapshots.proto +++ b/api/services/snapshot/v1/snapshots.proto @@ -4,6 +4,8 @@ package containerd.services.snapshots.v1; import "gogoproto/gogo.proto"; import "google/protobuf/empty.proto"; +import "google/protobuf/field_mask.proto"; +import "google/protobuf/timestamp.proto"; import "github.com/containerd/containerd/api/types/mount.proto"; option go_package = "github.com/containerd/containerd/api/services/snapshot/v1;snapshot"; @@ -16,6 +18,7 @@ service Snapshots { rpc Commit(CommitSnapshotRequest) returns (google.protobuf.Empty); rpc Remove(RemoveSnapshotRequest) returns (google.protobuf.Empty); rpc Stat(StatSnapshotRequest) returns (StatSnapshotResponse); + rpc Update(UpdateSnapshotRequest) returns (UpdateSnapshotResponse); rpc List(ListSnapshotsRequest) returns (stream ListSnapshotsResponse); rpc Usage(UsageRequest) returns (UsageResponse); } @@ -24,6 +27,9 @@ message PrepareSnapshotRequest { string snapshotter = 1; string key = 2; string parent = 3; + + // Labels are arbitrary data on snapshots. + map labels = 4; } message PrepareSnapshotResponse { @@ -34,6 +40,9 @@ message ViewSnapshotRequest { string snapshotter = 1; string key = 2; string parent = 3; + + // Labels are arbitrary data on snapshots. + map labels = 4; } message ViewSnapshotResponse { @@ -58,6 +67,9 @@ message CommitSnapshotRequest { string snapshotter = 1; string name = 2; string key = 3; + + // Labels are arbitrary data on snapshots. + map labels = 4; } message StatSnapshotRequest { @@ -79,12 +91,38 @@ message Info { string name = 1; string parent = 2; Kind kind = 3; + + // CreatedAt provides the time at which the snapshot was created. + google.protobuf.Timestamp created_at = 4 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false]; + + // UpdatedAt provides the time the info was last updated. + google.protobuf.Timestamp updated_at = 5 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false]; + + // Labels are arbitrary data on snapshots. + map labels = 6; } message StatSnapshotResponse { Info info = 1 [(gogoproto.nullable) = false]; } +message UpdateSnapshotRequest { + string snapshotter = 1; + Info info = 2 [(gogoproto.nullable) = false]; + + // UpdateMask specifies which fields to perform the update on. If empty, + // the operation applies to all fields. + // + // In info, Name, Parent, Kind, Created are immutable, + // other field may be updated using this mask. + // If no mask is provided, all mutable field are updated. + google.protobuf.FieldMask update_mask = 3; +} + +message UpdateSnapshotResponse { + Info info = 1 [(gogoproto.nullable) = false]; +} + message ListSnapshotsRequest{ string snapshotter = 1; } diff --git a/services/snapshot/client.go b/services/snapshot/client.go index c5b4ab53b..a9b9ffe67 100644 --- a/services/snapshot/client.go +++ b/services/snapshot/client.go @@ -9,6 +9,7 @@ import ( "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/mount" "github.com/containerd/containerd/snapshot" + protobuftypes "github.com/gogo/protobuf/types" ) // NewSnapshotterFromClient returns a new Snapshotter which communicates @@ -37,6 +38,21 @@ func (r *remoteSnapshotter) Stat(ctx context.Context, key string) (snapshot.Info return toInfo(resp.Info), nil } +func (r *remoteSnapshotter) Update(ctx context.Context, info snapshot.Info, fieldpaths ...string) (snapshot.Info, error) { + resp, err := r.client.Update(ctx, + &snapshotapi.UpdateSnapshotRequest{ + Snapshotter: r.snapshotterName, + Info: fromInfo(info), + UpdateMask: &protobuftypes.FieldMask{ + Paths: fieldpaths, + }, + }) + if err != nil { + return snapshot.Info{}, errdefs.FromGRPC(err) + } + return toInfo(resp.Info), nil +} + func (r *remoteSnapshotter) Usage(ctx context.Context, key string) (snapshot.Usage, error) { resp, err := r.client.Usage(ctx, &snapshotapi.UsageRequest{ Snapshotter: r.snapshotterName, @@ -59,11 +75,18 @@ func (r *remoteSnapshotter) Mounts(ctx context.Context, key string) ([]mount.Mou return toMounts(resp.Mounts), nil } -func (r *remoteSnapshotter) Prepare(ctx context.Context, key, parent string) ([]mount.Mount, error) { +func (r *remoteSnapshotter) Prepare(ctx context.Context, key, parent string, opts ...snapshot.Opt) ([]mount.Mount, error) { + var local snapshot.Info + for _, opt := range opts { + if err := opt(&local); err != nil { + return nil, err + } + } resp, err := r.client.Prepare(ctx, &snapshotapi.PrepareSnapshotRequest{ Snapshotter: r.snapshotterName, Key: key, Parent: parent, + Labels: local.Labels, }) if err != nil { return nil, errdefs.FromGRPC(err) @@ -71,11 +94,18 @@ func (r *remoteSnapshotter) Prepare(ctx context.Context, key, parent string) ([] return toMounts(resp.Mounts), nil } -func (r *remoteSnapshotter) View(ctx context.Context, key, parent string) ([]mount.Mount, error) { +func (r *remoteSnapshotter) View(ctx context.Context, key, parent string, opts ...snapshot.Opt) ([]mount.Mount, error) { + var local snapshot.Info + for _, opt := range opts { + if err := opt(&local); err != nil { + return nil, err + } + } resp, err := r.client.View(ctx, &snapshotapi.ViewSnapshotRequest{ Snapshotter: r.snapshotterName, Key: key, Parent: parent, + Labels: local.Labels, }) if err != nil { return nil, errdefs.FromGRPC(err) @@ -83,11 +113,18 @@ func (r *remoteSnapshotter) View(ctx context.Context, key, parent string) ([]mou return toMounts(resp.Mounts), nil } -func (r *remoteSnapshotter) Commit(ctx context.Context, name, key string) error { +func (r *remoteSnapshotter) Commit(ctx context.Context, name, key string, opts ...snapshot.Opt) error { + var local snapshot.Info + for _, opt := range opts { + if err := opt(&local); err != nil { + return err + } + } _, err := r.client.Commit(ctx, &snapshotapi.CommitSnapshotRequest{ Snapshotter: r.snapshotterName, Name: name, Key: key, + Labels: local.Labels, }) return errdefs.FromGRPC(err) } @@ -130,14 +167,20 @@ func toKind(kind snapshotapi.Kind) snapshot.Kind { if kind == snapshotapi.KindActive { return snapshot.KindActive } + if kind == snapshotapi.KindView { + return snapshot.KindView + } return snapshot.KindCommitted } func toInfo(info snapshotapi.Info) snapshot.Info { return snapshot.Info{ - Name: info.Name, - Parent: info.Parent, - Kind: toKind(info.Kind), + Name: info.Name, + Parent: info.Parent, + Kind: toKind(info.Kind), + Created: info.CreatedAt, + Updated: info.UpdatedAt, + Labels: info.Labels, } } diff --git a/services/snapshot/service.go b/services/snapshot/service.go index 8b105e8a2..6c6ef8818 100644 --- a/services/snapshot/service.go +++ b/services/snapshot/service.go @@ -97,9 +97,12 @@ func (s *service) Prepare(ctx context.Context, pr *snapshotapi.PrepareSnapshotRe if err != nil { return nil, err } - // TODO: Apply namespace - // TODO: Lookup snapshot id from metadata store - mounts, err := sn.Prepare(ctx, pr.Key, pr.Parent) + + var opts []snapshot.Opt + if pr.Labels != nil { + opts = append(opts, snapshot.WithLabels(pr.Labels)) + } + mounts, err := sn.Prepare(ctx, pr.Key, pr.Parent, opts...) if err != nil { return nil, errdefs.ToGRPC(err) } @@ -121,9 +124,11 @@ func (s *service) View(ctx context.Context, pr *snapshotapi.ViewSnapshotRequest) if err != nil { return nil, err } - // TODO: Apply namespace - // TODO: Lookup snapshot id from metadata store - mounts, err := sn.View(ctx, pr.Key, pr.Parent) + var opts []snapshot.Opt + if pr.Labels != nil { + opts = append(opts, snapshot.WithLabels(pr.Labels)) + } + mounts, err := sn.View(ctx, pr.Key, pr.Parent, opts...) if err != nil { return nil, errdefs.ToGRPC(err) } @@ -138,8 +143,7 @@ func (s *service) Mounts(ctx context.Context, mr *snapshotapi.MountsRequest) (*s if err != nil { return nil, err } - // TODO: Apply namespace - // TODO: Lookup snapshot id from metadata store + mounts, err := sn.Mounts(ctx, mr.Key) if err != nil { return nil, errdefs.ToGRPC(err) @@ -155,9 +159,12 @@ func (s *service) Commit(ctx context.Context, cr *snapshotapi.CommitSnapshotRequ if err != nil { return nil, err } - // TODO: Apply namespace - // TODO: Lookup snapshot id from metadata store - if err := sn.Commit(ctx, cr.Name, cr.Key); err != nil { + + var opts []snapshot.Opt + if cr.Labels != nil { + opts = append(opts, snapshot.WithLabels(cr.Labels)) + } + if err := sn.Commit(ctx, cr.Name, cr.Key, opts...); err != nil { return nil, errdefs.ToGRPC(err) } @@ -176,8 +183,7 @@ func (s *service) Remove(ctx context.Context, rr *snapshotapi.RemoveSnapshotRequ if err != nil { return nil, err } - // TODO: Apply namespace - // TODO: Lookup snapshot id from metadata store + if err := sn.Remove(ctx, rr.Key); err != nil { return nil, errdefs.ToGRPC(err) } @@ -196,7 +202,7 @@ func (s *service) Stat(ctx context.Context, sr *snapshotapi.StatSnapshotRequest) if err != nil { return nil, err } - // TODO: Apply namespace + info, err := sn.Stat(ctx, sr.Key) if err != nil { return nil, errdefs.ToGRPC(err) @@ -205,12 +211,27 @@ func (s *service) Stat(ctx context.Context, sr *snapshotapi.StatSnapshotRequest) return &snapshotapi.StatSnapshotResponse{Info: fromInfo(info)}, nil } +func (s *service) Update(ctx context.Context, sr *snapshotapi.UpdateSnapshotRequest) (*snapshotapi.UpdateSnapshotResponse, error) { + log.G(ctx).WithField("key", sr.Info.Name).Debugf("Updating snapshot") + sn, err := s.getSnapshotter(sr.Snapshotter) + if err != nil { + return nil, err + } + + info, err := sn.Update(ctx, toInfo(sr.Info), sr.UpdateMask.GetPaths()...) + if err != nil { + return nil, errdefs.ToGRPC(err) + } + + return &snapshotapi.UpdateSnapshotResponse{Info: fromInfo(info)}, nil +} + func (s *service) List(sr *snapshotapi.ListSnapshotsRequest, ss snapshotapi.Snapshots_ListServer) error { sn, err := s.getSnapshotter(sr.Snapshotter) if err != nil { return err } - // TODO: Apply namespace + var ( buffer []snapshotapi.Info sendBlock = func(block []snapshotapi.Info) error { @@ -250,7 +271,7 @@ func (s *service) Usage(ctx context.Context, ur *snapshotapi.UsageRequest) (*sna if err != nil { return nil, err } - // TODO: Apply namespace + usage, err := sn.Usage(ctx, ur.Key) if err != nil { return nil, errdefs.ToGRPC(err) @@ -263,14 +284,20 @@ func fromKind(kind snapshot.Kind) snapshotapi.Kind { if kind == snapshot.KindActive { return snapshotapi.KindActive } + if kind == snapshot.KindView { + return snapshotapi.KindView + } return snapshotapi.KindCommitted } func fromInfo(info snapshot.Info) snapshotapi.Info { return snapshotapi.Info{ - Name: info.Name, - Parent: info.Parent, - Kind: fromKind(info.Kind), + Name: info.Name, + Parent: info.Parent, + Kind: fromKind(info.Kind), + CreatedAt: info.Created, + UpdatedAt: info.Updated, + Labels: info.Labels, } } From 24783b9e11b80de029b9300a2686e9149e4845bf Mon Sep 17 00:00:00 2001 From: Derek McGowan Date: Wed, 2 Aug 2017 15:48:17 -0700 Subject: [PATCH 5/6] Add snapshot test suite for update Signed-off-by: Derek McGowan --- snapshot/testsuite/testsuite.go | 221 ++++++++++++++++++++++++++++++++ 1 file changed, 221 insertions(+) diff --git a/snapshot/testsuite/testsuite.go b/snapshot/testsuite/testsuite.go index 04825a2d1..f06adba68 100644 --- a/snapshot/testsuite/testsuite.go +++ b/snapshot/testsuite/testsuite.go @@ -7,7 +7,9 @@ import ( "os" "path/filepath" "testing" + "time" + "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/fs/fstest" "github.com/containerd/containerd/mount" "github.com/containerd/containerd/namespaces" @@ -23,6 +25,8 @@ func SnapshotterSuite(t *testing.T, name string, snapshotterFn func(ctx context. t.Run("StatComitted", makeTest(t, name, snapshotterFn, checkSnapshotterStatCommitted)) t.Run("TransitivityTest", makeTest(t, name, snapshotterFn, checkSnapshotterTransitivity)) t.Run("PreareViewFailingtest", makeTest(t, name, snapshotterFn, checkSnapshotterPrepareView)) + t.Run("Update", makeTest(t, name, snapshotterFn, checkUpdate)) + t.Run("Remove", makeTest(t, name, snapshotterFn, checkRemove)) t.Run("LayerFileupdate", makeTest(t, name, snapshotterFn, checkLayerFileUpdate)) t.Run("RemoveDirectoryInLowerLayer", makeTest(t, name, snapshotterFn, checkRemoveDirectoryInLowerLayer)) @@ -414,3 +418,220 @@ func checkSnapshotterPrepareView(ctx context.Context, t *testing.T, snapshotter assert.NotNil(t, err) } + +// baseTestSnapshots creates a base set of snapshots for tests, each snapshot is empty +// Tests snapshots: +// c1 - committed snapshot, no parent +// c2 - commited snapshot, c1 is parent +// a1 - active snapshot, c2 is parent +// a1 - active snapshot, no parent +// v1 - view snapshot, v1 is parent +// v2 - view snapshot, no parent +func baseTestSnapshots(ctx context.Context, snapshotter snapshot.Snapshotter) error { + if _, err := snapshotter.Prepare(ctx, "c1-a", ""); err != nil { + return err + } + if err := snapshotter.Commit(ctx, "c1", "c1-a"); err != nil { + return err + } + if _, err := snapshotter.Prepare(ctx, "c2-a", "c1"); err != nil { + return err + } + if err := snapshotter.Commit(ctx, "c2", "c2-a"); err != nil { + return err + } + if _, err := snapshotter.Prepare(ctx, "a1", "c2"); err != nil { + return err + } + if _, err := snapshotter.Prepare(ctx, "a2", ""); err != nil { + return err + } + if _, err := snapshotter.View(ctx, "v1", "c2"); err != nil { + return err + } + if _, err := snapshotter.View(ctx, "v2", ""); err != nil { + return err + } + return nil +} + +func checkUpdate(ctx context.Context, t *testing.T, snapshotter snapshot.Snapshotter, work string) { + t1 := time.Now().UTC() + if err := baseTestSnapshots(ctx, snapshotter); err != nil { + t.Fatalf("Failed to create base snapshots: %v", err) + } + t2 := time.Now().UTC() + testcases := []struct { + name string + kind snapshot.Kind + parent string + }{ + { + name: "c1", + kind: snapshot.KindCommitted, + }, + { + name: "c2", + kind: snapshot.KindCommitted, + parent: "c1", + }, + { + name: "a1", + kind: snapshot.KindActive, + parent: "c2", + }, + { + name: "a2", + kind: snapshot.KindActive, + }, + { + name: "v1", + kind: snapshot.KindView, + parent: "c2", + }, + { + name: "v2", + kind: snapshot.KindView, + }, + } + for _, tc := range testcases { + st, err := snapshotter.Stat(ctx, tc.name) + if err != nil { + t.Fatalf("Failed to stat %s: %v", tc.name, err) + } + if st.Created.Before(t1) || st.Created.After(t2) { + t.Errorf("(%s) wrong created time %s: expected between %s and %s", tc.name, st.Created, t1, t2) + continue + } + if st.Created != st.Updated { + t.Errorf("(%s) unexpected updated time %s: expected %s", tc.name, st.Updated, st.Created) + continue + } + if st.Kind != tc.kind { + t.Errorf("(%s) unexpected kind %s, expected %s", tc.name, st.Kind, tc.kind) + continue + } + if st.Parent != tc.parent { + t.Errorf("(%s) unexpected parent %q, expected %q", tc.name, st.Parent, tc.parent) + continue + } + if st.Name != tc.name { + t.Errorf("(%s) unexpected name %q, expected %q", tc.name, st.Name, tc.name) + continue + } + + createdAt := st.Created + expected := map[string]string{ + "l1": "v1", + "l2": "v2", + "l3": "v3", + } + st.Parent = "doesnotexist" + st.Labels = expected + u1 := time.Now().UTC() + st, err = snapshotter.Update(ctx, st) + if err != nil { + t.Fatalf("Failed to update %s: %v", tc.name, err) + } + u2 := time.Now().UTC() + + if st.Created != createdAt { + t.Errorf("(%s) wrong created time %s: expected %s", tc.name, st.Created, createdAt) + continue + } + if st.Updated.Before(u1) || st.Updated.After(u2) { + t.Errorf("(%s) wrong updated time %s: expected between %s and %s", tc.name, st.Updated, u1, u2) + continue + } + if st.Kind != tc.kind { + t.Errorf("(%s) unexpected kind %s, expected %s", tc.name, st.Kind, tc.kind) + continue + } + if st.Parent != tc.parent { + t.Errorf("(%s) unexpected parent %q, expected %q", tc.name, st.Parent, tc.parent) + continue + } + if st.Name != tc.name { + t.Errorf("(%s) unexpected name %q, expected %q", tc.name, st.Name, tc.name) + continue + } + assertLabels(t, st.Labels, expected) + + expected = map[string]string{ + "l1": "updated", + "l3": "v3", + } + st.Labels = map[string]string{ + "l1": "updated", + "l4": "v4", + } + st, err = snapshotter.Update(ctx, st, "labels.l1", "labels.l2") + if err != nil { + t.Fatalf("Failed to update %s: %v", tc.name, err) + } + assertLabels(t, st.Labels, expected) + + expected = map[string]string{ + "l4": "v4", + } + st.Labels = expected + st, err = snapshotter.Update(ctx, st, "labels") + if err != nil { + t.Fatalf("Failed to update %s: %v", tc.name, err) + } + assertLabels(t, st.Labels, expected) + + // Test failure received when providing immutable field path + st.Parent = "doesnotexist" + st, err = snapshotter.Update(ctx, st, "parent") + if err == nil { + t.Errorf("Expected error updating with immutable field path") + } else if !errdefs.IsInvalidArgument(err) { + t.Fatalf("Unexpected error updating %s: %+v", tc.name, err) + } + } +} + +func assertLabels(t *testing.T, actual, expected map[string]string) { + if len(actual) != len(expected) { + t.Fatalf("Label size mismatch: %d vs %d\n\tActual: %#v\n\tExpected: %#v", len(actual), len(expected), actual, expected) + } + for k, v := range expected { + if a := actual[k]; v != a { + t.Errorf("Wrong label value for %s, got %q, expected %q", k, a, v) + } + } + if t.Failed() { + t.FailNow() + } +} + +func checkRemove(ctx context.Context, t *testing.T, snapshotter snapshot.Snapshotter, work string) { + if _, err := snapshotter.Prepare(ctx, "committed-a", ""); err != nil { + t.Fatal(err) + } + if err := snapshotter.Commit(ctx, "committed-1", "committed-a"); err != nil { + t.Fatal(err) + } + if _, err := snapshotter.Prepare(ctx, "reuse-1", "committed-1"); err != nil { + t.Fatal(err) + } + if err := snapshotter.Remove(ctx, "reuse-1"); err != nil { + t.Fatal(err) + } + if _, err := snapshotter.View(ctx, "reuse-1", "committed-1"); err != nil { + t.Fatal(err) + } + if err := snapshotter.Remove(ctx, "reuse-1"); err != nil { + t.Fatal(err) + } + if _, err := snapshotter.Prepare(ctx, "reuse-1", ""); err != nil { + t.Fatal(err) + } + if err := snapshotter.Remove(ctx, "committed-1"); err != nil { + t.Fatal(err) + } + if err := snapshotter.Commit(ctx, "commited-1", "reuse-1"); err != nil { + t.Fatal(err) + } +} From be36d26eb14008dac79994c21a204dc61585c452 Mon Sep 17 00:00:00 2001 From: Derek McGowan Date: Wed, 2 Aug 2017 16:32:52 -0700 Subject: [PATCH 6/6] Update windows snapshotter Signed-off-by: Derek McGowan --- snapshot/windows/windows.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/snapshot/windows/windows.go b/snapshot/windows/windows.go index 0225ab3d3..d677254fb 100644 --- a/snapshot/windows/windows.go +++ b/snapshot/windows/windows.go @@ -44,15 +44,19 @@ func (o *Snapshotter) Stat(ctx context.Context, key string) (snapshot.Info, erro panic("not implemented") } +func (o *Snapshotter) Update(ctx context.Context, info snapshot.Info, fieldpaths ...string) (snapshot.Info, error) { + panic("not implemented") +} + func (o *Snapshotter) Usage(ctx context.Context, key string) (snapshot.Usage, error) { panic("not implemented") } -func (o *Snapshotter) Prepare(ctx context.Context, key, parent string) ([]mount.Mount, error) { +func (o *Snapshotter) Prepare(ctx context.Context, key, parent string, opts ...snapshot.Opt) ([]mount.Mount, error) { panic("not implemented") } -func (o *Snapshotter) View(ctx context.Context, key, parent string) ([]mount.Mount, error) { +func (o *Snapshotter) View(ctx context.Context, key, parent string, opts ...snapshot.Opt) ([]mount.Mount, error) { panic("not implemented") } @@ -64,7 +68,7 @@ func (o *Snapshotter) Mounts(ctx context.Context, key string) ([]mount.Mount, er panic("not implemented") } -func (o *Snapshotter) Commit(ctx context.Context, name, key string) error { +func (o *Snapshotter) Commit(ctx context.Context, name, key string, opts ...snapshot.Opt) error { panic("not implemented") }