Browse code

Move all daemon image methods into imageService

imageService provides the backend for the image API and handles the
imageStore, and referenceStore.

Signed-off-by: Daniel Nephin <dnephin@docker.com>

Daniel Nephin authored on 2018/02/03 07:18:46
Showing 46 changed files
... ...
@@ -253,6 +253,7 @@ func (cli *DaemonCli) start(opts *daemonOptions) (err error) {
253 253
 		Root:                   cli.Config.Root,
254 254
 		Name:                   name,
255 255
 		Backend:                d,
256
+		ImageBackend:           d.ImageService(),
256 257
 		PluginBackend:          d.PluginManager(),
257 258
 		NetworkSubnetsProvider: d,
258 259
 		DefaultAdvertiseAddr:   cli.Config.SwarmDefaultAdvertiseAddr,
... ...
@@ -345,12 +346,12 @@ func newRouterOptions(config *config.Config, daemon *daemon.Daemon) (routerOptio
345 345
 		return opts, errors.Wrap(err, "failed to create fscache")
346 346
 	}
347 347
 
348
-	manager, err := dockerfile.NewBuildManager(daemon, sm, buildCache, daemon.IDMappings())
348
+	manager, err := dockerfile.NewBuildManager(daemon.BuilderBackend(), sm, buildCache, daemon.IDMappings())
349 349
 	if err != nil {
350 350
 		return opts, err
351 351
 	}
352 352
 
353
-	bb, err := buildbackend.NewBackend(daemon, manager, buildCache)
353
+	bb, err := buildbackend.NewBackend(daemon.ImageService(), manager, buildCache)
354 354
 	if err != nil {
355 355
 		return opts, errors.Wrap(err, "failed to create buildmanager")
356 356
 	}
... ...
@@ -507,14 +508,14 @@ func initRouter(opts routerOptions) {
507 507
 		// we need to add the checkpoint router before the container router or the DELETE gets masked
508 508
 		checkpointrouter.NewRouter(opts.daemon, decoder),
509 509
 		container.NewRouter(opts.daemon, decoder),
510
-		image.NewRouter(opts.daemon),
510
+		image.NewRouter(opts.daemon.ImageService()),
511 511
 		systemrouter.NewRouter(opts.daemon, opts.cluster, opts.buildCache),
512 512
 		volume.NewRouter(opts.daemon),
513 513
 		build.NewRouter(opts.buildBackend, opts.daemon),
514 514
 		sessionrouter.NewRouter(opts.sessionManager),
515 515
 		swarmrouter.NewRouter(opts.cluster),
516 516
 		pluginrouter.NewRouter(opts.daemon.PluginManager()),
517
-		distributionrouter.NewRouter(opts.daemon),
517
+		distributionrouter.NewRouter(opts.daemon.ImageService()),
518 518
 	}
519 519
 
520 520
 	if opts.daemon.NetworkControllerEnabled() {
521 521
deleted file mode 100644
... ...
@@ -1,225 +0,0 @@
1
-package daemon // import "github.com/docker/docker/daemon"
2
-
3
-import (
4
-	"io"
5
-
6
-	"github.com/docker/distribution/reference"
7
-	"github.com/docker/docker/api/types"
8
-	"github.com/docker/docker/api/types/backend"
9
-	"github.com/docker/docker/builder"
10
-	"github.com/docker/docker/image"
11
-	"github.com/docker/docker/layer"
12
-	"github.com/docker/docker/pkg/containerfs"
13
-	"github.com/docker/docker/pkg/idtools"
14
-	"github.com/docker/docker/pkg/stringid"
15
-	"github.com/docker/docker/pkg/system"
16
-	"github.com/docker/docker/registry"
17
-	"github.com/pkg/errors"
18
-	"golang.org/x/net/context"
19
-)
20
-
21
-type roLayer struct {
22
-	released   bool
23
-	layerStore layer.Store
24
-	roLayer    layer.Layer
25
-}
26
-
27
-func (l *roLayer) DiffID() layer.DiffID {
28
-	if l.roLayer == nil {
29
-		return layer.DigestSHA256EmptyTar
30
-	}
31
-	return l.roLayer.DiffID()
32
-}
33
-
34
-func (l *roLayer) Release() error {
35
-	if l.released {
36
-		return nil
37
-	}
38
-	if l.roLayer != nil {
39
-		metadata, err := l.layerStore.Release(l.roLayer)
40
-		layer.LogReleaseMetadata(metadata)
41
-		if err != nil {
42
-			return errors.Wrap(err, "failed to release ROLayer")
43
-		}
44
-	}
45
-	l.roLayer = nil
46
-	l.released = true
47
-	return nil
48
-}
49
-
50
-func (l *roLayer) NewRWLayer() (builder.RWLayer, error) {
51
-	var chainID layer.ChainID
52
-	if l.roLayer != nil {
53
-		chainID = l.roLayer.ChainID()
54
-	}
55
-
56
-	mountID := stringid.GenerateRandomID()
57
-	newLayer, err := l.layerStore.CreateRWLayer(mountID, chainID, nil)
58
-	if err != nil {
59
-		return nil, errors.Wrap(err, "failed to create rwlayer")
60
-	}
61
-
62
-	rwLayer := &rwLayer{layerStore: l.layerStore, rwLayer: newLayer}
63
-
64
-	fs, err := newLayer.Mount("")
65
-	if err != nil {
66
-		rwLayer.Release()
67
-		return nil, err
68
-	}
69
-
70
-	rwLayer.fs = fs
71
-
72
-	return rwLayer, nil
73
-}
74
-
75
-type rwLayer struct {
76
-	released   bool
77
-	layerStore layer.Store
78
-	rwLayer    layer.RWLayer
79
-	fs         containerfs.ContainerFS
80
-}
81
-
82
-func (l *rwLayer) Root() containerfs.ContainerFS {
83
-	return l.fs
84
-}
85
-
86
-func (l *rwLayer) Commit() (builder.ROLayer, error) {
87
-	stream, err := l.rwLayer.TarStream()
88
-	if err != nil {
89
-		return nil, err
90
-	}
91
-	defer stream.Close()
92
-
93
-	var chainID layer.ChainID
94
-	if parent := l.rwLayer.Parent(); parent != nil {
95
-		chainID = parent.ChainID()
96
-	}
97
-
98
-	newLayer, err := l.layerStore.Register(stream, chainID)
99
-	if err != nil {
100
-		return nil, err
101
-	}
102
-	// TODO: An optimization would be to handle empty layers before returning
103
-	return &roLayer{layerStore: l.layerStore, roLayer: newLayer}, nil
104
-}
105
-
106
-func (l *rwLayer) Release() error {
107
-	if l.released {
108
-		return nil
109
-	}
110
-
111
-	if l.fs != nil {
112
-		if err := l.rwLayer.Unmount(); err != nil {
113
-			return errors.Wrap(err, "failed to unmount RWLayer")
114
-		}
115
-		l.fs = nil
116
-	}
117
-
118
-	metadata, err := l.layerStore.ReleaseRWLayer(l.rwLayer)
119
-	layer.LogReleaseMetadata(metadata)
120
-	if err != nil {
121
-		return errors.Wrap(err, "failed to release RWLayer")
122
-	}
123
-	l.released = true
124
-	return nil
125
-}
126
-
127
-func newROLayerForImage(img *image.Image, layerStore layer.Store) (builder.ROLayer, error) {
128
-	if img == nil || img.RootFS.ChainID() == "" {
129
-		return &roLayer{layerStore: layerStore}, nil
130
-	}
131
-	// Hold a reference to the image layer so that it can't be removed before
132
-	// it is released
133
-	layer, err := layerStore.Get(img.RootFS.ChainID())
134
-	if err != nil {
135
-		return nil, errors.Wrapf(err, "failed to get layer for image %s", img.ImageID())
136
-	}
137
-	return &roLayer{layerStore: layerStore, roLayer: layer}, nil
138
-}
139
-
140
-// TODO: could this use the regular daemon PullImage ?
141
-func (daemon *Daemon) pullForBuilder(ctx context.Context, name string, authConfigs map[string]types.AuthConfig, output io.Writer, os string) (*image.Image, error) {
142
-	ref, err := reference.ParseNormalizedNamed(name)
143
-	if err != nil {
144
-		return nil, err
145
-	}
146
-	ref = reference.TagNameOnly(ref)
147
-
148
-	pullRegistryAuth := &types.AuthConfig{}
149
-	if len(authConfigs) > 0 {
150
-		// The request came with a full auth config, use it
151
-		repoInfo, err := daemon.RegistryService.ResolveRepository(ref)
152
-		if err != nil {
153
-			return nil, err
154
-		}
155
-
156
-		resolvedConfig := registry.ResolveAuthConfig(authConfigs, repoInfo.Index)
157
-		pullRegistryAuth = &resolvedConfig
158
-	}
159
-
160
-	if err := daemon.pullImageWithReference(ctx, ref, os, nil, pullRegistryAuth, output); err != nil {
161
-		return nil, err
162
-	}
163
-	return daemon.GetImage(name)
164
-}
165
-
166
-// GetImageAndReleasableLayer returns an image and releaseable layer for a reference or ID.
167
-// Every call to GetImageAndReleasableLayer MUST call releasableLayer.Release() to prevent
168
-// leaking of layers.
169
-func (daemon *Daemon) GetImageAndReleasableLayer(ctx context.Context, refOrID string, opts backend.GetImageAndLayerOptions) (builder.Image, builder.ROLayer, error) {
170
-	if refOrID == "" {
171
-		if !system.IsOSSupported(opts.OS) {
172
-			return nil, nil, system.ErrNotSupportedOperatingSystem
173
-		}
174
-		layer, err := newROLayerForImage(nil, daemon.layerStores[opts.OS])
175
-		return nil, layer, err
176
-	}
177
-
178
-	if opts.PullOption != backend.PullOptionForcePull {
179
-		image, err := daemon.GetImage(refOrID)
180
-		if err != nil && opts.PullOption == backend.PullOptionNoPull {
181
-			return nil, nil, err
182
-		}
183
-		// TODO: shouldn't we error out if error is different from "not found" ?
184
-		if image != nil {
185
-			if !system.IsOSSupported(image.OperatingSystem()) {
186
-				return nil, nil, system.ErrNotSupportedOperatingSystem
187
-			}
188
-			layer, err := newROLayerForImage(image, daemon.layerStores[image.OperatingSystem()])
189
-			return image, layer, err
190
-		}
191
-	}
192
-
193
-	image, err := daemon.pullForBuilder(ctx, refOrID, opts.AuthConfig, opts.Output, opts.OS)
194
-	if err != nil {
195
-		return nil, nil, err
196
-	}
197
-	if !system.IsOSSupported(image.OperatingSystem()) {
198
-		return nil, nil, system.ErrNotSupportedOperatingSystem
199
-	}
200
-	layer, err := newROLayerForImage(image, daemon.layerStores[image.OperatingSystem()])
201
-	return image, layer, err
202
-}
203
-
204
-// CreateImage creates a new image by adding a config and ID to the image store.
205
-// This is similar to LoadImage() except that it receives JSON encoded bytes of
206
-// an image instead of a tar archive.
207
-func (daemon *Daemon) CreateImage(config []byte, parent string) (builder.Image, error) {
208
-	id, err := daemon.imageStore.Create(config)
209
-	if err != nil {
210
-		return nil, errors.Wrapf(err, "failed to create image")
211
-	}
212
-
213
-	if parent != "" {
214
-		if err := daemon.imageStore.SetParent(id, image.ID(parent)); err != nil {
215
-			return nil, errors.Wrapf(err, "failed to set parent %s", parent)
216
-		}
217
-	}
218
-
219
-	return daemon.imageStore.Get(id)
220
-}
221
-
222
-// IDMappings returns uid/gid mappings for the builder
223
-func (daemon *Daemon) IDMappings() *idtools.IDMappings {
224
-	return daemon.idMappings
225
-}
... ...
@@ -7,15 +7,15 @@ import (
7 7
 )
8 8
 
9 9
 // MakeImageCache creates a stateful image cache.
10
-func (daemon *Daemon) MakeImageCache(sourceRefs []string) builder.ImageCache {
10
+func (i *imageService) MakeImageCache(sourceRefs []string) builder.ImageCache {
11 11
 	if len(sourceRefs) == 0 {
12
-		return cache.NewLocal(daemon.imageStore)
12
+		return cache.NewLocal(i.imageStore)
13 13
 	}
14 14
 
15
-	cache := cache.New(daemon.imageStore)
15
+	cache := cache.New(i.imageStore)
16 16
 
17 17
 	for _, ref := range sourceRefs {
18
-		img, err := daemon.GetImage(ref)
18
+		img, err := i.GetImage(ref)
19 19
 		if err != nil {
20 20
 			logrus.Warnf("Could not look up %s for cache resolution, skipping: %+v", ref, err)
21 21
 			continue
... ...
@@ -83,6 +83,7 @@ type Config struct {
83 83
 	Root                   string
84 84
 	Name                   string
85 85
 	Backend                executorpkg.Backend
86
+	ImageBackend           executorpkg.ImageBackend
86 87
 	PluginBackend          plugin.Backend
87 88
 	NetworkSubnetsProvider NetworkSubnetsProvider
88 89
 
... ...
@@ -31,7 +31,6 @@ type Backend interface {
31 31
 	FindNetwork(idName string) (libnetwork.Network, error)
32 32
 	SetupIngress(clustertypes.NetworkCreateRequest, string) (<-chan struct{}, error)
33 33
 	ReleaseIngress() (<-chan struct{}, error)
34
-	PullImage(ctx context.Context, image, tag, platform string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error
35 34
 	CreateManagedContainer(config types.ContainerCreateConfig) (container.ContainerCreateCreatedBody, error)
36 35
 	ContainerStart(name string, hostConfig *container.HostConfig, checkpoint string, checkpointDir string) error
37 36
 	ContainerStop(name string, seconds *int) error
... ...
@@ -58,9 +57,13 @@ type Backend interface {
58 58
 	UnsubscribeFromEvents(listener chan interface{})
59 59
 	UpdateAttachment(string, string, string, *network.NetworkingConfig) error
60 60
 	WaitForDetachment(context.Context, string, string, string, string) error
61
-	GetRepository(context.Context, reference.Named, *types.AuthConfig) (distribution.Repository, bool, error)
62
-	LookupImage(name string) (*types.ImageInspect, error)
63 61
 	PluginManager() *plugin.Manager
64 62
 	PluginGetter() *plugin.Store
65 63
 	GetAttachmentStore() *networkSettings.AttachmentStore
66 64
 }
65
+
66
+type ImageBackend interface {
67
+	PullImage(ctx context.Context, image, tag, platform string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error
68
+	GetRepository(context.Context, reference.Named, *types.AuthConfig) (distribution.Repository, bool, error)
69
+	LookupImage(name string) (*types.ImageInspect, error)
70
+}
... ...
@@ -36,11 +36,12 @@ import (
36 36
 // containerConfig.
37 37
 type containerAdapter struct {
38 38
 	backend      executorpkg.Backend
39
+	imageBackend executorpkg.ImageBackend
39 40
 	container    *containerConfig
40 41
 	dependencies exec.DependencyGetter
41 42
 }
42 43
 
43
-func newContainerAdapter(b executorpkg.Backend, task *api.Task, node *api.NodeDescription, dependencies exec.DependencyGetter) (*containerAdapter, error) {
44
+func newContainerAdapter(b executorpkg.Backend, i executorpkg.ImageBackend, task *api.Task, node *api.NodeDescription, dependencies exec.DependencyGetter) (*containerAdapter, error) {
44 45
 	ctnr, err := newContainerConfig(task, node)
45 46
 	if err != nil {
46 47
 		return nil, err
... ...
@@ -49,6 +50,7 @@ func newContainerAdapter(b executorpkg.Backend, task *api.Task, node *api.NodeDe
49 49
 	return &containerAdapter{
50 50
 		container:    ctnr,
51 51
 		backend:      b,
52
+		imageBackend: i,
52 53
 		dependencies: dependencies,
53 54
 	}, nil
54 55
 }
... ...
@@ -66,7 +68,7 @@ func (c *containerAdapter) pullImage(ctx context.Context) error {
66 66
 	named, err := reference.ParseNormalizedNamed(spec.Image)
67 67
 	if err == nil {
68 68
 		if _, ok := named.(reference.Canonical); ok {
69
-			_, err := c.backend.LookupImage(spec.Image)
69
+			_, err := c.imageBackend.LookupImage(spec.Image)
70 70
 			if err == nil {
71 71
 				return nil
72 72
 			}
... ...
@@ -92,7 +94,7 @@ func (c *containerAdapter) pullImage(ctx context.Context) error {
92 92
 		// TODO @jhowardmsft LCOW Support: This will need revisiting as
93 93
 		// the stack is built up to include LCOW support for swarm.
94 94
 		platform := runtime.GOOS
95
-		err := c.backend.PullImage(ctx, c.container.image(), "", platform, metaHeaders, authConfig, pw)
95
+		err := c.imageBackend.PullImage(ctx, c.container.image(), "", platform, metaHeaders, authConfig, pw)
96 96
 		pw.CloseWithError(err)
97 97
 	}()
98 98
 
... ...
@@ -20,8 +20,8 @@ type networkAttacherController struct {
20 20
 	closed  chan struct{}
21 21
 }
22 22
 
23
-func newNetworkAttacherController(b executorpkg.Backend, task *api.Task, node *api.NodeDescription, dependencies exec.DependencyGetter) (*networkAttacherController, error) {
24
-	adapter, err := newContainerAdapter(b, task, node, dependencies)
23
+func newNetworkAttacherController(b executorpkg.Backend, i executorpkg.ImageBackend, task *api.Task, node *api.NodeDescription, dependencies exec.DependencyGetter) (*networkAttacherController, error) {
24
+	adapter, err := newContainerAdapter(b, i, task, node, dependencies)
25 25
 	if err != nil {
26 26
 		return nil, err
27 27
 	}
... ...
@@ -40,8 +40,8 @@ type controller struct {
40 40
 var _ exec.Controller = &controller{}
41 41
 
42 42
 // NewController returns a docker exec runner for the provided task.
43
-func newController(b executorpkg.Backend, task *api.Task, node *api.NodeDescription, dependencies exec.DependencyGetter) (*controller, error) {
44
-	adapter, err := newContainerAdapter(b, task, node, dependencies)
43
+func newController(b executorpkg.Backend, i executorpkg.ImageBackend, task *api.Task, node *api.NodeDescription, dependencies exec.DependencyGetter) (*controller, error) {
44
+	adapter, err := newContainerAdapter(b, i, task, node, dependencies)
45 45
 	if err != nil {
46 46
 		return nil, err
47 47
 	}
... ...
@@ -26,6 +26,7 @@ import (
26 26
 
27 27
 type executor struct {
28 28
 	backend       executorpkg.Backend
29
+	imageBackend  executorpkg.ImageBackend
29 30
 	pluginBackend plugin.Backend
30 31
 	dependencies  exec.DependencyManager
31 32
 	mutex         sync.Mutex // This mutex protects the following node field
... ...
@@ -33,10 +34,11 @@ type executor struct {
33 33
 }
34 34
 
35 35
 // NewExecutor returns an executor from the docker client.
36
-func NewExecutor(b executorpkg.Backend, p plugin.Backend) exec.Executor {
36
+func NewExecutor(b executorpkg.Backend, p plugin.Backend, i executorpkg.ImageBackend) exec.Executor {
37 37
 	return &executor{
38 38
 		backend:       b,
39 39
 		pluginBackend: p,
40
+		imageBackend:  i,
40 41
 		dependencies:  agent.NewDependencyManager(),
41 42
 	}
42 43
 }
... ...
@@ -200,7 +202,7 @@ func (e *executor) Controller(t *api.Task) (exec.Controller, error) {
200 200
 	e.mutex.Unlock()
201 201
 
202 202
 	if t.Spec.GetAttachment() != nil {
203
-		return newNetworkAttacherController(e.backend, t, nodeDescription, dependencyGetter)
203
+		return newNetworkAttacherController(e.backend, e.imageBackend, t, nodeDescription, dependencyGetter)
204 204
 	}
205 205
 
206 206
 	var ctlr exec.Controller
... ...
@@ -229,7 +231,7 @@ func (e *executor) Controller(t *api.Task) (exec.Controller, error) {
229 229
 			return ctlr, fmt.Errorf("unsupported runtime type: %q", runtimeKind)
230 230
 		}
231 231
 	case *api.TaskSpec_Container:
232
-		c, err := newController(e.backend, t, nodeDescription, dependencyGetter)
232
+		c, err := newController(e.backend, e.imageBackend, t, nodeDescription, dependencyGetter)
233 233
 		if err != nil {
234 234
 			return ctlr, err
235 235
 		}
... ...
@@ -52,7 +52,7 @@ func TestHealthStates(t *testing.T) {
52 52
 		EventsService: e,
53 53
 	}
54 54
 
55
-	controller, err := newController(daemon, task, nil, nil)
55
+	controller, err := newController(daemon, nil, task, nil, nil)
56 56
 	if err != nil {
57 57
 		t.Fatalf("create controller fail %v", err)
58 58
 	}
... ...
@@ -12,7 +12,7 @@ import (
12 12
 )
13 13
 
14 14
 func newTestControllerWithMount(m api.Mount) (*controller, error) {
15
-	return newController(&daemon.Daemon{}, &api.Task{
15
+	return newController(&daemon.Daemon{}, nil, &api.Task{
16 16
 		ID:        stringid.GenerateRandomID(),
17 17
 		ServiceID: stringid.GenerateRandomID(),
18 18
 		Spec: api.TaskSpec{
... ...
@@ -120,12 +120,15 @@ func (n *nodeRunner) start(conf nodeStartConfig) error {
120 120
 		JoinAddr:           joinAddr,
121 121
 		StateDir:           n.cluster.root,
122 122
 		JoinToken:          conf.joinToken,
123
-		Executor:           container.NewExecutor(n.cluster.config.Backend, n.cluster.config.PluginBackend),
124
-		HeartbeatTick:      1,
125
-		ElectionTick:       3,
126
-		UnlockKey:          conf.lockKey,
127
-		AutoLockManagers:   conf.autolock,
128
-		PluginGetter:       n.cluster.config.Backend.PluginGetter(),
123
+		Executor: container.NewExecutor(
124
+			n.cluster.config.Backend,
125
+			n.cluster.config.PluginBackend,
126
+			n.cluster.config.ImageBackend),
127
+		HeartbeatTick:    1,
128
+		ElectionTick:     3,
129
+		UnlockKey:        conf.lockKey,
130
+		AutoLockManagers: conf.autolock,
131
+		PluginGetter:     n.cluster.config.Backend.PluginGetter(),
129 132
 	}
130 133
 	if conf.availability != "" {
131 134
 		avail, ok := swarmapi.NodeSpec_Availability_value[strings.ToUpper(string(conf.availability))]
... ...
@@ -570,7 +570,7 @@ func (c *Cluster) imageWithDigestString(ctx context.Context, image string, authC
570 570
 			return "", errors.Errorf("image reference not tagged: %s", image)
571 571
 		}
572 572
 
573
-		repo, _, err := c.config.Backend.GetRepository(ctx, taggedRef, authConfig)
573
+		repo, _, err := c.config.ImageBackend.GetRepository(ctx, taggedRef, authConfig)
574 574
 		if err != nil {
575 575
 			return "", err
576 576
 		}
... ...
@@ -155,7 +155,7 @@ func (daemon *Daemon) CreateImageFromContainer(name string, c *backend.CreateIma
155 155
 		return "", err
156 156
 	}
157 157
 
158
-	id, err := daemon.commitImage(backend.CommitConfig{
158
+	id, err := daemon.imageService.CommitImage(backend.CommitConfig{
159 159
 		Author:              c.Author,
160 160
 		Comment:             c.Comment,
161 161
 		Config:              newConfig,
... ...
@@ -171,7 +171,7 @@ func (daemon *Daemon) CreateImageFromContainer(name string, c *backend.CreateIma
171 171
 
172 172
 	var imageRef string
173 173
 	if c.Repo != "" {
174
-		imageRef, err = daemon.TagImage(string(id), c.Repo, c.Tag)
174
+		imageRef, err = daemon.imageService.TagImage(string(id), c.Repo, c.Tag)
175 175
 		if err != nil {
176 176
 			return "", err
177 177
 		}
... ...
@@ -158,7 +158,7 @@ func (daemon *Daemon) newContainer(name string, operatingSystem string, config *
158 158
 	base.ImageID = imgID
159 159
 	base.NetworkSettings = &network.Settings{IsAnonymousEndpoint: noExplicitName}
160 160
 	base.Name = name
161
-	base.Driver = daemon.GraphDriverName(operatingSystem)
161
+	base.Driver = daemon.imageService.GraphDriverForOS(operatingSystem)
162 162
 	base.OS = operatingSystem
163 163
 	return base, err
164 164
 }
... ...
@@ -15,7 +15,6 @@ import (
15 15
 	"github.com/docker/docker/container"
16 16
 	"github.com/docker/docker/errdefs"
17 17
 	"github.com/docker/docker/image"
18
-	"github.com/docker/docker/layer"
19 18
 	"github.com/docker/docker/pkg/idtools"
20 19
 	"github.com/docker/docker/pkg/stringid"
21 20
 	"github.com/docker/docker/pkg/system"
... ...
@@ -42,7 +41,7 @@ func (daemon *Daemon) containerCreate(params types.ContainerCreateConfig, manage
42 42
 
43 43
 	os := runtime.GOOS
44 44
 	if params.Config.Image != "" {
45
-		img, err := daemon.GetImage(params.Config.Image)
45
+		img, err := daemon.imageService.GetImage(params.Config.Image)
46 46
 		if err == nil {
47 47
 			os = img.OS
48 48
 		}
... ...
@@ -92,7 +91,7 @@ func (daemon *Daemon) create(params types.ContainerCreateConfig, managed bool) (
92 92
 
93 93
 	os := runtime.GOOS
94 94
 	if params.Config.Image != "" {
95
-		img, err = daemon.GetImage(params.Config.Image)
95
+		img, err = daemon.imageService.GetImage(params.Config.Image)
96 96
 		if err != nil {
97 97
 			return nil, err
98 98
 		}
... ...
@@ -158,9 +157,11 @@ func (daemon *Daemon) create(params types.ContainerCreateConfig, managed bool) (
158 158
 	}
159 159
 
160 160
 	// Set RWLayer for container after mount labels have been set
161
-	if err := daemon.setRWLayer(container); err != nil {
161
+	rwLayer, err := daemon.imageService.GetRWLayer(container, setupInitLayer(daemon.idMappings))
162
+	if err != nil {
162 163
 		return nil, errdefs.System(err)
163 164
 	}
165
+	container.RWLayer = rwLayer
164 166
 
165 167
 	rootIDs := daemon.idMappings.RootPair()
166 168
 	if err := idtools.MkdirAndChown(container.Root, 0700, rootIDs); err != nil {
... ...
@@ -254,33 +255,6 @@ func (daemon *Daemon) generateSecurityOpt(hostConfig *containertypes.HostConfig)
254 254
 	return nil, nil
255 255
 }
256 256
 
257
-func (daemon *Daemon) setRWLayer(container *container.Container) error {
258
-	var layerID layer.ChainID
259
-	if container.ImageID != "" {
260
-		img, err := daemon.imageStore.Get(container.ImageID)
261
-		if err != nil {
262
-			return err
263
-		}
264
-		layerID = img.RootFS.ChainID()
265
-	}
266
-
267
-	rwLayerOpts := &layer.CreateRWLayerOpts{
268
-		MountLabel: container.MountLabel,
269
-		InitFunc:   setupInitLayer(daemon.idMappings),
270
-		StorageOpt: container.HostConfig.StorageOpt,
271
-	}
272
-
273
-	// Indexing by OS is safe here as validation of OS has already been performed in create() (the only
274
-	// caller), and guaranteed non-nil
275
-	rwLayer, err := daemon.layerStores[container.OS].CreateRWLayer(container.ID, layerID, rwLayerOpts)
276
-	if err != nil {
277
-		return err
278
-	}
279
-	container.RWLayer = rwLayer
280
-
281
-	return nil
282
-}
283
-
284 257
 // VolumeCreate creates a volume with the specified name, driver, and opts
285 258
 // This is called directly from the Engine API
286 259
 func (daemon *Daemon) VolumeCreate(name, driverName string, opts, labels map[string]string) (*types.Volume, error) {
... ...
@@ -31,6 +31,7 @@ import (
31 31
 	"github.com/docker/docker/errdefs"
32 32
 	"github.com/sirupsen/logrus"
33 33
 	// register graph drivers
34
+	"github.com/docker/docker/builder"
34 35
 	_ "github.com/docker/docker/daemon/graphdriver/register"
35 36
 	"github.com/docker/docker/daemon/stats"
36 37
 	dmetadata "github.com/docker/docker/distribution/metadata"
... ...
@@ -57,7 +58,6 @@ import (
57 57
 	"github.com/docker/libnetwork"
58 58
 	"github.com/docker/libnetwork/cluster"
59 59
 	nwconfig "github.com/docker/libnetwork/config"
60
-	"github.com/docker/libtrust"
61 60
 	"github.com/pkg/errors"
62 61
 )
63 62
 
... ...
@@ -70,44 +70,40 @@ var (
70 70
 
71 71
 // Daemon holds information about the Docker daemon.
72 72
 type Daemon struct {
73
-	ID                        string
74
-	repository                string
75
-	containers                container.Store
76
-	containersReplica         container.ViewDB
77
-	execCommands              *exec.Store
78
-	downloadManager           *xfer.LayerDownloadManager
79
-	uploadManager             *xfer.LayerUploadManager
80
-	trustKey                  libtrust.PrivateKey
81
-	idIndex                   *truncindex.TruncIndex
82
-	configStore               *config.Config
83
-	statsCollector            *stats.Collector
84
-	defaultLogConfig          containertypes.LogConfig
85
-	RegistryService           registry.Service
86
-	EventsService             *events.Events
87
-	netController             libnetwork.NetworkController
88
-	volumes                   *store.VolumeStore
89
-	discoveryWatcher          discovery.Reloader
90
-	root                      string
91
-	seccompEnabled            bool
92
-	apparmorEnabled           bool
93
-	shutdown                  bool
94
-	idMappings                *idtools.IDMappings
95
-	graphDrivers              map[string]string // By operating system
96
-	referenceStore            refstore.Store
97
-	imageStore                image.Store
98
-	imageRoot                 string
99
-	layerStores               map[string]layer.Store // By operating system
100
-	distributionMetadataStore dmetadata.Store
101
-	PluginStore               *plugin.Store // todo: remove
102
-	pluginManager             *plugin.Manager
103
-	linkIndex                 *linkIndex
104
-	containerd                libcontainerd.Client
105
-	containerdRemote          libcontainerd.Remote
106
-	defaultIsolation          containertypes.Isolation // Default isolation mode on Windows
107
-	clusterProvider           cluster.Provider
108
-	cluster                   Cluster
109
-	genericResources          []swarm.GenericResource
110
-	metricsPluginListener     net.Listener
73
+	ID                string
74
+	repository        string
75
+	containers        container.Store
76
+	containersReplica container.ViewDB
77
+	execCommands      *exec.Store
78
+
79
+	imageService *imageService
80
+
81
+	idIndex          *truncindex.TruncIndex
82
+	configStore      *config.Config
83
+	statsCollector   *stats.Collector
84
+	defaultLogConfig containertypes.LogConfig
85
+	RegistryService  registry.Service
86
+	EventsService    *events.Events
87
+	netController    libnetwork.NetworkController
88
+	volumes          *store.VolumeStore
89
+	discoveryWatcher discovery.Reloader
90
+	root             string
91
+	seccompEnabled   bool
92
+	apparmorEnabled  bool
93
+	shutdown         bool
94
+	idMappings       *idtools.IDMappings
95
+	// TODO: move graphDrivers field to an InfoService
96
+	graphDrivers map[string]string // By operating system
97
+
98
+	PluginStore           *plugin.Store // todo: remove
99
+	pluginManager         *plugin.Manager
100
+	linkIndex             *linkIndex
101
+	containerd            libcontainerd.Client
102
+	defaultIsolation      containertypes.Isolation // Default isolation mode on Windows
103
+	clusterProvider       cluster.Provider
104
+	cluster               Cluster
105
+	genericResources      []swarm.GenericResource
106
+	metricsPluginListener net.Listener
111 107
 
112 108
 	machineMemory uint64
113 109
 
... ...
@@ -162,7 +158,7 @@ func (daemon *Daemon) restore() error {
162 162
 		// Ignore the container if it does not support the current driver being used by the graph
163 163
 		currentDriverForContainerOS := daemon.graphDrivers[container.OS]
164 164
 		if (container.Driver == "" && currentDriverForContainerOS == "aufs") || container.Driver == currentDriverForContainerOS {
165
-			rwlayer, err := daemon.layerStores[container.OS].GetRWLayer(container.ID)
165
+			rwlayer, err := daemon.imageService.GetRWLayerByID(container.ID, container.OS)
166 166
 			if err != nil {
167 167
 				logrus.Errorf("Failed to load container mount %v: %v", id, err)
168 168
 				continue
... ...
@@ -705,7 +701,7 @@ func NewDaemon(config *config.Config, registryService registry.Service, containe
705 705
 	// be set through an environment variable, a daemon start parameter, or chosen through
706 706
 	// initialization of the layerstore through driver priority order for example.
707 707
 	d.graphDrivers = make(map[string]string)
708
-	d.layerStores = make(map[string]layer.Store)
708
+	layerStores := make(map[string]layer.Store)
709 709
 	if runtime.GOOS == "windows" {
710 710
 		d.graphDrivers[runtime.GOOS] = "windowsfilter"
711 711
 		if system.LCOWSupported() {
... ...
@@ -754,7 +750,7 @@ func NewDaemon(config *config.Config, registryService registry.Service, containe
754 754
 	}
755 755
 
756 756
 	for operatingSystem, gd := range d.graphDrivers {
757
-		d.layerStores[operatingSystem], err = layer.NewStoreFromOptions(layer.StoreOptions{
757
+		layerStores[operatingSystem], err = layer.NewStoreFromOptions(layer.StoreOptions{
758 758
 			Root: config.Root,
759 759
 			MetadataStorePathTemplate: filepath.Join(config.Root, "image", "%s", "layerdb"),
760 760
 			GraphDriver:               gd,
... ...
@@ -771,7 +767,7 @@ func NewDaemon(config *config.Config, registryService registry.Service, containe
771 771
 
772 772
 	// As layerstore initialization may set the driver
773 773
 	for os := range d.graphDrivers {
774
-		d.graphDrivers[os] = d.layerStores[os].DriverName()
774
+		d.graphDrivers[os] = layerStores[os].DriverName()
775 775
 	}
776 776
 
777 777
 	// Configure and validate the kernels security support. Note this is a Linux/FreeBSD
... ...
@@ -780,22 +776,17 @@ func NewDaemon(config *config.Config, registryService registry.Service, containe
780 780
 		return nil, err
781 781
 	}
782 782
 
783
-	logrus.Debugf("Max Concurrent Downloads: %d", *config.MaxConcurrentDownloads)
784
-	d.downloadManager = xfer.NewLayerDownloadManager(d.layerStores, *config.MaxConcurrentDownloads)
785
-	logrus.Debugf("Max Concurrent Uploads: %d", *config.MaxConcurrentUploads)
786
-	d.uploadManager = xfer.NewLayerUploadManager(*config.MaxConcurrentUploads)
787
-
788
-	d.imageRoot = filepath.Join(config.Root, "image", d.graphDrivers[runtime.GOOS])
789
-	ifs, err := image.NewFSStoreBackend(filepath.Join(d.imageRoot, "imagedb"))
783
+	imageRoot := filepath.Join(config.Root, "image", d.graphDrivers[runtime.GOOS])
784
+	ifs, err := image.NewFSStoreBackend(filepath.Join(imageRoot, "imagedb"))
790 785
 	if err != nil {
791 786
 		return nil, err
792 787
 	}
793 788
 
794 789
 	lgrMap := make(map[string]image.LayerGetReleaser)
795
-	for os, ls := range d.layerStores {
790
+	for os, ls := range layerStores {
796 791
 		lgrMap[os] = ls
797 792
 	}
798
-	d.imageStore, err = image.NewImageStore(ifs, lgrMap)
793
+	imageStore, err := image.NewImageStore(ifs, lgrMap)
799 794
 	if err != nil {
800 795
 		return nil, err
801 796
 	}
... ...
@@ -829,14 +820,13 @@ func NewDaemon(config *config.Config, registryService registry.Service, containe
829 829
 	// operating systems, the list of graphdrivers available isn't user configurable.
830 830
 	// For backwards compatibility, we just put it under the windowsfilter
831 831
 	// directory regardless.
832
-	refStoreLocation := filepath.Join(d.imageRoot, `repositories.json`)
832
+	refStoreLocation := filepath.Join(imageRoot, `repositories.json`)
833 833
 	rs, err := refstore.NewReferenceStore(refStoreLocation)
834 834
 	if err != nil {
835 835
 		return nil, fmt.Errorf("Couldn't create reference store repository: %s", err)
836 836
 	}
837
-	d.referenceStore = rs
838 837
 
839
-	d.distributionMetadataStore, err = dmetadata.NewFSMetadataStore(filepath.Join(d.imageRoot, "distribution"))
838
+	distributionMetadataStore, err := dmetadata.NewFSMetadataStore(filepath.Join(imageRoot, "distribution"))
840 839
 	if err != nil {
841 840
 		return nil, err
842 841
 	}
... ...
@@ -844,7 +834,7 @@ func NewDaemon(config *config.Config, registryService registry.Service, containe
844 844
 	// No content-addressability migration on Windows as it never supported pre-CA
845 845
 	if runtime.GOOS != "windows" {
846 846
 		migrationStart := time.Now()
847
-		if err := v1.Migrate(config.Root, d.graphDrivers[runtime.GOOS], d.layerStores[runtime.GOOS], d.imageStore, rs, d.distributionMetadataStore); err != nil {
847
+		if err := v1.Migrate(config.Root, d.graphDrivers[runtime.GOOS], layerStores[runtime.GOOS], imageStore, rs, distributionMetadataStore); err != nil {
848 848
 			logrus.Errorf("Graph migration failed: %q. Your old graph data was found to be too inconsistent for upgrading to content-addressable storage. Some of the old data was probably not upgraded. We recommend starting over with a clean storage directory if possible.", err)
849 849
 		}
850 850
 		logrus.Infof("Graph migration to content-addressability took %.2f seconds", time.Since(migrationStart).Seconds())
... ...
@@ -870,7 +860,6 @@ func NewDaemon(config *config.Config, registryService registry.Service, containe
870 870
 		return nil, err
871 871
 	}
872 872
 	d.execCommands = exec.NewStore()
873
-	d.trustKey = trustKey
874 873
 	d.idIndex = truncindex.NewTruncIndex([]string{})
875 874
 	d.statsCollector = d.newStatsCollector(1 * time.Second)
876 875
 
... ...
@@ -880,10 +869,23 @@ func NewDaemon(config *config.Config, registryService registry.Service, containe
880 880
 	d.idMappings = idMappings
881 881
 	d.seccompEnabled = sysInfo.Seccomp
882 882
 	d.apparmorEnabled = sysInfo.AppArmor
883
-	d.containerdRemote = containerdRemote
884 883
 
885 884
 	d.linkIndex = newLinkIndex()
886 885
 
886
+	logrus.Debugf("Max Concurrent Downloads: %d", *config.MaxConcurrentDownloads)
887
+	logrus.Debugf("Max Concurrent Uploads: %d", *config.MaxConcurrentUploads)
888
+	d.imageService = &imageService{
889
+		trustKey:                  trustKey,
890
+		uploadManager:             xfer.NewLayerUploadManager(*config.MaxConcurrentUploads),
891
+		downloadManager:           xfer.NewLayerDownloadManager(layerStores, *config.MaxConcurrentDownloads),
892
+		registryService:           registryService,
893
+		referenceStore:            rs,
894
+		distributionMetadataStore: distributionMetadataStore,
895
+		imageStore:                imageStore,
896
+		eventsService:             eventsService,
897
+		containers:                d.containers,
898
+	}
899
+
887 900
 	go d.execCommandGC()
888 901
 
889 902
 	d.containerd, err = containerdRemote.NewClient(ContainersNamespace, d)
... ...
@@ -1005,7 +1007,7 @@ func (daemon *Daemon) Shutdown() error {
1005 1005
 				logrus.Errorf("Stop container error: %v", err)
1006 1006
 				return
1007 1007
 			}
1008
-			if mountid, err := daemon.layerStores[c.OS].GetMountID(c.ID); err == nil {
1008
+			if mountid, err := daemon.imageService.GetContainerMountID(c.ID, c.OS); err == nil {
1009 1009
 				daemon.cleanupMountsByID(mountid)
1010 1010
 			}
1011 1011
 			logrus.Debugf("container stopped %s", c.ID)
... ...
@@ -1018,13 +1020,7 @@ func (daemon *Daemon) Shutdown() error {
1018 1018
 		}
1019 1019
 	}
1020 1020
 
1021
-	for os, ls := range daemon.layerStores {
1022
-		if ls != nil {
1023
-			if err := ls.Cleanup(); err != nil {
1024
-				logrus.Errorf("Error during layer Store.Cleanup(): %v %s", err, os)
1025
-			}
1026
-		}
1027
-	}
1021
+	daemon.imageService.Cleanup()
1028 1022
 
1029 1023
 	// If we are part of a cluster, clean up cluster's stuff
1030 1024
 	if daemon.clusterProvider != nil {
... ...
@@ -1064,7 +1060,7 @@ func (daemon *Daemon) Mount(container *container.Container) error {
1064 1064
 		if runtime.GOOS != "windows" {
1065 1065
 			daemon.Unmount(container)
1066 1066
 			return fmt.Errorf("Error: driver %s is returning inconsistent paths for container %s ('%s' then '%s')",
1067
-				daemon.GraphDriverName(container.OS), container.ID, container.BaseFS, dir)
1067
+				daemon.imageService.GraphDriverForOS(container.OS), container.ID, container.BaseFS, dir)
1068 1068
 		}
1069 1069
 	}
1070 1070
 	container.BaseFS = dir // TODO: combine these fields
... ...
@@ -1108,11 +1104,6 @@ func (daemon *Daemon) Subnets() ([]net.IPNet, []net.IPNet) {
1108 1108
 	return v4Subnets, v6Subnets
1109 1109
 }
1110 1110
 
1111
-// GraphDriverName returns the name of the graph driver used by the layer.Store
1112
-func (daemon *Daemon) GraphDriverName(os string) string {
1113
-	return daemon.layerStores[os].DriverName()
1114
-}
1115
-
1116 1111
 // prepareTempDir prepares and returns the default directory to use
1117 1112
 // for temporary files.
1118 1113
 // If it doesn't exist, it is created. If it exists, its content is removed.
... ...
@@ -1323,3 +1314,20 @@ func fixMemorySwappiness(resources *containertypes.Resources) {
1323 1323
 func (daemon *Daemon) GetAttachmentStore() *network.AttachmentStore {
1324 1324
 	return &daemon.attachmentStore
1325 1325
 }
1326
+
1327
+// IDMappings returns uid/gid mappings for the builder
1328
+func (daemon *Daemon) IDMappings() *idtools.IDMappings {
1329
+	return daemon.idMappings
1330
+}
1331
+
1332
+func (daemon *Daemon) ImageService() *imageService {
1333
+	return daemon.imageService
1334
+}
1335
+
1336
+// TODO: tmp hack to merge interfaces
1337
+func (daemon *Daemon) BuilderBackend() builder.Backend {
1338
+	return struct {
1339
+		*Daemon
1340
+		*imageService
1341
+	}{daemon, daemon.imageService}
1342
+}
... ...
@@ -10,7 +10,6 @@ import (
10 10
 	"github.com/docker/docker/api/types"
11 11
 	"github.com/docker/docker/container"
12 12
 	"github.com/docker/docker/errdefs"
13
-	"github.com/docker/docker/layer"
14 13
 	"github.com/docker/docker/pkg/system"
15 14
 	"github.com/docker/docker/volume"
16 15
 	volumestore "github.com/docker/docker/volume/store"
... ...
@@ -121,12 +120,11 @@ func (daemon *Daemon) cleanupContainer(container *container.Container, forceRemo
121 121
 	// When container creation fails and `RWLayer` has not been created yet, we
122 122
 	// do not call `ReleaseRWLayer`
123 123
 	if container.RWLayer != nil {
124
-		metadata, err := daemon.layerStores[container.OS].ReleaseRWLayer(container.RWLayer)
125
-		layer.LogReleaseMetadata(metadata)
126
-		if err != nil && err != layer.ErrMountDoesNotExist && !os.IsNotExist(errors.Cause(err)) {
127
-			e := errors.Wrapf(err, "driver %q failed to remove root filesystem for %s", daemon.GraphDriverName(container.OS), container.ID)
128
-			container.SetRemovalError(e)
129
-			return e
124
+		err := daemon.imageService.ReleaseContainerLayer(container.RWLayer, container.OS)
125
+		if err != nil {
126
+			err = errors.Wrapf(err, "container %s", container.ID)
127
+			container.SetRemovalError(err)
128
+			return err
130 129
 		}
131 130
 		container.RWLayer = nil
132 131
 	}
... ...
@@ -8,34 +8,11 @@ import (
8 8
 
9 9
 	"github.com/docker/docker/api/types"
10 10
 	"github.com/docker/docker/api/types/filters"
11
-	"github.com/docker/docker/layer"
12 11
 	"github.com/docker/docker/pkg/directory"
13 12
 	"github.com/docker/docker/volume"
14
-	"github.com/opencontainers/go-digest"
15 13
 	"github.com/sirupsen/logrus"
16 14
 )
17 15
 
18
-func (daemon *Daemon) getLayerRefs() map[layer.ChainID]int {
19
-	tmpImages := daemon.imageStore.Map()
20
-	layerRefs := map[layer.ChainID]int{}
21
-	for id, img := range tmpImages {
22
-		dgst := digest.Digest(id)
23
-		if len(daemon.referenceStore.References(dgst)) == 0 && len(daemon.imageStore.Children(id)) != 0 {
24
-			continue
25
-		}
26
-
27
-		rootFS := *img.RootFS
28
-		rootFS.DiffIDs = nil
29
-		for _, id := range img.RootFS.DiffIDs {
30
-			rootFS.Append(id)
31
-			chid := rootFS.ChainID()
32
-			layerRefs[chid]++
33
-		}
34
-	}
35
-
36
-	return layerRefs
37
-}
38
-
39 16
 // SystemDiskUsage returns information about the daemon data disk usage
40 17
 func (daemon *Daemon) SystemDiskUsage(ctx context.Context) (*types.DiskUsage, error) {
41 18
 	if !atomic.CompareAndSwapInt32(&daemon.diskUsageRunning, 0, 1) {
... ...
@@ -53,7 +30,7 @@ func (daemon *Daemon) SystemDiskUsage(ctx context.Context) (*types.DiskUsage, er
53 53
 	}
54 54
 
55 55
 	// Get all top images with extra attributes
56
-	allImages, err := daemon.Images(filters.NewArgs(), false, true)
56
+	allImages, err := daemon.imageService.Images(filters.NewArgs(), false, true)
57 57
 	if err != nil {
58 58
 		return nil, fmt.Errorf("failed to retrieve image list: %v", err)
59 59
 	}
... ...
@@ -93,28 +70,9 @@ func (daemon *Daemon) SystemDiskUsage(ctx context.Context) (*types.DiskUsage, er
93 93
 		return nil, err
94 94
 	}
95 95
 
96
-	// Get total layers size on disk
97
-	var allLayersSize int64
98
-	layerRefs := daemon.getLayerRefs()
99
-	for _, ls := range daemon.layerStores {
100
-		allLayers := ls.Map()
101
-		for _, l := range allLayers {
102
-			select {
103
-			case <-ctx.Done():
104
-				return nil, ctx.Err()
105
-			default:
106
-				size, err := l.DiffSize()
107
-				if err == nil {
108
-					if _, ok := layerRefs[l.ChainID()]; ok {
109
-						allLayersSize += size
110
-					} else {
111
-						logrus.Warnf("found leaked image layer %v", l.ChainID())
112
-					}
113
-				} else {
114
-					logrus.Warnf("failed to get diff size for layer %v", l.ChainID())
115
-				}
116
-			}
117
-		}
96
+	allLayersSize, err := daemon.imageService.LayerDiskUsage(ctx)
97
+	if err != nil {
98
+		return nil, err
118 99
 	}
119 100
 
120 101
 	return &types.DiskUsage{
... ...
@@ -51,13 +51,13 @@ func (daemon *Daemon) containerExport(container *container.Container) (arch io.R
51 51
 	if !system.IsOSSupported(container.OS) {
52 52
 		return nil, fmt.Errorf("cannot export %s: %s ", container.ID, system.ErrNotSupportedOperatingSystem)
53 53
 	}
54
-	rwlayer, err := daemon.layerStores[container.OS].GetRWLayer(container.ID)
54
+	rwlayer, err := daemon.imageService.GetRWLayerByID(container.ID, container.OS)
55 55
 	if err != nil {
56 56
 		return nil, err
57 57
 	}
58 58
 	defer func() {
59 59
 		if err != nil {
60
-			daemon.layerStores[container.OS].ReleaseRWLayer(rwlayer)
60
+			daemon.imageService.ReleaseContainerLayer(rwlayer, container.OS)
61 61
 		}
62 62
 	}()
63 63
 
... ...
@@ -78,7 +78,7 @@ func (daemon *Daemon) containerExport(container *container.Container) (arch io.R
78 78
 	arch = ioutils.NewReadCloserWrapper(archive, func() error {
79 79
 		err := archive.Close()
80 80
 		rwlayer.Unmount()
81
-		daemon.layerStores[container.OS].ReleaseRWLayer(rwlayer)
81
+		daemon.imageService.ReleaseContainerLayer(rwlayer, container.OS)
82 82
 		return err
83 83
 	})
84 84
 	daemon.LogContainerEvent(container, "export")
85 85
deleted file mode 100644
... ...
@@ -1,45 +0,0 @@
1
-// +build linux freebsd
2
-
3
-package daemon // import "github.com/docker/docker/daemon"
4
-
5
-import (
6
-	"runtime"
7
-
8
-	"github.com/sirupsen/logrus"
9
-)
10
-
11
-// getSize returns the real size & virtual size of the container.
12
-func (daemon *Daemon) getSize(containerID string) (int64, int64) {
13
-	var (
14
-		sizeRw, sizeRootfs int64
15
-		err                error
16
-	)
17
-
18
-	// Safe to index by runtime.GOOS as Unix hosts don't support multiple
19
-	// container operating systems.
20
-	rwlayer, err := daemon.layerStores[runtime.GOOS].GetRWLayer(containerID)
21
-	if err != nil {
22
-		logrus.Errorf("Failed to compute size of container rootfs %v: %v", containerID, err)
23
-		return sizeRw, sizeRootfs
24
-	}
25
-	defer daemon.layerStores[runtime.GOOS].ReleaseRWLayer(rwlayer)
26
-
27
-	sizeRw, err = rwlayer.Size()
28
-	if err != nil {
29
-		logrus.Errorf("Driver %s couldn't return diff size of container %s: %s",
30
-			daemon.GraphDriverName(runtime.GOOS), containerID, err)
31
-		// FIXME: GetSize should return an error. Not changing it now in case
32
-		// there is a side-effect.
33
-		sizeRw = -1
34
-	}
35
-
36
-	if parent := rwlayer.Parent(); parent != nil {
37
-		sizeRootfs, err = parent.Size()
38
-		if err != nil {
39
-			sizeRootfs = -1
40
-		} else if sizeRw != -1 {
41
-			sizeRootfs += sizeRw
42
-		}
43
-	}
44
-	return sizeRw, sizeRootfs
45
-}
... ...
@@ -1,11 +1,25 @@
1 1
 package daemon // import "github.com/docker/docker/daemon"
2 2
 
3 3
 import (
4
+	"context"
4 5
 	"fmt"
6
+	"os"
5 7
 
6 8
 	"github.com/docker/distribution/reference"
9
+	"github.com/docker/docker/api/types/events"
10
+	"github.com/docker/docker/container"
11
+	daemonevents "github.com/docker/docker/daemon/events"
12
+	"github.com/docker/docker/distribution/metadata"
13
+	"github.com/docker/docker/distribution/xfer"
7 14
 	"github.com/docker/docker/errdefs"
8 15
 	"github.com/docker/docker/image"
16
+	"github.com/docker/docker/layer"
17
+	dockerreference "github.com/docker/docker/reference"
18
+	"github.com/docker/docker/registry"
19
+	"github.com/docker/libtrust"
20
+	"github.com/opencontainers/go-digest"
21
+	"github.com/pkg/errors"
22
+	"github.com/sirupsen/logrus"
9 23
 )
10 24
 
11 25
 // errImageDoesNotExist is error returned when no image can be found for a reference.
... ...
@@ -25,7 +39,8 @@ func (e errImageDoesNotExist) NotFound() {}
25 25
 
26 26
 // GetImageIDAndOS returns an image ID and operating system corresponding to the image referred to by
27 27
 // refOrID.
28
-func (daemon *Daemon) GetImageIDAndOS(refOrID string) (image.ID, string, error) {
28
+// called from list.go foldFilter()
29
+func (i imageService) GetImageIDAndOS(refOrID string) (image.ID, string, error) {
29 30
 	ref, err := reference.ParseAnyReference(refOrID)
30 31
 	if err != nil {
31 32
 		return "", "", errdefs.InvalidParameter(err)
... ...
@@ -37,23 +52,23 @@ func (daemon *Daemon) GetImageIDAndOS(refOrID string) (image.ID, string, error)
37 37
 			return "", "", errImageDoesNotExist{ref}
38 38
 		}
39 39
 		id := image.IDFromDigest(digested.Digest())
40
-		if img, err := daemon.imageStore.Get(id); err == nil {
40
+		if img, err := i.imageStore.Get(id); err == nil {
41 41
 			return id, img.OperatingSystem(), nil
42 42
 		}
43 43
 		return "", "", errImageDoesNotExist{ref}
44 44
 	}
45 45
 
46
-	if digest, err := daemon.referenceStore.Get(namedRef); err == nil {
46
+	if digest, err := i.referenceStore.Get(namedRef); err == nil {
47 47
 		// Search the image stores to get the operating system, defaulting to host OS.
48 48
 		id := image.IDFromDigest(digest)
49
-		if img, err := daemon.imageStore.Get(id); err == nil {
49
+		if img, err := i.imageStore.Get(id); err == nil {
50 50
 			return id, img.OperatingSystem(), nil
51 51
 		}
52 52
 	}
53 53
 
54 54
 	// Search based on ID
55
-	if id, err := daemon.imageStore.Search(refOrID); err == nil {
56
-		img, err := daemon.imageStore.Get(id)
55
+	if id, err := i.imageStore.Search(refOrID); err == nil {
56
+		img, err := i.imageStore.Get(id)
57 57
 		if err != nil {
58 58
 			return "", "", errImageDoesNotExist{ref}
59 59
 		}
... ...
@@ -64,10 +79,188 @@ func (daemon *Daemon) GetImageIDAndOS(refOrID string) (image.ID, string, error)
64 64
 }
65 65
 
66 66
 // GetImage returns an image corresponding to the image referred to by refOrID.
67
-func (daemon *Daemon) GetImage(refOrID string) (*image.Image, error) {
68
-	imgID, _, err := daemon.GetImageIDAndOS(refOrID)
67
+func (i *imageService) GetImage(refOrID string) (*image.Image, error) {
68
+	imgID, _, err := i.GetImageIDAndOS(refOrID)
69 69
 	if err != nil {
70 70
 		return nil, err
71 71
 	}
72
-	return daemon.imageStore.Get(imgID)
72
+	return i.imageStore.Get(imgID)
73
+}
74
+
75
+type containerStore interface {
76
+	// used by image delete
77
+	First(container.StoreFilter) *container.Container
78
+	// used by image prune, and image list
79
+	List() []*container.Container
80
+	// TODO: remove, only used for CommitBuildStep
81
+	Get(string) *container.Container
82
+}
83
+
84
+type imageService struct {
85
+	eventsService   *daemonevents.Events
86
+	containers      containerStore
87
+	downloadManager *xfer.LayerDownloadManager
88
+	uploadManager   *xfer.LayerUploadManager
89
+
90
+	// TODO: should accept a trust service instead of a key
91
+	trustKey libtrust.PrivateKey
92
+
93
+	registryService           registry.Service
94
+	referenceStore            dockerreference.Store
95
+	distributionMetadataStore metadata.Store
96
+	imageStore                image.Store
97
+	layerStores               map[string]layer.Store // By operating system
98
+
99
+	pruneRunning int32
100
+}
101
+
102
+// called from info.go
103
+func (i *imageService) CountImages() int {
104
+	return len(i.imageStore.Map())
105
+}
106
+
107
+// called from list.go to filter containers
108
+func (i *imageService) Children(id image.ID) []image.ID {
109
+	return i.imageStore.Children(id)
110
+}
111
+
112
+// TODO: accept an opt struct instead of container?
113
+// called from create.go
114
+func (i *imageService) GetRWLayer(container *container.Container, initFunc layer.MountInit) (layer.RWLayer, error) {
115
+	var layerID layer.ChainID
116
+	if container.ImageID != "" {
117
+		img, err := i.imageStore.Get(container.ImageID)
118
+		if err != nil {
119
+			return nil, err
120
+		}
121
+		layerID = img.RootFS.ChainID()
122
+	}
123
+
124
+	rwLayerOpts := &layer.CreateRWLayerOpts{
125
+		MountLabel: container.MountLabel,
126
+		InitFunc:   initFunc,
127
+		StorageOpt: container.HostConfig.StorageOpt,
128
+	}
129
+
130
+	// Indexing by OS is safe here as validation of OS has already been performed in create() (the only
131
+	// caller), and guaranteed non-nil
132
+	return i.layerStores[container.OS].CreateRWLayer(container.ID, layerID, rwLayerOpts)
133
+}
134
+
135
+// called from daemon.go Daemon.restore(), and Daemon.containerExport()
136
+func (i *imageService) GetRWLayerByID(cid string, os string) (layer.RWLayer, error) {
137
+	return i.layerStores[os].GetRWLayer(cid)
138
+}
139
+
140
+// called from info.go
141
+func (i *imageService) GraphDriverStatuses() map[string][][2]string {
142
+	result := make(map[string][][2]string)
143
+	for os, store := range i.layerStores {
144
+		result[os] = store.DriverStatus()
145
+	}
146
+	return result
147
+}
148
+
149
+// called from daemon.go Daemon.Shutdown(), and Daemon.Cleanup() (cleanup is actually continerCleanup)
150
+func (i *imageService) GetContainerMountID(cid string, os string) (string, error) {
151
+	return i.layerStores[os].GetMountID(cid)
152
+}
153
+
154
+// called from daemon.go Daemon.Shutdown()
155
+func (i *imageService) Cleanup() {
156
+	for os, ls := range i.layerStores {
157
+		if ls != nil {
158
+			if err := ls.Cleanup(); err != nil {
159
+				logrus.Errorf("Error during layer Store.Cleanup(): %v %s", err, os)
160
+			}
161
+		}
162
+	}
163
+}
164
+
165
+// moved from Daemon.GraphDriverName, multiple calls
166
+func (i *imageService) GraphDriverForOS(os string) string {
167
+	return i.layerStores[os].DriverName()
168
+}
169
+
170
+// called from delete.go Daemon.cleanupContainer(), and Daemon.containerExport()
171
+func (i *imageService) ReleaseContainerLayer(rwlayer layer.RWLayer, containerOS string) error {
172
+	metadata, err := i.layerStores[containerOS].ReleaseRWLayer(rwlayer)
173
+	layer.LogReleaseMetadata(metadata)
174
+	if err != nil && err != layer.ErrMountDoesNotExist && !os.IsNotExist(errors.Cause(err)) {
175
+		return errors.Wrapf(err, "driver %q failed to remove root filesystem",
176
+			i.layerStores[containerOS].DriverName())
177
+	}
178
+	return nil
179
+}
180
+
181
+// called from disk_usage.go
182
+func (i *imageService) LayerDiskUsage(ctx context.Context) (int64, error) {
183
+	var allLayersSize int64
184
+	layerRefs := i.getLayerRefs()
185
+	for _, ls := range i.layerStores {
186
+		allLayers := ls.Map()
187
+		for _, l := range allLayers {
188
+			select {
189
+			case <-ctx.Done():
190
+				return allLayersSize, ctx.Err()
191
+			default:
192
+				size, err := l.DiffSize()
193
+				if err == nil {
194
+					if _, ok := layerRefs[l.ChainID()]; ok {
195
+						allLayersSize += size
196
+					} else {
197
+						logrus.Warnf("found leaked image layer %v", l.ChainID())
198
+					}
199
+				} else {
200
+					logrus.Warnf("failed to get diff size for layer %v", l.ChainID())
201
+				}
202
+			}
203
+		}
204
+	}
205
+	return allLayersSize, nil
206
+}
207
+
208
+func (i *imageService) getLayerRefs() map[layer.ChainID]int {
209
+	tmpImages := i.imageStore.Map()
210
+	layerRefs := map[layer.ChainID]int{}
211
+	for id, img := range tmpImages {
212
+		dgst := digest.Digest(id)
213
+		if len(i.referenceStore.References(dgst)) == 0 && len(i.imageStore.Children(id)) != 0 {
214
+			continue
215
+		}
216
+
217
+		rootFS := *img.RootFS
218
+		rootFS.DiffIDs = nil
219
+		for _, id := range img.RootFS.DiffIDs {
220
+			rootFS.Append(id)
221
+			chid := rootFS.ChainID()
222
+			layerRefs[chid]++
223
+		}
224
+	}
225
+
226
+	return layerRefs
227
+}
228
+
229
+// LogImageEvent generates an event related to an image with only the default attributes.
230
+func (i *imageService) LogImageEvent(imageID, refName, action string) {
231
+	i.LogImageEventWithAttributes(imageID, refName, action, map[string]string{})
232
+}
233
+
234
+// LogImageEventWithAttributes generates an event related to an image with specific given attributes.
235
+func (i *imageService) LogImageEventWithAttributes(imageID, refName, action string, attributes map[string]string) {
236
+	img, err := i.GetImage(imageID)
237
+	if err == nil && img.Config != nil {
238
+		// image has not been removed yet.
239
+		// it could be missing if the event is `delete`.
240
+		copyAttributes(attributes, img.Config.Labels)
241
+	}
242
+	if refName != "" {
243
+		attributes["name"] = refName
244
+	}
245
+	actor := events.Actor{
246
+		ID:         imageID,
247
+		Attributes: attributes,
248
+	}
249
+
250
+	i.eventsService.Log(action, events.ImageEventType, actor)
73 251
 }
74 252
new file mode 100644
... ...
@@ -0,0 +1,220 @@
0
+package daemon // import "github.com/docker/docker/daemon"
1
+
2
+import (
3
+	"io"
4
+
5
+	"github.com/docker/distribution/reference"
6
+	"github.com/docker/docker/api/types"
7
+	"github.com/docker/docker/api/types/backend"
8
+	"github.com/docker/docker/builder"
9
+	"github.com/docker/docker/image"
10
+	"github.com/docker/docker/image/cache"
11
+	"github.com/docker/docker/layer"
12
+	"github.com/docker/docker/pkg/containerfs"
13
+	"github.com/docker/docker/pkg/stringid"
14
+	"github.com/docker/docker/pkg/system"
15
+	"github.com/docker/docker/registry"
16
+	"github.com/pkg/errors"
17
+	"golang.org/x/net/context"
18
+)
19
+
20
+type roLayer struct {
21
+	released   bool
22
+	layerStore layer.Store
23
+	roLayer    layer.Layer
24
+}
25
+
26
+func (l *roLayer) DiffID() layer.DiffID {
27
+	if l.roLayer == nil {
28
+		return layer.DigestSHA256EmptyTar
29
+	}
30
+	return l.roLayer.DiffID()
31
+}
32
+
33
+func (l *roLayer) Release() error {
34
+	if l.released {
35
+		return nil
36
+	}
37
+	if l.roLayer != nil {
38
+		metadata, err := l.layerStore.Release(l.roLayer)
39
+		layer.LogReleaseMetadata(metadata)
40
+		if err != nil {
41
+			return errors.Wrap(err, "failed to release ROLayer")
42
+		}
43
+	}
44
+	l.roLayer = nil
45
+	l.released = true
46
+	return nil
47
+}
48
+
49
+func (l *roLayer) NewRWLayer() (builder.RWLayer, error) {
50
+	var chainID layer.ChainID
51
+	if l.roLayer != nil {
52
+		chainID = l.roLayer.ChainID()
53
+	}
54
+
55
+	mountID := stringid.GenerateRandomID()
56
+	newLayer, err := l.layerStore.CreateRWLayer(mountID, chainID, nil)
57
+	if err != nil {
58
+		return nil, errors.Wrap(err, "failed to create rwlayer")
59
+	}
60
+
61
+	rwLayer := &rwLayer{layerStore: l.layerStore, rwLayer: newLayer}
62
+
63
+	fs, err := newLayer.Mount("")
64
+	if err != nil {
65
+		rwLayer.Release()
66
+		return nil, err
67
+	}
68
+
69
+	rwLayer.fs = fs
70
+
71
+	return rwLayer, nil
72
+}
73
+
74
+type rwLayer struct {
75
+	released   bool
76
+	layerStore layer.Store
77
+	rwLayer    layer.RWLayer
78
+	fs         containerfs.ContainerFS
79
+}
80
+
81
+func (l *rwLayer) Root() containerfs.ContainerFS {
82
+	return l.fs
83
+}
84
+
85
+func (l *rwLayer) Commit() (builder.ROLayer, error) {
86
+	stream, err := l.rwLayer.TarStream()
87
+	if err != nil {
88
+		return nil, err
89
+	}
90
+	defer stream.Close()
91
+
92
+	var chainID layer.ChainID
93
+	if parent := l.rwLayer.Parent(); parent != nil {
94
+		chainID = parent.ChainID()
95
+	}
96
+
97
+	newLayer, err := l.layerStore.Register(stream, chainID)
98
+	if err != nil {
99
+		return nil, err
100
+	}
101
+	// TODO: An optimization would be to handle empty layers before returning
102
+	return &roLayer{layerStore: l.layerStore, roLayer: newLayer}, nil
103
+}
104
+
105
+func (l *rwLayer) Release() error {
106
+	if l.released {
107
+		return nil
108
+	}
109
+
110
+	if l.fs != nil {
111
+		if err := l.rwLayer.Unmount(); err != nil {
112
+			return errors.Wrap(err, "failed to unmount RWLayer")
113
+		}
114
+		l.fs = nil
115
+	}
116
+
117
+	metadata, err := l.layerStore.ReleaseRWLayer(l.rwLayer)
118
+	layer.LogReleaseMetadata(metadata)
119
+	if err != nil {
120
+		return errors.Wrap(err, "failed to release RWLayer")
121
+	}
122
+	l.released = true
123
+	return nil
124
+}
125
+
126
+func newROLayerForImage(img *image.Image, layerStore layer.Store) (builder.ROLayer, error) {
127
+	if img == nil || img.RootFS.ChainID() == "" {
128
+		return &roLayer{layerStore: layerStore}, nil
129
+	}
130
+	// Hold a reference to the image layer so that it can't be removed before
131
+	// it is released
132
+	layer, err := layerStore.Get(img.RootFS.ChainID())
133
+	if err != nil {
134
+		return nil, errors.Wrapf(err, "failed to get layer for image %s", img.ImageID())
135
+	}
136
+	return &roLayer{layerStore: layerStore, roLayer: layer}, nil
137
+}
138
+
139
+// TODO: could this use the regular daemon PullImage ?
140
+func (i *imageService) pullForBuilder(ctx context.Context, name string, authConfigs map[string]types.AuthConfig, output io.Writer, os string) (*image.Image, error) {
141
+	ref, err := reference.ParseNormalizedNamed(name)
142
+	if err != nil {
143
+		return nil, err
144
+	}
145
+	ref = reference.TagNameOnly(ref)
146
+
147
+	pullRegistryAuth := &types.AuthConfig{}
148
+	if len(authConfigs) > 0 {
149
+		// The request came with a full auth config, use it
150
+		repoInfo, err := i.registryService.ResolveRepository(ref)
151
+		if err != nil {
152
+			return nil, err
153
+		}
154
+
155
+		resolvedConfig := registry.ResolveAuthConfig(authConfigs, repoInfo.Index)
156
+		pullRegistryAuth = &resolvedConfig
157
+	}
158
+
159
+	if err := i.pullImageWithReference(ctx, ref, os, nil, pullRegistryAuth, output); err != nil {
160
+		return nil, err
161
+	}
162
+	return i.GetImage(name)
163
+}
164
+
165
+// GetImageAndReleasableLayer returns an image and releaseable layer for a reference or ID.
166
+// Every call to GetImageAndReleasableLayer MUST call releasableLayer.Release() to prevent
167
+// leaking of layers.
168
+func (i *imageService) GetImageAndReleasableLayer(ctx context.Context, refOrID string, opts backend.GetImageAndLayerOptions) (builder.Image, builder.ROLayer, error) {
169
+	if refOrID == "" {
170
+		if !system.IsOSSupported(opts.OS) {
171
+			return nil, nil, system.ErrNotSupportedOperatingSystem
172
+		}
173
+		layer, err := newROLayerForImage(nil, i.layerStores[opts.OS])
174
+		return nil, layer, err
175
+	}
176
+
177
+	if opts.PullOption != backend.PullOptionForcePull {
178
+		image, err := i.GetImage(refOrID)
179
+		if err != nil && opts.PullOption == backend.PullOptionNoPull {
180
+			return nil, nil, err
181
+		}
182
+		// TODO: shouldn't we error out if error is different from "not found" ?
183
+		if image != nil {
184
+			if !system.IsOSSupported(image.OperatingSystem()) {
185
+				return nil, nil, system.ErrNotSupportedOperatingSystem
186
+			}
187
+			layer, err := newROLayerForImage(image, i.layerStores[image.OperatingSystem()])
188
+			return image, layer, err
189
+		}
190
+	}
191
+
192
+	image, err := i.pullForBuilder(ctx, refOrID, opts.AuthConfig, opts.Output, opts.OS)
193
+	if err != nil {
194
+		return nil, nil, err
195
+	}
196
+	if !system.IsOSSupported(image.OperatingSystem()) {
197
+		return nil, nil, system.ErrNotSupportedOperatingSystem
198
+	}
199
+	layer, err := newROLayerForImage(image, i.layerStores[image.OperatingSystem()])
200
+	return image, layer, err
201
+}
202
+
203
+// CreateImage creates a new image by adding a config and ID to the image store.
204
+// This is similar to LoadImage() except that it receives JSON encoded bytes of
205
+// an image instead of a tar archive.
206
+func (i *imageService) CreateImage(config []byte, parent string) (builder.Image, error) {
207
+	id, err := i.imageStore.Create(config)
208
+	if err != nil {
209
+		return nil, errors.Wrapf(err, "failed to create image")
210
+	}
211
+
212
+	if parent != "" {
213
+		if err := i.imageStore.SetParent(id, image.ID(parent)); err != nil {
214
+			return nil, errors.Wrapf(err, "failed to set parent %s", parent)
215
+		}
216
+	}
217
+
218
+	return i.imageStore.Get(id)
219
+}
... ...
@@ -9,10 +9,12 @@ import (
9 9
 	"github.com/docker/docker/layer"
10 10
 	"github.com/docker/docker/pkg/ioutils"
11 11
 	"github.com/docker/docker/pkg/system"
12
+	"github.com/pkg/errors"
12 13
 )
13 14
 
14
-func (daemon *Daemon) commitImage(c backend.CommitConfig) (image.ID, error) {
15
-	layerStore, ok := daemon.layerStores[c.ContainerOS]
15
+// CommitImage creates a new image from a commit config
16
+func (i *imageService) CommitImage(c backend.CommitConfig) (image.ID, error) {
17
+	layerStore, ok := i.layerStores[c.ContainerOS]
16 18
 	if !ok {
17 19
 		return "", system.ErrNotSupportedOperatingSystem
18 20
 	}
... ...
@@ -31,7 +33,7 @@ func (daemon *Daemon) commitImage(c backend.CommitConfig) (image.ID, error) {
31 31
 		parent = new(image.Image)
32 32
 		parent.RootFS = image.NewRootFS()
33 33
 	} else {
34
-		parent, err = daemon.imageStore.Get(image.ID(c.ParentImageID))
34
+		parent, err = i.imageStore.Get(image.ID(c.ParentImageID))
35 35
 		if err != nil {
36 36
 			return "", err
37 37
 		}
... ...
@@ -56,13 +58,13 @@ func (daemon *Daemon) commitImage(c backend.CommitConfig) (image.ID, error) {
56 56
 		return "", err
57 57
 	}
58 58
 
59
-	id, err := daemon.imageStore.Create(config)
59
+	id, err := i.imageStore.Create(config)
60 60
 	if err != nil {
61 61
 		return "", err
62 62
 	}
63 63
 
64 64
 	if c.ParentImageID != "" {
65
-		if err := daemon.imageStore.SetParent(id, image.ID(c.ParentImageID)); err != nil {
65
+		if err := i.imageStore.SetParent(id, image.ID(c.ParentImageID)); err != nil {
66 66
 			return "", err
67 67
 		}
68 68
 	}
... ...
@@ -112,13 +114,14 @@ func exportContainerRw(layerStore layer.Store, id, mountLabel string) (arch io.R
112 112
 //   * it doesn't log a container commit event
113 113
 //
114 114
 // This is a temporary shim. Should be removed when builder stops using commit.
115
-func (daemon *Daemon) CommitBuildStep(c backend.CommitConfig) (image.ID, error) {
116
-	container, err := daemon.GetContainer(c.ContainerID)
117
-	if err != nil {
118
-		return "", err
115
+func (i *imageService) CommitBuildStep(c backend.CommitConfig) (image.ID, error) {
116
+	container := i.containers.Get(c.ContainerID)
117
+	if container == nil {
118
+		// TODO: use typed error
119
+		return "", errors.Errorf("container not found: %s", c.ContainerID)
119 120
 	}
120 121
 	c.ContainerMountLabel = container.MountLabel
121 122
 	c.ContainerOS = container.OS
122 123
 	c.ParentImageID = string(container.ImageID)
123
-	return daemon.commitImage(c)
124
+	return i.CommitImage(c)
124 125
 }
... ...
@@ -60,14 +60,11 @@ const (
60 60
 // meaning any delete conflicts will cause the image to not be deleted and the
61 61
 // conflict will not be reported.
62 62
 //
63
-// FIXME: remove ImageDelete's dependency on Daemon, then move to the graph
64
-// package. This would require that we no longer need the daemon to determine
65
-// whether images are being used by a stopped or running container.
66
-func (daemon *Daemon) ImageDelete(imageRef string, force, prune bool) ([]types.ImageDeleteResponseItem, error) {
63
+func (i *imageService) ImageDelete(imageRef string, force, prune bool) ([]types.ImageDeleteResponseItem, error) {
67 64
 	start := time.Now()
68 65
 	records := []types.ImageDeleteResponseItem{}
69 66
 
70
-	imgID, operatingSystem, err := daemon.GetImageIDAndOS(imageRef)
67
+	imgID, operatingSystem, err := i.GetImageIDAndOS(imageRef)
71 68
 	if err != nil {
72 69
 		return nil, err
73 70
 	}
... ...
@@ -75,7 +72,11 @@ func (daemon *Daemon) ImageDelete(imageRef string, force, prune bool) ([]types.I
75 75
 		return nil, errors.Errorf("unable to delete image: %q", system.ErrNotSupportedOperatingSystem)
76 76
 	}
77 77
 
78
-	repoRefs := daemon.referenceStore.References(imgID.Digest())
78
+	repoRefs := i.referenceStore.References(imgID.Digest())
79
+
80
+	using := func(c *container.Container) bool {
81
+		return c.ImageID == imgID
82
+	}
79 83
 
80 84
 	var removedRepositoryRef bool
81 85
 	if !isImageIDPrefix(imgID.String(), imageRef) {
... ...
@@ -84,7 +85,7 @@ func (daemon *Daemon) ImageDelete(imageRef string, force, prune bool) ([]types.I
84 84
 		// true, there are multiple repository references to this
85 85
 		// image, or there are no containers using the given reference.
86 86
 		if !force && isSingleReference(repoRefs) {
87
-			if container := daemon.getContainerUsingImage(imgID); container != nil {
87
+			if container := i.containers.First(using); container != nil {
88 88
 				// If we removed the repository reference then
89 89
 				// this image would remain "dangling" and since
90 90
 				// we really want to avoid that the client must
... ...
@@ -99,17 +100,17 @@ func (daemon *Daemon) ImageDelete(imageRef string, force, prune bool) ([]types.I
99 99
 			return nil, err
100 100
 		}
101 101
 
102
-		parsedRef, err = daemon.removeImageRef(parsedRef)
102
+		parsedRef, err = i.removeImageRef(parsedRef)
103 103
 		if err != nil {
104 104
 			return nil, err
105 105
 		}
106 106
 
107 107
 		untaggedRecord := types.ImageDeleteResponseItem{Untagged: reference.FamiliarString(parsedRef)}
108 108
 
109
-		daemon.LogImageEvent(imgID.String(), imgID.String(), "untag")
109
+		i.LogImageEvent(imgID.String(), imgID.String(), "untag")
110 110
 		records = append(records, untaggedRecord)
111 111
 
112
-		repoRefs = daemon.referenceStore.References(imgID.Digest())
112
+		repoRefs = i.referenceStore.References(imgID.Digest())
113 113
 
114 114
 		// If a tag reference was removed and the only remaining
115 115
 		// references to the same repository are digest references,
... ...
@@ -127,7 +128,7 @@ func (daemon *Daemon) ImageDelete(imageRef string, force, prune bool) ([]types.I
127 127
 				remainingRefs := []reference.Named{}
128 128
 				for _, repoRef := range repoRefs {
129 129
 					if _, repoRefIsCanonical := repoRef.(reference.Canonical); repoRefIsCanonical && parsedRef.Name() == repoRef.Name() {
130
-						if _, err := daemon.removeImageRef(repoRef); err != nil {
130
+						if _, err := i.removeImageRef(repoRef); err != nil {
131 131
 							return records, err
132 132
 						}
133 133
 
... ...
@@ -157,25 +158,25 @@ func (daemon *Daemon) ImageDelete(imageRef string, force, prune bool) ([]types.I
157 157
 			if !force {
158 158
 				c |= conflictSoft &^ conflictActiveReference
159 159
 			}
160
-			if conflict := daemon.checkImageDeleteConflict(imgID, c); conflict != nil {
160
+			if conflict := i.checkImageDeleteConflict(imgID, c); conflict != nil {
161 161
 				return nil, conflict
162 162
 			}
163 163
 
164 164
 			for _, repoRef := range repoRefs {
165
-				parsedRef, err := daemon.removeImageRef(repoRef)
165
+				parsedRef, err := i.removeImageRef(repoRef)
166 166
 				if err != nil {
167 167
 					return nil, err
168 168
 				}
169 169
 
170 170
 				untaggedRecord := types.ImageDeleteResponseItem{Untagged: reference.FamiliarString(parsedRef)}
171 171
 
172
-				daemon.LogImageEvent(imgID.String(), imgID.String(), "untag")
172
+				i.LogImageEvent(imgID.String(), imgID.String(), "untag")
173 173
 				records = append(records, untaggedRecord)
174 174
 			}
175 175
 		}
176 176
 	}
177 177
 
178
-	if err := daemon.imageDeleteHelper(imgID, &records, force, prune, removedRepositoryRef); err != nil {
178
+	if err := i.imageDeleteHelper(imgID, &records, force, prune, removedRepositoryRef); err != nil {
179 179
 		return nil, err
180 180
 	}
181 181
 
... ...
@@ -223,26 +224,18 @@ func isImageIDPrefix(imageID, possiblePrefix string) bool {
223 223
 	return false
224 224
 }
225 225
 
226
-// getContainerUsingImage returns a container that was created using the given
227
-// imageID. Returns nil if there is no such container.
228
-func (daemon *Daemon) getContainerUsingImage(imageID image.ID) *container.Container {
229
-	return daemon.containers.First(func(c *container.Container) bool {
230
-		return c.ImageID == imageID
231
-	})
232
-}
233
-
234 226
 // removeImageRef attempts to parse and remove the given image reference from
235 227
 // this daemon's store of repository tag/digest references. The given
236 228
 // repositoryRef must not be an image ID but a repository name followed by an
237 229
 // optional tag or digest reference. If tag or digest is omitted, the default
238 230
 // tag is used. Returns the resolved image reference and an error.
239
-func (daemon *Daemon) removeImageRef(ref reference.Named) (reference.Named, error) {
231
+func (i *imageService) removeImageRef(ref reference.Named) (reference.Named, error) {
240 232
 	ref = reference.TagNameOnly(ref)
241 233
 
242 234
 	// Ignore the boolean value returned, as far as we're concerned, this
243 235
 	// is an idempotent operation and it's okay if the reference didn't
244 236
 	// exist in the first place.
245
-	_, err := daemon.referenceStore.Delete(ref)
237
+	_, err := i.referenceStore.Delete(ref)
246 238
 
247 239
 	return ref, err
248 240
 }
... ...
@@ -252,18 +245,18 @@ func (daemon *Daemon) removeImageRef(ref reference.Named) (reference.Named, erro
252 252
 // on the first encountered error. Removed references are logged to this
253 253
 // daemon's event service. An "Untagged" types.ImageDeleteResponseItem is added to the
254 254
 // given list of records.
255
-func (daemon *Daemon) removeAllReferencesToImageID(imgID image.ID, records *[]types.ImageDeleteResponseItem) error {
256
-	imageRefs := daemon.referenceStore.References(imgID.Digest())
255
+func (i *imageService) removeAllReferencesToImageID(imgID image.ID, records *[]types.ImageDeleteResponseItem) error {
256
+	imageRefs := i.referenceStore.References(imgID.Digest())
257 257
 
258 258
 	for _, imageRef := range imageRefs {
259
-		parsedRef, err := daemon.removeImageRef(imageRef)
259
+		parsedRef, err := i.removeImageRef(imageRef)
260 260
 		if err != nil {
261 261
 			return err
262 262
 		}
263 263
 
264 264
 		untaggedRecord := types.ImageDeleteResponseItem{Untagged: reference.FamiliarString(parsedRef)}
265 265
 
266
-		daemon.LogImageEvent(imgID.String(), imgID.String(), "untag")
266
+		i.LogImageEvent(imgID.String(), imgID.String(), "untag")
267 267
 		*records = append(*records, untaggedRecord)
268 268
 	}
269 269
 
... ...
@@ -303,15 +296,15 @@ func (idc *imageDeleteConflict) Conflict() {}
303 303
 // conflict is encountered, it will be returned immediately without deleting
304 304
 // the image. If quiet is true, any encountered conflicts will be ignored and
305 305
 // the function will return nil immediately without deleting the image.
306
-func (daemon *Daemon) imageDeleteHelper(imgID image.ID, records *[]types.ImageDeleteResponseItem, force, prune, quiet bool) error {
306
+func (i *imageService) imageDeleteHelper(imgID image.ID, records *[]types.ImageDeleteResponseItem, force, prune, quiet bool) error {
307 307
 	// First, determine if this image has any conflicts. Ignore soft conflicts
308 308
 	// if force is true.
309 309
 	c := conflictHard
310 310
 	if !force {
311 311
 		c |= conflictSoft
312 312
 	}
313
-	if conflict := daemon.checkImageDeleteConflict(imgID, c); conflict != nil {
314
-		if quiet && (!daemon.imageIsDangling(imgID) || conflict.used) {
313
+	if conflict := i.checkImageDeleteConflict(imgID, c); conflict != nil {
314
+		if quiet && (!i.imageIsDangling(imgID) || conflict.used) {
315 315
 			// Ignore conflicts UNLESS the image is "dangling" or not being used in
316 316
 			// which case we want the user to know.
317 317
 			return nil
... ...
@@ -322,23 +315,23 @@ func (daemon *Daemon) imageDeleteHelper(imgID image.ID, records *[]types.ImageDe
322 322
 		return conflict
323 323
 	}
324 324
 
325
-	parent, err := daemon.imageStore.GetParent(imgID)
325
+	parent, err := i.imageStore.GetParent(imgID)
326 326
 	if err != nil {
327 327
 		// There may be no parent
328 328
 		parent = ""
329 329
 	}
330 330
 
331 331
 	// Delete all repository tag/digest references to this image.
332
-	if err := daemon.removeAllReferencesToImageID(imgID, records); err != nil {
332
+	if err := i.removeAllReferencesToImageID(imgID, records); err != nil {
333 333
 		return err
334 334
 	}
335 335
 
336
-	removedLayers, err := daemon.imageStore.Delete(imgID)
336
+	removedLayers, err := i.imageStore.Delete(imgID)
337 337
 	if err != nil {
338 338
 		return err
339 339
 	}
340 340
 
341
-	daemon.LogImageEvent(imgID.String(), imgID.String(), "delete")
341
+	i.LogImageEvent(imgID.String(), imgID.String(), "delete")
342 342
 	*records = append(*records, types.ImageDeleteResponseItem{Deleted: imgID.String()})
343 343
 	for _, removedLayer := range removedLayers {
344 344
 		*records = append(*records, types.ImageDeleteResponseItem{Deleted: removedLayer.ChainID.String()})
... ...
@@ -353,7 +346,7 @@ func (daemon *Daemon) imageDeleteHelper(imgID image.ID, records *[]types.ImageDe
353 353
 	// either running or stopped).
354 354
 	// Do not force prunings, but do so quietly (stopping on any encountered
355 355
 	// conflicts).
356
-	return daemon.imageDeleteHelper(parent, records, false, true, true)
356
+	return i.imageDeleteHelper(parent, records, false, true, true)
357 357
 }
358 358
 
359 359
 // checkImageDeleteConflict determines whether there are any conflicts
... ...
@@ -362,9 +355,9 @@ func (daemon *Daemon) imageDeleteHelper(imgID image.ID, records *[]types.ImageDe
362 362
 // using the image. A soft conflict is any tags/digest referencing the given
363 363
 // image or any stopped container using the image. If ignoreSoftConflicts is
364 364
 // true, this function will not check for soft conflict conditions.
365
-func (daemon *Daemon) checkImageDeleteConflict(imgID image.ID, mask conflictType) *imageDeleteConflict {
365
+func (i *imageService) checkImageDeleteConflict(imgID image.ID, mask conflictType) *imageDeleteConflict {
366 366
 	// Check if the image has any descendant images.
367
-	if mask&conflictDependentChild != 0 && len(daemon.imageStore.Children(imgID)) > 0 {
367
+	if mask&conflictDependentChild != 0 && len(i.imageStore.Children(imgID)) > 0 {
368 368
 		return &imageDeleteConflict{
369 369
 			hard:    true,
370 370
 			imgID:   imgID,
... ...
@@ -377,7 +370,7 @@ func (daemon *Daemon) checkImageDeleteConflict(imgID image.ID, mask conflictType
377 377
 		running := func(c *container.Container) bool {
378 378
 			return c.IsRunning() && c.ImageID == imgID
379 379
 		}
380
-		if container := daemon.containers.First(running); container != nil {
380
+		if container := i.containers.First(running); container != nil {
381 381
 			return &imageDeleteConflict{
382 382
 				imgID:   imgID,
383 383
 				hard:    true,
... ...
@@ -388,7 +381,7 @@ func (daemon *Daemon) checkImageDeleteConflict(imgID image.ID, mask conflictType
388 388
 	}
389 389
 
390 390
 	// Check if any repository tags/digest reference this image.
391
-	if mask&conflictActiveReference != 0 && len(daemon.referenceStore.References(imgID.Digest())) > 0 {
391
+	if mask&conflictActiveReference != 0 && len(i.referenceStore.References(imgID.Digest())) > 0 {
392 392
 		return &imageDeleteConflict{
393 393
 			imgID:   imgID,
394 394
 			message: "image is referenced in multiple repositories",
... ...
@@ -400,7 +393,7 @@ func (daemon *Daemon) checkImageDeleteConflict(imgID image.ID, mask conflictType
400 400
 		stopped := func(c *container.Container) bool {
401 401
 			return !c.IsRunning() && c.ImageID == imgID
402 402
 		}
403
-		if container := daemon.containers.First(stopped); container != nil {
403
+		if container := i.containers.First(stopped); container != nil {
404 404
 			return &imageDeleteConflict{
405 405
 				imgID:   imgID,
406 406
 				used:    true,
... ...
@@ -415,6 +408,6 @@ func (daemon *Daemon) checkImageDeleteConflict(imgID image.ID, mask conflictType
415 415
 // imageIsDangling returns whether the given image is "dangling" which means
416 416
 // that there are no repository references to the given image and it has no
417 417
 // child images.
418
-func (daemon *Daemon) imageIsDangling(imgID image.ID) bool {
419
-	return !(len(daemon.referenceStore.References(imgID.Digest())) > 0 || len(daemon.imageStore.Children(imgID)) > 0)
418
+func (i *imageService) imageIsDangling(imgID image.ID) bool {
419
+	return !(len(i.referenceStore.References(imgID.Digest())) > 0 || len(i.imageStore.Children(imgID)) > 0)
420 420
 }
... ...
@@ -11,15 +11,15 @@ import (
11 11
 // stream. All images with the given tag and all versions containing
12 12
 // the same tag are exported. names is the set of tags to export, and
13 13
 // outStream is the writer which the images are written to.
14
-func (daemon *Daemon) ExportImage(names []string, outStream io.Writer) error {
15
-	imageExporter := tarexport.NewTarExporter(daemon.imageStore, daemon.layerStores, daemon.referenceStore, daemon)
14
+func (i *imageService) ExportImage(names []string, outStream io.Writer) error {
15
+	imageExporter := tarexport.NewTarExporter(i.imageStore, i.layerStores, i.referenceStore, i)
16 16
 	return imageExporter.Save(names, outStream)
17 17
 }
18 18
 
19 19
 // LoadImage uploads a set of images into the repository. This is the
20 20
 // complement of ImageExport.  The input stream is an uncompressed tar
21 21
 // ball containing images and metadata.
22
-func (daemon *Daemon) LoadImage(inTar io.ReadCloser, outStream io.Writer, quiet bool) error {
23
-	imageExporter := tarexport.NewTarExporter(daemon.imageStore, daemon.layerStores, daemon.referenceStore, daemon)
22
+func (i *imageService) LoadImage(inTar io.ReadCloser, outStream io.Writer, quiet bool) error {
23
+	imageExporter := tarexport.NewTarExporter(i.imageStore, i.layerStores, i.referenceStore, i)
24 24
 	return imageExporter.Load(inTar, outStream, quiet)
25 25
 }
26 26
new file mode 100644
... ...
@@ -0,0 +1,45 @@
0
+// +build linux freebsd
1
+
2
+package daemon // import "github.com/docker/docker/daemon"
3
+
4
+import (
5
+	"runtime"
6
+
7
+	"github.com/sirupsen/logrus"
8
+)
9
+
10
+// getSize returns the real size & virtual size of the container.
11
+func (i *imageService) GetContainerLayerSize(containerID string) (int64, int64) {
12
+	var (
13
+		sizeRw, sizeRootfs int64
14
+		err                error
15
+	)
16
+
17
+	// Safe to index by runtime.GOOS as Unix hosts don't support multiple
18
+	// container operating systems.
19
+	rwlayer, err := i.layerStores[runtime.GOOS].GetRWLayer(containerID)
20
+	if err != nil {
21
+		logrus.Errorf("Failed to compute size of container rootfs %v: %v", containerID, err)
22
+		return sizeRw, sizeRootfs
23
+	}
24
+	defer i.layerStores[runtime.GOOS].ReleaseRWLayer(rwlayer)
25
+
26
+	sizeRw, err = rwlayer.Size()
27
+	if err != nil {
28
+		logrus.Errorf("Driver %s couldn't return diff size of container %s: %s",
29
+			i.layerStores[runtime.GOOS].DriverName(), containerID, err)
30
+		// FIXME: GetSize should return an error. Not changing it now in case
31
+		// there is a side-effect.
32
+		sizeRw = -1
33
+	}
34
+
35
+	if parent := rwlayer.Parent(); parent != nil {
36
+		sizeRootfs, err = parent.Size()
37
+		if err != nil {
38
+			sizeRootfs = -1
39
+		} else if sizeRw != -1 {
40
+			sizeRootfs += sizeRw
41
+		}
42
+	}
43
+	return sizeRw, sizeRootfs
44
+}
... ...
@@ -11,9 +11,9 @@ import (
11 11
 
12 12
 // ImageHistory returns a slice of ImageHistory structures for the specified image
13 13
 // name by walking the image lineage.
14
-func (daemon *Daemon) ImageHistory(name string) ([]*image.HistoryResponseItem, error) {
14
+func (i *imageService) ImageHistory(name string) ([]*image.HistoryResponseItem, error) {
15 15
 	start := time.Now()
16
-	img, err := daemon.GetImage(name)
16
+	img, err := i.GetImage(name)
17 17
 	if err != nil {
18 18
 		return nil, err
19 19
 	}
... ...
@@ -33,12 +33,12 @@ func (daemon *Daemon) ImageHistory(name string) ([]*image.HistoryResponseItem, e
33 33
 			}
34 34
 
35 35
 			rootFS.Append(img.RootFS.DiffIDs[layerCounter])
36
-			l, err := daemon.layerStores[img.OperatingSystem()].Get(rootFS.ChainID())
36
+			l, err := i.layerStores[img.OperatingSystem()].Get(rootFS.ChainID())
37 37
 			if err != nil {
38 38
 				return nil, err
39 39
 			}
40 40
 			layerSize, err = l.DiffSize()
41
-			layer.ReleaseAndLog(daemon.layerStores[img.OperatingSystem()], l)
41
+			layer.ReleaseAndLog(i.layerStores[img.OperatingSystem()], l)
42 42
 			if err != nil {
43 43
 				return nil, err
44 44
 			}
... ...
@@ -62,7 +62,7 @@ func (daemon *Daemon) ImageHistory(name string) ([]*image.HistoryResponseItem, e
62 62
 		h.ID = id.String()
63 63
 
64 64
 		var tags []string
65
-		for _, r := range daemon.referenceStore.References(id.Digest()) {
65
+		for _, r := range i.referenceStore.References(id.Digest()) {
66 66
 			if _, ok := r.(reference.NamedTagged); ok {
67 67
 				tags = append(tags, reference.FamiliarString(r))
68 68
 			}
... ...
@@ -74,7 +74,7 @@ func (daemon *Daemon) ImageHistory(name string) ([]*image.HistoryResponseItem, e
74 74
 		if id == "" {
75 75
 			break
76 76
 		}
77
-		histImg, err = daemon.GetImage(id.String())
77
+		histImg, err = i.GetImage(id.String())
78 78
 		if err != nil {
79 79
 			break
80 80
 		}
81 81
new file mode 100644
... ...
@@ -0,0 +1,138 @@
0
+package daemon // import "github.com/docker/docker/daemon"
1
+
2
+import (
3
+	"encoding/json"
4
+	"io"
5
+	"net/http"
6
+	"net/url"
7
+	"runtime"
8
+	"strings"
9
+	"time"
10
+
11
+	"github.com/docker/distribution/reference"
12
+	"github.com/docker/docker/api/types/container"
13
+	"github.com/docker/docker/builder/dockerfile"
14
+	"github.com/docker/docker/builder/remotecontext"
15
+	"github.com/docker/docker/dockerversion"
16
+	"github.com/docker/docker/errdefs"
17
+	"github.com/docker/docker/image"
18
+	"github.com/docker/docker/layer"
19
+	"github.com/docker/docker/pkg/archive"
20
+	"github.com/docker/docker/pkg/progress"
21
+	"github.com/docker/docker/pkg/streamformatter"
22
+	"github.com/pkg/errors"
23
+)
24
+
25
+// ImportImage imports an image, getting the archived layer data either from
26
+// inConfig (if src is "-"), or from a URI specified in src. Progress output is
27
+// written to outStream. Repository and tag names can optionally be given in
28
+// the repo and tag arguments, respectively.
29
+func (i *imageService) ImportImage(src string, repository, os string, tag string, msg string, inConfig io.ReadCloser, outStream io.Writer, changes []string) error {
30
+	var (
31
+		rc     io.ReadCloser
32
+		resp   *http.Response
33
+		newRef reference.Named
34
+	)
35
+
36
+	// Default the operating system if not supplied.
37
+	if os == "" {
38
+		os = runtime.GOOS
39
+	}
40
+
41
+	if repository != "" {
42
+		var err error
43
+		newRef, err = reference.ParseNormalizedNamed(repository)
44
+		if err != nil {
45
+			return errdefs.InvalidParameter(err)
46
+		}
47
+		if _, isCanonical := newRef.(reference.Canonical); isCanonical {
48
+			return errdefs.InvalidParameter(errors.New("cannot import digest reference"))
49
+		}
50
+
51
+		if tag != "" {
52
+			newRef, err = reference.WithTag(newRef, tag)
53
+			if err != nil {
54
+				return errdefs.InvalidParameter(err)
55
+			}
56
+		}
57
+	}
58
+
59
+	config, err := dockerfile.BuildFromConfig(&container.Config{}, changes, os)
60
+	if err != nil {
61
+		return err
62
+	}
63
+	if src == "-" {
64
+		rc = inConfig
65
+	} else {
66
+		inConfig.Close()
67
+		if len(strings.Split(src, "://")) == 1 {
68
+			src = "http://" + src
69
+		}
70
+		u, err := url.Parse(src)
71
+		if err != nil {
72
+			return errdefs.InvalidParameter(err)
73
+		}
74
+
75
+		resp, err = remotecontext.GetWithStatusError(u.String())
76
+		if err != nil {
77
+			return err
78
+		}
79
+		outStream.Write(streamformatter.FormatStatus("", "Downloading from %s", u))
80
+		progressOutput := streamformatter.NewJSONProgressOutput(outStream, true)
81
+		rc = progress.NewProgressReader(resp.Body, progressOutput, resp.ContentLength, "", "Importing")
82
+	}
83
+
84
+	defer rc.Close()
85
+	if len(msg) == 0 {
86
+		msg = "Imported from " + src
87
+	}
88
+
89
+	inflatedLayerData, err := archive.DecompressStream(rc)
90
+	if err != nil {
91
+		return err
92
+	}
93
+	l, err := i.layerStores[os].Register(inflatedLayerData, "")
94
+	if err != nil {
95
+		return err
96
+	}
97
+	defer layer.ReleaseAndLog(i.layerStores[os], l)
98
+
99
+	created := time.Now().UTC()
100
+	imgConfig, err := json.Marshal(&image.Image{
101
+		V1Image: image.V1Image{
102
+			DockerVersion: dockerversion.Version,
103
+			Config:        config,
104
+			Architecture:  runtime.GOARCH,
105
+			OS:            os,
106
+			Created:       created,
107
+			Comment:       msg,
108
+		},
109
+		RootFS: &image.RootFS{
110
+			Type:    "layers",
111
+			DiffIDs: []layer.DiffID{l.DiffID()},
112
+		},
113
+		History: []image.History{{
114
+			Created: created,
115
+			Comment: msg,
116
+		}},
117
+	})
118
+	if err != nil {
119
+		return err
120
+	}
121
+
122
+	id, err := i.imageStore.Create(imgConfig)
123
+	if err != nil {
124
+		return err
125
+	}
126
+
127
+	// FIXME: connect with commit code and call refstore directly
128
+	if newRef != nil {
129
+		if err := i.TagImageWithReference(id, newRef); err != nil {
130
+			return err
131
+		}
132
+	}
133
+
134
+	i.LogImageEvent(id.String(), id.String(), "import")
135
+	outStream.Write(streamformatter.FormatStatus("", id.String()))
136
+	return nil
137
+}
... ...
@@ -13,15 +13,15 @@ import (
13 13
 
14 14
 // LookupImage looks up an image by name and returns it as an ImageInspect
15 15
 // structure.
16
-func (daemon *Daemon) LookupImage(name string) (*types.ImageInspect, error) {
17
-	img, err := daemon.GetImage(name)
16
+func (i *imageService) LookupImage(name string) (*types.ImageInspect, error) {
17
+	img, err := i.GetImage(name)
18 18
 	if err != nil {
19 19
 		return nil, errors.Wrapf(err, "no such image: %s", name)
20 20
 	}
21 21
 	if !system.IsOSSupported(img.OperatingSystem()) {
22 22
 		return nil, system.ErrNotSupportedOperatingSystem
23 23
 	}
24
-	refs := daemon.referenceStore.References(img.ID().Digest())
24
+	refs := i.referenceStore.References(img.ID().Digest())
25 25
 	repoTags := []string{}
26 26
 	repoDigests := []string{}
27 27
 	for _, ref := range refs {
... ...
@@ -37,11 +37,11 @@ func (daemon *Daemon) LookupImage(name string) (*types.ImageInspect, error) {
37 37
 	var layerMetadata map[string]string
38 38
 	layerID := img.RootFS.ChainID()
39 39
 	if layerID != "" {
40
-		l, err := daemon.layerStores[img.OperatingSystem()].Get(layerID)
40
+		l, err := i.layerStores[img.OperatingSystem()].Get(layerID)
41 41
 		if err != nil {
42 42
 			return nil, err
43 43
 		}
44
-		defer layer.ReleaseAndLog(daemon.layerStores[img.OperatingSystem()], l)
44
+		defer layer.ReleaseAndLog(i.layerStores[img.OperatingSystem()], l)
45 45
 		size, err = l.Size()
46 46
 		if err != nil {
47 47
 			return nil, err
... ...
@@ -58,7 +58,7 @@ func (daemon *Daemon) LookupImage(name string) (*types.ImageInspect, error) {
58 58
 		comment = img.History[len(img.History)-1].Comment
59 59
 	}
60 60
 
61
-	lastUpdated, err := daemon.imageStore.GetLastUpdated(img.ID())
61
+	lastUpdated, err := i.imageStore.GetLastUpdated(img.ID())
62 62
 	if err != nil {
63 63
 		return nil, err
64 64
 	}
... ...
@@ -86,7 +86,7 @@ func (daemon *Daemon) LookupImage(name string) (*types.ImageInspect, error) {
86 86
 		},
87 87
 	}
88 88
 
89
-	imageInspect.GraphDriver.Name = daemon.GraphDriverName(img.OperatingSystem())
89
+	imageInspect.GraphDriver.Name = i.GraphDriverForOS(img.OperatingSystem())
90 90
 	imageInspect.GraphDriver.Data = layerMetadata
91 91
 
92 92
 	return imageInspect, nil
... ...
@@ -22,11 +22,11 @@ var imagesAcceptedFilters = map[string]bool{
22 22
 }
23 23
 
24 24
 // ImagesPrune removes unused images
25
-func (daemon *Daemon) ImagesPrune(ctx context.Context, pruneFilters filters.Args) (*types.ImagesPruneReport, error) {
26
-	if !atomic.CompareAndSwapInt32(&daemon.pruneRunning, 0, 1) {
25
+func (i *imageService) ImagesPrune(ctx context.Context, pruneFilters filters.Args) (*types.ImagesPruneReport, error) {
26
+	if !atomic.CompareAndSwapInt32(&i.pruneRunning, 0, 1) {
27 27
 		return nil, errPruneRunning
28 28
 	}
29
-	defer atomic.StoreInt32(&daemon.pruneRunning, 0)
29
+	defer atomic.StoreInt32(&i.pruneRunning, 0)
30 30
 
31 31
 	// make sure that only accepted filters have been received
32 32
 	err := pruneFilters.Validate(imagesAcceptedFilters)
... ...
@@ -52,14 +52,14 @@ func (daemon *Daemon) ImagesPrune(ctx context.Context, pruneFilters filters.Args
52 52
 
53 53
 	var allImages map[image.ID]*image.Image
54 54
 	if danglingOnly {
55
-		allImages = daemon.imageStore.Heads()
55
+		allImages = i.imageStore.Heads()
56 56
 	} else {
57
-		allImages = daemon.imageStore.Map()
57
+		allImages = i.imageStore.Map()
58 58
 	}
59 59
 
60 60
 	// Filter intermediary images and get their unique size
61 61
 	allLayers := make(map[layer.ChainID]layer.Layer)
62
-	for _, ls := range daemon.layerStores {
62
+	for _, ls := range i.layerStores {
63 63
 		for k, v := range ls.Map() {
64 64
 			allLayers[k] = v
65 65
 		}
... ...
@@ -71,7 +71,7 @@ func (daemon *Daemon) ImagesPrune(ctx context.Context, pruneFilters filters.Args
71 71
 			return nil, ctx.Err()
72 72
 		default:
73 73
 			dgst := digest.Digest(id)
74
-			if len(daemon.referenceStore.References(dgst)) == 0 && len(daemon.imageStore.Children(id)) != 0 {
74
+			if len(i.referenceStore.References(dgst)) == 0 && len(i.imageStore.Children(id)) != 0 {
75 75
 				continue
76 76
 			}
77 77
 			if !until.IsZero() && img.Created.After(until) {
... ...
@@ -96,7 +96,7 @@ deleteImagesLoop:
96 96
 		}
97 97
 
98 98
 		deletedImages := []types.ImageDeleteResponseItem{}
99
-		refs := daemon.referenceStore.References(id.Digest())
99
+		refs := i.referenceStore.References(dgst)
100 100
 		if len(refs) > 0 {
101 101
 			shouldDelete := !danglingOnly
102 102
 			if !shouldDelete {
... ...
@@ -114,7 +114,7 @@ deleteImagesLoop:
114 114
 
115 115
 			if shouldDelete {
116 116
 				for _, ref := range refs {
117
-					imgDel, err := daemon.ImageDelete(ref.String(), false, true)
117
+					imgDel, err := i.ImageDelete(ref.String(), false, true)
118 118
 					if imageDeleteFailed(ref.String(), err) {
119 119
 						continue
120 120
 					}
... ...
@@ -123,7 +123,7 @@ deleteImagesLoop:
123 123
 			}
124 124
 		} else {
125 125
 			hex := id.Digest().Hex()
126
-			imgDel, err := daemon.ImageDelete(hex, false, true)
126
+			imgDel, err := i.ImageDelete(hex, false, true)
127 127
 			if imageDeleteFailed(hex, err) {
128 128
 				continue
129 129
 			}
... ...
@@ -19,7 +19,7 @@ import (
19 19
 
20 20
 // PullImage initiates a pull operation. image is the repository name to pull, and
21 21
 // tag may be either empty, or indicate a specific tag to pull.
22
-func (daemon *Daemon) PullImage(ctx context.Context, image, tag, os string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error {
22
+func (i *imageService) PullImage(ctx context.Context, image, tag, os string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error {
23 23
 	// Special case: "pull -a" may send an image name with a
24 24
 	// trailing :. This is ugly, but let's not break API
25 25
 	// compatibility.
... ...
@@ -44,10 +44,10 @@ func (daemon *Daemon) PullImage(ctx context.Context, image, tag, os string, meta
44 44
 		}
45 45
 	}
46 46
 
47
-	return daemon.pullImageWithReference(ctx, ref, os, metaHeaders, authConfig, outStream)
47
+	return i.pullImageWithReference(ctx, ref, os, metaHeaders, authConfig, outStream)
48 48
 }
49 49
 
50
-func (daemon *Daemon) pullImageWithReference(ctx context.Context, ref reference.Named, os string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error {
50
+func (i *imageService) pullImageWithReference(ctx context.Context, ref reference.Named, os string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error {
51 51
 	// Include a buffer so that slow client connections don't affect
52 52
 	// transfer performance.
53 53
 	progressChan := make(chan progress.Progress, 100)
... ...
@@ -71,13 +71,13 @@ func (daemon *Daemon) pullImageWithReference(ctx context.Context, ref reference.
71 71
 			MetaHeaders:      metaHeaders,
72 72
 			AuthConfig:       authConfig,
73 73
 			ProgressOutput:   progress.ChanOutput(progressChan),
74
-			RegistryService:  daemon.RegistryService,
75
-			ImageEventLogger: daemon.LogImageEvent,
76
-			MetadataStore:    daemon.distributionMetadataStore,
77
-			ImageStore:       distribution.NewImageConfigStoreFromStore(daemon.imageStore),
78
-			ReferenceStore:   daemon.referenceStore,
74
+			RegistryService:  i.registryService,
75
+			ImageEventLogger: i.LogImageEvent,
76
+			MetadataStore:    i.distributionMetadataStore,
77
+			ImageStore:       distribution.NewImageConfigStoreFromStore(i.imageStore),
78
+			ReferenceStore:   i.referenceStore,
79 79
 		},
80
-		DownloadManager: daemon.downloadManager,
80
+		DownloadManager: i.downloadManager,
81 81
 		Schema2Types:    distribution.ImageTypes,
82 82
 		OS:              os,
83 83
 	}
... ...
@@ -89,9 +89,9 @@ func (daemon *Daemon) pullImageWithReference(ctx context.Context, ref reference.
89 89
 }
90 90
 
91 91
 // GetRepository returns a repository from the registry.
92
-func (daemon *Daemon) GetRepository(ctx context.Context, ref reference.Named, authConfig *types.AuthConfig) (dist.Repository, bool, error) {
92
+func (i *imageService) GetRepository(ctx context.Context, ref reference.Named, authConfig *types.AuthConfig) (dist.Repository, bool, error) {
93 93
 	// get repository info
94
-	repoInfo, err := daemon.RegistryService.ResolveRepository(ref)
94
+	repoInfo, err := i.registryService.ResolveRepository(ref)
95 95
 	if err != nil {
96 96
 		return nil, false, err
97 97
 	}
... ...
@@ -101,7 +101,7 @@ func (daemon *Daemon) GetRepository(ctx context.Context, ref reference.Named, au
101 101
 	}
102 102
 
103 103
 	// get endpoints
104
-	endpoints, err := daemon.RegistryService.LookupPullEndpoints(reference.Domain(repoInfo.Name))
104
+	endpoints, err := i.registryService.LookupPullEndpoints(reference.Domain(repoInfo.Name))
105 105
 	if err != nil {
106 106
 		return nil, false, err
107 107
 	}
... ...
@@ -13,7 +13,7 @@ import (
13 13
 )
14 14
 
15 15
 // PushImage initiates a push operation on the repository named localName.
16
-func (daemon *Daemon) PushImage(ctx context.Context, image, tag string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error {
16
+func (i *imageService) PushImage(ctx context.Context, image, tag string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error {
17 17
 	ref, err := reference.ParseNormalizedNamed(image)
18 18
 	if err != nil {
19 19
 		return err
... ...
@@ -44,16 +44,16 @@ func (daemon *Daemon) PushImage(ctx context.Context, image, tag string, metaHead
44 44
 			MetaHeaders:      metaHeaders,
45 45
 			AuthConfig:       authConfig,
46 46
 			ProgressOutput:   progress.ChanOutput(progressChan),
47
-			RegistryService:  daemon.RegistryService,
48
-			ImageEventLogger: daemon.LogImageEvent,
49
-			MetadataStore:    daemon.distributionMetadataStore,
50
-			ImageStore:       distribution.NewImageConfigStoreFromStore(daemon.imageStore),
51
-			ReferenceStore:   daemon.referenceStore,
47
+			RegistryService:  i.registryService,
48
+			ImageEventLogger: i.LogImageEvent,
49
+			MetadataStore:    i.distributionMetadataStore,
50
+			ImageStore:       distribution.NewImageConfigStoreFromStore(i.imageStore),
51
+			ReferenceStore:   i.referenceStore,
52 52
 		},
53 53
 		ConfigMediaType: schema2.MediaTypeImageConfig,
54
-		LayerStores:     distribution.NewLayerProvidersFromStores(daemon.layerStores),
55
-		TrustKey:        daemon.trustKey,
56
-		UploadManager:   daemon.uploadManager,
54
+		LayerStores:     distribution.NewLayerProvidersFromStores(i.layerStores),
55
+		TrustKey:        i.trustKey,
56
+		UploadManager:   i.uploadManager,
57 57
 	}
58 58
 
59 59
 	err = distribution.Push(ctx, ref, imagePushConfig)
60 60
new file mode 100644
... ...
@@ -0,0 +1,96 @@
0
+package daemon // import "github.com/docker/docker/daemon"
1
+
2
+import (
3
+	"strconv"
4
+
5
+	"golang.org/x/net/context"
6
+
7
+	"github.com/docker/docker/api/types"
8
+	"github.com/docker/docker/api/types/filters"
9
+	registrytypes "github.com/docker/docker/api/types/registry"
10
+	"github.com/docker/docker/dockerversion"
11
+)
12
+
13
+var acceptedSearchFilterTags = map[string]bool{
14
+	"is-automated": true,
15
+	"is-official":  true,
16
+	"stars":        true,
17
+}
18
+
19
+// SearchRegistryForImages queries the registry for images matching
20
+// term. authConfig is used to login.
21
+//
22
+// TODO: this could be implemented in a registry service instead of the image
23
+// service.
24
+func (i *imageService) SearchRegistryForImages(ctx context.Context, filtersArgs string, term string, limit int,
25
+	authConfig *types.AuthConfig,
26
+	headers map[string][]string) (*registrytypes.SearchResults, error) {
27
+
28
+	searchFilters, err := filters.FromJSON(filtersArgs)
29
+	if err != nil {
30
+		return nil, err
31
+	}
32
+	if err := searchFilters.Validate(acceptedSearchFilterTags); err != nil {
33
+		return nil, err
34
+	}
35
+
36
+	var isAutomated, isOfficial bool
37
+	var hasStarFilter = 0
38
+	if searchFilters.Contains("is-automated") {
39
+		if searchFilters.UniqueExactMatch("is-automated", "true") {
40
+			isAutomated = true
41
+		} else if !searchFilters.UniqueExactMatch("is-automated", "false") {
42
+			return nil, invalidFilter{"is-automated", searchFilters.Get("is-automated")}
43
+		}
44
+	}
45
+	if searchFilters.Contains("is-official") {
46
+		if searchFilters.UniqueExactMatch("is-official", "true") {
47
+			isOfficial = true
48
+		} else if !searchFilters.UniqueExactMatch("is-official", "false") {
49
+			return nil, invalidFilter{"is-official", searchFilters.Get("is-official")}
50
+		}
51
+	}
52
+	if searchFilters.Contains("stars") {
53
+		hasStars := searchFilters.Get("stars")
54
+		for _, hasStar := range hasStars {
55
+			iHasStar, err := strconv.Atoi(hasStar)
56
+			if err != nil {
57
+				return nil, invalidFilter{"stars", hasStar}
58
+			}
59
+			if iHasStar > hasStarFilter {
60
+				hasStarFilter = iHasStar
61
+			}
62
+		}
63
+	}
64
+
65
+	unfilteredResult, err := i.registryService.Search(ctx, term, limit, authConfig, dockerversion.DockerUserAgent(ctx), headers)
66
+	if err != nil {
67
+		return nil, err
68
+	}
69
+
70
+	filteredResults := []registrytypes.SearchResult{}
71
+	for _, result := range unfilteredResult.Results {
72
+		if searchFilters.Contains("is-automated") {
73
+			if isAutomated != result.IsAutomated {
74
+				continue
75
+			}
76
+		}
77
+		if searchFilters.Contains("is-official") {
78
+			if isOfficial != result.IsOfficial {
79
+				continue
80
+			}
81
+		}
82
+		if searchFilters.Contains("stars") {
83
+			if result.StarCount < hasStarFilter {
84
+				continue
85
+			}
86
+		}
87
+		filteredResults = append(filteredResults, result)
88
+	}
89
+
90
+	return &registrytypes.SearchResults{
91
+		Query:      unfilteredResult.Query,
92
+		NumResults: len(filteredResults),
93
+		Results:    filteredResults,
94
+	}, nil
95
+}
... ...
@@ -7,8 +7,8 @@ import (
7 7
 
8 8
 // TagImage creates the tag specified by newTag, pointing to the image named
9 9
 // imageName (alternatively, imageName can also be an image ID).
10
-func (daemon *Daemon) TagImage(imageName, repository, tag string) (string, error) {
11
-	imageID, _, err := daemon.GetImageIDAndOS(imageName)
10
+func (i *imageService) TagImage(imageName, repository, tag string) (string, error) {
11
+	imageID, _, err := i.GetImageIDAndOS(imageName)
12 12
 	if err != nil {
13 13
 		return "", err
14 14
 	}
... ...
@@ -23,19 +23,19 @@ func (daemon *Daemon) TagImage(imageName, repository, tag string) (string, error
23 23
 		}
24 24
 	}
25 25
 
26
-	err = daemon.TagImageWithReference(imageID, newTag)
26
+	err = i.TagImageWithReference(imageID, newTag)
27 27
 	return reference.FamiliarString(newTag), err
28 28
 }
29 29
 
30 30
 // TagImageWithReference adds the given reference to the image ID provided.
31
-func (daemon *Daemon) TagImageWithReference(imageID image.ID, newTag reference.Named) error {
32
-	if err := daemon.referenceStore.AddTag(newTag, imageID.Digest(), true); err != nil {
31
+func (i *imageService) TagImageWithReference(imageID image.ID, newTag reference.Named) error {
32
+	if err := i.referenceStore.AddTag(newTag, imageID.Digest(), true); err != nil {
33 33
 		return err
34 34
 	}
35 35
 
36
-	if err := daemon.imageStore.SetLastUpdated(imageID); err != nil {
36
+	if err := i.imageStore.SetLastUpdated(imageID); err != nil {
37 37
 		return err
38 38
 	}
39
-	daemon.LogImageEvent(imageID.String(), reference.FamiliarString(newTag), "tag")
39
+	i.LogImageEvent(imageID.String(), reference.FamiliarString(newTag), "tag")
40 40
 	return nil
41 41
 }
... ...
@@ -34,8 +34,8 @@ func (r byCreated) Swap(i, j int)      { r[i], r[j] = r[j], r[i] }
34 34
 func (r byCreated) Less(i, j int) bool { return r[i].Created < r[j].Created }
35 35
 
36 36
 // Map returns a map of all images in the ImageStore
37
-func (daemon *Daemon) Map() map[image.ID]*image.Image {
38
-	return daemon.imageStore.Map()
37
+func (i *imageService) Map() map[image.ID]*image.Image {
38
+	return i.imageStore.Map()
39 39
 }
40 40
 
41 41
 // Images returns a filtered list of images. filterArgs is a JSON-encoded set
... ...
@@ -43,7 +43,7 @@ func (daemon *Daemon) Map() map[image.ID]*image.Image {
43 43
 // filter is a shell glob string applied to repository names. The argument
44 44
 // named all controls whether all images in the graph are filtered, or just
45 45
 // the heads.
46
-func (daemon *Daemon) Images(imageFilters filters.Args, all bool, withExtraAttrs bool) ([]*types.ImageSummary, error) {
46
+func (i *imageService) Images(imageFilters filters.Args, all bool, withExtraAttrs bool) ([]*types.ImageSummary, error) {
47 47
 	var (
48 48
 		allImages    map[image.ID]*image.Image
49 49
 		err          error
... ...
@@ -62,14 +62,14 @@ func (daemon *Daemon) Images(imageFilters filters.Args, all bool, withExtraAttrs
62 62
 		}
63 63
 	}
64 64
 	if danglingOnly {
65
-		allImages = daemon.imageStore.Heads()
65
+		allImages = i.imageStore.Heads()
66 66
 	} else {
67
-		allImages = daemon.imageStore.Map()
67
+		allImages = i.imageStore.Map()
68 68
 	}
69 69
 
70 70
 	var beforeFilter, sinceFilter *image.Image
71 71
 	err = imageFilters.WalkValues("before", func(value string) error {
72
-		beforeFilter, err = daemon.GetImage(value)
72
+		beforeFilter, err = i.GetImage(value)
73 73
 		return err
74 74
 	})
75 75
 	if err != nil {
... ...
@@ -77,7 +77,7 @@ func (daemon *Daemon) Images(imageFilters filters.Args, all bool, withExtraAttrs
77 77
 	}
78 78
 
79 79
 	err = imageFilters.WalkValues("since", func(value string) error {
80
-		sinceFilter, err = daemon.GetImage(value)
80
+		sinceFilter, err = i.GetImage(value)
81 81
 		return err
82 82
 	})
83 83
 	if err != nil {
... ...
@@ -124,7 +124,7 @@ func (daemon *Daemon) Images(imageFilters filters.Args, all bool, withExtraAttrs
124 124
 		layerID := img.RootFS.ChainID()
125 125
 		var size int64
126 126
 		if layerID != "" {
127
-			l, err := daemon.layerStores[img.OperatingSystem()].Get(layerID)
127
+			l, err := i.layerStores[img.OperatingSystem()].Get(layerID)
128 128
 			if err != nil {
129 129
 				// The layer may have been deleted between the call to `Map()` or
130 130
 				// `Heads()` and the call to `Get()`, so we just ignore this error
... ...
@@ -135,7 +135,7 @@ func (daemon *Daemon) Images(imageFilters filters.Args, all bool, withExtraAttrs
135 135
 			}
136 136
 
137 137
 			size, err = l.Size()
138
-			layer.ReleaseAndLog(daemon.layerStores[img.OperatingSystem()], l)
138
+			layer.ReleaseAndLog(i.layerStores[img.OperatingSystem()], l)
139 139
 			if err != nil {
140 140
 				return nil, err
141 141
 			}
... ...
@@ -143,7 +143,7 @@ func (daemon *Daemon) Images(imageFilters filters.Args, all bool, withExtraAttrs
143 143
 
144 144
 		newImage := newImage(img, size)
145 145
 
146
-		for _, ref := range daemon.referenceStore.References(id.Digest()) {
146
+		for _, ref := range i.referenceStore.References(id.Digest()) {
147 147
 			if imageFilters.Contains("reference") {
148 148
 				var found bool
149 149
 				var matchErr error
... ...
@@ -165,7 +165,7 @@ func (daemon *Daemon) Images(imageFilters filters.Args, all bool, withExtraAttrs
165 165
 			}
166 166
 		}
167 167
 		if newImage.RepoDigests == nil && newImage.RepoTags == nil {
168
-			if all || len(daemon.imageStore.Children(id)) == 0 {
168
+			if all || len(i.imageStore.Children(id)) == 0 {
169 169
 
170 170
 				if imageFilters.Contains("dangling") && !danglingOnly {
171 171
 					//dangling=false case, so dangling image is not needed
... ...
@@ -186,8 +186,8 @@ func (daemon *Daemon) Images(imageFilters filters.Args, all bool, withExtraAttrs
186 186
 		if withExtraAttrs {
187 187
 			// lazily init variables
188 188
 			if imagesMap == nil {
189
-				allContainers = daemon.List()
190
-				allLayers = daemon.layerStores[img.OperatingSystem()].Map()
189
+				allContainers = i.containers.List()
190
+				allLayers = i.layerStores[img.OperatingSystem()].Map()
191 191
 				imagesMap = make(map[*image.Image]*types.ImageSummary)
192 192
 				layerRefs = make(map[layer.ChainID]int)
193 193
 			}
... ...
@@ -249,20 +249,20 @@ func (daemon *Daemon) Images(imageFilters filters.Args, all bool, withExtraAttrs
249 249
 // This new image contains only the layers from it's parent + 1 extra layer which contains the diff of all the layers in between.
250 250
 // The existing image(s) is not destroyed.
251 251
 // If no parent is specified, a new image with the diff of all the specified image's layers merged into a new layer that has no parents.
252
-func (daemon *Daemon) SquashImage(id, parent string) (string, error) {
252
+func (i *imageService) SquashImage(id, parent string) (string, error) {
253 253
 
254 254
 	var (
255 255
 		img *image.Image
256 256
 		err error
257 257
 	)
258
-	if img, err = daemon.imageStore.Get(image.ID(id)); err != nil {
258
+	if img, err = i.imageStore.Get(image.ID(id)); err != nil {
259 259
 		return "", err
260 260
 	}
261 261
 
262 262
 	var parentImg *image.Image
263 263
 	var parentChainID layer.ChainID
264 264
 	if len(parent) != 0 {
265
-		parentImg, err = daemon.imageStore.Get(image.ID(parent))
265
+		parentImg, err = i.imageStore.Get(image.ID(parent))
266 266
 		if err != nil {
267 267
 			return "", errors.Wrap(err, "error getting specified parent layer")
268 268
 		}
... ...
@@ -272,11 +272,11 @@ func (daemon *Daemon) SquashImage(id, parent string) (string, error) {
272 272
 		parentImg = &image.Image{RootFS: rootFS}
273 273
 	}
274 274
 
275
-	l, err := daemon.layerStores[img.OperatingSystem()].Get(img.RootFS.ChainID())
275
+	l, err := i.layerStores[img.OperatingSystem()].Get(img.RootFS.ChainID())
276 276
 	if err != nil {
277 277
 		return "", errors.Wrap(err, "error getting image layer")
278 278
 	}
279
-	defer daemon.layerStores[img.OperatingSystem()].Release(l)
279
+	defer i.layerStores[img.OperatingSystem()].Release(l)
280 280
 
281 281
 	ts, err := l.TarStreamFrom(parentChainID)
282 282
 	if err != nil {
... ...
@@ -284,11 +284,11 @@ func (daemon *Daemon) SquashImage(id, parent string) (string, error) {
284 284
 	}
285 285
 	defer ts.Close()
286 286
 
287
-	newL, err := daemon.layerStores[img.OperatingSystem()].Register(ts, parentChainID)
287
+	newL, err := i.layerStores[img.OperatingSystem()].Register(ts, parentChainID)
288 288
 	if err != nil {
289 289
 		return "", errors.Wrap(err, "error registering layer")
290 290
 	}
291
-	defer daemon.layerStores[img.OperatingSystem()].Release(newL)
291
+	defer i.layerStores[img.OperatingSystem()].Release(newL)
292 292
 
293 293
 	newImage := *img
294 294
 	newImage.RootFS = nil
... ...
@@ -323,7 +323,7 @@ func (daemon *Daemon) SquashImage(id, parent string) (string, error) {
323 323
 		return "", errors.Wrap(err, "error marshalling image config")
324 324
 	}
325 325
 
326
-	newImgID, err := daemon.imageStore.Create(b)
326
+	newImgID, err := i.imageStore.Create(b)
327 327
 	if err != nil {
328 328
 		return "", errors.Wrap(err, "error creating new image after squash")
329 329
 	}
330 330
deleted file mode 100644
... ...
@@ -1,138 +0,0 @@
1
-package daemon // import "github.com/docker/docker/daemon"
2
-
3
-import (
4
-	"encoding/json"
5
-	"io"
6
-	"net/http"
7
-	"net/url"
8
-	"runtime"
9
-	"strings"
10
-	"time"
11
-
12
-	"github.com/docker/distribution/reference"
13
-	"github.com/docker/docker/api/types/container"
14
-	"github.com/docker/docker/builder/dockerfile"
15
-	"github.com/docker/docker/builder/remotecontext"
16
-	"github.com/docker/docker/dockerversion"
17
-	"github.com/docker/docker/errdefs"
18
-	"github.com/docker/docker/image"
19
-	"github.com/docker/docker/layer"
20
-	"github.com/docker/docker/pkg/archive"
21
-	"github.com/docker/docker/pkg/progress"
22
-	"github.com/docker/docker/pkg/streamformatter"
23
-	"github.com/pkg/errors"
24
-)
25
-
26
-// ImportImage imports an image, getting the archived layer data either from
27
-// inConfig (if src is "-"), or from a URI specified in src. Progress output is
28
-// written to outStream. Repository and tag names can optionally be given in
29
-// the repo and tag arguments, respectively.
30
-func (daemon *Daemon) ImportImage(src string, repository, os string, tag string, msg string, inConfig io.ReadCloser, outStream io.Writer, changes []string) error {
31
-	var (
32
-		rc     io.ReadCloser
33
-		resp   *http.Response
34
-		newRef reference.Named
35
-	)
36
-
37
-	// Default the operating system if not supplied.
38
-	if os == "" {
39
-		os = runtime.GOOS
40
-	}
41
-
42
-	if repository != "" {
43
-		var err error
44
-		newRef, err = reference.ParseNormalizedNamed(repository)
45
-		if err != nil {
46
-			return errdefs.InvalidParameter(err)
47
-		}
48
-		if _, isCanonical := newRef.(reference.Canonical); isCanonical {
49
-			return errdefs.InvalidParameter(errors.New("cannot import digest reference"))
50
-		}
51
-
52
-		if tag != "" {
53
-			newRef, err = reference.WithTag(newRef, tag)
54
-			if err != nil {
55
-				return errdefs.InvalidParameter(err)
56
-			}
57
-		}
58
-	}
59
-
60
-	config, err := dockerfile.BuildFromConfig(&container.Config{}, changes, os)
61
-	if err != nil {
62
-		return err
63
-	}
64
-	if src == "-" {
65
-		rc = inConfig
66
-	} else {
67
-		inConfig.Close()
68
-		if len(strings.Split(src, "://")) == 1 {
69
-			src = "http://" + src
70
-		}
71
-		u, err := url.Parse(src)
72
-		if err != nil {
73
-			return errdefs.InvalidParameter(err)
74
-		}
75
-
76
-		resp, err = remotecontext.GetWithStatusError(u.String())
77
-		if err != nil {
78
-			return err
79
-		}
80
-		outStream.Write(streamformatter.FormatStatus("", "Downloading from %s", u))
81
-		progressOutput := streamformatter.NewJSONProgressOutput(outStream, true)
82
-		rc = progress.NewProgressReader(resp.Body, progressOutput, resp.ContentLength, "", "Importing")
83
-	}
84
-
85
-	defer rc.Close()
86
-	if len(msg) == 0 {
87
-		msg = "Imported from " + src
88
-	}
89
-
90
-	inflatedLayerData, err := archive.DecompressStream(rc)
91
-	if err != nil {
92
-		return err
93
-	}
94
-	l, err := daemon.layerStores[os].Register(inflatedLayerData, "")
95
-	if err != nil {
96
-		return err
97
-	}
98
-	defer layer.ReleaseAndLog(daemon.layerStores[os], l)
99
-
100
-	created := time.Now().UTC()
101
-	imgConfig, err := json.Marshal(&image.Image{
102
-		V1Image: image.V1Image{
103
-			DockerVersion: dockerversion.Version,
104
-			Config:        config,
105
-			Architecture:  runtime.GOARCH,
106
-			OS:            os,
107
-			Created:       created,
108
-			Comment:       msg,
109
-		},
110
-		RootFS: &image.RootFS{
111
-			Type:    "layers",
112
-			DiffIDs: []layer.DiffID{l.DiffID()},
113
-		},
114
-		History: []image.History{{
115
-			Created: created,
116
-			Comment: msg,
117
-		}},
118
-	})
119
-	if err != nil {
120
-		return err
121
-	}
122
-
123
-	id, err := daemon.imageStore.Create(imgConfig)
124
-	if err != nil {
125
-		return err
126
-	}
127
-
128
-	// FIXME: connect with commit code and call refstore directly
129
-	if newRef != nil {
130
-		if err := daemon.TagImageWithReference(id, newRef); err != nil {
131
-			return err
132
-		}
133
-	}
134
-
135
-	daemon.LogImageEvent(id.String(), id.String(), "import")
136
-	outStream.Write(streamformatter.FormatStatus("", id.String()))
137
-	return nil
138
-}
... ...
@@ -80,8 +80,9 @@ func (daemon *Daemon) SystemInfo() (*types.Info, error) {
80 80
 
81 81
 	var ds [][2]string
82 82
 	drivers := ""
83
+	statuses := daemon.imageService.GraphDriverStatuses()
83 84
 	for os, gd := range daemon.graphDrivers {
84
-		ds = append(ds, daemon.layerStores[os].DriverStatus()...)
85
+		ds = append(ds, statuses[os]...)
85 86
 		drivers += gd
86 87
 		if len(daemon.graphDrivers) > 1 {
87 88
 			drivers += fmt.Sprintf(" (%s) ", os)
... ...
@@ -95,7 +96,7 @@ func (daemon *Daemon) SystemInfo() (*types.Info, error) {
95 95
 		ContainersRunning:  cRunning,
96 96
 		ContainersPaused:   cPaused,
97 97
 		ContainersStopped:  cStopped,
98
-		Images:             len(daemon.imageStore.Map()),
98
+		Images:             daemon.imageService.CountImages(),
99 99
 		Driver:             drivers,
100 100
 		DriverStatus:       ds,
101 101
 		Plugins:            daemon.showPluginsInfo(),
... ...
@@ -79,7 +79,7 @@ func (daemon *Daemon) ContainerInspectCurrent(name string, size bool) (*types.Co
79 79
 	container.Unlock()
80 80
 
81 81
 	if size {
82
-		sizeRw, sizeRootFs := daemon.getSize(base.ID)
82
+		sizeRw, sizeRootFs := daemon.imageService.GetContainerLayerSize(base.ID)
83 83
 		base.SizeRw = &sizeRw
84 84
 		base.SizeRootFs = &sizeRootFs
85 85
 	}
... ...
@@ -239,7 +239,7 @@ func (daemon *Daemon) reducePsContainer(container *container.Snapshot, ctx *list
239 239
 
240 240
 	// release lock because size calculation is slow
241 241
 	if ctx.Size {
242
-		sizeRw, sizeRootFs := daemon.getSize(newC.ID)
242
+		sizeRw, sizeRootFs := daemon.imageService.GetContainerLayerSize(newC.ID)
243 243
 		newC.SizeRw = sizeRw
244 244
 		newC.SizeRootFs = sizeRootFs
245 245
 	}
... ...
@@ -323,7 +323,7 @@ func (daemon *Daemon) foldFilter(view container.View, config *types.ContainerLis
323 323
 	if psFilters.Contains("ancestor") {
324 324
 		ancestorFilter = true
325 325
 		psFilters.WalkValues("ancestor", func(ancestor string) error {
326
-			id, _, err := daemon.GetImageIDAndOS(ancestor)
326
+			id, _, err := daemon.imageService.GetImageIDAndOS(ancestor)
327 327
 			if err != nil {
328 328
 				logrus.Warnf("Error while looking up for image %v", ancestor)
329 329
 				return nil
... ...
@@ -333,7 +333,7 @@ func (daemon *Daemon) foldFilter(view container.View, config *types.ContainerLis
333 333
 				return nil
334 334
 			}
335 335
 			// Then walk down the graph and put the imageIds in imagesFilter
336
-			populateImageFilterByParents(imagesFilter, id, daemon.imageStore.Children)
336
+			populateImageFilterByParents(imagesFilter, id, daemon.imageService.Children)
337 337
 			return nil
338 338
 		})
339 339
 	}
... ...
@@ -591,7 +591,7 @@ func (daemon *Daemon) refreshImage(s *container.Snapshot, ctx *listContext) (*ty
591 591
 	c := s.Container
592 592
 	image := s.Image // keep the original ref if still valid (hasn't changed)
593 593
 	if image != s.ImageID {
594
-		id, _, err := daemon.GetImageIDAndOS(image)
594
+		id, _, err := daemon.imageService.GetImageIDAndOS(image)
595 595
 		if _, isDNE := err.(errImageDoesNotExist); err != nil && !isDNE {
596 596
 			return nil, err
597 597
 		}
... ...
@@ -24,7 +24,7 @@ const (
24 24
 )
25 25
 
26 26
 func (daemon *Daemon) createSpec(c *container.Container) (*specs.Spec, error) {
27
-	img, err := daemon.GetImage(string(c.ImageID))
27
+	img, err := daemon.imageService.GetImage(string(c.ImageID))
28 28
 	if err != nil {
29 29
 		return nil, err
30 30
 	}
... ...
@@ -75,7 +75,7 @@ func (daemon *Daemon) ContainersPrune(ctx context.Context, pruneFilters filters.
75 75
 			if !matchLabels(pruneFilters, c.Config.Labels) {
76 76
 				continue
77 77
 			}
78
-			cSize, _ := daemon.getSize(c.ID)
78
+			cSize, _ := daemon.imageService.GetContainerLayerSize(c.ID)
79 79
 			// TODO: sets RmLink to true?
80 80
 			err := daemon.ContainerRm(c.ID, &types.ContainerRmConfig{})
81 81
 			if err != nil {
... ...
@@ -90,8 +90,8 @@ func (daemon *Daemon) reloadMaxConcurrentDownloadsAndUploads(conf *config.Config
90 90
 		daemon.configStore.MaxConcurrentDownloads = &maxConcurrentDownloads
91 91
 	}
92 92
 	logrus.Debugf("Reset Max Concurrent Downloads: %d", *daemon.configStore.MaxConcurrentDownloads)
93
-	if daemon.downloadManager != nil {
94
-		daemon.downloadManager.SetConcurrency(*daemon.configStore.MaxConcurrentDownloads)
93
+	if daemon.imageService.downloadManager != nil {
94
+		daemon.imageService.downloadManager.SetConcurrency(*daemon.configStore.MaxConcurrentDownloads)
95 95
 	}
96 96
 
97 97
 	// prepare reload event attributes with updatable configurations
... ...
@@ -106,8 +106,8 @@ func (daemon *Daemon) reloadMaxConcurrentDownloadsAndUploads(conf *config.Config
106 106
 		daemon.configStore.MaxConcurrentUploads = &maxConcurrentUploads
107 107
 	}
108 108
 	logrus.Debugf("Reset Max Concurrent Uploads: %d", *daemon.configStore.MaxConcurrentUploads)
109
-	if daemon.uploadManager != nil {
110
-		daemon.uploadManager.SetConcurrency(*daemon.configStore.MaxConcurrentUploads)
109
+	if daemon.imageService.uploadManager != nil {
110
+		daemon.imageService.uploadManager.SetConcurrency(*daemon.configStore.MaxConcurrentUploads)
111 111
 	}
112 112
 
113 113
 	// prepare reload event attributes with updatable configurations
... ...
@@ -15,11 +15,13 @@ import (
15 15
 )
16 16
 
17 17
 func TestDaemonReloadLabels(t *testing.T) {
18
-	daemon := &Daemon{}
19
-	daemon.configStore = &config.Config{
20
-		CommonConfig: config.CommonConfig{
21
-			Labels: []string{"foo:bar"},
18
+	daemon := &Daemon{
19
+		configStore: &config.Config{
20
+			CommonConfig: config.CommonConfig{
21
+				Labels: []string{"foo:bar"},
22
+			},
22 23
 		},
24
+		imageService: &imageService{},
23 25
 	}
24 26
 
25 27
 	valuesSets := make(map[string]interface{})
... ...
@@ -43,7 +45,8 @@ func TestDaemonReloadLabels(t *testing.T) {
43 43
 
44 44
 func TestDaemonReloadAllowNondistributableArtifacts(t *testing.T) {
45 45
 	daemon := &Daemon{
46
-		configStore: &config.Config{},
46
+		configStore:  &config.Config{},
47
+		imageService: &imageService{},
47 48
 	}
48 49
 
49 50
 	var err error
... ...
@@ -97,7 +100,9 @@ func TestDaemonReloadAllowNondistributableArtifacts(t *testing.T) {
97 97
 }
98 98
 
99 99
 func TestDaemonReloadMirrors(t *testing.T) {
100
-	daemon := &Daemon{}
100
+	daemon := &Daemon{
101
+		imageService: &imageService{},
102
+	}
101 103
 	var err error
102 104
 	daemon.RegistryService, err = registry.NewService(registry.ServiceOptions{
103 105
 		InsecureRegistries: []string{},
... ...
@@ -194,7 +199,9 @@ func TestDaemonReloadMirrors(t *testing.T) {
194 194
 }
195 195
 
196 196
 func TestDaemonReloadInsecureRegistries(t *testing.T) {
197
-	daemon := &Daemon{}
197
+	daemon := &Daemon{
198
+		imageService: &imageService{},
199
+	}
198 200
 	var err error
199 201
 	// initialize daemon with existing insecure registries: "127.0.0.0/8", "10.10.1.11:5000", "10.10.1.22:5000"
200 202
 	daemon.RegistryService, err = registry.NewService(registry.ServiceOptions{
... ...
@@ -284,7 +291,9 @@ func TestDaemonReloadInsecureRegistries(t *testing.T) {
284 284
 }
285 285
 
286 286
 func TestDaemonReloadNotAffectOthers(t *testing.T) {
287
-	daemon := &Daemon{}
287
+	daemon := &Daemon{
288
+		imageService: &imageService{},
289
+	}
288 290
 	daemon.configStore = &config.Config{
289 291
 		CommonConfig: config.CommonConfig{
290 292
 			Labels: []string{"foo:bar"},
... ...
@@ -316,7 +325,9 @@ func TestDaemonReloadNotAffectOthers(t *testing.T) {
316 316
 }
317 317
 
318 318
 func TestDaemonDiscoveryReload(t *testing.T) {
319
-	daemon := &Daemon{}
319
+	daemon := &Daemon{
320
+		imageService: &imageService{},
321
+	}
320 322
 	daemon.configStore = &config.Config{
321 323
 		CommonConfig: config.CommonConfig{
322 324
 			ClusterStore:     "memory://127.0.0.1",
... ...
@@ -393,7 +404,9 @@ func TestDaemonDiscoveryReload(t *testing.T) {
393 393
 }
394 394
 
395 395
 func TestDaemonDiscoveryReloadFromEmptyDiscovery(t *testing.T) {
396
-	daemon := &Daemon{}
396
+	daemon := &Daemon{
397
+		imageService: &imageService{},
398
+	}
397 399
 	daemon.configStore = &config.Config{}
398 400
 
399 401
 	valuesSet := make(map[string]interface{})
... ...
@@ -438,7 +451,9 @@ func TestDaemonDiscoveryReloadFromEmptyDiscovery(t *testing.T) {
438 438
 }
439 439
 
440 440
 func TestDaemonDiscoveryReloadOnlyClusterAdvertise(t *testing.T) {
441
-	daemon := &Daemon{}
441
+	daemon := &Daemon{
442
+		imageService: &imageService{},
443
+	}
442 444
 	daemon.configStore = &config.Config{
443 445
 		CommonConfig: config.CommonConfig{
444 446
 			ClusterStore: "memory://127.0.0.1",
... ...
@@ -482,7 +497,9 @@ func TestDaemonDiscoveryReloadOnlyClusterAdvertise(t *testing.T) {
482 482
 }
483 483
 
484 484
 func TestDaemonReloadNetworkDiagnosticPort(t *testing.T) {
485
-	daemon := &Daemon{}
485
+	daemon := &Daemon{
486
+		imageService: &imageService{},
487
+	}
486 488
 	daemon.configStore = &config.Config{}
487 489
 
488 490
 	valuesSet := make(map[string]interface{})
489 491
deleted file mode 100644
... ...
@@ -1,93 +0,0 @@
1
-package daemon // import "github.com/docker/docker/daemon"
2
-
3
-import (
4
-	"strconv"
5
-
6
-	"golang.org/x/net/context"
7
-
8
-	"github.com/docker/docker/api/types"
9
-	"github.com/docker/docker/api/types/filters"
10
-	registrytypes "github.com/docker/docker/api/types/registry"
11
-	"github.com/docker/docker/dockerversion"
12
-)
13
-
14
-var acceptedSearchFilterTags = map[string]bool{
15
-	"is-automated": true,
16
-	"is-official":  true,
17
-	"stars":        true,
18
-}
19
-
20
-// SearchRegistryForImages queries the registry for images matching
21
-// term. authConfig is used to login.
22
-func (daemon *Daemon) SearchRegistryForImages(ctx context.Context, filtersArgs string, term string, limit int,
23
-	authConfig *types.AuthConfig,
24
-	headers map[string][]string) (*registrytypes.SearchResults, error) {
25
-
26
-	searchFilters, err := filters.FromJSON(filtersArgs)
27
-	if err != nil {
28
-		return nil, err
29
-	}
30
-	if err := searchFilters.Validate(acceptedSearchFilterTags); err != nil {
31
-		return nil, err
32
-	}
33
-
34
-	var isAutomated, isOfficial bool
35
-	var hasStarFilter = 0
36
-	if searchFilters.Contains("is-automated") {
37
-		if searchFilters.UniqueExactMatch("is-automated", "true") {
38
-			isAutomated = true
39
-		} else if !searchFilters.UniqueExactMatch("is-automated", "false") {
40
-			return nil, invalidFilter{"is-automated", searchFilters.Get("is-automated")}
41
-		}
42
-	}
43
-	if searchFilters.Contains("is-official") {
44
-		if searchFilters.UniqueExactMatch("is-official", "true") {
45
-			isOfficial = true
46
-		} else if !searchFilters.UniqueExactMatch("is-official", "false") {
47
-			return nil, invalidFilter{"is-official", searchFilters.Get("is-official")}
48
-		}
49
-	}
50
-	if searchFilters.Contains("stars") {
51
-		hasStars := searchFilters.Get("stars")
52
-		for _, hasStar := range hasStars {
53
-			iHasStar, err := strconv.Atoi(hasStar)
54
-			if err != nil {
55
-				return nil, invalidFilter{"stars", hasStar}
56
-			}
57
-			if iHasStar > hasStarFilter {
58
-				hasStarFilter = iHasStar
59
-			}
60
-		}
61
-	}
62
-
63
-	unfilteredResult, err := daemon.RegistryService.Search(ctx, term, limit, authConfig, dockerversion.DockerUserAgent(ctx), headers)
64
-	if err != nil {
65
-		return nil, err
66
-	}
67
-
68
-	filteredResults := []registrytypes.SearchResult{}
69
-	for _, result := range unfilteredResult.Results {
70
-		if searchFilters.Contains("is-automated") {
71
-			if isAutomated != result.IsAutomated {
72
-				continue
73
-			}
74
-		}
75
-		if searchFilters.Contains("is-official") {
76
-			if isOfficial != result.IsOfficial {
77
-				continue
78
-			}
79
-		}
80
-		if searchFilters.Contains("stars") {
81
-			if result.StarCount < hasStarFilter {
82
-				continue
83
-			}
84
-		}
85
-		filteredResults = append(filteredResults, result)
86
-	}
87
-
88
-	return &registrytypes.SearchResults{
89
-		Query:      unfilteredResult.Query,
90
-		NumResults: len(filteredResults),
91
-		Results:    filteredResults,
92
-	}, nil
93
-}
... ...
@@ -223,7 +223,7 @@ func (daemon *Daemon) Cleanup(container *container.Container) {
223 223
 	if err := daemon.conditionalUnmountOnCleanup(container); err != nil {
224 224
 		// FIXME: remove once reference counting for graphdrivers has been refactored
225 225
 		// Ensure that all the mounts are gone
226
-		if mountid, err := daemon.layerStores[container.OS].GetMountID(container.ID); err == nil {
226
+		if mountid, err := daemon.imageService.GetContainerMountID(container.ID, container.OS); err == nil {
227 227
 			daemon.cleanupMountsByID(mountid)
228 228
 		}
229 229
 	}