github.com/Prakhar-Agarwal-byte/moby@v0.0.0-20231027092010-a14e3e8ab87e/daemon/containerd/image_snapshot.go (about)

     1  package containerd
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  
     7  	"github.com/Prakhar-Agarwal-byte/moby/errdefs"
     8  	"github.com/containerd/containerd"
     9  	cerrdefs "github.com/containerd/containerd/errdefs"
    10  	containerdimages "github.com/containerd/containerd/images"
    11  	"github.com/containerd/containerd/leases"
    12  	"github.com/containerd/containerd/mount"
    13  	"github.com/containerd/containerd/platforms"
    14  	"github.com/containerd/containerd/snapshots"
    15  	"github.com/opencontainers/image-spec/identity"
    16  	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
    17  	"github.com/pkg/errors"
    18  )
    19  
    20  const remapSuffix = "-remap"
    21  
    22  // PrepareSnapshot prepares a snapshot from a parent image for a container
    23  func (i *ImageService) PrepareSnapshot(ctx context.Context, id string, parentImage string, platform *ocispec.Platform, setupInit func(string) error) error {
    24  	var parentSnapshot string
    25  	if parentImage != "" {
    26  		img, err := i.resolveImage(ctx, parentImage)
    27  		if err != nil {
    28  			return err
    29  		}
    30  
    31  		cs := i.client.ContentStore()
    32  
    33  		matcher := platforms.Default()
    34  		if platform != nil {
    35  			matcher = platforms.Only(*platform)
    36  		}
    37  
    38  		platformImg := containerd.NewImageWithPlatform(i.client, img, matcher)
    39  		unpacked, err := platformImg.IsUnpacked(ctx, i.snapshotter)
    40  		if err != nil {
    41  			return err
    42  		}
    43  
    44  		if !unpacked {
    45  			if err := platformImg.Unpack(ctx, i.snapshotter); err != nil {
    46  				return err
    47  			}
    48  		}
    49  
    50  		desc, err := containerdimages.Config(ctx, cs, img.Target, matcher)
    51  		if err != nil {
    52  			return err
    53  		}
    54  
    55  		diffIDs, err := containerdimages.RootFS(ctx, cs, desc)
    56  		if err != nil {
    57  			return err
    58  		}
    59  
    60  		parentSnapshot = identity.ChainID(diffIDs).String()
    61  	}
    62  
    63  	ls := i.client.LeasesService()
    64  	lease, err := ls.Create(ctx, leases.WithID(id))
    65  	if err != nil {
    66  		return err
    67  	}
    68  	ctx = leases.WithLease(ctx, lease.ID)
    69  
    70  	snapshotter := i.client.SnapshotService(i.StorageDriver())
    71  
    72  	if err := i.prepareInitLayer(ctx, id, parentSnapshot, setupInit); err != nil {
    73  		return err
    74  	}
    75  
    76  	if !i.idMapping.Empty() {
    77  		return i.remapSnapshot(ctx, snapshotter, id, id+"-init")
    78  	}
    79  
    80  	_, err = snapshotter.Prepare(ctx, id, id+"-init")
    81  	return err
    82  }
    83  
    84  func (i *ImageService) prepareInitLayer(ctx context.Context, id string, parent string, setupInit func(string) error) error {
    85  	snapshotter := i.client.SnapshotService(i.StorageDriver())
    86  
    87  	mounts, err := snapshotter.Prepare(ctx, id+"-init-key", parent)
    88  	if err != nil {
    89  		return err
    90  	}
    91  
    92  	if err := mount.WithTempMount(ctx, mounts, func(root string) error {
    93  		return setupInit(root)
    94  	}); err != nil {
    95  		return err
    96  	}
    97  
    98  	return snapshotter.Commit(ctx, id+"-init", id+"-init-key")
    99  }
   100  
   101  // calculateSnapshotParentUsage returns the usage of all ancestors of the
   102  // provided snapshot. It doesn't include the size of the snapshot itself.
   103  func calculateSnapshotParentUsage(ctx context.Context, snapshotter snapshots.Snapshotter, snapshotID string) (snapshots.Usage, error) {
   104  	info, err := snapshotter.Stat(ctx, snapshotID)
   105  	if err != nil {
   106  		if cerrdefs.IsNotFound(err) {
   107  			return snapshots.Usage{}, errdefs.NotFound(err)
   108  		}
   109  		return snapshots.Usage{}, errdefs.System(errors.Wrapf(err, "snapshotter.Stat failed for %s", snapshotID))
   110  	}
   111  	if info.Parent == "" {
   112  		return snapshots.Usage{}, errdefs.NotFound(fmt.Errorf("snapshot %s has no parent", snapshotID))
   113  	}
   114  
   115  	return calculateSnapshotTotalUsage(ctx, snapshotter, info.Parent)
   116  }
   117  
   118  // calculateSnapshotTotalUsage returns the total usage of that snapshot
   119  // including all of its ancestors.
   120  func calculateSnapshotTotalUsage(ctx context.Context, snapshotter snapshots.Snapshotter, snapshotID string) (snapshots.Usage, error) {
   121  	var total snapshots.Usage
   122  	next := snapshotID
   123  
   124  	for next != "" {
   125  		usage, err := snapshotter.Usage(ctx, next)
   126  		if err != nil {
   127  			if cerrdefs.IsNotFound(err) {
   128  				return total, errdefs.NotFound(errors.Wrapf(err, "non-existing ancestor of %s", snapshotID))
   129  			}
   130  			return total, errdefs.System(errors.Wrapf(err, "snapshotter.Usage failed for %s", next))
   131  		}
   132  		total.Size += usage.Size
   133  		total.Inodes += usage.Inodes
   134  
   135  		info, err := snapshotter.Stat(ctx, next)
   136  		if err != nil {
   137  			return total, errdefs.System(errors.Wrapf(err, "snapshotter.Stat failed for %s", next))
   138  		}
   139  		next = info.Parent
   140  	}
   141  	return total, nil
   142  }