Update commit id unmap to directly use active mounts

Signed-off-by: Derek McGowan <derek@mcg.dev>
This commit is contained in:
Derek McGowan 2023-12-20 18:28:04 -08:00
parent cf5a3bc531
commit f74ca4ed36
No known key found for this signature in database
GPG key ID: F58C5D0A4405ACDB
3 changed files with 93 additions and 15 deletions

View file

@ -17,7 +17,7 @@ import (
"github.com/containerd/containerd/images"
"github.com/containerd/containerd/leases"
"github.com/containerd/containerd/mount"
"github.com/containerd/containerd/rootfs"
"github.com/containerd/containerd/pkg/cleanup"
"github.com/containerd/containerd/snapshots"
"github.com/containerd/log"
"github.com/docker/docker/api/types/backend"
@ -251,35 +251,77 @@ func writeContentsForImage(ctx context.Context, snName string, cs content.Store,
// createDiff creates a layer diff into containerd's content store.
// If the diff is empty it returns nil empty digest and no error.
func (i *ImageService) createDiff(ctx context.Context, name string, sn snapshots.Snapshotter, cs content.Store, comparer diff.Comparer) (*ocispec.Descriptor, digest.Digest, error) {
info, err := sn.Stat(ctx, name)
if err != nil {
return nil, "", err
}
var upper []mount.Mount
if !i.idMapping.Empty() {
// The rootfs of the container is remapped if an id mapping exists, we
// need to "unremap" it before committing the snapshot
rootPair := i.idMapping.RootPair()
usernsID := fmt.Sprintf("%s-%d-%d", name, rootPair.UID, rootPair.GID)
usernsID := fmt.Sprintf("%s-%d-%d-%s", name, rootPair.UID, rootPair.GID, uniquePart())
remappedID := usernsID + remapSuffix
baseName := name
err := sn.Commit(ctx, name+"-pre", name)
if err != nil && !cerrdefs.IsAlreadyExists(err) {
return nil, "", err
}
if !cerrdefs.IsAlreadyExists(err) {
mounts, err := sn.Prepare(ctx, remappedID, name+"-pre")
if info.Kind == snapshots.KindActive {
source, err := sn.Mounts(ctx, name)
if err != nil {
return nil, "", err
}
if err := i.unremapRootFS(ctx, mounts); err != nil {
// No need to use parent since the whole snapshot is copied.
// Using parent would require doing diff/apply while starting
// from empty can just copy the whole snapshot.
// TODO: Optimize this for overlay mounts, can use parent
// and just copy upper directories without mounting
upper, err = sn.Prepare(ctx, remappedID, "")
if err != nil {
return nil, "", err
}
if err := sn.Commit(ctx, name, remappedID); err != nil {
if err := i.copyAndUnremapRootFS(ctx, upper, source); err != nil {
return nil, "", err
}
} else {
upper, err = sn.Prepare(ctx, remappedID, baseName)
if err != nil {
return nil, "", err
}
if err := i.unremapRootFS(ctx, upper); err != nil {
return nil, "", err
}
}
} else {
if info.Kind == snapshots.KindActive {
upper, err = sn.Mounts(ctx, name)
if err != nil {
return nil, "", err
}
} else {
upperKey := fmt.Sprintf("%s-view-%s", name, uniquePart())
upper, err = sn.View(ctx, upperKey, name)
if err != nil {
return nil, "", err
}
defer cleanup.Do(ctx, func(ctx context.Context) {
sn.Remove(ctx, upperKey)
})
}
}
newDesc, err := rootfs.CreateDiff(ctx, name, sn, comparer)
lowerKey := fmt.Sprintf("%s-parent-view-%s", info.Parent, uniquePart())
lower, err := sn.View(ctx, lowerKey, info.Parent)
if err != nil {
return nil, "", err
}
defer cleanup.Do(ctx, func(ctx context.Context) {
sn.Remove(ctx, lowerKey)
})
newDesc, err := comparer.Compare(ctx, lower, upper)
if err != nil {
return nil, "", errors.Wrap(err, "CreateDiff")
}
@ -298,12 +340,12 @@ func (i *ImageService) createDiff(ctx context.Context, name string, sn snapshots
return nil, "", nil
}
info, err := cs.Info(ctx, newDesc.Digest)
cinfo, err := cs.Info(ctx, newDesc.Digest)
if err != nil {
return nil, "", fmt.Errorf("failed to get content info: %w", err)
}
diffIDStr, ok := info.Labels["containerd.io/uncompressed"]
diffIDStr, ok := cinfo.Labels["containerd.io/uncompressed"]
if !ok {
return nil, "", fmt.Errorf("invalid differ response with no diffID")
}
@ -316,7 +358,7 @@ func (i *ImageService) createDiff(ctx context.Context, name string, sn snapshots
return &ocispec.Descriptor{
MediaType: ocispec.MediaTypeImageLayerGzip,
Digest: newDesc.Digest,
Size: info.Size,
Size: cinfo.Size,
}, diffID, nil
}

View file

@ -11,6 +11,7 @@ import (
"github.com/containerd/containerd/mount"
"github.com/containerd/containerd/snapshots"
"github.com/containerd/continuity/fs"
"github.com/containerd/continuity/sysx"
"github.com/docker/docker/pkg/idtools"
)
@ -63,6 +64,35 @@ func (i *ImageService) remapRootFS(ctx context.Context, mounts []mount.Mount) er
})
}
func (i *ImageService) copyAndUnremapRootFS(ctx context.Context, dst, src []mount.Mount) error {
return mount.WithTempMount(ctx, src, func(source string) error {
return mount.WithTempMount(ctx, dst, func(root string) error {
// TODO: Update CopyDir to support remap directly
if err := fs.CopyDir(root, source); err != nil {
return fmt.Errorf("failed to copy: %w", err)
}
return filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
stat := info.Sys().(*syscall.Stat_t)
if stat == nil {
return fmt.Errorf("cannot get underlying data for %s", path)
}
uid, gid, err := i.idMapping.ToContainer(idtools.Identity{UID: int(stat.Uid), GID: int(stat.Gid)})
if err != nil {
return err
}
return chownWithCaps(path, uid, gid)
})
})
})
}
func (i *ImageService) unremapRootFS(ctx context.Context, mounts []mount.Mount) error {
return mount.WithTempMount(ctx, mounts, func(root string) error {
return filepath.Walk(root, func(path string, info os.FileInfo, err error) error {

View file

@ -7,6 +7,12 @@ import (
"github.com/containerd/containerd/snapshots"
)
const remapSuffix = "-remap"
func (i *ImageService) copyAndUnremapRootFS(ctx context.Context, dst, src []mount.Mount) error {
return nil
}
func (i *ImageService) remapSnapshot(ctx context.Context, snapshotter snapshots.Snapshotter, id string, parentSnapshot string) error {
return nil
}