github.com/containerd/containerd@v22.0.0-20200918172823-438c87b8e050+incompatible/contrib/snapshotservice/service.go (about)

     1  /*
     2     Copyright The containerd Authors.
     3  
     4     Licensed under the Apache License, Version 2.0 (the "License");
     5     you may not use this file except in compliance with the License.
     6     You may obtain a copy of the License at
     7  
     8         http://www.apache.org/licenses/LICENSE-2.0
     9  
    10     Unless required by applicable law or agreed to in writing, software
    11     distributed under the License is distributed on an "AS IS" BASIS,
    12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13     See the License for the specific language governing permissions and
    14     limitations under the License.
    15  */
    16  
    17  package snapshotservice
    18  
    19  import (
    20  	"context"
    21  
    22  	snapshotsapi "github.com/containerd/containerd/api/services/snapshots/v1"
    23  	"github.com/containerd/containerd/api/types"
    24  	"github.com/containerd/containerd/errdefs"
    25  	"github.com/containerd/containerd/mount"
    26  	"github.com/containerd/containerd/snapshots"
    27  	ptypes "github.com/gogo/protobuf/types"
    28  )
    29  
    30  var empty = &ptypes.Empty{}
    31  
    32  type service struct {
    33  	sn snapshots.Snapshotter
    34  }
    35  
    36  // FromSnapshotter returns a Snapshot API server from a containerd snapshotter
    37  func FromSnapshotter(sn snapshots.Snapshotter) snapshotsapi.SnapshotsServer {
    38  	return service{sn: sn}
    39  }
    40  
    41  func (s service) Prepare(ctx context.Context, pr *snapshotsapi.PrepareSnapshotRequest) (*snapshotsapi.PrepareSnapshotResponse, error) {
    42  	var opts []snapshots.Opt
    43  	if pr.Labels != nil {
    44  		opts = append(opts, snapshots.WithLabels(pr.Labels))
    45  	}
    46  	mounts, err := s.sn.Prepare(ctx, pr.Key, pr.Parent, opts...)
    47  	if err != nil {
    48  		return nil, errdefs.ToGRPC(err)
    49  	}
    50  
    51  	return &snapshotsapi.PrepareSnapshotResponse{
    52  		Mounts: fromMounts(mounts),
    53  	}, nil
    54  }
    55  
    56  func (s service) View(ctx context.Context, pr *snapshotsapi.ViewSnapshotRequest) (*snapshotsapi.ViewSnapshotResponse, error) {
    57  	var opts []snapshots.Opt
    58  	if pr.Labels != nil {
    59  		opts = append(opts, snapshots.WithLabels(pr.Labels))
    60  	}
    61  	mounts, err := s.sn.View(ctx, pr.Key, pr.Parent, opts...)
    62  	if err != nil {
    63  		return nil, errdefs.ToGRPC(err)
    64  	}
    65  	return &snapshotsapi.ViewSnapshotResponse{
    66  		Mounts: fromMounts(mounts),
    67  	}, nil
    68  }
    69  
    70  func (s service) Mounts(ctx context.Context, mr *snapshotsapi.MountsRequest) (*snapshotsapi.MountsResponse, error) {
    71  	mounts, err := s.sn.Mounts(ctx, mr.Key)
    72  	if err != nil {
    73  		return nil, errdefs.ToGRPC(err)
    74  	}
    75  	return &snapshotsapi.MountsResponse{
    76  		Mounts: fromMounts(mounts),
    77  	}, nil
    78  }
    79  
    80  func (s service) Commit(ctx context.Context, cr *snapshotsapi.CommitSnapshotRequest) (*ptypes.Empty, error) {
    81  	var opts []snapshots.Opt
    82  	if cr.Labels != nil {
    83  		opts = append(opts, snapshots.WithLabels(cr.Labels))
    84  	}
    85  	if err := s.sn.Commit(ctx, cr.Name, cr.Key, opts...); err != nil {
    86  		return nil, errdefs.ToGRPC(err)
    87  	}
    88  
    89  	return empty, nil
    90  }
    91  
    92  func (s service) Remove(ctx context.Context, rr *snapshotsapi.RemoveSnapshotRequest) (*ptypes.Empty, error) {
    93  	if err := s.sn.Remove(ctx, rr.Key); err != nil {
    94  		return nil, errdefs.ToGRPC(err)
    95  	}
    96  
    97  	return empty, nil
    98  }
    99  
   100  func (s service) Stat(ctx context.Context, sr *snapshotsapi.StatSnapshotRequest) (*snapshotsapi.StatSnapshotResponse, error) {
   101  	info, err := s.sn.Stat(ctx, sr.Key)
   102  	if err != nil {
   103  		return nil, errdefs.ToGRPC(err)
   104  	}
   105  
   106  	return &snapshotsapi.StatSnapshotResponse{Info: fromInfo(info)}, nil
   107  }
   108  
   109  func (s service) Update(ctx context.Context, sr *snapshotsapi.UpdateSnapshotRequest) (*snapshotsapi.UpdateSnapshotResponse, error) {
   110  	info, err := s.sn.Update(ctx, toInfo(sr.Info), sr.UpdateMask.GetPaths()...)
   111  	if err != nil {
   112  		return nil, errdefs.ToGRPC(err)
   113  	}
   114  
   115  	return &snapshotsapi.UpdateSnapshotResponse{Info: fromInfo(info)}, nil
   116  }
   117  
   118  func (s service) List(sr *snapshotsapi.ListSnapshotsRequest, ss snapshotsapi.Snapshots_ListServer) error {
   119  	var (
   120  		buffer    []snapshotsapi.Info
   121  		sendBlock = func(block []snapshotsapi.Info) error {
   122  			return ss.Send(&snapshotsapi.ListSnapshotsResponse{
   123  				Info: block,
   124  			})
   125  		}
   126  	)
   127  	err := s.sn.Walk(ss.Context(), func(ctx context.Context, info snapshots.Info) error {
   128  		buffer = append(buffer, fromInfo(info))
   129  
   130  		if len(buffer) >= 100 {
   131  			if err := sendBlock(buffer); err != nil {
   132  				return err
   133  			}
   134  
   135  			buffer = buffer[:0]
   136  		}
   137  
   138  		return nil
   139  	}, sr.Filters...)
   140  	if err != nil {
   141  		return err
   142  	}
   143  	if len(buffer) > 0 {
   144  		// Send remaining infos
   145  		if err := sendBlock(buffer); err != nil {
   146  			return err
   147  		}
   148  	}
   149  
   150  	return nil
   151  
   152  }
   153  
   154  func (s service) Usage(ctx context.Context, ur *snapshotsapi.UsageRequest) (*snapshotsapi.UsageResponse, error) {
   155  	usage, err := s.sn.Usage(ctx, ur.Key)
   156  	if err != nil {
   157  		return nil, errdefs.ToGRPC(err)
   158  	}
   159  
   160  	return &snapshotsapi.UsageResponse{
   161  		Inodes: usage.Inodes,
   162  		Size_:  usage.Size,
   163  	}, nil
   164  }
   165  
   166  func (s service) Cleanup(ctx context.Context, cr *snapshotsapi.CleanupRequest) (*ptypes.Empty, error) {
   167  	c, ok := s.sn.(snapshots.Cleaner)
   168  	if !ok {
   169  		return nil, errdefs.ToGRPCf(errdefs.ErrNotImplemented, "snapshotter does not implement Cleanup method")
   170  	}
   171  
   172  	if err := c.Cleanup(ctx); err != nil {
   173  		return nil, errdefs.ToGRPC(err)
   174  	}
   175  
   176  	return empty, nil
   177  }
   178  
   179  func fromKind(kind snapshots.Kind) snapshotsapi.Kind {
   180  	if kind == snapshots.KindActive {
   181  		return snapshotsapi.KindActive
   182  	}
   183  	if kind == snapshots.KindView {
   184  		return snapshotsapi.KindView
   185  	}
   186  	return snapshotsapi.KindCommitted
   187  }
   188  
   189  func fromInfo(info snapshots.Info) snapshotsapi.Info {
   190  	return snapshotsapi.Info{
   191  		Name:      info.Name,
   192  		Parent:    info.Parent,
   193  		Kind:      fromKind(info.Kind),
   194  		CreatedAt: info.Created,
   195  		UpdatedAt: info.Updated,
   196  		Labels:    info.Labels,
   197  	}
   198  }
   199  
   200  func fromMounts(mounts []mount.Mount) []*types.Mount {
   201  	out := make([]*types.Mount, len(mounts))
   202  	for i, m := range mounts {
   203  		out[i] = &types.Mount{
   204  			Type:    m.Type,
   205  			Source:  m.Source,
   206  			Options: m.Options,
   207  		}
   208  	}
   209  	return out
   210  }
   211  
   212  func toInfo(info snapshotsapi.Info) snapshots.Info {
   213  	return snapshots.Info{
   214  		Name:    info.Name,
   215  		Parent:  info.Parent,
   216  		Kind:    toKind(info.Kind),
   217  		Created: info.CreatedAt,
   218  		Updated: info.UpdatedAt,
   219  		Labels:  info.Labels,
   220  	}
   221  }
   222  
   223  func toKind(kind snapshotsapi.Kind) snapshots.Kind {
   224  	if kind == snapshotsapi.KindActive {
   225  		return snapshots.KindActive
   226  	}
   227  	if kind == snapshotsapi.KindView {
   228  		return snapshots.KindView
   229  	}
   230  	return snapshots.KindCommitted
   231  }