From 47305392c6434ae428342ada6f3088828ac17f7f Mon Sep 17 00:00:00 2001 From: Tony Fang Date: Tue, 7 Feb 2023 20:58:03 +0000 Subject: [PATCH] Add configuration options to local transfer service Signed-off-by: Tony Fang --- cmd/ctr/commands/images/import.go | 33 +++++++++- cmd/ctr/commands/images/pull.go | 8 ++- cmd/ctr/commands/images/push.go | 3 +- cmd/ctr/commands/resolver.go | 10 +-- pkg/transfer/image/imagestore.go | 28 +++----- pkg/transfer/local/import.go | 41 ++++++++++-- pkg/transfer/local/pull.go | 61 ++++++++++++----- pkg/transfer/local/push.go | 3 +- pkg/transfer/local/transfer.go | 69 +++++++++++++++----- pkg/transfer/proxy/transfer.go | 5 +- pkg/transfer/{image => registry}/registry.go | 2 +- pkg/transfer/transfer.go | 15 +++-- plugins/transfer/plugin.go | 11 ++-- remotes/resolver.go | 2 +- 14 files changed, 209 insertions(+), 82 deletions(-) rename pkg/transfer/{image => registry}/registry.go (99%) diff --git a/cmd/ctr/commands/images/import.go b/cmd/ctr/commands/images/import.go index f05bd4da8..5d663df3b 100644 --- a/cmd/ctr/commands/images/import.go +++ b/cmd/ctr/commands/images/import.go @@ -22,6 +22,9 @@ import ( "os" "time" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/urfave/cli" + "github.com/containerd/containerd" "github.com/containerd/containerd/cmd/ctr/commands" "github.com/containerd/containerd/images/archive" @@ -30,7 +33,6 @@ import ( tarchive "github.com/containerd/containerd/pkg/transfer/archive" "github.com/containerd/containerd/pkg/transfer/image" "github.com/containerd/containerd/platforms" - "github.com/urfave/cli" ) var importCommand = cli.Command{ @@ -127,9 +129,34 @@ If foobar.tar contains an OCI ref named "latest" and anonymous ref "sha256:deadb opts = append(opts, image.WithNamedPrefix(prefix, overwrite)) } - // TODO: Add platform options + var platSpec ocispec.Platform + //Only when all-platforms not specified, we will check platform value + //Implicitly if the platforms is empty, it means all-platforms + if !context.Bool("all-platforms") { + //If platform specified, use that one, if not use default + if platform := context.String("platform"); platform != "" { + platSpec, err = platforms.Parse(platform) + if err != nil { + return err + } + } else { + platSpec = platforms.DefaultSpec() + } + opts = append(opts, image.WithPlatforms(platSpec)) + } - // TODO: Add unpack options + if !context.Bool("no-unpack") { + snapshotter := context.String("snapshotter") + //If OS field is not empty, it means platSpec was updated in the above block + //i.e all-platforms was not specified + if platSpec.OS != "" { + opts = append(opts, image.WithUnpack(platSpec, snapshotter)) + } else { + //empty spec means all platforms + var emptySpec ocispec.Platform + opts = append(opts, image.WithUnpack(emptySpec, snapshotter)) + } + } is := image.NewStore(context.String("index-name"), opts...) diff --git a/cmd/ctr/commands/images/pull.go b/cmd/ctr/commands/images/pull.go index a6612148c..d4f245729 100644 --- a/cmd/ctr/commands/images/pull.go +++ b/cmd/ctr/commands/images/pull.go @@ -32,6 +32,7 @@ import ( "github.com/containerd/containerd/pkg/progress" "github.com/containerd/containerd/pkg/transfer" "github.com/containerd/containerd/pkg/transfer/image" + "github.com/containerd/containerd/pkg/transfer/registry" "github.com/containerd/containerd/platforms" "github.com/opencontainers/image-spec/identity" ocispec "github.com/opencontainers/image-spec/specs-go/v1" @@ -112,6 +113,11 @@ command. As part of this process, we do the following: p = append(p, platforms.DefaultSpec()) } sopts = append(sopts, image.WithPlatforms(p...)) + + //set unpack configuration + for _, platform := range p { + sopts = append(sopts, image.WithUnpack(platform, context.String("snapshotter"))) + } } // TODO: Support unpack for all platforms..? // Pass in a *? @@ -125,7 +131,7 @@ command. As part of this process, we do the following: sopts = append(sopts, image.WithAllMetadata) } - reg := image.NewOCIRegistry(ref, nil, ch) + reg := registry.NewOCIRegistry(ref, nil, ch) is := image.NewStore(ref, sopts...) pf, done := ProgressHandler(ctx, os.Stdout) diff --git a/cmd/ctr/commands/images/push.go b/cmd/ctr/commands/images/push.go index 760b7bf81..a0d42bbea 100644 --- a/cmd/ctr/commands/images/push.go +++ b/cmd/ctr/commands/images/push.go @@ -34,6 +34,7 @@ import ( "github.com/containerd/containerd/pkg/progress" "github.com/containerd/containerd/pkg/transfer" "github.com/containerd/containerd/pkg/transfer/image" + "github.com/containerd/containerd/pkg/transfer/registry" "github.com/containerd/containerd/platforms" "github.com/containerd/containerd/remotes" "github.com/containerd/containerd/remotes/docker" @@ -103,7 +104,7 @@ var pushCommand = cli.Command{ if local == "" { local = ref } - reg := image.NewOCIRegistry(ref, nil, ch) + reg := registry.NewOCIRegistry(ref, nil, ch) is := image.NewStore(local) pf, done := ProgressHandler(ctx, os.Stdout) diff --git a/cmd/ctr/commands/resolver.go b/cmd/ctr/commands/resolver.go index 4b2aa4944..2c12acff5 100644 --- a/cmd/ctr/commands/resolver.go +++ b/cmd/ctr/commands/resolver.go @@ -32,7 +32,7 @@ import ( "github.com/containerd/console" "github.com/containerd/containerd/log" - "github.com/containerd/containerd/pkg/transfer/image" + "github.com/containerd/containerd/pkg/transfer/registry" "github.com/containerd/containerd/remotes" "github.com/containerd/containerd/remotes/docker" "github.com/containerd/containerd/remotes/docker/config" @@ -218,7 +218,7 @@ type staticCredentials struct { } // NewStaticCredentials gets credentials from passing in cli context -func NewStaticCredentials(ctx gocontext.Context, clicontext *cli.Context, ref string) (image.CredentialHelper, error) { +func NewStaticCredentials(ctx gocontext.Context, clicontext *cli.Context, ref string) (registry.CredentialHelper, error) { username := clicontext.String("user") var secret string if i := strings.IndexByte(username, ':'); i > 0 { @@ -248,12 +248,12 @@ func NewStaticCredentials(ctx gocontext.Context, clicontext *cli.Context, ref st }, nil } -func (sc *staticCredentials) GetCredentials(ctx gocontext.Context, ref, host string) (image.Credentials, error) { +func (sc *staticCredentials) GetCredentials(ctx gocontext.Context, ref, host string) (registry.Credentials, error) { if ref == sc.ref { - return image.Credentials{ + return registry.Credentials{ Username: sc.username, Secret: sc.secret, }, nil } - return image.Credentials{}, nil + return registry.Credentials{}, nil } diff --git a/pkg/transfer/image/imagestore.go b/pkg/transfer/image/imagestore.go index 01170df49..547228a15 100644 --- a/pkg/transfer/image/imagestore.go +++ b/pkg/transfer/image/imagestore.go @@ -27,8 +27,8 @@ import ( "github.com/containerd/containerd/images" "github.com/containerd/containerd/images/archive" "github.com/containerd/containerd/pkg/streaming" + "github.com/containerd/containerd/pkg/transfer" "github.com/containerd/containerd/pkg/transfer/plugins" - "github.com/containerd/containerd/pkg/unpack" "github.com/containerd/containerd/platforms" "github.com/containerd/containerd/remotes" "github.com/containerd/typeurl/v2" @@ -51,7 +51,7 @@ type Store struct { // extraReferences are used to store or lookup multiple references extraReferences []Reference - unpacks []UnpackConfiguration + unpacks []transfer.UnpackConfiguration } // Reference is used to create or find a reference for an image @@ -84,14 +84,6 @@ type Reference struct { SkipNamedDigest bool } -// UnpackConfiguration specifies the platform and snapshotter to use for resolving -// the unpack Platform, if snapshotter is not specified the platform default will -// be used. -type UnpackConfiguration struct { - Platform ocispec.Platform - Snapshotter string -} - // StoreOpt defines options when configuring an image store source or destination type StoreOpt func(*Store) @@ -171,7 +163,7 @@ func WithExtraReference(name string) StoreOpt { // WithUnpack specifies a platform to unpack for and an optional snapshotter to use func WithUnpack(p ocispec.Platform, snapshotter string) StoreOpt { return func(s *Store) { - s.unpacks = append(s.unpacks, UnpackConfiguration{ + s.unpacks = append(s.unpacks, transfer.UnpackConfiguration{ Platform: p, Snapshotter: snapshotter, }) @@ -333,11 +325,11 @@ func (is *Store) Get(ctx context.Context, store images.Store) (images.Image, err return store.Get(ctx, is.imageName) } -func (is *Store) UnpackPlatforms() []unpack.Platform { - unpacks := make([]unpack.Platform, len(is.unpacks)) +func (is *Store) UnpackPlatforms() []transfer.UnpackConfiguration { + unpacks := make([]transfer.UnpackConfiguration, len(is.unpacks)) for i, uc := range is.unpacks { - unpacks[i].SnapshotterKey = uc.Snapshotter - unpacks[i].Platform = platforms.Only(uc.Platform) + unpacks[i].Snapshotter = uc.Snapshotter + unpacks[i].Platform = uc.Platform } return unpacks } @@ -424,7 +416,7 @@ func referencesFromProto(references []*transfertypes.ImageReference) []Reference } return or } -func unpackToProto(uc []UnpackConfiguration) []*transfertypes.UnpackConfiguration { +func unpackToProto(uc []transfer.UnpackConfiguration) []*transfertypes.UnpackConfiguration { auc := make([]*transfertypes.UnpackConfiguration, len(uc)) for i := range uc { p := types.Platform{ @@ -440,8 +432,8 @@ func unpackToProto(uc []UnpackConfiguration) []*transfertypes.UnpackConfiguratio return auc } -func unpackFromProto(auc []*transfertypes.UnpackConfiguration) []UnpackConfiguration { - uc := make([]UnpackConfiguration, len(auc)) +func unpackFromProto(auc []*transfertypes.UnpackConfiguration) []transfer.UnpackConfiguration { + uc := make([]transfer.UnpackConfiguration, len(auc)) for i := range auc { uc[i].Snapshotter = auc[i].Snapshotter if auc[i].Platform != nil { diff --git a/pkg/transfer/local/import.go b/pkg/transfer/local/import.go index 5da67ff92..9b7dcd9ea 100644 --- a/pkg/transfer/local/import.go +++ b/pkg/transfer/local/import.go @@ -19,13 +19,16 @@ package local import ( "context" "encoding/json" + "fmt" + + ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/containerd/containerd/content" "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/images" "github.com/containerd/containerd/log" "github.com/containerd/containerd/pkg/transfer" - ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/containerd/containerd/pkg/unpack" ) func (ts *localTransferService) importStream(ctx context.Context, i transfer.ImageImporter, is transfer.ImageStorer, tops *transfer.Config) error { @@ -46,12 +49,16 @@ func (ts *localTransferService) importStream(ctx context.Context, i transfer.Ima return err } - var descriptors []ocispec.Descriptor + var ( + descriptors []ocispec.Descriptor + handler images.Handler + unpacker *unpack.Unpacker + ) // If save index, add index descriptors = append(descriptors, index) - var handler images.HandlerFunc = func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) { + var handlerFunc images.HandlerFunc = func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) { // Only save images at top level if desc.Digest != index.Digest { return images.Children(ctx, ts.content, desc) @@ -76,7 +83,33 @@ func (ts *localTransferService) importStream(ctx context.Context, i transfer.Ima } if f, ok := is.(transfer.ImageFilterer); ok { - handler = f.ImageFilter(handler, ts.content) + handlerFunc = f.ImageFilter(handlerFunc, ts.content) + } + + handler = images.Handlers(handlerFunc) + + // First find suitable platforms to unpack into + //If image storer is also an unpacker type, i.e implemented UnpackPlatforms() func + if iu, ok := is.(transfer.ImageUnpacker); ok { + unpacks := iu.UnpackPlatforms() + if len(unpacks) > 0 { + uopts := []unpack.UnpackerOpt{} + for _, u := range unpacks { + matched, mu := getSupportedPlatform(u, ts.config.UnpackPlatforms) + if matched { + uopts = append(uopts, unpack.WithUnpackPlatform(mu)) + } + } + + if ts.config.DuplicationSuppressor != nil { + uopts = append(uopts, unpack.WithDuplicationSuppressor(ts.config.DuplicationSuppressor)) + } + unpacker, err = unpack.NewUnpacker(ctx, ts.content, uopts...) + if err != nil { + return fmt.Errorf("unable to initialize unpacker: %w", err) + } + handler = unpacker.Unpack(handler) + } } if err := images.WalkNotEmpty(ctx, handler, index); err != nil { diff --git a/pkg/transfer/local/pull.go b/pkg/transfer/local/pull.go index 9a5fb623e..b6891f90f 100644 --- a/pkg/transfer/local/pull.go +++ b/pkg/transfer/local/pull.go @@ -20,6 +20,7 @@ import ( "context" "fmt" + "github.com/containerd/containerd" "github.com/containerd/containerd/content" "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/images" @@ -73,6 +74,8 @@ func (ts *localTransferService) pull(ctx context.Context, ir transfer.ImageFetch var ( handler images.Handler + baseHandlers []images.Handler + unpacker *unpack.Unpacker // has a config media type bug (distribution#1622) @@ -97,12 +100,6 @@ func (ts *localTransferService) pull(ctx context.Context, ir transfer.ImageFetch childrenHandler = f.ImageFilter(childrenHandler, store) } - // Sort and limit manifests if a finite number is needed - //if limit > 0 { - // childrenHandler = images.LimitManifests(childrenHandler, rCtx.PlatformMatcher, limit) - //} - //SetChildrenMappedLabels(manager content.Manager, f HandlerFunc, labelMap func(ocispec.Descriptor) []string) HandlerFunc { - checkNeedsFix := images.HandlerFunc( func(_ context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) { // set to true if there is application/octet-stream media type @@ -119,8 +116,12 @@ func (ts *localTransferService) pull(ctx context.Context, ir transfer.ImageFetch return err } - // TODO: Allow initialization from configuration - baseHandlers := []images.Handler{} + //Set up baseHandlers from service configuration if present or create a new one + if ts.config.BaseHandlers != nil { + baseHandlers = ts.config.BaseHandlers + } else { + baseHandlers = []images.Handler{} + } if tops.Progress != nil { baseHandlers = append(baseHandlers, images.HandlerFunc( @@ -149,22 +150,28 @@ func (ts *localTransferService) pull(ctx context.Context, ir transfer.ImageFetch appendDistSrcLabelHandler, )...) - // TODO: Should available platforms be a configuration of the service? // First find suitable platforms to unpack into - //if unpacker, ok := is. + //If image storer is also an unpacker type, i.e implemented UnpackPlatforms() func if iu, ok := is.(transfer.ImageUnpacker); ok { unpacks := iu.UnpackPlatforms() if len(unpacks) > 0 { uopts := []unpack.UnpackerOpt{} + //Only unpack if requested unpackconfig matches default/supported unpackconfigs for _, u := range unpacks { - uopts = append(uopts, unpack.WithUnpackPlatform(u)) + matched, mu := getSupportedPlatform(u, ts.config.UnpackPlatforms) + if matched { + uopts = append(uopts, unpack.WithUnpackPlatform(mu)) + } } - if ts.limiter != nil { - uopts = append(uopts, unpack.WithLimiter(ts.limiter)) + + if ts.limiterD != nil { + uopts = append(uopts, unpack.WithLimiter(ts.limiterD)) } - //if uconfig.DuplicationSuppressor != nil { - // uopts = append(uopts, unpack.WithDuplicationSuppressor(uconfig.DuplicationSuppressor)) - //} + + if ts.config.DuplicationSuppressor != nil { + uopts = append(uopts, unpack.WithDuplicationSuppressor(ts.config.DuplicationSuppressor)) + } + unpacker, err = unpack.NewUnpacker(ctx, ts.content, uopts...) if err != nil { return fmt.Errorf("unable to initialize unpacker: %w", err) @@ -173,7 +180,7 @@ func (ts *localTransferService) pull(ctx context.Context, ir transfer.ImageFetch } } - if err := images.Dispatch(ctx, handler, ts.limiter, desc); err != nil { + if err := images.Dispatch(ctx, handler, ts.limiterD, desc); err != nil { if unpacker != nil { // wait for unpacker to cleanup unpacker.Wait() @@ -241,3 +248,23 @@ func fetchHandler(ingester content.Ingester, fetcher remotes.Fetcher, pt *Progre } } } + +// getSupportedPlatform returns a matched platform comparing input UnpackConfiguration to the supported platform/snapshotter combinations +// If input platform didn't specify snapshotter, default will be used if there is a match on platform. +func getSupportedPlatform(uc transfer.UnpackConfiguration, supportedPlatforms []unpack.Platform) (bool, unpack.Platform) { + var u unpack.Platform + for _, sp := range supportedPlatforms { + //If both platform and snapshotter match, return the supportPlatform + //If platform matched and SnapshotterKey is empty, we assume client didn't pass SnapshotterKey + //use default Snapshotter + if sp.Platform.Match(uc.Platform) { + //assuming sp.SnapshotterKey is not empty + if uc.Snapshotter == sp.SnapshotterKey { + return true, sp + } else if uc.Snapshotter == "" && sp.SnapshotterKey == containerd.DefaultSnapshotter { + return true, sp + } + } + } + return false, u +} diff --git a/pkg/transfer/local/push.go b/pkg/transfer/local/push.go index 6e4ca4e8a..cd635203f 100644 --- a/pkg/transfer/local/push.go +++ b/pkg/transfer/local/push.go @@ -105,8 +105,7 @@ func (ts *localTransferService) push(ctx context.Context, ig transfer.ImageGette wrapper = pushCtx.HandlerWrapper } */ - - if err := remotes.PushContent(ctx, pusher, img.Target, ts.content, ts.limiter, matcher, wrapper); err != nil { + if err := remotes.PushContent(ctx, pusher, img.Target, ts.content, ts.limiterU, matcher, wrapper); err != nil { return err } if tops.Progress != nil { diff --git a/pkg/transfer/local/transfer.go b/pkg/transfer/local/transfer.go index a014d7d3f..2148ecb97 100644 --- a/pkg/transfer/local/transfer.go +++ b/pkg/transfer/local/transfer.go @@ -22,11 +22,15 @@ import ( "io" "time" + "github.com/containerd/containerd" "github.com/containerd/containerd/content" "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/images" "github.com/containerd/containerd/leases" + "github.com/containerd/containerd/pkg/kmutex" "github.com/containerd/containerd/pkg/transfer" + "github.com/containerd/containerd/pkg/unpack" + "github.com/containerd/containerd/platforms" "github.com/containerd/typeurl/v2" "golang.org/x/sync/semaphore" ) @@ -35,25 +39,21 @@ type localTransferService struct { leases leases.Manager content content.Store images images.Store - - // semaphore.NewWeighted(int64(rCtx.MaxConcurrentDownloads)) - limiter *semaphore.Weighted - - // TODO: Duplication suppressor - - // Configuration - // - Max downloads - // - Max uploads - - // Supported platforms - // - Platform -> snapshotter defaults? + //limiter for upload + limiterU *semaphore.Weighted + //limiter for download operation + limiterD *semaphore.Weighted + config TransferConfig } -func NewTransferService(lm leases.Manager, cs content.Store, is images.Store) transfer.Transferrer { +func NewTransferService(lm leases.Manager, cs content.Store, is images.Store, tc *TransferConfig) transfer.Transferrer { return &localTransferService{ - leases: lm, - content: cs, - images: is, + leases: lm, + content: cs, + images: is, + limiterU: semaphore.NewWeighted(int64(tc.MaxConcurrentUploadedLayers)), + limiterD: semaphore.NewWeighted(int64(tc.MaxConcurrentDownloads)), + config: *tc, } } @@ -150,3 +150,40 @@ func (ts *localTransferService) withLease(ctx context.Context, opts ...leases.Op return ls.Delete(ctx, l) }, nil } + +type TransferConfig struct { + // 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"` + + // DuplicationSuppressor is used to make sure that there is only one + // in-flight fetch request or unpack handler for a given descriptor's + // digest or chain ID. + DuplicationSuppressor kmutex.KeyedLocker + + // BaseHandlers are a set of handlers which get are called on dispatch. + // These handlers always get called before any operation specific + // handlers. + BaseHandlers []images.Handler + + //UnpackPlatforms are used to specify supported combination of platforms and snapshotters + UnpackPlatforms []unpack.Platform `toml:"unpack_platforms"` + + // RegistryConfigPath is a path to the root directory containing registry-specific configurations + RegistryConfigPath string `toml:"config_path"` +} + +func DefaultConfig() *TransferConfig { + return &TransferConfig{ + MaxConcurrentDownloads: 3, + MaxConcurrentUploadedLayers: 3, + UnpackPlatforms: []unpack.Platform{ + { + Platform: platforms.Only(platforms.DefaultSpec()), + SnapshotterKey: containerd.DefaultSnapshotter, + }, + }, + } +} diff --git a/pkg/transfer/proxy/transfer.go b/pkg/transfer/proxy/transfer.go index e79e60558..50dba0b37 100644 --- a/pkg/transfer/proxy/transfer.go +++ b/pkg/transfer/proxy/transfer.go @@ -21,6 +21,8 @@ import ( "errors" "io" + "google.golang.org/protobuf/types/known/anypb" + transferapi "github.com/containerd/containerd/api/services/transfer/v1" transfertypes "github.com/containerd/containerd/api/types/transfer" "github.com/containerd/containerd/log" @@ -28,7 +30,6 @@ import ( "github.com/containerd/containerd/pkg/transfer" tstreaming "github.com/containerd/containerd/pkg/transfer/streaming" "github.com/containerd/typeurl/v2" - "google.golang.org/protobuf/types/known/anypb" ) type proxyTransferrer struct { @@ -36,7 +37,7 @@ type proxyTransferrer struct { streamCreator streaming.StreamCreator } -// NewTransferrer returns a new transferr which communicates over a GRPC +// NewTransferrer returns a new transferrer which communicates over a GRPC // connection using the containerd transfer API func NewTransferrer(client transferapi.TransferClient, sc streaming.StreamCreator) transfer.Transferrer { return &proxyTransferrer{ diff --git a/pkg/transfer/image/registry.go b/pkg/transfer/registry/registry.go similarity index 99% rename from pkg/transfer/image/registry.go rename to pkg/transfer/registry/registry.go index 6f44c7002..d11af3c92 100644 --- a/pkg/transfer/image/registry.go +++ b/pkg/transfer/registry/registry.go @@ -14,7 +14,7 @@ limitations under the License. */ -package image +package registry import ( "context" diff --git a/pkg/transfer/transfer.go b/pkg/transfer/transfer.go index 9bb22d30a..a9c4fcd73 100644 --- a/pkg/transfer/transfer.go +++ b/pkg/transfer/transfer.go @@ -20,10 +20,10 @@ import ( "context" "io" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/containerd/containerd/content" "github.com/containerd/containerd/images" - "github.com/containerd/containerd/pkg/unpack" - ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) type Transferrer interface { @@ -86,8 +86,15 @@ type ImageExportStreamer interface { } type ImageUnpacker interface { - // TODO: consider using unpack options - UnpackPlatforms() []unpack.Platform + UnpackPlatforms() []UnpackConfiguration +} + +// UnpackConfiguration specifies the platform and snapshotter to use for resolving +// the unpack Platform, if snapshotter is not specified the platform default will +// be used. +type UnpackConfiguration struct { + Platform ocispec.Platform + Snapshotter string } type ProgressFunc func(Progress) diff --git a/plugins/transfer/plugin.go b/plugins/transfer/plugin.go index 439978ac5..72d0ece10 100644 --- a/plugins/transfer/plugin.go +++ b/plugins/transfer/plugin.go @@ -27,6 +27,7 @@ import ( _ "github.com/containerd/containerd/pkg/transfer/image" ) +// Register local transfer service plugin func init() { plugin.Register(&plugin.Registration{ Type: plugin.TransferPlugin, @@ -35,8 +36,9 @@ func init() { plugin.LeasePlugin, plugin.MetadataPlugin, }, - Config: &transferConfig{}, + Config: local.DefaultConfig(), InitFn: func(ic *plugin.InitContext) (interface{}, error) { + config := ic.Config.(*local.TransferConfig) m, err := ic.Get(plugin.MetadataPlugin) if err != nil { return nil, err @@ -47,12 +49,7 @@ func init() { return nil, err } - return local.NewTransferService(l.(leases.Manager), ms.ContentStore(), metadata.NewImageStore(ms)), nil + return local.NewTransferService(l.(leases.Manager), ms.ContentStore(), metadata.NewImageStore(ms), config), nil }, }) } - -type transferConfig struct { - // Max concurrent downloads - // Snapshotter platforms -} diff --git a/remotes/resolver.go b/remotes/resolver.go index 702d220f1..f200c84bc 100644 --- a/remotes/resolver.go +++ b/remotes/resolver.go @@ -34,7 +34,7 @@ type Resolver interface { // reference a specific host or be matched against a specific handler. // // The returned name should be used to identify the referenced entity. - // Dependending on the remote namespace, this may be immutable or mutable. + // Depending on the remote namespace, this may be immutable or mutable. // While the name may differ from ref, it should itself be a valid ref. // // If the resolution fails, an error will be returned.