build.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. package daemon
  2. import (
  3. "github.com/Sirupsen/logrus"
  4. "github.com/docker/distribution/reference"
  5. "github.com/docker/docker/api/types"
  6. "github.com/docker/docker/api/types/backend"
  7. "github.com/docker/docker/builder"
  8. "github.com/docker/docker/image"
  9. "github.com/docker/docker/layer"
  10. "github.com/docker/docker/pkg/stringid"
  11. "github.com/docker/docker/registry"
  12. "github.com/pkg/errors"
  13. "golang.org/x/net/context"
  14. "io"
  15. )
  16. type releaseableLayer struct {
  17. layerStore layer.Store
  18. roLayer layer.Layer
  19. rwLayer layer.RWLayer
  20. }
  21. func (rl *releaseableLayer) Mount() (string, error) {
  22. if rl.roLayer == nil {
  23. return "", errors.New("can not mount an image with no root FS")
  24. }
  25. var err error
  26. mountID := stringid.GenerateRandomID()
  27. rl.rwLayer, err = rl.layerStore.CreateRWLayer(mountID, rl.roLayer.ChainID(), nil)
  28. if err != nil {
  29. return "", errors.Wrap(err, "failed to create rwlayer")
  30. }
  31. return rl.rwLayer.Mount("")
  32. }
  33. func (rl *releaseableLayer) Release() error {
  34. rl.releaseRWLayer()
  35. return rl.releaseROLayer()
  36. }
  37. func (rl *releaseableLayer) releaseRWLayer() error {
  38. if rl.rwLayer == nil {
  39. return nil
  40. }
  41. metadata, err := rl.layerStore.ReleaseRWLayer(rl.rwLayer)
  42. layer.LogReleaseMetadata(metadata)
  43. if err != nil {
  44. logrus.Errorf("Failed to release RWLayer: %s", err)
  45. }
  46. return err
  47. }
  48. func (rl *releaseableLayer) releaseROLayer() error {
  49. if rl.roLayer == nil {
  50. return nil
  51. }
  52. metadata, err := rl.layerStore.Release(rl.roLayer)
  53. layer.LogReleaseMetadata(metadata)
  54. return err
  55. }
  56. func newReleasableLayerForImage(img *image.Image, layerStore layer.Store) (builder.ReleaseableLayer, error) {
  57. if img.RootFS.ChainID() == "" {
  58. return nil, nil
  59. }
  60. // Hold a reference to the image layer so that it can't be removed before
  61. // it is released
  62. roLayer, err := layerStore.Get(img.RootFS.ChainID())
  63. if err != nil {
  64. return nil, errors.Wrapf(err, "failed to get layer for image %s", img.ImageID())
  65. }
  66. return &releaseableLayer{layerStore: layerStore, roLayer: roLayer}, nil
  67. }
  68. // TODO: could this use the regular daemon PullImage ?
  69. func (daemon *Daemon) pullForBuilder(ctx context.Context, name string, authConfigs map[string]types.AuthConfig, output io.Writer) (*image.Image, error) {
  70. ref, err := reference.ParseNormalizedNamed(name)
  71. if err != nil {
  72. return nil, err
  73. }
  74. ref = reference.TagNameOnly(ref)
  75. pullRegistryAuth := &types.AuthConfig{}
  76. if len(authConfigs) > 0 {
  77. // The request came with a full auth config, use it
  78. repoInfo, err := daemon.RegistryService.ResolveRepository(ref)
  79. if err != nil {
  80. return nil, err
  81. }
  82. resolvedConfig := registry.ResolveAuthConfig(authConfigs, repoInfo.Index)
  83. pullRegistryAuth = &resolvedConfig
  84. }
  85. if err := daemon.pullImageWithReference(ctx, ref, nil, pullRegistryAuth, output); err != nil {
  86. return nil, err
  87. }
  88. return daemon.GetImage(name)
  89. }
  90. // GetImageAndReleasableLayer returns an image and releaseable layer for a reference or ID.
  91. // Every call to GetImageAndReleasableLayer MUST call releasableLayer.Release() to prevent
  92. // leaking of layers.
  93. func (daemon *Daemon) GetImageAndReleasableLayer(ctx context.Context, refOrID string, opts backend.GetImageAndLayerOptions) (builder.Image, builder.ReleaseableLayer, error) {
  94. if !opts.ForcePull {
  95. image, _ := daemon.GetImage(refOrID)
  96. // TODO: shouldn't we error out if error is different from "not found" ?
  97. if image != nil {
  98. layer, err := newReleasableLayerForImage(image, daemon.layerStore)
  99. return image, layer, err
  100. }
  101. }
  102. image, err := daemon.pullForBuilder(ctx, refOrID, opts.AuthConfig, opts.Output)
  103. if err != nil {
  104. return nil, nil, err
  105. }
  106. layer, err := newReleasableLayerForImage(image, daemon.layerStore)
  107. return image, layer, err
  108. }