Ensure manifests are marked as root during pull
For schema1 mark blobs as roots and remove labels once referenced by the created manifest. Signed-off-by: Derek McGowan <derek@mcgstyle.net>
This commit is contained in:
parent
91614a57dc
commit
b798d87bd4
@ -228,7 +228,7 @@ func (c *Client) Pull(ctx context.Context, ref string, opts ...RemoteOpt) (Image
|
|||||||
handler = images.Handlers(append(pullCtx.BaseHandlers, schema1Converter)...)
|
handler = images.Handlers(append(pullCtx.BaseHandlers, schema1Converter)...)
|
||||||
} else {
|
} else {
|
||||||
handler = images.Handlers(append(pullCtx.BaseHandlers,
|
handler = images.Handlers(append(pullCtx.BaseHandlers,
|
||||||
remotes.FetchHandler(store, fetcher),
|
remotes.FetchHandler(store, fetcher, desc),
|
||||||
images.ChildrenHandler(store, platforms.Default()))...,
|
images.ChildrenHandler(store, platforms.Default()))...,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -265,6 +265,11 @@ func (c *Client) Pull(ctx context.Context, ref string, opts ...RemoteOpt) (Image
|
|||||||
imgrec = updated
|
imgrec = updated
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove root tag from manifest now that image refers to it
|
||||||
|
if _, err := store.Update(ctx, content.Info{Digest: desc.Digest}, "labels.containerd.io/gc.root"); err != nil {
|
||||||
|
return nil, errors.Wrap(err, "failed to remove manifest root tag")
|
||||||
|
}
|
||||||
|
|
||||||
img := &image{
|
img := &image{
|
||||||
client: c,
|
client: c,
|
||||||
i: imgrec,
|
i: imgrec,
|
||||||
|
@ -48,7 +48,7 @@ func ReadBlob(ctx context.Context, provider Provider, dgst digest.Digest) ([]byt
|
|||||||
// This is useful when the digest and size are known beforehand.
|
// This is useful when the digest and size are known beforehand.
|
||||||
//
|
//
|
||||||
// Copy is buffered, so no need to wrap reader in buffered io.
|
// Copy is buffered, so no need to wrap reader in buffered io.
|
||||||
func WriteBlob(ctx context.Context, cs Ingester, ref string, r io.Reader, size int64, expected digest.Digest) error {
|
func WriteBlob(ctx context.Context, cs Ingester, ref string, r io.Reader, size int64, expected digest.Digest, opts ...Opt) error {
|
||||||
cw, err := cs.Writer(ctx, ref, size, expected)
|
cw, err := cs.Writer(ctx, ref, size, expected)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !errdefs.IsAlreadyExists(err) {
|
if !errdefs.IsAlreadyExists(err) {
|
||||||
@ -59,7 +59,7 @@ func WriteBlob(ctx context.Context, cs Ingester, ref string, r io.Reader, size i
|
|||||||
}
|
}
|
||||||
defer cw.Close()
|
defer cw.Close()
|
||||||
|
|
||||||
return Copy(ctx, cw, r, size, expected)
|
return Copy(ctx, cw, r, size, expected, opts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy copies data with the expected digest from the reader into the
|
// Copy copies data with the expected digest from the reader into the
|
||||||
|
@ -132,11 +132,6 @@ func (c *Converter) Convert(ctx context.Context) (ocispec.Descriptor, error) {
|
|||||||
Size: int64(len(b)),
|
Size: int64(len(b)),
|
||||||
}
|
}
|
||||||
|
|
||||||
ref := remotes.MakeRefKey(ctx, config)
|
|
||||||
if err := content.WriteBlob(ctx, c.contentStore, ref, bytes.NewReader(b), config.Size, config.Digest); err != nil {
|
|
||||||
return ocispec.Descriptor{}, errors.Wrap(err, "failed to write config")
|
|
||||||
}
|
|
||||||
|
|
||||||
layers := make([]ocispec.Descriptor, len(diffIDs))
|
layers := make([]ocispec.Descriptor, len(diffIDs))
|
||||||
for i, diffID := range diffIDs {
|
for i, diffID := range diffIDs {
|
||||||
layers[i] = c.layerBlobs[diffID]
|
layers[i] = c.layerBlobs[diffID]
|
||||||
@ -150,22 +145,40 @@ func (c *Converter) Convert(ctx context.Context) (ocispec.Descriptor, error) {
|
|||||||
Layers: layers,
|
Layers: layers,
|
||||||
}
|
}
|
||||||
|
|
||||||
b, err = json.Marshal(manifest)
|
mb, err := json.Marshal(manifest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ocispec.Descriptor{}, errors.Wrap(err, "failed to marshal image")
|
return ocispec.Descriptor{}, errors.Wrap(err, "failed to marshal image")
|
||||||
}
|
}
|
||||||
|
|
||||||
desc := ocispec.Descriptor{
|
desc := ocispec.Descriptor{
|
||||||
MediaType: ocispec.MediaTypeImageManifest,
|
MediaType: ocispec.MediaTypeImageManifest,
|
||||||
Digest: digest.Canonical.FromBytes(b),
|
Digest: digest.Canonical.FromBytes(mb),
|
||||||
Size: int64(len(b)),
|
Size: int64(len(mb)),
|
||||||
}
|
}
|
||||||
|
|
||||||
ref = remotes.MakeRefKey(ctx, desc)
|
labels := map[string]string{}
|
||||||
if err := content.WriteBlob(ctx, c.contentStore, ref, bytes.NewReader(b), desc.Size, desc.Digest); err != nil {
|
labels["containerd.io/gc.root"] = time.Now().UTC().Format(time.RFC3339)
|
||||||
|
labels["containerd.io/gc.ref.content.0"] = manifest.Config.Digest.String()
|
||||||
|
for i, ch := range manifest.Layers {
|
||||||
|
labels[fmt.Sprintf("containerd.io/gc.ref.content.%d", i+1)] = ch.Digest.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
ref := remotes.MakeRefKey(ctx, desc)
|
||||||
|
if err := content.WriteBlob(ctx, c.contentStore, ref, bytes.NewReader(mb), desc.Size, desc.Digest, content.WithLabels(labels)); err != nil {
|
||||||
return ocispec.Descriptor{}, errors.Wrap(err, "failed to write config")
|
return ocispec.Descriptor{}, errors.Wrap(err, "failed to write config")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ref = remotes.MakeRefKey(ctx, config)
|
||||||
|
if err := content.WriteBlob(ctx, c.contentStore, ref, bytes.NewReader(b), config.Size, config.Digest); err != nil {
|
||||||
|
return ocispec.Descriptor{}, errors.Wrap(err, "failed to write config")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ch := range manifest.Layers {
|
||||||
|
if _, err := c.contentStore.Update(ctx, content.Info{Digest: ch.Digest}, "labels.containerd.io/gc.root"); err != nil {
|
||||||
|
return ocispec.Descriptor{}, errors.Wrap(err, "failed to remove blob root tag")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return desc, nil
|
return desc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -255,14 +268,15 @@ func (c *Converter) fetchBlob(ctx context.Context, desc ocispec.Descriptor) erro
|
|||||||
|
|
||||||
eg.Go(func() error {
|
eg.Go(func() error {
|
||||||
defer pw.Close()
|
defer pw.Close()
|
||||||
return content.Copy(ctx, cw, io.TeeReader(rc, pw), desc.Size, desc.Digest)
|
opt := content.WithLabels(map[string]string{
|
||||||
|
"containerd.io/gc.root": time.Now().UTC().Format(time.RFC3339),
|
||||||
|
})
|
||||||
|
return content.Copy(ctx, cw, io.TeeReader(rc, pw), desc.Size, desc.Digest, opt)
|
||||||
})
|
})
|
||||||
|
|
||||||
if err := eg.Wait(); err != nil {
|
if err := eg.Wait(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Label blob
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if desc.Size == 0 {
|
if desc.Size == 0 {
|
||||||
|
@ -44,7 +44,7 @@ func MakeRefKey(ctx context.Context, desc ocispec.Descriptor) string {
|
|||||||
// FetchHandler returns a handler that will fetch all content into the ingester
|
// 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
|
// discovered in a call to Dispatch. Use with ChildrenHandler to do a full
|
||||||
// recursive fetch.
|
// recursive fetch.
|
||||||
func FetchHandler(ingester content.Ingester, fetcher Fetcher) images.HandlerFunc {
|
func FetchHandler(ingester content.Ingester, fetcher Fetcher, root ocispec.Descriptor) images.HandlerFunc {
|
||||||
return func(ctx context.Context, desc ocispec.Descriptor) (subdescs []ocispec.Descriptor, err error) {
|
return func(ctx context.Context, desc ocispec.Descriptor) (subdescs []ocispec.Descriptor, err error) {
|
||||||
ctx = log.WithLogger(ctx, log.G(ctx).WithFields(logrus.Fields{
|
ctx = log.WithLogger(ctx, log.G(ctx).WithFields(logrus.Fields{
|
||||||
"digest": desc.Digest,
|
"digest": desc.Digest,
|
||||||
@ -56,13 +56,13 @@ func FetchHandler(ingester content.Ingester, fetcher Fetcher) images.HandlerFunc
|
|||||||
case images.MediaTypeDockerSchema1Manifest:
|
case images.MediaTypeDockerSchema1Manifest:
|
||||||
return nil, fmt.Errorf("%v not supported", desc.MediaType)
|
return nil, fmt.Errorf("%v not supported", desc.MediaType)
|
||||||
default:
|
default:
|
||||||
err := fetch(ctx, ingester, fetcher, desc)
|
err := fetch(ctx, ingester, fetcher, desc, desc.Digest == root.Digest)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetch(ctx context.Context, ingester content.Ingester, fetcher Fetcher, desc ocispec.Descriptor) error {
|
func fetch(ctx context.Context, ingester content.Ingester, fetcher Fetcher, desc ocispec.Descriptor, root bool) error {
|
||||||
log.G(ctx).Debug("fetch")
|
log.G(ctx).Debug("fetch")
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -104,13 +104,13 @@ func fetch(ctx context.Context, ingester content.Ingester, fetcher Fetcher, desc
|
|||||||
}
|
}
|
||||||
defer rc.Close()
|
defer rc.Close()
|
||||||
|
|
||||||
r, opts := commitOpts(desc, rc)
|
r, opts := commitOpts(desc, rc, root)
|
||||||
return content.Copy(ctx, cw, r, desc.Size, desc.Digest, opts...)
|
return content.Copy(ctx, cw, r, desc.Size, desc.Digest, opts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// commitOpts gets the appropriate content options to alter
|
// commitOpts gets the appropriate content options to alter
|
||||||
// the content info on commit based on media type.
|
// the content info on commit based on media type.
|
||||||
func commitOpts(desc ocispec.Descriptor, r io.Reader) (io.Reader, []content.Opt) {
|
func commitOpts(desc ocispec.Descriptor, r io.Reader, root bool) (io.Reader, []content.Opt) {
|
||||||
var childrenF func(r io.Reader) ([]ocispec.Descriptor, error)
|
var childrenF func(r io.Reader) ([]ocispec.Descriptor, error)
|
||||||
|
|
||||||
switch desc.MediaType {
|
switch desc.MediaType {
|
||||||
@ -162,10 +162,13 @@ func commitOpts(desc ocispec.Descriptor, r io.Reader) (io.Reader, []content.Opt)
|
|||||||
return errors.Wrap(err, "unable to get commit labels")
|
return errors.Wrap(err, "unable to get commit labels")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(children) > 0 {
|
if len(children) > 0 || root {
|
||||||
if info.Labels == nil {
|
if info.Labels == nil {
|
||||||
info.Labels = map[string]string{}
|
info.Labels = map[string]string{}
|
||||||
}
|
}
|
||||||
|
if root {
|
||||||
|
info.Labels["containerd.io/gc.root"] = time.Now().UTC().Format(time.RFC3339)
|
||||||
|
}
|
||||||
for i, ch := range children {
|
for i, ch := range children {
|
||||||
info.Labels[fmt.Sprintf("containerd.io/gc.ref.content.%d", i)] = ch.Digest.String()
|
info.Labels[fmt.Sprintf("containerd.io/gc.ref.content.%d", i)] = ch.Digest.String()
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user