imageService provides the backend for the image API and handles the
imageStore, and referenceStore.
Signed-off-by: Daniel Nephin <dnephin@docker.com>
| ... | ... |
@@ -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 |
| ... | ... |
@@ -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 ®istrytypes.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 ®istrytypes.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 |
} |