image_commit.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. package images // import "github.com/docker/docker/daemon/images"
  2. import (
  3. "context"
  4. "encoding/json"
  5. "io"
  6. "github.com/docker/docker/api/types/backend"
  7. "github.com/docker/docker/image"
  8. "github.com/docker/docker/layer"
  9. "github.com/docker/docker/pkg/ioutils"
  10. "github.com/pkg/errors"
  11. )
  12. // CommitImage creates a new image from a commit config
  13. func (i *ImageService) CommitImage(ctx context.Context, c backend.CommitConfig) (image.ID, error) {
  14. if err := ctx.Err(); err != nil {
  15. return "", err
  16. }
  17. rwTar, err := exportContainerRw(i.layerStore, c.ContainerID, c.ContainerMountLabel)
  18. if err != nil {
  19. return "", err
  20. }
  21. defer func() {
  22. if rwTar != nil {
  23. rwTar.Close()
  24. }
  25. }()
  26. var parent *image.Image
  27. if c.ParentImageID == "" {
  28. parent = new(image.Image)
  29. parent.RootFS = image.NewRootFS()
  30. } else {
  31. parent, err = i.imageStore.Get(image.ID(c.ParentImageID))
  32. if err != nil {
  33. return "", err
  34. }
  35. }
  36. l, err := i.layerStore.Register(rwTar, parent.RootFS.ChainID())
  37. if err != nil {
  38. return "", err
  39. }
  40. defer layer.ReleaseAndLog(i.layerStore, l)
  41. cc := image.ChildConfig{
  42. ContainerID: c.ContainerID,
  43. Author: c.Author,
  44. Comment: c.Comment,
  45. ContainerConfig: c.ContainerConfig,
  46. Config: c.Config,
  47. DiffID: l.DiffID(),
  48. }
  49. config, err := json.Marshal(image.NewChildImage(parent, cc, c.ContainerOS))
  50. if err != nil {
  51. return "", err
  52. }
  53. id, err := i.imageStore.Create(config)
  54. if err != nil {
  55. return "", err
  56. }
  57. if c.ParentImageID != "" {
  58. if err := i.imageStore.SetParent(id, image.ID(c.ParentImageID)); err != nil {
  59. return "", err
  60. }
  61. }
  62. return id, nil
  63. }
  64. func exportContainerRw(layerStore layer.Store, id, mountLabel string) (arch io.ReadCloser, err error) {
  65. rwlayer, err := layerStore.GetRWLayer(id)
  66. if err != nil {
  67. return nil, err
  68. }
  69. defer func() {
  70. if err != nil {
  71. layerStore.ReleaseRWLayer(rwlayer)
  72. }
  73. }()
  74. // TODO: this mount call is not necessary as we assume that TarStream() should
  75. // mount the layer if needed. But the Diff() function for windows requests that
  76. // the layer should be mounted when calling it. So we reserve this mount call
  77. // until windows driver can implement Diff() interface correctly.
  78. _, err = rwlayer.Mount(mountLabel)
  79. if err != nil {
  80. return nil, err
  81. }
  82. archive, err := rwlayer.TarStream()
  83. if err != nil {
  84. rwlayer.Unmount()
  85. return nil, err
  86. }
  87. return ioutils.NewReadCloserWrapper(archive, func() error {
  88. archive.Close()
  89. err = rwlayer.Unmount()
  90. layerStore.ReleaseRWLayer(rwlayer)
  91. return err
  92. }),
  93. nil
  94. }
  95. // CommitBuildStep is used by the builder to create an image for each step in
  96. // the build.
  97. //
  98. // This method is different from CreateImageFromContainer:
  99. // - it doesn't attempt to validate container state
  100. // - it doesn't send a commit action to metrics
  101. // - it doesn't log a container commit event
  102. //
  103. // This is a temporary shim. Should be removed when builder stops using commit.
  104. func (i *ImageService) CommitBuildStep(ctx context.Context, c backend.CommitConfig) (image.ID, error) {
  105. ctr := i.containers.Get(c.ContainerID)
  106. if ctr == nil {
  107. // TODO: use typed error
  108. return "", errors.Errorf("container not found: %s", c.ContainerID)
  109. }
  110. c.ContainerMountLabel = ctr.MountLabel
  111. c.ContainerOS = ctr.OS
  112. c.ParentImageID = string(ctr.ImageID)
  113. return i.CommitImage(ctx, c)
  114. }