| package containerd | |
| import ( | |
| "context" | |
| "fmt" | |
| "github.com/containerd/containerd/v2/core/mount" | |
| "github.com/containerd/log" | |
| "github.com/moby/go-archive" | |
| "github.com/moby/moby/v2/daemon/container" | |
| "github.com/moby/moby/v2/daemon/internal/stringid" | |
| ) | |
| func (i *ImageService) Changes(ctx context.Context, ctr *container.Container) ([]archive.Change, error) { | |
| rwl := ctr.RWLayer | |
| if rwl == nil { | |
| return nil, fmt.Errorf("RWLayer is unexpectedly nil for container %s", ctr.ID) | |
| } | |
| snapshotter := i.client.SnapshotService(ctr.Driver) | |
| info, err := snapshotter.Stat(ctx, ctr.ID) | |
| if err != nil { | |
| return nil, err | |
| } | |
| id := stringid.GenerateRandomID() | |
| parentViewKey := ctr.ID + "-parent-view-" + id | |
| imageMounts, _ := snapshotter.View(ctx, parentViewKey, info.Parent) | |
| defer func() { | |
| if err := snapshotter.Remove(ctx, parentViewKey); err != nil { | |
| log.G(ctx).WithError(err).Warn("error removing the parent view snapshot") | |
| } | |
| }() | |
| containerRoot, err := rwl.Mount(ctr.GetMountLabel()) | |
| if err != nil { | |
| return nil, err | |
| } | |
| defer func() { | |
| if err := rwl.Unmount(); err != nil { | |
| log.G(ctx).WithFields(log.Fields{"error": err, "container": ctr.ID}).Warn("Failed to unmount container RWLayer after export") | |
| } | |
| }() | |
| var changes []archive.Change | |
| err = mount.WithReadonlyTempMount(ctx, imageMounts, func(imageRoot string) error { | |
| changes, err = archive.ChangesDirs(containerRoot, imageRoot) | |
| return err | |
| }) | |
| return changes, err | |
| } |