image_changes.go 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. package containerd
  2. import (
  3. "context"
  4. "encoding/json"
  5. "github.com/containerd/containerd/content"
  6. "github.com/containerd/containerd/log"
  7. "github.com/containerd/containerd/mount"
  8. "github.com/docker/docker/container"
  9. "github.com/docker/docker/pkg/archive"
  10. "github.com/google/uuid"
  11. "github.com/opencontainers/image-spec/identity"
  12. ocispec "github.com/opencontainers/image-spec/specs-go/v1"
  13. )
  14. func (i *ImageService) Changes(ctx context.Context, container *container.Container) ([]archive.Change, error) {
  15. cs := i.client.ContentStore()
  16. imageManifest, err := getContainerImageManifest(container)
  17. if err != nil {
  18. return nil, err
  19. }
  20. imageManifestBytes, err := content.ReadBlob(ctx, cs, imageManifest)
  21. if err != nil {
  22. return nil, err
  23. }
  24. var manifest ocispec.Manifest
  25. if err := json.Unmarshal(imageManifestBytes, &manifest); err != nil {
  26. return nil, err
  27. }
  28. imageConfigBytes, err := content.ReadBlob(ctx, cs, manifest.Config)
  29. if err != nil {
  30. return nil, err
  31. }
  32. var image ocispec.Image
  33. if err := json.Unmarshal(imageConfigBytes, &image); err != nil {
  34. return nil, err
  35. }
  36. rnd, err := uuid.NewRandom()
  37. if err != nil {
  38. return nil, err
  39. }
  40. snapshotter := i.client.SnapshotService(container.Driver)
  41. diffIDs := image.RootFS.DiffIDs
  42. parent, err := snapshotter.View(ctx, rnd.String(), identity.ChainID(diffIDs).String())
  43. if err != nil {
  44. return nil, err
  45. }
  46. defer func() {
  47. if err := snapshotter.Remove(ctx, rnd.String()); err != nil {
  48. log.G(ctx).WithError(err).WithField("key", rnd.String()).Warn("remove temporary snapshot")
  49. }
  50. }()
  51. mounts, err := snapshotter.Mounts(ctx, container.ID)
  52. if err != nil {
  53. return nil, err
  54. }
  55. var changes []archive.Change
  56. err = mount.WithReadonlyTempMount(ctx, mounts, func(fs string) error {
  57. return mount.WithTempMount(ctx, parent, func(root string) error {
  58. changes, err = archive.ChangesDirs(fs, root)
  59. return err
  60. })
  61. })
  62. return changes, err
  63. }