github.com/demonoid81/containerd@v1.3.4/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 }) 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 fromKind(kind snapshots.Kind) snapshotsapi.Kind { 259 if kind == snapshots.KindActive { 260 return snapshotsapi.KindActive 261 } 262 if kind == snapshots.KindView { 263 return snapshotsapi.KindView 264 } 265 return snapshotsapi.KindCommitted 266 } 267 268 func fromInfo(info snapshots.Info) snapshotsapi.Info { 269 return snapshotsapi.Info{ 270 Name: info.Name, 271 Parent: info.Parent, 272 Kind: fromKind(info.Kind), 273 CreatedAt: info.Created, 274 UpdatedAt: info.Updated, 275 Labels: info.Labels, 276 } 277 } 278 279 func fromUsage(usage snapshots.Usage) *snapshotsapi.UsageResponse { 280 return &snapshotsapi.UsageResponse{ 281 Inodes: usage.Inodes, 282 Size_: usage.Size, 283 } 284 } 285 286 func fromMounts(mounts []mount.Mount) []*types.Mount { 287 out := make([]*types.Mount, len(mounts)) 288 for i, m := range mounts { 289 out[i] = &types.Mount{ 290 Type: m.Type, 291 Source: m.Source, 292 Options: m.Options, 293 } 294 } 295 return out 296 } 297 298 func toInfo(info snapshotsapi.Info) snapshots.Info { 299 return snapshots.Info{ 300 Name: info.Name, 301 Parent: info.Parent, 302 Kind: toKind(info.Kind), 303 Created: info.CreatedAt, 304 Updated: info.UpdatedAt, 305 Labels: info.Labels, 306 } 307 } 308 309 func toKind(kind snapshotsapi.Kind) snapshots.Kind { 310 if kind == snapshotsapi.KindActive { 311 return snapshots.KindActive 312 } 313 if kind == snapshotsapi.KindView { 314 return snapshots.KindView 315 } 316 return snapshots.KindCommitted 317 }