Update client Image to have configurable platform
Separate Fetch and Pull commands in client to distinguish between platform specific and non-platform specific operations. `ctr images pull` with all platforms will now unpack all platforms. `ctr content fetch` now supports platform flags. Signed-off-by: Derek McGowan <derek@mcgstyle.net>
This commit is contained in:
100
client.go
100
client.go
@@ -45,6 +45,7 @@ import (
|
||||
"github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/namespaces"
|
||||
"github.com/containerd/containerd/pkg/dialer"
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/containerd/containerd/plugin"
|
||||
"github.com/containerd/containerd/remotes"
|
||||
"github.com/containerd/containerd/remotes/docker"
|
||||
@@ -284,7 +285,31 @@ func defaultRemoteContext() *RemoteContext {
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch downloads the provided content into containerd's content store
|
||||
// and returns a non-platform specific image reference
|
||||
func (c *Client) Fetch(ctx context.Context, ref string, opts ...RemoteOpt) (images.Image, error) {
|
||||
fetchCtx := defaultRemoteContext()
|
||||
for _, o := range opts {
|
||||
if err := o(c, fetchCtx); err != nil {
|
||||
return images.Image{}, err
|
||||
}
|
||||
}
|
||||
|
||||
if fetchCtx.Unpack {
|
||||
return images.Image{}, errors.New("unpack on fetch not supported, try pull")
|
||||
}
|
||||
|
||||
ctx, done, err := c.WithLease(ctx)
|
||||
if err != nil {
|
||||
return images.Image{}, err
|
||||
}
|
||||
defer done(ctx)
|
||||
|
||||
return c.fetch(ctx, fetchCtx, ref)
|
||||
}
|
||||
|
||||
// Pull downloads the provided content into containerd's content store
|
||||
// and returns a platform specific image object
|
||||
func (c *Client) Pull(ctx context.Context, ref string, opts ...RemoteOpt) (Image, error) {
|
||||
pullCtx := defaultRemoteContext()
|
||||
for _, o := range opts {
|
||||
@@ -292,7 +317,12 @@ func (c *Client) Pull(ctx context.Context, ref string, opts ...RemoteOpt) (Image
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
store := c.ContentStore()
|
||||
|
||||
if len(pullCtx.Platforms) > 1 {
|
||||
return nil, errors.New("cannot pull multiplatform image locally, try Fetch")
|
||||
} else if len(pullCtx.Platforms) == 0 {
|
||||
pullCtx.Platforms = []string{platforms.Default()}
|
||||
}
|
||||
|
||||
ctx, done, err := c.WithLease(ctx)
|
||||
if err != nil {
|
||||
@@ -300,82 +330,92 @@ func (c *Client) Pull(ctx context.Context, ref string, opts ...RemoteOpt) (Image
|
||||
}
|
||||
defer done(ctx)
|
||||
|
||||
name, desc, err := pullCtx.Resolver.Resolve(ctx, ref)
|
||||
img, err := c.fetch(ctx, pullCtx, ref)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to resolve reference %q", ref)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fetcher, err := pullCtx.Resolver.Fetcher(ctx, name)
|
||||
i := NewImageWithPlatform(c, img, pullCtx.Platforms[0])
|
||||
|
||||
if pullCtx.Unpack {
|
||||
if err := i.Unpack(ctx, pullCtx.Snapshotter); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to unpack image on snapshotter %s", pullCtx.Snapshotter)
|
||||
}
|
||||
}
|
||||
|
||||
return i, nil
|
||||
}
|
||||
|
||||
func (c *Client) fetch(ctx context.Context, rCtx *RemoteContext, ref string) (images.Image, error) {
|
||||
store := c.ContentStore()
|
||||
name, desc, err := rCtx.Resolver.Resolve(ctx, ref)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to get fetcher for %q", name)
|
||||
return images.Image{}, errors.Wrapf(err, "failed to resolve reference %q", ref)
|
||||
}
|
||||
|
||||
fetcher, err := rCtx.Resolver.Fetcher(ctx, name)
|
||||
if err != nil {
|
||||
return images.Image{}, errors.Wrapf(err, "failed to get fetcher for %q", name)
|
||||
}
|
||||
|
||||
var (
|
||||
schema1Converter *schema1.Converter
|
||||
handler images.Handler
|
||||
)
|
||||
if desc.MediaType == images.MediaTypeDockerSchema1Manifest && pullCtx.ConvertSchema1 {
|
||||
if desc.MediaType == images.MediaTypeDockerSchema1Manifest && rCtx.ConvertSchema1 {
|
||||
schema1Converter = schema1.NewConverter(store, fetcher)
|
||||
handler = images.Handlers(append(pullCtx.BaseHandlers, schema1Converter)...)
|
||||
handler = images.Handlers(append(rCtx.BaseHandlers, schema1Converter)...)
|
||||
} else {
|
||||
// Get all the children for a descriptor
|
||||
childrenHandler := images.ChildrenHandler(store)
|
||||
// Set any children labels for that content
|
||||
childrenHandler = images.SetChildrenLabels(store, childrenHandler)
|
||||
// Filter children by platforms
|
||||
childrenHandler = images.FilterPlatforms(childrenHandler, pullCtx.Platforms...)
|
||||
childrenHandler = images.FilterPlatforms(childrenHandler, rCtx.Platforms...)
|
||||
|
||||
handler = images.Handlers(append(pullCtx.BaseHandlers,
|
||||
handler = images.Handlers(append(rCtx.BaseHandlers,
|
||||
remotes.FetchHandler(store, fetcher),
|
||||
childrenHandler,
|
||||
)...)
|
||||
}
|
||||
|
||||
if err := images.Dispatch(ctx, handler, desc); err != nil {
|
||||
return nil, err
|
||||
return images.Image{}, err
|
||||
}
|
||||
if schema1Converter != nil {
|
||||
desc, err = schema1Converter.Convert(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return images.Image{}, err
|
||||
}
|
||||
}
|
||||
|
||||
img := &image{
|
||||
client: c,
|
||||
i: images.Image{
|
||||
Name: name,
|
||||
Target: desc,
|
||||
Labels: pullCtx.Labels,
|
||||
},
|
||||
}
|
||||
|
||||
if pullCtx.Unpack {
|
||||
if err := img.Unpack(ctx, pullCtx.Snapshotter); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to unpack image on snapshotter %s", pullCtx.Snapshotter)
|
||||
}
|
||||
img := images.Image{
|
||||
Name: name,
|
||||
Target: desc,
|
||||
Labels: rCtx.Labels,
|
||||
}
|
||||
|
||||
is := c.ImageService()
|
||||
for {
|
||||
if created, err := is.Create(ctx, img.i); err != nil {
|
||||
if created, err := is.Create(ctx, img); err != nil {
|
||||
if !errdefs.IsAlreadyExists(err) {
|
||||
return nil, err
|
||||
return images.Image{}, err
|
||||
}
|
||||
|
||||
updated, err := is.Update(ctx, img.i)
|
||||
updated, err := is.Update(ctx, img)
|
||||
if err != nil {
|
||||
// if image was removed, try create again
|
||||
if errdefs.IsNotFound(err) {
|
||||
continue
|
||||
}
|
||||
return nil, err
|
||||
return images.Image{}, err
|
||||
}
|
||||
|
||||
img.i = updated
|
||||
img = updated
|
||||
} else {
|
||||
img.i = created
|
||||
img = created
|
||||
}
|
||||
|
||||
return img, nil
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user