github.com/moby/docker@v26.1.3+incompatible/daemon/containerd/image_snapshot.go (about) 1 package containerd 2 3 import ( 4 "context" 5 "fmt" 6 7 "github.com/containerd/containerd" 8 cerrdefs "github.com/containerd/containerd/errdefs" 9 containerdimages "github.com/containerd/containerd/images" 10 "github.com/containerd/containerd/leases" 11 "github.com/containerd/containerd/mount" 12 "github.com/containerd/containerd/platforms" 13 "github.com/containerd/containerd/snapshots" 14 "github.com/docker/docker/errdefs" 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 // PrepareSnapshot prepares a snapshot from a parent image for a container 21 func (i *ImageService) PrepareSnapshot(ctx context.Context, id string, parentImage string, platform *ocispec.Platform, setupInit func(string) error) error { 22 var parentSnapshot string 23 if parentImage != "" { 24 img, err := i.resolveImage(ctx, parentImage) 25 if err != nil { 26 return err 27 } 28 29 cs := i.content 30 31 matcher := matchAllWithPreference(platforms.Default()) 32 if platform != nil { 33 matcher = platforms.Only(*platform) 34 } 35 36 platformImg := containerd.NewImageWithPlatform(i.client, img, matcher) 37 unpacked, err := platformImg.IsUnpacked(ctx, i.snapshotter) 38 if err != nil { 39 return err 40 } 41 42 if !unpacked { 43 if err := platformImg.Unpack(ctx, i.snapshotter); err != nil { 44 return err 45 } 46 } 47 48 desc, err := containerdimages.Config(ctx, cs, img.Target, matcher) 49 if err != nil { 50 return err 51 } 52 53 diffIDs, err := containerdimages.RootFS(ctx, cs, desc) 54 if err != nil { 55 return err 56 } 57 58 parentSnapshot = identity.ChainID(diffIDs).String() 59 } 60 61 ls := i.client.LeasesService() 62 lease, err := ls.Create(ctx, leases.WithID(id)) 63 if err != nil { 64 return err 65 } 66 ctx = leases.WithLease(ctx, lease.ID) 67 68 snapshotter := i.client.SnapshotService(i.StorageDriver()) 69 70 if err := i.prepareInitLayer(ctx, id, parentSnapshot, setupInit); err != nil { 71 return err 72 } 73 74 if !i.idMapping.Empty() { 75 return i.remapSnapshot(ctx, snapshotter, id, id+"-init") 76 } 77 78 _, err = snapshotter.Prepare(ctx, id, id+"-init") 79 return err 80 } 81 82 func (i *ImageService) prepareInitLayer(ctx context.Context, id string, parent string, setupInit func(string) error) error { 83 snapshotter := i.client.SnapshotService(i.StorageDriver()) 84 85 mounts, err := snapshotter.Prepare(ctx, id+"-init-key", parent) 86 if err != nil { 87 return err 88 } 89 90 if setupInit != nil { 91 if err := mount.WithTempMount(ctx, mounts, func(root string) error { 92 return setupInit(root) 93 }); err != nil { 94 return err 95 } 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 }