imagecontext.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. package dockerfile
  2. import (
  3. "github.com/docker/docker/api/types/backend"
  4. "github.com/docker/docker/builder"
  5. "github.com/docker/docker/builder/remotecontext"
  6. dockerimage "github.com/docker/docker/image"
  7. "github.com/pkg/errors"
  8. "github.com/sirupsen/logrus"
  9. "golang.org/x/net/context"
  10. )
  11. type getAndMountFunc func(string, bool) (builder.Image, builder.ReleaseableLayer, error)
  12. // imageSources mounts images and provides a cache for mounted images. It tracks
  13. // all images so they can be unmounted at the end of the build.
  14. type imageSources struct {
  15. byImageID map[string]*imageMount
  16. mounts []*imageMount
  17. getImage getAndMountFunc
  18. cache pathCache // TODO: remove
  19. }
  20. // TODO @jhowardmsft LCOW Support: Eventually, platform can be moved to options.Options.Platform,
  21. // and removed from builderOptions, but that can't be done yet as it would affect the API.
  22. func newImageSources(ctx context.Context, options builderOptions) *imageSources {
  23. getAndMount := func(idOrRef string, localOnly bool) (builder.Image, builder.ReleaseableLayer, error) {
  24. pullOption := backend.PullOptionNoPull
  25. if !localOnly {
  26. if options.Options.PullParent {
  27. pullOption = backend.PullOptionForcePull
  28. } else {
  29. pullOption = backend.PullOptionPreferLocal
  30. }
  31. }
  32. return options.Backend.GetImageAndReleasableLayer(ctx, idOrRef, backend.GetImageAndLayerOptions{
  33. PullOption: pullOption,
  34. AuthConfig: options.Options.AuthConfigs,
  35. Output: options.ProgressWriter.Output,
  36. Platform: options.Platform,
  37. })
  38. }
  39. return &imageSources{
  40. byImageID: make(map[string]*imageMount),
  41. getImage: getAndMount,
  42. }
  43. }
  44. func (m *imageSources) Get(idOrRef string, localOnly bool) (*imageMount, error) {
  45. if im, ok := m.byImageID[idOrRef]; ok {
  46. return im, nil
  47. }
  48. image, layer, err := m.getImage(idOrRef, localOnly)
  49. if err != nil {
  50. return nil, err
  51. }
  52. im := newImageMount(image, layer)
  53. m.Add(im)
  54. return im, nil
  55. }
  56. func (m *imageSources) Unmount() (retErr error) {
  57. for _, im := range m.mounts {
  58. if err := im.unmount(); err != nil {
  59. logrus.Error(err)
  60. retErr = err
  61. }
  62. }
  63. return
  64. }
  65. func (m *imageSources) Add(im *imageMount) {
  66. switch im.image {
  67. case nil:
  68. im.image = &dockerimage.Image{}
  69. default:
  70. m.byImageID[im.image.ImageID()] = im
  71. }
  72. m.mounts = append(m.mounts, im)
  73. }
  74. // imageMount is a reference to an image that can be used as a builder.Source
  75. type imageMount struct {
  76. image builder.Image
  77. source builder.Source
  78. layer builder.ReleaseableLayer
  79. }
  80. func newImageMount(image builder.Image, layer builder.ReleaseableLayer) *imageMount {
  81. im := &imageMount{image: image, layer: layer}
  82. return im
  83. }
  84. func (im *imageMount) Source() (builder.Source, error) {
  85. if im.source == nil {
  86. if im.layer == nil {
  87. return nil, errors.Errorf("empty context")
  88. }
  89. mountPath, err := im.layer.Mount()
  90. if err != nil {
  91. return nil, errors.Wrapf(err, "failed to mount %s", im.image.ImageID())
  92. }
  93. source, err := remotecontext.NewLazySource(mountPath)
  94. if err != nil {
  95. return nil, errors.Wrapf(err, "failed to create lazycontext for %s", mountPath)
  96. }
  97. im.source = source
  98. }
  99. return im.source, nil
  100. }
  101. func (im *imageMount) unmount() error {
  102. if im.layer == nil {
  103. return nil
  104. }
  105. if err := im.layer.Release(); err != nil {
  106. return errors.Wrapf(err, "failed to unmount previous build image %s", im.image.ImageID())
  107. }
  108. im.layer = nil
  109. return nil
  110. }
  111. func (im *imageMount) Image() builder.Image {
  112. return im.image
  113. }
  114. func (im *imageMount) Layer() builder.ReleaseableLayer {
  115. return im.layer
  116. }
  117. func (im *imageMount) ImageID() string {
  118. return im.image.ImageID()
  119. }