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 }