imagecontext.go 3.5 KB

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