7 "github.com/Sirupsen/logrus"
8 "github.com/docker/distribution/reference"
9 "github.com/docker/docker/api/types"
10 "github.com/docker/docker/api/types/backend"
11 "github.com/docker/docker/builder"
12 "github.com/docker/docker/image"
13 "github.com/docker/docker/layer"
14 "github.com/docker/docker/pkg/idtools"
15 "github.com/docker/docker/pkg/stringid"
16 "github.com/docker/docker/registry"
17 "github.com/pkg/errors"
18 "golang.org/x/net/context"
21 type releaseableLayer struct {
23 layerStore layer.Store
28 func (rl *releaseableLayer) Mount() (string, error) {
30 var chainID layer.ChainID
31 if rl.roLayer != nil {
32 chainID = rl.roLayer.ChainID()
35 mountID := stringid.GenerateRandomID()
36 rl.rwLayer, err = rl.layerStore.CreateRWLayer(mountID, chainID, nil)
38 return "", errors.Wrap(err, "failed to create rwlayer")
41 return rl.rwLayer.Mount("")
44 func (rl *releaseableLayer) Commit(platform string) (builder.ReleaseableLayer, error) {
45 var chainID layer.ChainID
46 if rl.roLayer != nil {
47 chainID = rl.roLayer.ChainID()
50 stream, err := rl.rwLayer.TarStream()
55 newLayer, err := rl.layerStore.Register(stream, chainID, layer.Platform(platform))
60 if layer.IsEmpty(newLayer.DiffID()) {
61 _, err := rl.layerStore.Release(newLayer)
62 return &releaseableLayer{layerStore: rl.layerStore}, err
64 return &releaseableLayer{layerStore: rl.layerStore, roLayer: newLayer}, nil
67 func (rl *releaseableLayer) DiffID() layer.DiffID {
68 if rl.roLayer == nil {
69 return layer.DigestSHA256EmptyTar
71 return rl.roLayer.DiffID()
74 func (rl *releaseableLayer) Release() error {
80 return rl.releaseROLayer()
83 func (rl *releaseableLayer) releaseRWLayer() error {
84 if rl.rwLayer == nil {
87 metadata, err := rl.layerStore.ReleaseRWLayer(rl.rwLayer)
88 layer.LogReleaseMetadata(metadata)
90 logrus.Errorf("Failed to release RWLayer: %s", err)
95 func (rl *releaseableLayer) releaseROLayer() error {
96 if rl.roLayer == nil {
99 metadata, err := rl.layerStore.Release(rl.roLayer)
100 layer.LogReleaseMetadata(metadata)
104 func newReleasableLayerForImage(img *image.Image, layerStore layer.Store) (builder.ReleaseableLayer, error) {
105 if img == nil || img.RootFS.ChainID() == "" {
106 return &releaseableLayer{layerStore: layerStore}, nil
108 // Hold a reference to the image layer so that it can't be removed before
110 roLayer, err := layerStore.Get(img.RootFS.ChainID())
112 return nil, errors.Wrapf(err, "failed to get layer for image %s", img.ImageID())
114 return &releaseableLayer{layerStore: layerStore, roLayer: roLayer}, nil
117 // TODO: could this use the regular daemon PullImage ?
118 func (daemon *Daemon) pullForBuilder(ctx context.Context, name string, authConfigs map[string]types.AuthConfig, output io.Writer, platform string) (*image.Image, error) {
119 ref, err := reference.ParseNormalizedNamed(name)
123 ref = reference.TagNameOnly(ref)
125 pullRegistryAuth := &types.AuthConfig{}
126 if len(authConfigs) > 0 {
127 // The request came with a full auth config, use it
128 repoInfo, err := daemon.RegistryService.ResolveRepository(ref)
133 resolvedConfig := registry.ResolveAuthConfig(authConfigs, repoInfo.Index)
134 pullRegistryAuth = &resolvedConfig
137 if err := daemon.pullImageWithReference(ctx, ref, platform, nil, pullRegistryAuth, output); err != nil {
140 return daemon.GetImage(name)
143 // GetImageAndReleasableLayer returns an image and releaseable layer for a reference or ID.
144 // Every call to GetImageAndReleasableLayer MUST call releasableLayer.Release() to prevent
145 // leaking of layers.
146 func (daemon *Daemon) GetImageAndReleasableLayer(ctx context.Context, refOrID string, opts backend.GetImageAndLayerOptions) (builder.Image, builder.ReleaseableLayer, error) {
148 layer, err := newReleasableLayerForImage(nil, daemon.stores[opts.Platform].layerStore)
149 return nil, layer, err
152 if opts.PullOption != backend.PullOptionForcePull {
153 image, err := daemon.GetImage(refOrID)
154 if err != nil && opts.PullOption == backend.PullOptionNoPull {
157 // TODO: shouldn't we error out if error is different from "not found" ?
159 layer, err := newReleasableLayerForImage(image, daemon.stores[opts.Platform].layerStore)
160 return image, layer, err
164 image, err := daemon.pullForBuilder(ctx, refOrID, opts.AuthConfig, opts.Output, opts.Platform)
168 layer, err := newReleasableLayerForImage(image, daemon.stores[opts.Platform].layerStore)
169 return image, layer, err
172 // CreateImage creates a new image by adding a config and ID to the image store.
173 // This is similar to LoadImage() except that it receives JSON encoded bytes of
174 // an image instead of a tar archive.
175 func (daemon *Daemon) CreateImage(config []byte, parent string, platform string) (builder.Image, error) {
177 platform = runtime.GOOS
179 id, err := daemon.stores[platform].imageStore.Create(config)
181 return nil, errors.Wrapf(err, "failed to create image")
185 if err := daemon.stores[platform].imageStore.SetParent(id, image.ID(parent)); err != nil {
186 return nil, errors.Wrapf(err, "failed to set parent %s", parent)
190 return daemon.stores[platform].imageStore.Get(id)
193 // IDMappings returns uid/gid mappings for the builder
194 func (daemon *Daemon) IDMappings() *idtools.IDMappings {
195 return daemon.idMappings