github.com/lalkh/containerd@v1.4.3/services/diff/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 diff 18 19 import ( 20 "context" 21 22 diffapi "github.com/containerd/containerd/api/services/diff/v1" 23 "github.com/containerd/containerd/api/types" 24 "github.com/containerd/containerd/diff" 25 "github.com/containerd/containerd/errdefs" 26 "github.com/containerd/containerd/mount" 27 "github.com/containerd/containerd/plugin" 28 "github.com/containerd/containerd/services" 29 ocispec "github.com/opencontainers/image-spec/specs-go/v1" 30 "github.com/pkg/errors" 31 "google.golang.org/grpc" 32 ) 33 34 type config struct { 35 // Order is the order of preference in which to try diff algorithms, the 36 // first differ which is supported is used. 37 // Note when multiple differs may be supported, this order will be 38 // respected for which is chosen. Each differ should return the same 39 // correct output, allowing any ordering to be used to prefer 40 // more optimimal implementations. 41 Order []string `toml:"default"` 42 } 43 44 type differ interface { 45 diff.Comparer 46 diff.Applier 47 } 48 49 func init() { 50 plugin.Register(&plugin.Registration{ 51 Type: plugin.ServicePlugin, 52 ID: services.DiffService, 53 Requires: []plugin.Type{ 54 plugin.DiffPlugin, 55 }, 56 Config: defaultDifferConfig, 57 InitFn: func(ic *plugin.InitContext) (interface{}, error) { 58 differs, err := ic.GetByType(plugin.DiffPlugin) 59 if err != nil { 60 return nil, err 61 } 62 63 orderedNames := ic.Config.(*config).Order 64 ordered := make([]differ, len(orderedNames)) 65 for i, n := range orderedNames { 66 differp, ok := differs[n] 67 if !ok { 68 return nil, errors.Errorf("needed differ not loaded: %s", n) 69 } 70 d, err := differp.Instance() 71 if err != nil { 72 return nil, errors.Wrapf(err, "could not load required differ due plugin init error: %s", n) 73 } 74 75 ordered[i], ok = d.(differ) 76 if !ok { 77 return nil, errors.Errorf("differ does not implement Comparer and Applier interface: %s", n) 78 } 79 } 80 81 return &local{ 82 differs: ordered, 83 }, nil 84 }, 85 }) 86 } 87 88 type local struct { 89 differs []differ 90 } 91 92 var _ diffapi.DiffClient = &local{} 93 94 func (l *local) Apply(ctx context.Context, er *diffapi.ApplyRequest, _ ...grpc.CallOption) (*diffapi.ApplyResponse, error) { 95 var ( 96 ocidesc ocispec.Descriptor 97 err error 98 desc = toDescriptor(er.Diff) 99 mounts = toMounts(er.Mounts) 100 ) 101 102 var opts []diff.ApplyOpt 103 if er.Payloads != nil { 104 opts = append(opts, diff.WithPayloads(er.Payloads)) 105 } 106 107 for _, differ := range l.differs { 108 ocidesc, err = differ.Apply(ctx, desc, mounts, opts...) 109 if !errdefs.IsNotImplemented(err) { 110 break 111 } 112 } 113 114 if err != nil { 115 return nil, errdefs.ToGRPC(err) 116 } 117 118 return &diffapi.ApplyResponse{ 119 Applied: fromDescriptor(ocidesc), 120 }, nil 121 122 } 123 124 func (l *local) Diff(ctx context.Context, dr *diffapi.DiffRequest, _ ...grpc.CallOption) (*diffapi.DiffResponse, error) { 125 var ( 126 ocidesc ocispec.Descriptor 127 err error 128 aMounts = toMounts(dr.Left) 129 bMounts = toMounts(dr.Right) 130 ) 131 132 var opts []diff.Opt 133 if dr.MediaType != "" { 134 opts = append(opts, diff.WithMediaType(dr.MediaType)) 135 } 136 if dr.Ref != "" { 137 opts = append(opts, diff.WithReference(dr.Ref)) 138 } 139 if dr.Labels != nil { 140 opts = append(opts, diff.WithLabels(dr.Labels)) 141 } 142 143 for _, d := range l.differs { 144 ocidesc, err = d.Compare(ctx, aMounts, bMounts, opts...) 145 if !errdefs.IsNotImplemented(err) { 146 break 147 } 148 } 149 if err != nil { 150 return nil, errdefs.ToGRPC(err) 151 } 152 153 return &diffapi.DiffResponse{ 154 Diff: fromDescriptor(ocidesc), 155 }, nil 156 } 157 158 func toMounts(apim []*types.Mount) []mount.Mount { 159 mounts := make([]mount.Mount, len(apim)) 160 for i, m := range apim { 161 mounts[i] = mount.Mount{ 162 Type: m.Type, 163 Source: m.Source, 164 Options: m.Options, 165 } 166 } 167 return mounts 168 } 169 170 func toDescriptor(d *types.Descriptor) ocispec.Descriptor { 171 return ocispec.Descriptor{ 172 MediaType: d.MediaType, 173 Digest: d.Digest, 174 Size: d.Size_, 175 Annotations: d.Annotations, 176 } 177 } 178 179 func fromDescriptor(d ocispec.Descriptor) *types.Descriptor { 180 return &types.Descriptor{ 181 MediaType: d.MediaType, 182 Digest: d.Digest, 183 Size_: d.Size, 184 Annotations: d.Annotations, 185 } 186 }