Tizen_4.0 base
[platform/upstream/docker-engine.git] / daemon / build.go
1 package daemon
2
3 import (
4         "io"
5         "runtime"
6
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"
19 )
20
21 type releaseableLayer struct {
22         released   bool
23         layerStore layer.Store
24         roLayer    layer.Layer
25         rwLayer    layer.RWLayer
26 }
27
28 func (rl *releaseableLayer) Mount() (string, error) {
29         var err error
30         var chainID layer.ChainID
31         if rl.roLayer != nil {
32                 chainID = rl.roLayer.ChainID()
33         }
34
35         mountID := stringid.GenerateRandomID()
36         rl.rwLayer, err = rl.layerStore.CreateRWLayer(mountID, chainID, nil)
37         if err != nil {
38                 return "", errors.Wrap(err, "failed to create rwlayer")
39         }
40
41         return rl.rwLayer.Mount("")
42 }
43
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()
48         }
49
50         stream, err := rl.rwLayer.TarStream()
51         if err != nil {
52                 return nil, err
53         }
54
55         newLayer, err := rl.layerStore.Register(stream, chainID, layer.Platform(platform))
56         if err != nil {
57                 return nil, err
58         }
59
60         if layer.IsEmpty(newLayer.DiffID()) {
61                 _, err := rl.layerStore.Release(newLayer)
62                 return &releaseableLayer{layerStore: rl.layerStore}, err
63         }
64         return &releaseableLayer{layerStore: rl.layerStore, roLayer: newLayer}, nil
65 }
66
67 func (rl *releaseableLayer) DiffID() layer.DiffID {
68         if rl.roLayer == nil {
69                 return layer.DigestSHA256EmptyTar
70         }
71         return rl.roLayer.DiffID()
72 }
73
74 func (rl *releaseableLayer) Release() error {
75         if rl.released {
76                 return nil
77         }
78         rl.released = true
79         rl.releaseRWLayer()
80         return rl.releaseROLayer()
81 }
82
83 func (rl *releaseableLayer) releaseRWLayer() error {
84         if rl.rwLayer == nil {
85                 return nil
86         }
87         metadata, err := rl.layerStore.ReleaseRWLayer(rl.rwLayer)
88         layer.LogReleaseMetadata(metadata)
89         if err != nil {
90                 logrus.Errorf("Failed to release RWLayer: %s", err)
91         }
92         return err
93 }
94
95 func (rl *releaseableLayer) releaseROLayer() error {
96         if rl.roLayer == nil {
97                 return nil
98         }
99         metadata, err := rl.layerStore.Release(rl.roLayer)
100         layer.LogReleaseMetadata(metadata)
101         return err
102 }
103
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
107         }
108         // Hold a reference to the image layer so that it can't be removed before
109         // it is released
110         roLayer, err := layerStore.Get(img.RootFS.ChainID())
111         if err != nil {
112                 return nil, errors.Wrapf(err, "failed to get layer for image %s", img.ImageID())
113         }
114         return &releaseableLayer{layerStore: layerStore, roLayer: roLayer}, nil
115 }
116
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)
120         if err != nil {
121                 return nil, err
122         }
123         ref = reference.TagNameOnly(ref)
124
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)
129                 if err != nil {
130                         return nil, err
131                 }
132
133                 resolvedConfig := registry.ResolveAuthConfig(authConfigs, repoInfo.Index)
134                 pullRegistryAuth = &resolvedConfig
135         }
136
137         if err := daemon.pullImageWithReference(ctx, ref, platform, nil, pullRegistryAuth, output); err != nil {
138                 return nil, err
139         }
140         return daemon.GetImage(name)
141 }
142
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) {
147         if refOrID == "" {
148                 layer, err := newReleasableLayerForImage(nil, daemon.stores[opts.Platform].layerStore)
149                 return nil, layer, err
150         }
151
152         if opts.PullOption != backend.PullOptionForcePull {
153                 image, err := daemon.GetImage(refOrID)
154                 if err != nil && opts.PullOption == backend.PullOptionNoPull {
155                         return nil, nil, err
156                 }
157                 // TODO: shouldn't we error out if error is different from "not found" ?
158                 if image != nil {
159                         layer, err := newReleasableLayerForImage(image, daemon.stores[opts.Platform].layerStore)
160                         return image, layer, err
161                 }
162         }
163
164         image, err := daemon.pullForBuilder(ctx, refOrID, opts.AuthConfig, opts.Output, opts.Platform)
165         if err != nil {
166                 return nil, nil, err
167         }
168         layer, err := newReleasableLayerForImage(image, daemon.stores[opts.Platform].layerStore)
169         return image, layer, err
170 }
171
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) {
176         if platform == "" {
177                 platform = runtime.GOOS
178         }
179         id, err := daemon.stores[platform].imageStore.Create(config)
180         if err != nil {
181                 return nil, errors.Wrapf(err, "failed to create image")
182         }
183
184         if parent != "" {
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)
187                 }
188         }
189
190         return daemon.stores[platform].imageStore.Get(id)
191 }
192
193 // IDMappings returns uid/gid mappings for the builder
194 func (daemon *Daemon) IDMappings() *idtools.IDMappings {
195         return daemon.idMappings
196 }