github.com/containerd/containerd@v22.0.0-20200918172823-438c87b8e050+incompatible/services/images/local.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 images 18 19 import ( 20 "context" 21 22 eventstypes "github.com/containerd/containerd/api/events" 23 imagesapi "github.com/containerd/containerd/api/services/images/v1" 24 "github.com/containerd/containerd/errdefs" 25 "github.com/containerd/containerd/events" 26 "github.com/containerd/containerd/gc" 27 "github.com/containerd/containerd/images" 28 "github.com/containerd/containerd/log" 29 "github.com/containerd/containerd/metadata" 30 "github.com/containerd/containerd/plugin" 31 "github.com/containerd/containerd/services" 32 ptypes "github.com/gogo/protobuf/types" 33 "google.golang.org/grpc" 34 "google.golang.org/grpc/codes" 35 "google.golang.org/grpc/status" 36 ) 37 38 func init() { 39 plugin.Register(&plugin.Registration{ 40 Type: plugin.ServicePlugin, 41 ID: services.ImagesService, 42 Requires: []plugin.Type{ 43 plugin.MetadataPlugin, 44 plugin.GCPlugin, 45 }, 46 InitFn: func(ic *plugin.InitContext) (interface{}, error) { 47 m, err := ic.Get(plugin.MetadataPlugin) 48 if err != nil { 49 return nil, err 50 } 51 g, err := ic.Get(plugin.GCPlugin) 52 if err != nil { 53 return nil, err 54 } 55 56 return &local{ 57 store: metadata.NewImageStore(m.(*metadata.DB)), 58 publisher: ic.Events, 59 gc: g.(gcScheduler), 60 }, nil 61 }, 62 }) 63 } 64 65 type gcScheduler interface { 66 ScheduleAndWait(context.Context) (gc.Stats, error) 67 } 68 69 type local struct { 70 store images.Store 71 gc gcScheduler 72 publisher events.Publisher 73 } 74 75 var _ imagesapi.ImagesClient = &local{} 76 77 func (l *local) Get(ctx context.Context, req *imagesapi.GetImageRequest, _ ...grpc.CallOption) (*imagesapi.GetImageResponse, error) { 78 image, err := l.store.Get(ctx, req.Name) 79 if err != nil { 80 return nil, errdefs.ToGRPC(err) 81 } 82 83 imagepb := imageToProto(&image) 84 return &imagesapi.GetImageResponse{ 85 Image: &imagepb, 86 }, nil 87 } 88 89 func (l *local) List(ctx context.Context, req *imagesapi.ListImagesRequest, _ ...grpc.CallOption) (*imagesapi.ListImagesResponse, error) { 90 images, err := l.store.List(ctx, req.Filters...) 91 if err != nil { 92 return nil, errdefs.ToGRPC(err) 93 } 94 95 return &imagesapi.ListImagesResponse{ 96 Images: imagesToProto(images), 97 }, nil 98 } 99 100 func (l *local) Create(ctx context.Context, req *imagesapi.CreateImageRequest, _ ...grpc.CallOption) (*imagesapi.CreateImageResponse, error) { 101 log.G(ctx).WithField("name", req.Image.Name).WithField("target", req.Image.Target.Digest).Debugf("create image") 102 if req.Image.Name == "" { 103 return nil, status.Errorf(codes.InvalidArgument, "Image.Name required") 104 } 105 106 var ( 107 image = imageFromProto(&req.Image) 108 resp imagesapi.CreateImageResponse 109 ) 110 created, err := l.store.Create(ctx, image) 111 if err != nil { 112 return nil, errdefs.ToGRPC(err) 113 } 114 115 resp.Image = imageToProto(&created) 116 117 if err := l.publisher.Publish(ctx, "/images/create", &eventstypes.ImageCreate{ 118 Name: resp.Image.Name, 119 Labels: resp.Image.Labels, 120 }); err != nil { 121 return nil, err 122 } 123 124 return &resp, nil 125 126 } 127 128 func (l *local) Update(ctx context.Context, req *imagesapi.UpdateImageRequest, _ ...grpc.CallOption) (*imagesapi.UpdateImageResponse, error) { 129 if req.Image.Name == "" { 130 return nil, status.Errorf(codes.InvalidArgument, "Image.Name required") 131 } 132 133 var ( 134 image = imageFromProto(&req.Image) 135 resp imagesapi.UpdateImageResponse 136 fieldpaths []string 137 ) 138 139 if req.UpdateMask != nil && len(req.UpdateMask.Paths) > 0 { 140 fieldpaths = append(fieldpaths, req.UpdateMask.Paths...) 141 } 142 143 updated, err := l.store.Update(ctx, image, fieldpaths...) 144 if err != nil { 145 return nil, errdefs.ToGRPC(err) 146 } 147 148 resp.Image = imageToProto(&updated) 149 150 if err := l.publisher.Publish(ctx, "/images/update", &eventstypes.ImageUpdate{ 151 Name: resp.Image.Name, 152 Labels: resp.Image.Labels, 153 }); err != nil { 154 return nil, err 155 } 156 157 return &resp, nil 158 } 159 160 func (l *local) Delete(ctx context.Context, req *imagesapi.DeleteImageRequest, _ ...grpc.CallOption) (*ptypes.Empty, error) { 161 log.G(ctx).WithField("name", req.Name).Debugf("delete image") 162 163 if err := l.store.Delete(ctx, req.Name); err != nil { 164 return nil, errdefs.ToGRPC(err) 165 } 166 167 if err := l.publisher.Publish(ctx, "/images/delete", &eventstypes.ImageDelete{ 168 Name: req.Name, 169 }); err != nil { 170 return nil, err 171 } 172 173 if req.Sync { 174 if _, err := l.gc.ScheduleAndWait(ctx); err != nil { 175 return nil, err 176 } 177 } 178 179 return &ptypes.Empty{}, nil 180 }