github.com/containerd/containerd@v22.0.0-20200918172823-438c87b8e050+incompatible/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 }