package containerd import ( "context" "io" snapshotapi "github.com/containerd/containerd/api/services/snapshot/v1" "github.com/containerd/containerd/api/types" "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 // over a GRPC connection. func NewSnapshotterFromClient(client snapshotapi.SnapshotsClient, snapshotterName string) snapshot.Snapshotter { return &remoteSnapshotter{ client: client, snapshotterName: snapshotterName, } } type remoteSnapshotter struct { client snapshotapi.SnapshotsClient snapshotterName string } func (r *remoteSnapshotter) Stat(ctx context.Context, key string) (snapshot.Info, error) { resp, err := r.client.Stat(ctx, &snapshotapi.StatSnapshotRequest{ Snapshotter: r.snapshotterName, Key: key, }) if err != nil { return snapshot.Info{}, errdefs.FromGRPC(err) } 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, Key: key, }) if err != nil { return snapshot.Usage{}, errdefs.FromGRPC(err) } return toUsage(resp), nil } func (r *remoteSnapshotter) Mounts(ctx context.Context, key string) ([]mount.Mount, error) { resp, err := r.client.Mounts(ctx, &snapshotapi.MountsRequest{ Snapshotter: r.snapshotterName, Key: key, }) if err != nil { return nil, errdefs.FromGRPC(err) } return toMounts(resp.Mounts), nil } 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) } return toMounts(resp.Mounts), nil } 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) } return toMounts(resp.Mounts), nil } 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) } func (r *remoteSnapshotter) Remove(ctx context.Context, key string) error { _, err := r.client.Remove(ctx, &snapshotapi.RemoveSnapshotRequest{ Snapshotter: r.snapshotterName, Key: key, }) return errdefs.FromGRPC(err) } func (r *remoteSnapshotter) Walk(ctx context.Context, fn func(context.Context, snapshot.Info) error) error { sc, err := r.client.List(ctx, &snapshotapi.ListSnapshotsRequest{ Snapshotter: r.snapshotterName, }) if err != nil { return errdefs.FromGRPC(err) } for { resp, err := sc.Recv() if err != nil { if err == io.EOF { return nil } return errdefs.FromGRPC(err) } if resp == nil { return nil } for _, info := range resp.Info { if err := fn(ctx, toInfo(info)); err != nil { return err } } } } func (r *remoteSnapshotter) Close() error { return nil } 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), Created: info.CreatedAt, Updated: info.UpdatedAt, Labels: info.Labels, } } func toUsage(resp *snapshotapi.UsageResponse) snapshot.Usage { return snapshot.Usage{ Inodes: resp.Inodes, Size: resp.Size_, } } func toMounts(mm []*types.Mount) []mount.Mount { mounts := make([]mount.Mount, len(mm)) for i, m := range mm { mounts[i] = mount.Mount{ Type: m.Type, Source: m.Source, Options: m.Options, } } return mounts } 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), CreatedAt: info.Created, UpdatedAt: info.Updated, Labels: info.Labels, } }