github.com/containerd/Containerd@v1.4.13/services/snapshots/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 snapshots
    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/log"
    26  	"github.com/containerd/containerd/mount"
    27  	"github.com/containerd/containerd/plugin"
    28  	"github.com/containerd/containerd/services"
    29  	"github.com/containerd/containerd/snapshots"
    30  	ptypes "github.com/gogo/protobuf/types"
    31  	"github.com/pkg/errors"
    32  	"google.golang.org/grpc"
    33  )
    34  
    35  func init() {
    36  	plugin.Register(&plugin.Registration{
    37  		Type: plugin.GRPCPlugin,
    38  		ID:   "snapshots",
    39  		Requires: []plugin.Type{
    40  			plugin.ServicePlugin,
    41  		},
    42  		InitFn: newService,
    43  	})
    44  }
    45  
    46  var empty = &ptypes.Empty{}
    47  
    48  type service struct {
    49  	ss map[string]snapshots.Snapshotter
    50  }
    51  
    52  func newService(ic *plugin.InitContext) (interface{}, error) {
    53  	plugins, err := ic.GetByType(plugin.ServicePlugin)
    54  	if err != nil {
    55  		return nil, err
    56  	}
    57  	p, ok := plugins[services.SnapshotsService]
    58  	if !ok {
    59  		return nil, errors.New("snapshots service not found")
    60  	}
    61  	i, err := p.Instance()
    62  	if err != nil {
    63  		return nil, err
    64  	}
    65  	ss := i.(map[string]snapshots.Snapshotter)
    66  	return &service{ss: ss}, nil
    67  }
    68  
    69  func (s *service) getSnapshotter(name string) (snapshots.Snapshotter, error) {
    70  	if name == "" {
    71  		return nil, errdefs.ToGRPCf(errdefs.ErrInvalidArgument, "snapshotter argument missing")
    72  	}
    73  
    74  	sn := s.ss[name]
    75  	if sn == nil {
    76  		return nil, errdefs.ToGRPCf(errdefs.ErrInvalidArgument, "snapshotter not loaded: %s", name)
    77  	}
    78  	return sn, nil
    79  }
    80  
    81  func (s *service) Register(gs *grpc.Server) error {
    82  	snapshotsapi.RegisterSnapshotsServer(gs, s)
    83  	return nil
    84  }
    85  
    86  func (s *service) Prepare(ctx context.Context, pr *snapshotsapi.PrepareSnapshotRequest) (*snapshotsapi.PrepareSnapshotResponse, error) {
    87  	log.G(ctx).WithField("parent", pr.Parent).WithField("key", pr.Key).Debugf("prepare snapshot")
    88  	sn, err := s.getSnapshotter(pr.Snapshotter)
    89  	if err != nil {
    90  		return nil, err
    91  	}
    92  
    93  	var opts []snapshots.Opt
    94  	if pr.Labels != nil {
    95  		opts = append(opts, snapshots.WithLabels(pr.Labels))
    96  	}
    97  	mounts, err := sn.Prepare(ctx, pr.Key, pr.Parent, opts...)
    98  	if err != nil {
    99  		return nil, errdefs.ToGRPC(err)
   100  	}
   101  
   102  	return &snapshotsapi.PrepareSnapshotResponse{
   103  		Mounts: fromMounts(mounts),
   104  	}, nil
   105  }
   106  
   107  func (s *service) View(ctx context.Context, pr *snapshotsapi.ViewSnapshotRequest) (*snapshotsapi.ViewSnapshotResponse, error) {
   108  	log.G(ctx).WithField("parent", pr.Parent).WithField("key", pr.Key).Debugf("prepare view snapshot")
   109  	sn, err := s.getSnapshotter(pr.Snapshotter)
   110  	if err != nil {
   111  		return nil, err
   112  	}
   113  	var opts []snapshots.Opt
   114  	if pr.Labels != nil {
   115  		opts = append(opts, snapshots.WithLabels(pr.Labels))
   116  	}
   117  	mounts, err := sn.View(ctx, pr.Key, pr.Parent, opts...)
   118  	if err != nil {
   119  		return nil, errdefs.ToGRPC(err)
   120  	}
   121  	return &snapshotsapi.ViewSnapshotResponse{
   122  		Mounts: fromMounts(mounts),
   123  	}, nil
   124  }
   125  
   126  func (s *service) Mounts(ctx context.Context, mr *snapshotsapi.MountsRequest) (*snapshotsapi.MountsResponse, error) {
   127  	log.G(ctx).WithField("key", mr.Key).Debugf("get snapshot mounts")
   128  	sn, err := s.getSnapshotter(mr.Snapshotter)
   129  	if err != nil {
   130  		return nil, err
   131  	}
   132  
   133  	mounts, err := sn.Mounts(ctx, mr.Key)
   134  	if err != nil {
   135  		return nil, errdefs.ToGRPC(err)
   136  	}
   137  	return &snapshotsapi.MountsResponse{
   138  		Mounts: fromMounts(mounts),
   139  	}, nil
   140  }
   141  
   142  func (s *service) Commit(ctx context.Context, cr *snapshotsapi.CommitSnapshotRequest) (*ptypes.Empty, error) {
   143  	log.G(ctx).WithField("key", cr.Key).WithField("name", cr.Name).Debugf("commit snapshot")
   144  	sn, err := s.getSnapshotter(cr.Snapshotter)
   145  	if err != nil {
   146  		return nil, err
   147  	}
   148  
   149  	var opts []snapshots.Opt
   150  	if cr.Labels != nil {
   151  		opts = append(opts, snapshots.WithLabels(cr.Labels))
   152  	}
   153  	if err := sn.Commit(ctx, cr.Name, cr.Key, opts...); err != nil {
   154  		return nil, errdefs.ToGRPC(err)
   155  	}
   156  
   157  	return empty, nil
   158  }
   159  
   160  func (s *service) Remove(ctx context.Context, rr *snapshotsapi.RemoveSnapshotRequest) (*ptypes.Empty, error) {
   161  	log.G(ctx).WithField("key", rr.Key).Debugf("remove snapshot")
   162  	sn, err := s.getSnapshotter(rr.Snapshotter)
   163  	if err != nil {
   164  		return nil, err
   165  	}
   166  
   167  	if err := sn.Remove(ctx, rr.Key); err != nil {
   168  		return nil, errdefs.ToGRPC(err)
   169  	}
   170  
   171  	return empty, nil
   172  }
   173  
   174  func (s *service) Stat(ctx context.Context, sr *snapshotsapi.StatSnapshotRequest) (*snapshotsapi.StatSnapshotResponse, error) {
   175  	log.G(ctx).WithField("key", sr.Key).Debugf("stat snapshot")
   176  	sn, err := s.getSnapshotter(sr.Snapshotter)
   177  	if err != nil {
   178  		return nil, err
   179  	}
   180  
   181  	info, err := sn.Stat(ctx, sr.Key)
   182  	if err != nil {
   183  		return nil, errdefs.ToGRPC(err)
   184  	}
   185  
   186  	return &snapshotsapi.StatSnapshotResponse{Info: fromInfo(info)}, nil
   187  }
   188  
   189  func (s *service) Update(ctx context.Context, sr *snapshotsapi.UpdateSnapshotRequest) (*snapshotsapi.UpdateSnapshotResponse, error) {
   190  	log.G(ctx).WithField("key", sr.Info.Name).Debugf("update snapshot")
   191  	sn, err := s.getSnapshotter(sr.Snapshotter)
   192  	if err != nil {
   193  		return nil, err
   194  	}
   195  
   196  	info, err := sn.Update(ctx, toInfo(sr.Info), sr.UpdateMask.GetPaths()...)
   197  	if err != nil {
   198  		return nil, errdefs.ToGRPC(err)
   199  	}
   200  
   201  	return &snapshotsapi.UpdateSnapshotResponse{Info: fromInfo(info)}, nil
   202  }
   203  
   204  func (s *service) List(sr *snapshotsapi.ListSnapshotsRequest, ss snapshotsapi.Snapshots_ListServer) error {
   205  	sn, err := s.getSnapshotter(sr.Snapshotter)
   206  	if err != nil {
   207  		return err
   208  	}
   209  
   210  	var (
   211  		buffer    []snapshotsapi.Info
   212  		sendBlock = func(block []snapshotsapi.Info) error {
   213  			return ss.Send(&snapshotsapi.ListSnapshotsResponse{
   214  				Info: block,
   215  			})
   216  		}
   217  	)
   218  	err = sn.Walk(ss.Context(), func(ctx context.Context, info snapshots.Info) error {
   219  		buffer = append(buffer, fromInfo(info))
   220  
   221  		if len(buffer) >= 100 {
   222  			if err := sendBlock(buffer); err != nil {
   223  				return err
   224  			}
   225  
   226  			buffer = buffer[:0]
   227  		}
   228  
   229  		return nil
   230  	}, sr.Filters...)
   231  	if err != nil {
   232  		return err
   233  	}
   234  	if len(buffer) > 0 {
   235  		// Send remaining infos
   236  		if err := sendBlock(buffer); err != nil {
   237  			return err
   238  		}
   239  	}
   240  
   241  	return nil
   242  }
   243  
   244  func (s *service) Usage(ctx context.Context, ur *snapshotsapi.UsageRequest) (*snapshotsapi.UsageResponse, error) {
   245  	sn, err := s.getSnapshotter(ur.Snapshotter)
   246  	if err != nil {
   247  		return nil, err
   248  	}
   249  
   250  	usage, err := sn.Usage(ctx, ur.Key)
   251  	if err != nil {
   252  		return nil, errdefs.ToGRPC(err)
   253  	}
   254  
   255  	return fromUsage(usage), nil
   256  }
   257  
   258  func (s *service) Cleanup(ctx context.Context, cr *snapshotsapi.CleanupRequest) (*ptypes.Empty, error) {
   259  	sn, err := s.getSnapshotter(cr.Snapshotter)
   260  	if err != nil {
   261  		return nil, err
   262  	}
   263  
   264  	c, ok := sn.(snapshots.Cleaner)
   265  	if !ok {
   266  		return nil, errdefs.ToGRPCf(errdefs.ErrNotImplemented, "snapshotter does not implement Cleanup method")
   267  	}
   268  
   269  	err = c.Cleanup(ctx)
   270  	if err != nil {
   271  		return nil, errdefs.ToGRPC(err)
   272  	}
   273  
   274  	return empty, nil
   275  }
   276  
   277  func fromKind(kind snapshots.Kind) snapshotsapi.Kind {
   278  	if kind == snapshots.KindActive {
   279  		return snapshotsapi.KindActive
   280  	}
   281  	if kind == snapshots.KindView {
   282  		return snapshotsapi.KindView
   283  	}
   284  	return snapshotsapi.KindCommitted
   285  }
   286  
   287  func fromInfo(info snapshots.Info) snapshotsapi.Info {
   288  	return snapshotsapi.Info{
   289  		Name:      info.Name,
   290  		Parent:    info.Parent,
   291  		Kind:      fromKind(info.Kind),
   292  		CreatedAt: info.Created,
   293  		UpdatedAt: info.Updated,
   294  		Labels:    info.Labels,
   295  	}
   296  }
   297  
   298  func fromUsage(usage snapshots.Usage) *snapshotsapi.UsageResponse {
   299  	return &snapshotsapi.UsageResponse{
   300  		Inodes: usage.Inodes,
   301  		Size_:  usage.Size,
   302  	}
   303  }
   304  
   305  func fromMounts(mounts []mount.Mount) []*types.Mount {
   306  	out := make([]*types.Mount, len(mounts))
   307  	for i, m := range mounts {
   308  		out[i] = &types.Mount{
   309  			Type:    m.Type,
   310  			Source:  m.Source,
   311  			Options: m.Options,
   312  		}
   313  	}
   314  	return out
   315  }
   316  
   317  func toInfo(info snapshotsapi.Info) snapshots.Info {
   318  	return snapshots.Info{
   319  		Name:    info.Name,
   320  		Parent:  info.Parent,
   321  		Kind:    toKind(info.Kind),
   322  		Created: info.CreatedAt,
   323  		Updated: info.UpdatedAt,
   324  		Labels:  info.Labels,
   325  	}
   326  }
   327  
   328  func toKind(kind snapshotsapi.Kind) snapshots.Kind {
   329  	if kind == snapshotsapi.KindActive {
   330  		return snapshots.KindActive
   331  	}
   332  	if kind == snapshotsapi.KindView {
   333  		return snapshots.KindView
   334  	}
   335  	return snapshots.KindCommitted
   336  }