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 }