
Updates the differ service to support calling and configuring multiple differs. The differs are configured as an ordered list of differs which will each be attempting until a supported differ is called. Additionally a not supported error type was added to allow differs to be selective of whether the differ arguments are supported by the differ. This error type corresponds to the GRPC unimplemented error. Signed-off-by: Derek McGowan <derek@mcgstyle.net>
126 lines
2.9 KiB
Go
126 lines
2.9 KiB
Go
package diff
|
|
|
|
import (
|
|
diffapi "github.com/containerd/containerd/api/services/diff/v1"
|
|
"github.com/containerd/containerd/api/types"
|
|
"github.com/containerd/containerd/errdefs"
|
|
"github.com/containerd/containerd/mount"
|
|
"github.com/containerd/containerd/plugin"
|
|
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
|
"github.com/pkg/errors"
|
|
"golang.org/x/net/context"
|
|
"google.golang.org/grpc"
|
|
)
|
|
|
|
type config struct {
|
|
// Order is the order of preference in which to try diff algorithms, the
|
|
// first differ which is supported is used.
|
|
// Note when multiple differs may be supported, this order will be
|
|
// respected for which is choosen. Each differ should return the same
|
|
// correct output, allowing any ordering to be used to prefer
|
|
// more optimimal implementations.
|
|
Order []string `toml:"default,omitempty"`
|
|
}
|
|
|
|
func init() {
|
|
plugin.Register(&plugin.Registration{
|
|
Type: plugin.GRPCPlugin,
|
|
ID: "diff",
|
|
Requires: []plugin.PluginType{
|
|
plugin.DiffPlugin,
|
|
},
|
|
Config: &config{
|
|
Order: []string{"walking"},
|
|
},
|
|
Init: func(ic *plugin.InitContext) (interface{}, error) {
|
|
differs, err := ic.GetAll(plugin.DiffPlugin)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
orderedNames := ic.Config.(*config).Order
|
|
ordered := make([]plugin.Differ, len(orderedNames))
|
|
for i, n := range orderedNames {
|
|
differ, ok := differs[n]
|
|
if !ok {
|
|
return nil, errors.Errorf("needed differ not loaded: %s", n)
|
|
}
|
|
ordered[i] = differ.(plugin.Differ)
|
|
}
|
|
|
|
return &service{
|
|
differs: ordered,
|
|
}, nil
|
|
},
|
|
})
|
|
}
|
|
|
|
type service struct {
|
|
differs []plugin.Differ
|
|
}
|
|
|
|
func (s *service) Register(gs *grpc.Server) error {
|
|
diffapi.RegisterDiffServer(gs, s)
|
|
return nil
|
|
}
|
|
|
|
func (s *service) Apply(ctx context.Context, er *diffapi.ApplyRequest) (*diffapi.ApplyResponse, error) {
|
|
var (
|
|
ocidesc ocispec.Descriptor
|
|
err error
|
|
desc = toDescriptor(er.Diff)
|
|
mounts = toMounts(er.Mounts)
|
|
)
|
|
|
|
for _, differ := range s.differs {
|
|
ocidesc, err = differ.Apply(ctx, desc, mounts)
|
|
if !errdefs.IsNotSupported(err) {
|
|
break
|
|
}
|
|
}
|
|
|
|
if err != nil {
|
|
return nil, errdefs.ToGRPC(err)
|
|
}
|
|
|
|
return &diffapi.ApplyResponse{
|
|
Applied: fromDescriptor(ocidesc),
|
|
}, nil
|
|
|
|
}
|
|
|
|
func (s *service) Diff(ctx context.Context, dr *diffapi.DiffRequest) (*diffapi.DiffResponse, error) {
|
|
var (
|
|
ocidesc ocispec.Descriptor
|
|
err error
|
|
aMounts = toMounts(dr.Left)
|
|
bMounts = toMounts(dr.Right)
|
|
)
|
|
|
|
for _, differ := range s.differs {
|
|
ocidesc, err = differ.DiffMounts(ctx, aMounts, bMounts, dr.MediaType, dr.Ref)
|
|
if !errdefs.IsNotSupported(err) {
|
|
break
|
|
}
|
|
}
|
|
if err != nil {
|
|
return nil, errdefs.ToGRPC(err)
|
|
}
|
|
|
|
return &diffapi.DiffResponse{
|
|
Diff: fromDescriptor(ocidesc),
|
|
}, nil
|
|
}
|
|
|
|
func toMounts(apim []*types.Mount) []mount.Mount {
|
|
mounts := make([]mount.Mount, len(apim))
|
|
for i, m := range apim {
|
|
mounts[i] = mount.Mount{
|
|
Type: m.Type,
|
|
Source: m.Source,
|
|
Options: m.Options,
|
|
}
|
|
}
|
|
return mounts
|
|
}
|