5a3151eefc
With this PR, we introduce the concept of image handlers. They support walking a tree of image resource descriptors for doing various tasks related to processing them. Handlers can be dispatched sequentially or in parallel and can be stacked for various effects. The main functionality we introduce here is parameterized fetch without coupling format resolution to the process itself. Two important handlers, `remotes.FetchHandler` and `image.ChildrenHandler` can be composed to implement recursive fetch with full status reporting. The approach can also be modified to filter based on platform or other constraints, unlocking a lot of possibilities. This also includes some light refactoring in the fetch command, in preparation for submission of end to end pull. Signed-off-by: Stephen J Day <stephen.day@docker.com>
66 lines
2.3 KiB
Go
66 lines
2.3 KiB
Go
package remotes
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"github.com/Sirupsen/logrus"
|
|
"github.com/docker/containerd/content"
|
|
"github.com/docker/containerd/image"
|
|
"github.com/docker/containerd/log"
|
|
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
|
)
|
|
|
|
// MakeRef returns a unique reference for the descriptor. This reference can be
|
|
// used to lookup ongoing processes related to the descriptor. This function
|
|
// may look to the context to namespace the reference appropriately.
|
|
func MakeRefKey(ctx context.Context, desc ocispec.Descriptor) string {
|
|
// TODO(stevvooe): Need better remote key selection here. Should be a
|
|
// product of the context, which may include information about the ongoing
|
|
// fetch process.
|
|
switch desc.MediaType {
|
|
case image.MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest,
|
|
image.MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex:
|
|
return "manifest-" + desc.Digest.String()
|
|
case image.MediaTypeDockerSchema2Layer, image.MediaTypeDockerSchema2LayerGzip:
|
|
return "layer-" + desc.Digest.String()
|
|
case "application/vnd.docker.container.image.v1+json":
|
|
return "config-" + desc.Digest.String()
|
|
default:
|
|
log.G(ctx).Warnf("reference for unknown type: %s", desc.MediaType)
|
|
return "unknown-" + desc.Digest.String()
|
|
}
|
|
}
|
|
|
|
// FetchHandler returns a handler that will fetch all content into the ingester
|
|
// discovered in a call to Dispatch. Use with ChildrenHandler to do a full
|
|
// recursive fetch.
|
|
func FetchHandler(ingester content.Ingester, fetcher Fetcher) image.HandlerFunc {
|
|
return func(ctx context.Context, desc ocispec.Descriptor) (subdescs []ocispec.Descriptor, err error) {
|
|
ctx = log.WithLogger(ctx, log.G(ctx).WithFields(logrus.Fields{
|
|
"digest": desc.Digest,
|
|
"mediatype": desc.MediaType,
|
|
"size": desc.Size,
|
|
}))
|
|
|
|
switch desc.MediaType {
|
|
case image.MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex:
|
|
return nil, fmt.Errorf("%v not yet supported", desc.MediaType)
|
|
default:
|
|
err := fetch(ctx, ingester, fetcher, desc)
|
|
return nil, err
|
|
}
|
|
}
|
|
}
|
|
|
|
func fetch(ctx context.Context, ingester content.Ingester, fetcher Fetcher, desc ocispec.Descriptor) error {
|
|
log.G(ctx).Debug("fetch")
|
|
ref := MakeRefKey(ctx, desc)
|
|
rc, err := fetcher.Fetch(ctx, desc)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer rc.Close()
|
|
|
|
return content.WriteBlob(ctx, ingester, ref, rc, desc.Size, desc.Digest)
|
|
}
|