diff --git a/plugins/transfer/plugin.go b/plugins/transfer/plugin.go index e6da17d2242f..9ba0abd2435e 100644 --- a/plugins/transfer/plugin.go +++ b/plugins/transfer/plugin.go @@ -21,13 +21,14 @@ import ( "github.com/containerd/containerd" "github.com/containerd/containerd/diff" + "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/leases" + "github.com/containerd/containerd/log" "github.com/containerd/containerd/metadata" "github.com/containerd/containerd/pkg/transfer/local" "github.com/containerd/containerd/pkg/unpack" "github.com/containerd/containerd/platforms" "github.com/containerd/containerd/plugin" - "github.com/containerd/containerd/snapshots" // Load packages with type registrations _ "github.com/containerd/containerd/pkg/transfer/archive" @@ -43,7 +44,6 @@ func init() { Requires: []plugin.Type{ plugin.LeasePlugin, plugin.MetadataPlugin, - plugin.SnapshotPlugin, plugin.DiffPlugin, }, Config: defaultConfig(), @@ -59,35 +59,72 @@ func init() { return nil, err } - d, err := ic.Get(plugin.DiffPlugin) - if err != nil { - return nil, err - } - // Set configuration based on default or user input var lc local.TransferConfig - lc.MaxConcurrentDownloads = config.maxConcurrentDownloads - lc.MaxConcurrentUploadedLayers = config.maxConcurrentUploadedLayers - for _, uc := range config.unpackConfiguration { - p, err := platforms.Parse(uc.platform) + lc.MaxConcurrentDownloads = config.MaxConcurrentDownloads + lc.MaxConcurrentUploadedLayers = config.MaxConcurrentUploadedLayers + for _, uc := range config.UnpackConfiguration { + p, err := platforms.Parse(uc.Platform) if err != nil { - return nil, fmt.Errorf("%s: platform configuration %v invalid", plugin.TransferPlugin, uc.platform) + return nil, fmt.Errorf("%s: platform configuration %v invalid", plugin.TransferPlugin, uc.Platform) + } + + sn := ms.Snapshotter(uc.Snapshotter) + if sn == nil { + return nil, fmt.Errorf("snapshotter %q not found: %w", uc.Snapshotter, errdefs.ErrNotFound) } - s, err := ic.GetByID(plugin.SnapshotPlugin, uc.snapshotter) + diffPlugins, err := ic.GetByType(plugin.DiffPlugin) if err != nil { - return nil, err + return nil, fmt.Errorf("error loading diff plugins: %w", err) + } + var applier diff.Applier + target := platforms.OnlyStrict(p) + if uc.Differ != "" { + plugin, ok := diffPlugins[uc.Differ] + if !ok { + return nil, fmt.Errorf("diff plugin %q: %w", uc.Differ, errdefs.ErrNotFound) + } + inst, err := plugin.Instance() + if err != nil { + return nil, fmt.Errorf("failed to get instance for diff plugin %q: %w", uc.Differ, err) + } + applier = inst.(diff.Applier) + } else { + for name, plugin := range diffPlugins { + var matched bool + for _, p := range plugin.Meta.Platforms { + if target.Match(p) { + matched = true + } + } + if !matched { + continue + } + if applier != nil { + log.G(ic.Context).Warnf("multiple differs match for platform, set `differ` option to choose, skipping %q", name) + continue + } + inst, err := plugin.Instance() + if err != nil { + return nil, fmt.Errorf("failed to get instance for diff plugin %q: %w", name, err) + } + applier = inst.(diff.Applier) + } + } + if applier == nil { + return nil, fmt.Errorf("no matching diff plugins: %w", errdefs.ErrNotFound) } up := unpack.Platform{ - Platform: platforms.OnlyStrict(p), - SnapshotterKey: uc.snapshotter, - Snapshotter: s.(snapshots.Snapshotter), - Applier: d.(diff.Applier), + Platform: target, + SnapshotterKey: uc.Snapshotter, + Snapshotter: sn, + Applier: applier, } lc.UnpackPlatforms = append(lc.UnpackPlatforms, up) } - lc.RegistryConfigPath = config.registryConfigPath + lc.RegistryConfigPath = config.RegistryConfigPath return local.NewTransferService(l.(leases.Manager), ms.ContentStore(), metadata.NewImageStore(ms), &lc), nil }, @@ -95,32 +132,38 @@ func init() { } type transferConfig struct { - // maxConcurrentDownloads is the max concurrent content downloads for pull. - maxConcurrentDownloads int `toml:"max_concurrent_downloads"` + // MaxConcurrentDownloads is the max concurrent content downloads for pull. + MaxConcurrentDownloads int `toml:"max_concurrent_downloads"` - // maxConcurrentUploadedLayers is the max concurrent uploads for push - maxConcurrentUploadedLayers int `toml:"max_concurrent_uploaded_layers"` + // MaxConcurrentUploadedLayers is the max concurrent uploads for push + MaxConcurrentUploadedLayers int `toml:"max_concurrent_uploaded_layers"` - // unpackConfiguration is used to read config from toml - unpackConfiguration []unpackConfiguration `toml:"unpack_config"` + // UnpackConfiguration is used to read config from toml + UnpackConfiguration []unpackConfiguration `toml:"unpack_config"` - // registryConfigPath is a path to the root directory containing registry-specific configurations - registryConfigPath string `toml:"config_path"` + // RegistryConfigPath is a path to the root directory containing registry-specific configurations + RegistryConfigPath string `toml:"config_path"` } type unpackConfiguration struct { - platform string - snapshotter string + // Platform is the target unpack platform to match + Platform string `toml:"platform"` + + // Snapshotter is the snapshotter to use to unpack + Snapshotter string `toml:"snapshotter"` + + // Differ is the diff plugin to be used for apply + Differ string `toml:"differ"` } func defaultConfig() *transferConfig { return &transferConfig{ - maxConcurrentDownloads: 3, - maxConcurrentUploadedLayers: 3, - unpackConfiguration: []unpackConfiguration{ + MaxConcurrentDownloads: 3, + MaxConcurrentUploadedLayers: 3, + UnpackConfiguration: []unpackConfiguration{ { - platform: platforms.Format(platforms.DefaultSpec()), - snapshotter: containerd.DefaultSnapshotter, + Platform: platforms.Format(platforms.DefaultSpec()), + Snapshotter: containerd.DefaultSnapshotter, }, }, }