Skip to content

Commit

Permalink
c8d: Make sure the content isn't removed while we export
Browse files Browse the repository at this point in the history
This change add leases for all the content that will be exported, once
the image(s) are exported the lease is removed, thus letting
containerd's GC to do its job if needed. This fixes the case where
someone would remove an image that is still being exported.

This fixes the TestAPIImagesSaveAndLoad cli integration test.

Signed-off-by: Djordje Lukic <djordje.lukic@docker.com>
  • Loading branch information
rumpl committed Jul 19, 2023
1 parent ee79423 commit f3a6b0f
Showing 1 changed file with 38 additions and 2 deletions.
40 changes: 38 additions & 2 deletions daemon/containerd/image_exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ import (
"io"

"github.com/containerd/containerd"
"github.com/containerd/containerd/content"
cerrdefs "github.com/containerd/containerd/errdefs"
containerdimages "github.com/containerd/containerd/images"
"github.com/containerd/containerd/images/archive"
"github.com/containerd/containerd/leases"
"github.com/containerd/containerd/log"
"github.com/containerd/containerd/mount"
cplatforms "github.com/containerd/containerd/platforms"
Expand Down Expand Up @@ -58,18 +60,28 @@ func (i *ImageService) ExportImage(ctx context.Context, names []string, outStrea
archive.WithPlatform(platform),
}

ctx, release, err := i.client.WithLease(ctx)
contentStore := i.client.ContentStore()
leasesManager := i.client.LeasesService()
lease, err := leasesManager.Create(ctx, leases.WithRandomID())
if err != nil {
return errdefs.System(err)
}
defer release(ctx)
defer func() {
if err := leasesManager.Delete(ctx, lease); err != nil {
log.G(ctx).WithError(err).Warn("cleaning up lease")
}
}()

for _, name := range names {
target, err := i.resolveDescriptor(ctx, name)
if err != nil {
return err
}

if err = leaseContent(ctx, contentStore, leasesManager, lease, target); err != nil {
return err
}

// We may not have locally all the platforms that are specified in the index.
// Export only those manifests that we have.
// TODO(vvoland): Reconsider this when `--platform` is added.
Expand Down Expand Up @@ -101,6 +113,30 @@ func (i *ImageService) ExportImage(ctx context.Context, names []string, outStrea
return i.client.Export(ctx, outStream, opts...)
}

// leaseContent will add a resource to the lease for each child of the descriptor making sure that it and
// its children won't be deleted while the lease exists
func leaseContent(ctx context.Context, store content.Store, leasesManager leases.Manager, lease leases.Lease, desc ocispec.Descriptor) error {
return containerdimages.Walk(ctx, containerdimages.HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
_, err := store.Info(ctx, desc.Digest)
if err != nil {
if errors.Is(err, cerrdefs.ErrNotFound) {
return nil, nil
}
return nil, errdefs.System(err)
}

r := leases.Resource{
ID: desc.Digest.String(),
Type: "content",
}
if err := leasesManager.AddResource(ctx, lease, r); err != nil {
return nil, errdefs.System(err)
}

return containerdimages.Children(ctx, store, desc)
}), desc)
}

// LoadImage uploads a set of images into the repository. This is the
// complement of ExportImage. The input stream is an uncompressed tar
// ball containing images and metadata.
Expand Down

0 comments on commit f3a6b0f

Please sign in to comment.