LCOW: Move daemon stores to per platform
Signed-off-by: John Howard <jhoward@microsoft.com>
This commit is contained in:
parent
6c33684987
commit
3aa4a00715
40 changed files with 448 additions and 269 deletions
api
cmd/dockerd
daemon
build.gocache.gocommit.gocontainer.gocreate.godaemon.godaemon_solaris.godaemon_unix.godaemon_windows.godelete.godisk_usage.gogetsize_unix.go
graphdriver
image.goimage_delete.goimage_exporter.goimage_history.goimage_inspect.goimage_pull.goimage_push.goimage_tag.goimages.goimport.goinfo.goinspect.golist.goprune.gostart.gostart_windows.godistribution
reference
|
@ -17,7 +17,7 @@ import (
|
|||
// ImageComponent provides an interface for working with images
|
||||
type ImageComponent interface {
|
||||
SquashImage(from string, to string) (string, error)
|
||||
TagImageWithReference(image.ID, reference.Named) error
|
||||
TagImageWithReference(image.ID, string, reference.Named) error
|
||||
}
|
||||
|
||||
// Backend provides build functionality to the API router
|
||||
|
|
|
@ -3,9 +3,11 @@ package build
|
|||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"runtime"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
|
@ -33,7 +35,12 @@ func NewTagger(backend ImageComponent, stdout io.Writer, names []string) (*Tagge
|
|||
// TagImages creates image tags for the imageID
|
||||
func (bt *Tagger) TagImages(imageID image.ID) error {
|
||||
for _, rt := range bt.repoAndTags {
|
||||
if err := bt.imageComponent.TagImageWithReference(imageID, rt); err != nil {
|
||||
// TODO @jhowardmsft LCOW support. Will need revisiting.
|
||||
platform := runtime.GOOS
|
||||
if platform == "windows" && system.LCOWSupported() {
|
||||
platform = "linux"
|
||||
}
|
||||
if err := bt.imageComponent.TagImageWithReference(imageID, platform, rt); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(bt.stdout, "Successfully tagged %s\n", reference.FamiliarString(rt))
|
||||
|
|
|
@ -320,6 +320,7 @@ type ContainerJSONBase struct {
|
|||
Name string
|
||||
RestartCount int
|
||||
Driver string
|
||||
Platform string
|
||||
MountLabel string
|
||||
ProcessLabel string
|
||||
AppArmorProfile string
|
||||
|
|
|
@ -267,12 +267,6 @@ func (cli *DaemonCli) start(opts *daemonOptions) (err error) {
|
|||
|
||||
logrus.Info("Daemon has completed initialization")
|
||||
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"version": dockerversion.Version,
|
||||
"commit": dockerversion.GitCommit,
|
||||
"graphdriver": d.GraphDriverName(),
|
||||
}).Info("Docker daemon")
|
||||
|
||||
cli.d = d
|
||||
|
||||
initRouter(api, d, c)
|
||||
|
|
|
@ -2,6 +2,7 @@ package daemon
|
|||
|
||||
import (
|
||||
"io"
|
||||
"runtime"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/distribution/reference"
|
||||
|
@ -147,7 +148,8 @@ func (daemon *Daemon) GetImageAndReleasableLayer(ctx context.Context, refOrID st
|
|||
image, _ := daemon.GetImage(refOrID)
|
||||
// TODO: shouldn't we error out if error is different from "not found" ?
|
||||
if image != nil {
|
||||
layer, err := newReleasableLayerForImage(image, daemon.layerStore)
|
||||
// TODO LCOW @jhowardmsft. For now using runtime.GOOS for this, will need enhancing for platform when porting the builder
|
||||
layer, err := newReleasableLayerForImage(image, daemon.stores[runtime.GOOS].layerStore)
|
||||
return image, layer, err
|
||||
}
|
||||
}
|
||||
|
@ -156,7 +158,8 @@ func (daemon *Daemon) GetImageAndReleasableLayer(ctx context.Context, refOrID st
|
|||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
layer, err := newReleasableLayerForImage(image, daemon.layerStore)
|
||||
// TODO LCOW @jhowardmsft. For now using runtime.GOOS for this, will need enhancing for platform when porting the builder
|
||||
layer, err := newReleasableLayerForImage(image, daemon.stores[runtime.GOOS].layerStore)
|
||||
return image, layer, err
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package daemon
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/builder"
|
||||
"github.com/docker/docker/image/cache"
|
||||
|
@ -9,10 +11,12 @@ import (
|
|||
// MakeImageCache creates a stateful image cache.
|
||||
func (daemon *Daemon) MakeImageCache(sourceRefs []string) builder.ImageCache {
|
||||
if len(sourceRefs) == 0 {
|
||||
return cache.NewLocal(daemon.imageStore)
|
||||
// TODO @jhowardmsft LCOW. For now, assume it is the OS of the host
|
||||
return cache.NewLocal(daemon.stores[runtime.GOOS].imageStore)
|
||||
}
|
||||
|
||||
cache := cache.New(daemon.imageStore)
|
||||
// TODO @jhowardmsft LCOW. For now, assume it is the OS of the host
|
||||
cache := cache.New(daemon.stores[runtime.GOOS].imageStore)
|
||||
|
||||
for _, ref := range sourceRefs {
|
||||
img, err := daemon.GetImage(ref)
|
||||
|
|
|
@ -160,26 +160,21 @@ func (daemon *Daemon) Commit(name string, c *backend.ContainerCommitConfig) (str
|
|||
}()
|
||||
|
||||
var parent *image.Image
|
||||
os := runtime.GOOS
|
||||
if container.ImageID == "" {
|
||||
parent = new(image.Image)
|
||||
parent.RootFS = image.NewRootFS()
|
||||
} else {
|
||||
parent, err = daemon.imageStore.Get(container.ImageID)
|
||||
parent, err = daemon.stores[container.Platform].imageStore.Get(container.ImageID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
// To support LCOW, Windows needs to pass the platform in when registering the layer in the store
|
||||
if runtime.GOOS == "windows" {
|
||||
os = parent.OS
|
||||
}
|
||||
}
|
||||
|
||||
l, err := daemon.layerStore.Register(rwTar, parent.RootFS.ChainID(), layer.Platform(os))
|
||||
l, err := daemon.stores[container.Platform].layerStore.Register(rwTar, rootFS.ChainID(), layer.Platform(container.Platform))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer layer.ReleaseAndLog(daemon.layerStore, l)
|
||||
defer layer.ReleaseAndLog(daemon.stores[container.Platform].layerStore, l)
|
||||
|
||||
containerConfig := c.ContainerConfig
|
||||
if containerConfig == nil {
|
||||
|
@ -198,13 +193,13 @@ func (daemon *Daemon) Commit(name string, c *backend.ContainerCommitConfig) (str
|
|||
return "", err
|
||||
}
|
||||
|
||||
id, err := daemon.imageStore.Create(config)
|
||||
id, err := daemon.stores[container.Platform].imageStore.Create(config)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if container.ImageID != "" {
|
||||
if err := daemon.imageStore.SetParent(id, container.ImageID); err != nil {
|
||||
if err := daemon.stores[container.Platform].imageStore.SetParent(id, container.ImageID); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
@ -223,7 +218,7 @@ func (daemon *Daemon) Commit(name string, c *backend.ContainerCommitConfig) (str
|
|||
return "", err
|
||||
}
|
||||
}
|
||||
if err := daemon.TagImageWithReference(id, newTag); err != nil {
|
||||
if err := daemon.TagImageWithReference(id, container.Platform, newTag); err != nil {
|
||||
return "", err
|
||||
}
|
||||
imageRef = reference.FamiliarString(newTag)
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/errors"
|
||||
|
@ -144,8 +145,10 @@ func (daemon *Daemon) newContainer(name string, config *containertypes.Config, h
|
|||
base.ImageID = imgID
|
||||
base.NetworkSettings = &network.Settings{IsAnonymousEndpoint: noExplicitName}
|
||||
base.Name = name
|
||||
base.Driver = daemon.GraphDriverName()
|
||||
|
||||
// TODO @jhowardmsft LCOW - Get it from the platform of the container. For now, assume it is the OS of the host
|
||||
base.Driver = daemon.GraphDriverName(runtime.GOOS)
|
||||
// TODO @jhowardmsft LCOW - Similarly on this field. To solve this it will need a CLI/REST change in a subsequent PR during LCOW development
|
||||
base.Platform = runtime.GOOS
|
||||
return base, err
|
||||
}
|
||||
|
||||
|
|
|
@ -215,7 +215,7 @@ func (daemon *Daemon) generateSecurityOpt(hostConfig *containertypes.HostConfig)
|
|||
func (daemon *Daemon) setRWLayer(container *container.Container) error {
|
||||
var layerID layer.ChainID
|
||||
if container.ImageID != "" {
|
||||
img, err := daemon.imageStore.Get(container.ImageID)
|
||||
img, err := daemon.stores[container.Platform].imageStore.Get(container.ImageID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -228,7 +228,7 @@ func (daemon *Daemon) setRWLayer(container *container.Container) error {
|
|||
StorageOpt: container.HostConfig.StorageOpt,
|
||||
}
|
||||
|
||||
rwLayer, err := daemon.layerStore.CreateRWLayer(container.ID, layerID, rwLayerOpts)
|
||||
rwLayer, err := daemon.stores[container.Platform].layerStore.CreateRWLayer(container.ID, layerID, rwLayerOpts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
238
daemon/daemon.go
238
daemon/daemon.go
|
@ -69,43 +69,49 @@ var (
|
|||
errSystemNotSupported = errors.New("The Docker daemon is not supported on this platform.")
|
||||
)
|
||||
|
||||
type daemonStore struct {
|
||||
graphDriver string
|
||||
imageRoot string
|
||||
imageStore image.Store
|
||||
layerStore layer.Store
|
||||
distributionMetadataStore dmetadata.Store
|
||||
referenceStore refstore.Store
|
||||
}
|
||||
|
||||
// Daemon holds information about the Docker daemon.
|
||||
type Daemon struct {
|
||||
ID string
|
||||
repository string
|
||||
containers container.Store
|
||||
execCommands *exec.Store
|
||||
referenceStore refstore.Store
|
||||
downloadManager *xfer.LayerDownloadManager
|
||||
uploadManager *xfer.LayerUploadManager
|
||||
distributionMetadataStore dmetadata.Store
|
||||
trustKey libtrust.PrivateKey
|
||||
idIndex *truncindex.TruncIndex
|
||||
configStore *config.Config
|
||||
statsCollector *stats.Collector
|
||||
defaultLogConfig containertypes.LogConfig
|
||||
RegistryService registry.Service
|
||||
EventsService *events.Events
|
||||
netController libnetwork.NetworkController
|
||||
volumes *store.VolumeStore
|
||||
discoveryWatcher discovery.Reloader
|
||||
root string
|
||||
seccompEnabled bool
|
||||
apparmorEnabled bool
|
||||
shutdown bool
|
||||
idMappings *idtools.IDMappings
|
||||
layerStore layer.Store
|
||||
imageStore image.Store
|
||||
PluginStore *plugin.Store // todo: remove
|
||||
pluginManager *plugin.Manager
|
||||
nameIndex *registrar.Registrar
|
||||
linkIndex *linkIndex
|
||||
containerd libcontainerd.Client
|
||||
containerdRemote libcontainerd.Remote
|
||||
defaultIsolation containertypes.Isolation // Default isolation mode on Windows
|
||||
clusterProvider cluster.Provider
|
||||
cluster Cluster
|
||||
metricsPluginListener net.Listener
|
||||
ID string
|
||||
repository string
|
||||
containers container.Store
|
||||
execCommands *exec.Store
|
||||
downloadManager *xfer.LayerDownloadManager
|
||||
uploadManager *xfer.LayerUploadManager
|
||||
trustKey libtrust.PrivateKey
|
||||
idIndex *truncindex.TruncIndex
|
||||
configStore *config.Config
|
||||
statsCollector *stats.Collector
|
||||
defaultLogConfig containertypes.LogConfig
|
||||
RegistryService registry.Service
|
||||
EventsService *events.Events
|
||||
netController libnetwork.NetworkController
|
||||
volumes *store.VolumeStore
|
||||
discoveryWatcher discovery.Reloader
|
||||
root string
|
||||
seccompEnabled bool
|
||||
apparmorEnabled bool
|
||||
shutdown bool
|
||||
idMappings *idtools.IDMappings
|
||||
stores map[string]daemonStore // By container target platform
|
||||
PluginStore *plugin.Store // todo: remove
|
||||
pluginManager *plugin.Manager
|
||||
nameIndex *registrar.Registrar
|
||||
linkIndex *linkIndex
|
||||
containerd libcontainerd.Client
|
||||
containerdRemote libcontainerd.Remote
|
||||
defaultIsolation containertypes.Isolation // Default isolation mode on Windows
|
||||
clusterProvider cluster.Provider
|
||||
cluster Cluster
|
||||
metricsPluginListener net.Listener
|
||||
|
||||
machineMemory uint64
|
||||
|
||||
|
@ -137,10 +143,7 @@ func (daemon *Daemon) HasExperimental() bool {
|
|||
}
|
||||
|
||||
func (daemon *Daemon) restore() error {
|
||||
var (
|
||||
currentDriver = daemon.GraphDriverName()
|
||||
containers = make(map[string]*container.Container)
|
||||
)
|
||||
containers := make(map[string]*container.Container)
|
||||
|
||||
logrus.Info("Loading containers: start.")
|
||||
|
||||
|
@ -158,8 +161,9 @@ func (daemon *Daemon) restore() error {
|
|||
}
|
||||
|
||||
// Ignore the container if it does not support the current driver being used by the graph
|
||||
if (container.Driver == "" && currentDriver == "aufs") || container.Driver == currentDriver {
|
||||
rwlayer, err := daemon.layerStore.GetRWLayer(container.ID)
|
||||
currentDriverForContainerPlatform := daemon.stores[container.Platform].graphDriver
|
||||
if (container.Driver == "" && currentDriverForContainerPlatform == "aufs") || container.Driver == currentDriverForContainerPlatform {
|
||||
rwlayer, err := daemon.stores[container.Platform].layerStore.GetRWLayer(container.ID)
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to load container mount %v: %v", id, err)
|
||||
continue
|
||||
|
@ -595,9 +599,24 @@ func NewDaemon(config *config.Config, registryService registry.Service, containe
|
|||
}
|
||||
}
|
||||
|
||||
driverName := os.Getenv("DOCKER_DRIVER")
|
||||
if driverName == "" {
|
||||
driverName = config.GraphDriver
|
||||
// On Windows we don't support the environment variable, or a user supplied graphdriver
|
||||
// as Windows has no choice in terms of which graphdrivers to use. It's a case of
|
||||
// running Windows containers on Windows - windowsfilter, running Linux containers on Windows,
|
||||
// lcow. Unix platforms however run a single graphdriver for all containers, and it can
|
||||
// be set through an environment variable, a daemon start parameter, or chosen through
|
||||
// initialization of the layerstore through driver priority order for example.
|
||||
d.stores = make(map[string]daemonStore)
|
||||
if runtime.GOOS == "windows" {
|
||||
d.stores["windows"] = daemonStore{graphDriver: "windowsfilter"}
|
||||
if system.LCOWSupported() {
|
||||
d.stores["linux"] = daemonStore{graphDriver: "lcow"}
|
||||
}
|
||||
} else {
|
||||
driverName := os.Getenv("DOCKER_DRIVER")
|
||||
if driverName == "" {
|
||||
driverName = config.GraphDriver
|
||||
}
|
||||
d.stores[runtime.GOOS] = daemonStore{graphDriver: driverName} // May still be empty. Layerstore init determines instead.
|
||||
}
|
||||
|
||||
d.RegistryService = registryService
|
||||
|
@ -625,42 +644,55 @@ func NewDaemon(config *config.Config, registryService registry.Service, containe
|
|||
return nil, errors.Wrap(err, "couldn't create plugin manager")
|
||||
}
|
||||
|
||||
d.layerStore, err = layer.NewStoreFromOptions(layer.StoreOptions{
|
||||
StorePath: config.Root,
|
||||
MetadataStorePathTemplate: filepath.Join(config.Root, "image", "%s", "layerdb"),
|
||||
GraphDriver: driverName,
|
||||
GraphDriverOptions: config.GraphOptions,
|
||||
IDMappings: idMappings,
|
||||
PluginGetter: d.PluginStore,
|
||||
ExperimentalEnabled: config.Experimental,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
var graphDrivers []string
|
||||
for platform, ds := range d.stores {
|
||||
ls, err := layer.NewStoreFromOptions(layer.StoreOptions{
|
||||
StorePath: config.Root,
|
||||
MetadataStorePathTemplate: filepath.Join(config.Root, "image", "%s", "layerdb"),
|
||||
GraphDriver: ds.graphDriver,
|
||||
GraphDriverOptions: config.GraphOptions,
|
||||
IDMappings: idMappings,
|
||||
PluginGetter: d.PluginStore,
|
||||
ExperimentalEnabled: config.Experimental,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ds.graphDriver = ls.DriverName() // As layerstore may set the driver
|
||||
ds.layerStore = ls
|
||||
d.stores[platform] = ds
|
||||
graphDrivers = append(graphDrivers, ls.DriverName())
|
||||
}
|
||||
|
||||
graphDriver := d.layerStore.DriverName()
|
||||
imageRoot := filepath.Join(config.Root, "image", graphDriver)
|
||||
|
||||
// Configure and validate the kernels security support
|
||||
if err := configureKernelSecuritySupport(config, graphDriver); err != nil {
|
||||
if err := configureKernelSecuritySupport(config, graphDrivers); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
logrus.Debugf("Max Concurrent Downloads: %d", *config.MaxConcurrentDownloads)
|
||||
d.downloadManager = xfer.NewLayerDownloadManager(d.layerStore, *config.MaxConcurrentDownloads)
|
||||
lsMap := make(map[string]layer.Store)
|
||||
for platform, ds := range d.stores {
|
||||
lsMap[platform] = ds.layerStore
|
||||
}
|
||||
d.downloadManager = xfer.NewLayerDownloadManager(lsMap, *config.MaxConcurrentDownloads)
|
||||
logrus.Debugf("Max Concurrent Uploads: %d", *config.MaxConcurrentUploads)
|
||||
d.uploadManager = xfer.NewLayerUploadManager(*config.MaxConcurrentUploads)
|
||||
|
||||
ifs, err := image.NewFSStoreBackend(filepath.Join(imageRoot, "imagedb"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for platform, ds := range d.stores {
|
||||
imageRoot := filepath.Join(config.Root, "image", ds.graphDriver)
|
||||
ifs, err := image.NewFSStoreBackend(filepath.Join(imageRoot, "imagedb"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// TODO LCOW @jhowardmsft. For now assume it's the runtime OS. This will be modified
|
||||
// as the stores are split in a follow-up commit.
|
||||
d.imageStore, err = image.NewImageStore(ifs, runtime.GOOS, d.layerStore)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
var is image.Store
|
||||
is, err = image.NewImageStore(ifs, platform, ds.layerStore)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ds.imageRoot = imageRoot
|
||||
ds.imageStore = is
|
||||
d.stores[platform] = ds
|
||||
}
|
||||
|
||||
// Configure the volumes driver
|
||||
|
@ -680,23 +712,31 @@ func NewDaemon(config *config.Config, registryService registry.Service, containe
|
|||
return nil, err
|
||||
}
|
||||
|
||||
distributionMetadataStore, err := dmetadata.NewFSMetadataStore(filepath.Join(imageRoot, "distribution"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
eventsService := events.New()
|
||||
|
||||
referenceStore, err := refstore.NewReferenceStore(filepath.Join(imageRoot, "repositories.json"))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Couldn't create Tag store repositories: %s", err)
|
||||
}
|
||||
for platform, ds := range d.stores {
|
||||
dms, err := dmetadata.NewFSMetadataStore(filepath.Join(ds.imageRoot, "distribution"), platform)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
migrationStart := time.Now()
|
||||
if err := v1.Migrate(config.Root, graphDriver, d.layerStore, d.imageStore, referenceStore, distributionMetadataStore); err != nil {
|
||||
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)
|
||||
rs, err := refstore.NewReferenceStore(filepath.Join(ds.imageRoot, "repositories.json"), platform)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Couldn't create Tag store repositories: %s", err)
|
||||
}
|
||||
ds.distributionMetadataStore = dms
|
||||
ds.referenceStore = rs
|
||||
d.stores[platform] = ds
|
||||
|
||||
// No content-addressability migration on Windows as it never supported pre-CA
|
||||
if runtime.GOOS != "windows" {
|
||||
migrationStart := time.Now()
|
||||
if err := v1.Migrate(config.Root, ds.graphDriver, ds.layerStore, ds.imageStore, rs, dms); err != nil {
|
||||
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)
|
||||
}
|
||||
logrus.Infof("Graph migration to content-addressability took %.2f seconds", time.Since(migrationStart).Seconds())
|
||||
}
|
||||
}
|
||||
logrus.Infof("Graph migration to content-addressability took %.2f seconds", time.Since(migrationStart).Seconds())
|
||||
|
||||
// Discovery is only enabled when the daemon is launched with an address to advertise. When
|
||||
// initialized, the daemon is registered and we can store the discovery backend as it's read-only
|
||||
|
@ -715,8 +755,6 @@ func NewDaemon(config *config.Config, registryService registry.Service, containe
|
|||
d.repository = daemonRepo
|
||||
d.containers = container.NewMemoryStore()
|
||||
d.execCommands = exec.NewStore()
|
||||
d.referenceStore = referenceStore
|
||||
d.distributionMetadataStore = distributionMetadataStore
|
||||
d.trustKey = trustKey
|
||||
d.idIndex = truncindex.NewTruncIndex([]string{})
|
||||
d.statsCollector = d.newStatsCollector(1 * time.Second)
|
||||
|
@ -763,6 +801,22 @@ func NewDaemon(config *config.Config, registryService registry.Service, containe
|
|||
engineCpus.Set(float64(info.NCPU))
|
||||
engineMemory.Set(float64(info.MemTotal))
|
||||
|
||||
gd := ""
|
||||
for platform, ds := range d.stores {
|
||||
if len(gd) > 0 {
|
||||
gd += ", "
|
||||
}
|
||||
gd += ds.graphDriver
|
||||
if len(d.stores) > 1 {
|
||||
gd = fmt.Sprintf("%s (%s)", gd, platform)
|
||||
}
|
||||
}
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"version": dockerversion.Version,
|
||||
"commit": dockerversion.GitCommit,
|
||||
"graphdriver(s)": gd,
|
||||
}).Info("Docker daemon")
|
||||
|
||||
return d, nil
|
||||
}
|
||||
|
||||
|
@ -869,7 +923,7 @@ func (daemon *Daemon) Shutdown() error {
|
|||
logrus.Errorf("Stop container error: %v", err)
|
||||
return
|
||||
}
|
||||
if mountid, err := daemon.layerStore.GetMountID(c.ID); err == nil {
|
||||
if mountid, err := daemon.stores[c.Platform].layerStore.GetMountID(c.ID); err == nil {
|
||||
daemon.cleanupMountsByID(mountid)
|
||||
}
|
||||
logrus.Debugf("container stopped %s", c.ID)
|
||||
|
@ -882,9 +936,11 @@ func (daemon *Daemon) Shutdown() error {
|
|||
}
|
||||
}
|
||||
|
||||
if daemon.layerStore != nil {
|
||||
if err := daemon.layerStore.Cleanup(); err != nil {
|
||||
logrus.Errorf("Error during layer Store.Cleanup(): %v", err)
|
||||
for platform, ds := range daemon.stores {
|
||||
if ds.layerStore != nil {
|
||||
if err := ds.layerStore.Cleanup(); err != nil {
|
||||
logrus.Errorf("Error during layer Store.Cleanup(): %v %s", err, platform)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -927,7 +983,7 @@ func (daemon *Daemon) Mount(container *container.Container) error {
|
|||
if container.BaseFS != "" && runtime.GOOS != "windows" {
|
||||
daemon.Unmount(container)
|
||||
return fmt.Errorf("Error: driver %s is returning inconsistent paths for container %s ('%s' then '%s')",
|
||||
daemon.GraphDriverName(), container.ID, container.BaseFS, dir)
|
||||
daemon.GraphDriverName(container.Platform), container.ID, container.BaseFS, dir)
|
||||
}
|
||||
}
|
||||
container.BaseFS = dir // TODO: combine these fields
|
||||
|
@ -969,8 +1025,8 @@ func (daemon *Daemon) Subnets() ([]net.IPNet, []net.IPNet) {
|
|||
}
|
||||
|
||||
// GraphDriverName returns the name of the graph driver used by the layer.Store
|
||||
func (daemon *Daemon) GraphDriverName() string {
|
||||
return daemon.layerStore.DriverName()
|
||||
func (daemon *Daemon) GraphDriverName(platform string) string {
|
||||
return daemon.stores[platform].layerStore.DriverName()
|
||||
}
|
||||
|
||||
// prepareTempDir prepares and returns the default directory to use
|
||||
|
|
|
@ -353,7 +353,7 @@ func configureMaxThreads(config *Config) error {
|
|||
}
|
||||
|
||||
// configureKernelSecuritySupport configures and validate security support for the kernel
|
||||
func configureKernelSecuritySupport(config *Config, driverName string) error {
|
||||
func configureKernelSecuritySupport(config *config.Config, driverNames []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -702,14 +702,22 @@ func overlaySupportsSelinux() (bool, error) {
|
|||
}
|
||||
|
||||
// configureKernelSecuritySupport configures and validates security support for the kernel
|
||||
func configureKernelSecuritySupport(config *config.Config, driverName string) error {
|
||||
func configureKernelSecuritySupport(config *config.Config, driverNames []string) error {
|
||||
if config.EnableSelinuxSupport {
|
||||
if !selinuxEnabled() {
|
||||
logrus.Warn("Docker could not enable SELinux on the host system")
|
||||
return nil
|
||||
}
|
||||
|
||||
if driverName == "overlay" || driverName == "overlay2" {
|
||||
overlayFound := false
|
||||
for _, d := range driverNames {
|
||||
if d == "overlay" || d == "overlay2" {
|
||||
overlayFound = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if overlayFound {
|
||||
// If driver is overlay or overlay2, make sure kernel
|
||||
// supports selinux with overlay.
|
||||
supported, err := overlaySupportsSelinux()
|
||||
|
@ -718,7 +726,7 @@ func configureKernelSecuritySupport(config *config.Config, driverName string) er
|
|||
}
|
||||
|
||||
if !supported {
|
||||
logrus.Warnf("SELinux is not supported with the %s graph driver on this kernel", driverName)
|
||||
logrus.Warnf("SELinux is not supported with the %v graph driver on this kernel", driverNames)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -260,7 +260,7 @@ func checkSystem() error {
|
|||
}
|
||||
|
||||
// configureKernelSecuritySupport configures and validate security support for the kernel
|
||||
func configureKernelSecuritySupport(config *config.Config, driverName string) error {
|
||||
func configureKernelSecuritySupport(config *config.Config, driverNames []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -115,10 +115,10 @@ func (daemon *Daemon) cleanupContainer(container *container.Container, forceRemo
|
|||
// When container creation fails and `RWLayer` has not been created yet, we
|
||||
// do not call `ReleaseRWLayer`
|
||||
if container.RWLayer != nil {
|
||||
metadata, err := daemon.layerStore.ReleaseRWLayer(container.RWLayer)
|
||||
metadata, err := daemon.stores[container.Platform].layerStore.ReleaseRWLayer(container.RWLayer)
|
||||
layer.LogReleaseMetadata(metadata)
|
||||
if err != nil && err != layer.ErrMountDoesNotExist {
|
||||
return errors.Wrapf(err, "driver %q failed to remove root filesystem for %s", daemon.GraphDriverName(), container.ID)
|
||||
return errors.Wrapf(err, "driver %q failed to remove root filesystem for %s", daemon.GraphDriverName(container.Platform), container.ID)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,12 +15,12 @@ import (
|
|||
"github.com/opencontainers/go-digest"
|
||||
)
|
||||
|
||||
func (daemon *Daemon) getLayerRefs() map[layer.ChainID]int {
|
||||
tmpImages := daemon.imageStore.Map()
|
||||
func (daemon *Daemon) getLayerRefs(platform string) map[layer.ChainID]int {
|
||||
tmpImages := daemon.stores[platform].imageStore.Map()
|
||||
layerRefs := map[layer.ChainID]int{}
|
||||
for id, img := range tmpImages {
|
||||
dgst := digest.Digest(id)
|
||||
if len(daemon.referenceStore.References(dgst)) == 0 && len(daemon.imageStore.Children(id)) != 0 {
|
||||
if len(daemon.stores[platform].referenceStore.References(dgst)) == 0 && len(daemon.stores[platform].imageStore.Children(id)) != 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -53,6 +53,7 @@ func (daemon *Daemon) SystemDiskUsage(ctx context.Context) (*types.DiskUsage, er
|
|||
}
|
||||
|
||||
// Get all top images with extra attributes
|
||||
// TODO @jhowardmsft LCOW. This may need revisiting
|
||||
allImages, err := daemon.Images(filters.NewArgs(), false, true)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to retrieve image list: %v", err)
|
||||
|
@ -94,23 +95,26 @@ func (daemon *Daemon) SystemDiskUsage(ctx context.Context) (*types.DiskUsage, er
|
|||
}
|
||||
|
||||
// Get total layers size on disk
|
||||
layerRefs := daemon.getLayerRefs()
|
||||
allLayers := daemon.layerStore.Map()
|
||||
var allLayersSize int64
|
||||
for _, l := range allLayers {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
default:
|
||||
size, err := l.DiffSize()
|
||||
if err == nil {
|
||||
if _, ok := layerRefs[l.ChainID()]; ok {
|
||||
allLayersSize += size
|
||||
for platform := range daemon.stores {
|
||||
layerRefs := daemon.getLayerRefs(platform)
|
||||
allLayers := daemon.stores[platform].layerStore.Map()
|
||||
var allLayersSize int64
|
||||
for _, l := range allLayers {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
default:
|
||||
size, err := l.DiffSize()
|
||||
if err == nil {
|
||||
if _, ok := layerRefs[l.ChainID()]; ok {
|
||||
allLayersSize += size
|
||||
} else {
|
||||
logrus.Warnf("found leaked image layer %v platform %s", l.ChainID(), platform)
|
||||
}
|
||||
} else {
|
||||
logrus.Warnf("found leaked image layer %v", l.ChainID())
|
||||
logrus.Warnf("failed to get diff size for layer %v %s", l.ChainID(), platform)
|
||||
}
|
||||
} else {
|
||||
logrus.Warnf("failed to get diff size for layer %v", l.ChainID())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
package daemon
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
)
|
||||
|
||||
|
@ -13,17 +15,17 @@ func (daemon *Daemon) getSize(containerID string) (int64, int64) {
|
|||
err error
|
||||
)
|
||||
|
||||
rwlayer, err := daemon.layerStore.GetRWLayer(containerID)
|
||||
rwlayer, err := daemon.stores[runtime.GOOS].layerStore.GetRWLayer(containerID)
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to compute size of container rootfs %v: %v", containerID, err)
|
||||
return sizeRw, sizeRootfs
|
||||
}
|
||||
defer daemon.layerStore.ReleaseRWLayer(rwlayer)
|
||||
defer daemon.stores[runtime.GOOS].layerStore.ReleaseRWLayer(rwlayer)
|
||||
|
||||
sizeRw, err = rwlayer.Size()
|
||||
if err != nil {
|
||||
logrus.Errorf("Driver %s couldn't return diff size of container %s: %s",
|
||||
daemon.GraphDriverName(), containerID, err)
|
||||
daemon.GraphDriverName(runtime.GOOS), containerID, err)
|
||||
// FIXME: GetSize should return an error. Not changing it now in case
|
||||
// there is a side-effect.
|
||||
sizeRw = -1
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package register
|
||||
|
||||
import (
|
||||
// register the windows graph driver
|
||||
// register the windows graph drivers
|
||||
_ "github.com/docker/docker/daemon/graphdriver/lcow"
|
||||
_ "github.com/docker/docker/daemon/graphdriver/windows"
|
||||
)
|
||||
|
|
|
@ -94,6 +94,10 @@ func InitFilter(home string, options []string, uidMaps, gidMaps []idtools.IDMap)
|
|||
return nil, fmt.Errorf("%s is on an ReFS volume - ReFS volumes are not supported", home)
|
||||
}
|
||||
|
||||
if err := idtools.MkdirAllAs(home, 0700, 0, 0); err != nil {
|
||||
return nil, fmt.Errorf("windowsfilter failed to create '%s': %v", home, err)
|
||||
}
|
||||
|
||||
d := &Driver{
|
||||
info: hcsshim.DriverInfo{
|
||||
HomeDir: home,
|
||||
|
|
|
@ -21,37 +21,43 @@ func (e ErrImageDoesNotExist) Error() string {
|
|||
return fmt.Sprintf("No such image: %s", reference.FamiliarString(ref))
|
||||
}
|
||||
|
||||
// GetImageID returns an image ID corresponding to the image referred to by
|
||||
// GetImageIDAndPlatform returns an image ID and platform corresponding to the image referred to by
|
||||
// refOrID.
|
||||
func (daemon *Daemon) GetImageID(refOrID string) (image.ID, error) {
|
||||
func (daemon *Daemon) GetImageIDAndPlatform(refOrID string) (image.ID, string, error) {
|
||||
ref, err := reference.ParseAnyReference(refOrID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", "", err
|
||||
}
|
||||
namedRef, ok := ref.(reference.Named)
|
||||
if !ok {
|
||||
digested, ok := ref.(reference.Digested)
|
||||
if !ok {
|
||||
return "", ErrImageDoesNotExist{ref}
|
||||
return "", "", ErrImageDoesNotExist{ref}
|
||||
}
|
||||
id := image.IDFromDigest(digested.Digest())
|
||||
if _, err := daemon.imageStore.Get(id); err != nil {
|
||||
return "", ErrImageDoesNotExist{ref}
|
||||
for platform := range daemon.stores {
|
||||
if _, err = daemon.stores[platform].imageStore.Get(id); err == nil {
|
||||
return id, platform, nil
|
||||
}
|
||||
}
|
||||
return id, nil
|
||||
return "", "", ErrImageDoesNotExist{ref}
|
||||
}
|
||||
|
||||
if id, err := daemon.referenceStore.Get(namedRef); err == nil {
|
||||
return image.IDFromDigest(id), nil
|
||||
for platform := range daemon.stores {
|
||||
if id, err := daemon.stores[platform].referenceStore.Get(namedRef); err == nil {
|
||||
return image.IDFromDigest(id), platform, nil
|
||||
}
|
||||
}
|
||||
|
||||
// deprecated: repo:shortid https://github.com/docker/docker/pull/799
|
||||
if tagged, ok := namedRef.(reference.Tagged); ok {
|
||||
if tag := tagged.Tag(); stringid.IsShortID(stringid.TruncateID(tag)) {
|
||||
if id, err := daemon.imageStore.Search(tag); err == nil {
|
||||
for _, storeRef := range daemon.referenceStore.References(id.Digest()) {
|
||||
if storeRef.Name() == namedRef.Name() {
|
||||
return id, nil
|
||||
for platform := range daemon.stores {
|
||||
if id, err := daemon.stores[platform].imageStore.Search(tag); err == nil {
|
||||
for _, storeRef := range daemon.stores[platform].referenceStore.References(id.Digest()) {
|
||||
if storeRef.Name() == namedRef.Name() {
|
||||
return id, platform, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -59,18 +65,20 @@ func (daemon *Daemon) GetImageID(refOrID string) (image.ID, error) {
|
|||
}
|
||||
|
||||
// Search based on ID
|
||||
if id, err := daemon.imageStore.Search(refOrID); err == nil {
|
||||
return id, nil
|
||||
for platform := range daemon.stores {
|
||||
if id, err := daemon.stores[platform].imageStore.Search(refOrID); err == nil {
|
||||
return id, platform, nil
|
||||
}
|
||||
}
|
||||
|
||||
return "", ErrImageDoesNotExist{ref}
|
||||
return "", "", ErrImageDoesNotExist{ref}
|
||||
}
|
||||
|
||||
// GetImage returns an image corresponding to the image referred to by refOrID.
|
||||
func (daemon *Daemon) GetImage(refOrID string) (*image.Image, error) {
|
||||
imgID, err := daemon.GetImageID(refOrID)
|
||||
imgID, platform, err := daemon.GetImageIDAndPlatform(refOrID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return daemon.imageStore.Get(imgID)
|
||||
return daemon.stores[platform].imageStore.Get(imgID)
|
||||
}
|
||||
|
|
|
@ -65,12 +65,12 @@ func (daemon *Daemon) ImageDelete(imageRef string, force, prune bool) ([]types.I
|
|||
start := time.Now()
|
||||
records := []types.ImageDeleteResponseItem{}
|
||||
|
||||
imgID, err := daemon.GetImageID(imageRef)
|
||||
imgID, platform, err := daemon.GetImageIDAndPlatform(imageRef)
|
||||
if err != nil {
|
||||
return nil, daemon.imageNotExistToErrcode(err)
|
||||
}
|
||||
|
||||
repoRefs := daemon.referenceStore.References(imgID.Digest())
|
||||
repoRefs := daemon.stores[platform].referenceStore.References(imgID.Digest())
|
||||
|
||||
var removedRepositoryRef bool
|
||||
if !isImageIDPrefix(imgID.String(), imageRef) {
|
||||
|
@ -94,7 +94,7 @@ func (daemon *Daemon) ImageDelete(imageRef string, force, prune bool) ([]types.I
|
|||
return nil, err
|
||||
}
|
||||
|
||||
parsedRef, err = daemon.removeImageRef(parsedRef)
|
||||
parsedRef, err = daemon.removeImageRef(platform, parsedRef)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -104,7 +104,7 @@ func (daemon *Daemon) ImageDelete(imageRef string, force, prune bool) ([]types.I
|
|||
daemon.LogImageEvent(imgID.String(), imgID.String(), "untag")
|
||||
records = append(records, untaggedRecord)
|
||||
|
||||
repoRefs = daemon.referenceStore.References(imgID.Digest())
|
||||
repoRefs = daemon.stores[platform].referenceStore.References(imgID.Digest())
|
||||
|
||||
// If a tag reference was removed and the only remaining
|
||||
// references to the same repository are digest references,
|
||||
|
@ -122,7 +122,7 @@ func (daemon *Daemon) ImageDelete(imageRef string, force, prune bool) ([]types.I
|
|||
remainingRefs := []reference.Named{}
|
||||
for _, repoRef := range repoRefs {
|
||||
if _, repoRefIsCanonical := repoRef.(reference.Canonical); repoRefIsCanonical && parsedRef.Name() == repoRef.Name() {
|
||||
if _, err := daemon.removeImageRef(repoRef); err != nil {
|
||||
if _, err := daemon.removeImageRef(platform, repoRef); err != nil {
|
||||
return records, err
|
||||
}
|
||||
|
||||
|
@ -152,12 +152,12 @@ func (daemon *Daemon) ImageDelete(imageRef string, force, prune bool) ([]types.I
|
|||
if !force {
|
||||
c |= conflictSoft &^ conflictActiveReference
|
||||
}
|
||||
if conflict := daemon.checkImageDeleteConflict(imgID, c); conflict != nil {
|
||||
if conflict := daemon.checkImageDeleteConflict(imgID, platform, c); conflict != nil {
|
||||
return nil, conflict
|
||||
}
|
||||
|
||||
for _, repoRef := range repoRefs {
|
||||
parsedRef, err := daemon.removeImageRef(repoRef)
|
||||
parsedRef, err := daemon.removeImageRef(platform, repoRef)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -170,7 +170,7 @@ func (daemon *Daemon) ImageDelete(imageRef string, force, prune bool) ([]types.I
|
|||
}
|
||||
}
|
||||
|
||||
if err := daemon.imageDeleteHelper(imgID, &records, force, prune, removedRepositoryRef); err != nil {
|
||||
if err := daemon.imageDeleteHelper(imgID, platform, &records, force, prune, removedRepositoryRef); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -231,13 +231,13 @@ func (daemon *Daemon) getContainerUsingImage(imageID image.ID) *container.Contai
|
|||
// repositoryRef must not be an image ID but a repository name followed by an
|
||||
// optional tag or digest reference. If tag or digest is omitted, the default
|
||||
// tag is used. Returns the resolved image reference and an error.
|
||||
func (daemon *Daemon) removeImageRef(ref reference.Named) (reference.Named, error) {
|
||||
func (daemon *Daemon) removeImageRef(platform string, ref reference.Named) (reference.Named, error) {
|
||||
ref = reference.TagNameOnly(ref)
|
||||
|
||||
// Ignore the boolean value returned, as far as we're concerned, this
|
||||
// is an idempotent operation and it's okay if the reference didn't
|
||||
// exist in the first place.
|
||||
_, err := daemon.referenceStore.Delete(ref)
|
||||
_, err := daemon.stores[platform].referenceStore.Delete(ref)
|
||||
|
||||
return ref, err
|
||||
}
|
||||
|
@ -247,11 +247,11 @@ func (daemon *Daemon) removeImageRef(ref reference.Named) (reference.Named, erro
|
|||
// on the first encountered error. Removed references are logged to this
|
||||
// daemon's event service. An "Untagged" types.ImageDeleteResponseItem is added to the
|
||||
// given list of records.
|
||||
func (daemon *Daemon) removeAllReferencesToImageID(imgID image.ID, records *[]types.ImageDeleteResponseItem) error {
|
||||
imageRefs := daemon.referenceStore.References(imgID.Digest())
|
||||
func (daemon *Daemon) removeAllReferencesToImageID(imgID image.ID, platform string, records *[]types.ImageDeleteResponseItem) error {
|
||||
imageRefs := daemon.stores[platform].referenceStore.References(imgID.Digest())
|
||||
|
||||
for _, imageRef := range imageRefs {
|
||||
parsedRef, err := daemon.removeImageRef(imageRef)
|
||||
parsedRef, err := daemon.removeImageRef(platform, imageRef)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -296,15 +296,15 @@ func (idc *imageDeleteConflict) Error() string {
|
|||
// conflict is encountered, it will be returned immediately without deleting
|
||||
// the image. If quiet is true, any encountered conflicts will be ignored and
|
||||
// the function will return nil immediately without deleting the image.
|
||||
func (daemon *Daemon) imageDeleteHelper(imgID image.ID, records *[]types.ImageDeleteResponseItem, force, prune, quiet bool) error {
|
||||
func (daemon *Daemon) imageDeleteHelper(imgID image.ID, platform string, records *[]types.ImageDeleteResponseItem, force, prune, quiet bool) error {
|
||||
// First, determine if this image has any conflicts. Ignore soft conflicts
|
||||
// if force is true.
|
||||
c := conflictHard
|
||||
if !force {
|
||||
c |= conflictSoft
|
||||
}
|
||||
if conflict := daemon.checkImageDeleteConflict(imgID, c); conflict != nil {
|
||||
if quiet && (!daemon.imageIsDangling(imgID) || conflict.used) {
|
||||
if conflict := daemon.checkImageDeleteConflict(imgID, platform, c); conflict != nil {
|
||||
if quiet && (!daemon.imageIsDangling(imgID, platform) || conflict.used) {
|
||||
// Ignore conflicts UNLESS the image is "dangling" or not being used in
|
||||
// which case we want the user to know.
|
||||
return nil
|
||||
|
@ -315,18 +315,18 @@ func (daemon *Daemon) imageDeleteHelper(imgID image.ID, records *[]types.ImageDe
|
|||
return conflict
|
||||
}
|
||||
|
||||
parent, err := daemon.imageStore.GetParent(imgID)
|
||||
parent, err := daemon.stores[platform].imageStore.GetParent(imgID)
|
||||
if err != nil {
|
||||
// There may be no parent
|
||||
parent = ""
|
||||
}
|
||||
|
||||
// Delete all repository tag/digest references to this image.
|
||||
if err := daemon.removeAllReferencesToImageID(imgID, records); err != nil {
|
||||
if err := daemon.removeAllReferencesToImageID(imgID, platform, records); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
removedLayers, err := daemon.imageStore.Delete(imgID)
|
||||
removedLayers, err := daemon.stores[platform].imageStore.Delete(imgID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -346,7 +346,7 @@ func (daemon *Daemon) imageDeleteHelper(imgID image.ID, records *[]types.ImageDe
|
|||
// either running or stopped).
|
||||
// Do not force prunings, but do so quietly (stopping on any encountered
|
||||
// conflicts).
|
||||
return daemon.imageDeleteHelper(parent, records, false, true, true)
|
||||
return daemon.imageDeleteHelper(parent, platform, records, false, true, true)
|
||||
}
|
||||
|
||||
// checkImageDeleteConflict determines whether there are any conflicts
|
||||
|
@ -355,9 +355,9 @@ func (daemon *Daemon) imageDeleteHelper(imgID image.ID, records *[]types.ImageDe
|
|||
// using the image. A soft conflict is any tags/digest referencing the given
|
||||
// image or any stopped container using the image. If ignoreSoftConflicts is
|
||||
// true, this function will not check for soft conflict conditions.
|
||||
func (daemon *Daemon) checkImageDeleteConflict(imgID image.ID, mask conflictType) *imageDeleteConflict {
|
||||
func (daemon *Daemon) checkImageDeleteConflict(imgID image.ID, platform string, mask conflictType) *imageDeleteConflict {
|
||||
// Check if the image has any descendant images.
|
||||
if mask&conflictDependentChild != 0 && len(daemon.imageStore.Children(imgID)) > 0 {
|
||||
if mask&conflictDependentChild != 0 && len(daemon.stores[platform].imageStore.Children(imgID)) > 0 {
|
||||
return &imageDeleteConflict{
|
||||
hard: true,
|
||||
imgID: imgID,
|
||||
|
@ -381,7 +381,7 @@ func (daemon *Daemon) checkImageDeleteConflict(imgID image.ID, mask conflictType
|
|||
}
|
||||
|
||||
// Check if any repository tags/digest reference this image.
|
||||
if mask&conflictActiveReference != 0 && len(daemon.referenceStore.References(imgID.Digest())) > 0 {
|
||||
if mask&conflictActiveReference != 0 && len(daemon.stores[platform].referenceStore.References(imgID.Digest())) > 0 {
|
||||
return &imageDeleteConflict{
|
||||
imgID: imgID,
|
||||
message: "image is referenced in multiple repositories",
|
||||
|
@ -408,6 +408,6 @@ func (daemon *Daemon) checkImageDeleteConflict(imgID image.ID, mask conflictType
|
|||
// imageIsDangling returns whether the given image is "dangling" which means
|
||||
// that there are no repository references to the given image and it has no
|
||||
// child images.
|
||||
func (daemon *Daemon) imageIsDangling(imgID image.ID) bool {
|
||||
return !(len(daemon.referenceStore.References(imgID.Digest())) > 0 || len(daemon.imageStore.Children(imgID)) > 0)
|
||||
func (daemon *Daemon) imageIsDangling(imgID image.ID, platform string) bool {
|
||||
return !(len(daemon.stores[platform].referenceStore.References(imgID.Digest())) > 0 || len(daemon.stores[platform].imageStore.Children(imgID)) > 0)
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package daemon
|
|||
|
||||
import (
|
||||
"io"
|
||||
"runtime"
|
||||
|
||||
"github.com/docker/docker/image/tarexport"
|
||||
)
|
||||
|
@ -12,7 +13,8 @@ import (
|
|||
// the same tag are exported. names is the set of tags to export, and
|
||||
// outStream is the writer which the images are written to.
|
||||
func (daemon *Daemon) ExportImage(names []string, outStream io.Writer) error {
|
||||
imageExporter := tarexport.NewTarExporter(daemon.imageStore, daemon.layerStore, daemon.referenceStore, daemon)
|
||||
// TODO @jhowardmsft LCOW. For now, assume it is the OS of the host
|
||||
imageExporter := tarexport.NewTarExporter(daemon.stores[runtime.GOOS].imageStore, daemon.stores[runtime.GOOS].layerStore, daemon.stores[runtime.GOOS].referenceStore, daemon)
|
||||
return imageExporter.Save(names, outStream)
|
||||
}
|
||||
|
||||
|
@ -20,6 +22,7 @@ func (daemon *Daemon) ExportImage(names []string, outStream io.Writer) error {
|
|||
// complement of ImageExport. The input stream is an uncompressed tar
|
||||
// ball containing images and metadata.
|
||||
func (daemon *Daemon) LoadImage(inTar io.ReadCloser, outStream io.Writer, quiet bool) error {
|
||||
imageExporter := tarexport.NewTarExporter(daemon.imageStore, daemon.layerStore, daemon.referenceStore, daemon)
|
||||
// TODO @jhowardmsft LCOW. For now, assume it is the OS of the host
|
||||
imageExporter := tarexport.NewTarExporter(daemon.stores[runtime.GOOS].imageStore, daemon.stores[runtime.GOOS].layerStore, daemon.stores[runtime.GOOS].referenceStore, daemon)
|
||||
return imageExporter.Load(inTar, outStream, quiet)
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package daemon
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
|
@ -18,6 +19,12 @@ func (daemon *Daemon) ImageHistory(name string) ([]*image.HistoryResponseItem, e
|
|||
return nil, err
|
||||
}
|
||||
|
||||
// If the image OS isn't set, assume it's the host OS
|
||||
platform := img.OS
|
||||
if platform == "" {
|
||||
platform = runtime.GOOS
|
||||
}
|
||||
|
||||
history := []*image.HistoryResponseItem{}
|
||||
|
||||
layerCounter := 0
|
||||
|
@ -33,12 +40,12 @@ func (daemon *Daemon) ImageHistory(name string) ([]*image.HistoryResponseItem, e
|
|||
}
|
||||
|
||||
rootFS.Append(img.RootFS.DiffIDs[layerCounter])
|
||||
l, err := daemon.layerStore.Get(rootFS.ChainID())
|
||||
l, err := daemon.stores[platform].layerStore.Get(rootFS.ChainID())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
layerSize, err = l.DiffSize()
|
||||
layer.ReleaseAndLog(daemon.layerStore, l)
|
||||
layer.ReleaseAndLog(daemon.stores[platform].layerStore, l)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -62,7 +69,7 @@ func (daemon *Daemon) ImageHistory(name string) ([]*image.HistoryResponseItem, e
|
|||
h.ID = id.String()
|
||||
|
||||
var tags []string
|
||||
for _, r := range daemon.referenceStore.References(id.Digest()) {
|
||||
for _, r := range daemon.stores[platform].referenceStore.References(id.Digest()) {
|
||||
if _, ok := r.(reference.NamedTagged); ok {
|
||||
tags = append(tags, reference.FamiliarString(r))
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package daemon
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
|
@ -17,7 +18,13 @@ func (daemon *Daemon) LookupImage(name string) (*types.ImageInspect, error) {
|
|||
return nil, errors.Wrapf(err, "no such image: %s", name)
|
||||
}
|
||||
|
||||
refs := daemon.referenceStore.References(img.ID().Digest())
|
||||
// If the image OS isn't set, assume it's the host OS
|
||||
platform := img.OS
|
||||
if platform == "" {
|
||||
platform = runtime.GOOS
|
||||
}
|
||||
|
||||
refs := daemon.stores[platform].referenceStore.References(img.ID().Digest())
|
||||
repoTags := []string{}
|
||||
repoDigests := []string{}
|
||||
for _, ref := range refs {
|
||||
|
@ -33,11 +40,11 @@ func (daemon *Daemon) LookupImage(name string) (*types.ImageInspect, error) {
|
|||
var layerMetadata map[string]string
|
||||
layerID := img.RootFS.ChainID()
|
||||
if layerID != "" {
|
||||
l, err := daemon.layerStore.Get(layerID)
|
||||
l, err := daemon.stores[platform].layerStore.Get(layerID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer layer.ReleaseAndLog(daemon.layerStore, l)
|
||||
defer layer.ReleaseAndLog(daemon.stores[platform].layerStore, l)
|
||||
size, err = l.Size()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -67,15 +74,14 @@ func (daemon *Daemon) LookupImage(name string) (*types.ImageInspect, error) {
|
|||
Author: img.Author,
|
||||
Config: img.Config,
|
||||
Architecture: img.Architecture,
|
||||
Os: img.OS,
|
||||
Os: platform,
|
||||
OsVersion: img.OSVersion,
|
||||
Size: size,
|
||||
VirtualSize: size, // TODO: field unused, deprecate
|
||||
RootFS: rootFSToAPIType(img.RootFS),
|
||||
}
|
||||
|
||||
imageInspect.GraphDriver.Name = daemon.GraphDriverName()
|
||||
|
||||
imageInspect.GraphDriver.Name = daemon.GraphDriverName(platform)
|
||||
imageInspect.GraphDriver.Data = layerMetadata
|
||||
|
||||
return imageInspect, nil
|
||||
|
|
|
@ -2,6 +2,7 @@ package daemon
|
|||
|
||||
import (
|
||||
"io"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
dist "github.com/docker/distribution"
|
||||
|
@ -59,6 +60,12 @@ func (daemon *Daemon) pullImageWithReference(ctx context.Context, ref reference.
|
|||
close(writesDone)
|
||||
}()
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// TODO @jhowardmsft LCOW. For now, use just the store for the host OS. This will
|
||||
// need some work to complete - we won't know the platform until after metadata
|
||||
// is pulled from the repository. This affects plugin as well to complete.
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
imagePullConfig := &distribution.ImagePullConfig{
|
||||
Config: distribution.Config{
|
||||
MetaHeaders: metaHeaders,
|
||||
|
@ -66,9 +73,9 @@ func (daemon *Daemon) pullImageWithReference(ctx context.Context, ref reference.
|
|||
ProgressOutput: progress.ChanOutput(progressChan),
|
||||
RegistryService: daemon.RegistryService,
|
||||
ImageEventLogger: daemon.LogImageEvent,
|
||||
MetadataStore: daemon.distributionMetadataStore,
|
||||
ImageStore: distribution.NewImageConfigStoreFromStore(daemon.imageStore),
|
||||
ReferenceStore: daemon.referenceStore,
|
||||
MetadataStore: daemon.stores[runtime.GOOS].distributionMetadataStore,
|
||||
ImageStore: distribution.NewImageConfigStoreFromStore(daemon.stores[runtime.GOOS].imageStore),
|
||||
ReferenceStore: daemon.stores[runtime.GOOS].referenceStore,
|
||||
},
|
||||
DownloadManager: daemon.downloadManager,
|
||||
Schema2Types: distribution.ImageTypes,
|
||||
|
|
|
@ -2,6 +2,7 @@ package daemon
|
|||
|
||||
import (
|
||||
"io"
|
||||
"runtime"
|
||||
|
||||
"github.com/docker/distribution/manifest/schema2"
|
||||
"github.com/docker/distribution/reference"
|
||||
|
@ -39,6 +40,11 @@ func (daemon *Daemon) PushImage(ctx context.Context, image, tag string, metaHead
|
|||
close(writesDone)
|
||||
}()
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// TODO @jhowardmsft LCOW. For now, use just the store for the host OS. This will
|
||||
// need some work to complete.
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
imagePushConfig := &distribution.ImagePushConfig{
|
||||
Config: distribution.Config{
|
||||
MetaHeaders: metaHeaders,
|
||||
|
@ -46,12 +52,12 @@ func (daemon *Daemon) PushImage(ctx context.Context, image, tag string, metaHead
|
|||
ProgressOutput: progress.ChanOutput(progressChan),
|
||||
RegistryService: daemon.RegistryService,
|
||||
ImageEventLogger: daemon.LogImageEvent,
|
||||
MetadataStore: daemon.distributionMetadataStore,
|
||||
ImageStore: distribution.NewImageConfigStoreFromStore(daemon.imageStore),
|
||||
ReferenceStore: daemon.referenceStore,
|
||||
MetadataStore: daemon.stores[runtime.GOOS].distributionMetadataStore,
|
||||
ImageStore: distribution.NewImageConfigStoreFromStore(daemon.stores[runtime.GOOS].imageStore),
|
||||
ReferenceStore: daemon.stores[runtime.GOOS].referenceStore,
|
||||
},
|
||||
ConfigMediaType: schema2.MediaTypeImageConfig,
|
||||
LayerStore: distribution.NewLayerProviderFromStore(daemon.layerStore),
|
||||
LayerStore: distribution.NewLayerProviderFromStore(daemon.stores[runtime.GOOS].layerStore),
|
||||
TrustKey: daemon.trustKey,
|
||||
UploadManager: daemon.uploadManager,
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
// TagImage creates the tag specified by newTag, pointing to the image named
|
||||
// imageName (alternatively, imageName can also be an image ID).
|
||||
func (daemon *Daemon) TagImage(imageName, repository, tag string) error {
|
||||
imageID, err := daemon.GetImageID(imageName)
|
||||
imageID, platform, err := daemon.GetImageIDAndPlatform(imageName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -23,12 +23,12 @@ func (daemon *Daemon) TagImage(imageName, repository, tag string) error {
|
|||
}
|
||||
}
|
||||
|
||||
return daemon.TagImageWithReference(imageID, newTag)
|
||||
return daemon.TagImageWithReference(imageID, platform, newTag)
|
||||
}
|
||||
|
||||
// TagImageWithReference adds the given reference to the image ID provided.
|
||||
func (daemon *Daemon) TagImageWithReference(imageID image.ID, newTag reference.Named) error {
|
||||
if err := daemon.referenceStore.AddTag(newTag, imageID.Digest(), true); err != nil {
|
||||
func (daemon *Daemon) TagImageWithReference(imageID image.ID, platform string, newTag reference.Named) error {
|
||||
if err := daemon.stores[platform].referenceStore.AddTag(newTag, imageID.Digest(), true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ import (
|
|||
"github.com/docker/docker/container"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/layer"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
)
|
||||
|
||||
var acceptedImageFilterTags = map[string]bool{
|
||||
|
@ -35,7 +36,12 @@ func (r byCreated) Less(i, j int) bool { return r[i].Created < r[j].Created }
|
|||
|
||||
// Map returns a map of all images in the ImageStore
|
||||
func (daemon *Daemon) Map() map[image.ID]*image.Image {
|
||||
return daemon.imageStore.Map()
|
||||
// TODO @jhowardmsft LCOW. This will need work to enumerate the stores for all platforms.
|
||||
platform := runtime.GOOS
|
||||
if platform == "windows" && system.LCOWSupported() {
|
||||
platform = "linux"
|
||||
}
|
||||
return daemon.stores[platform].imageStore.Map()
|
||||
}
|
||||
|
||||
// Images returns a filtered list of images. filterArgs is a JSON-encoded set
|
||||
|
@ -44,6 +50,13 @@ func (daemon *Daemon) Map() map[image.ID]*image.Image {
|
|||
// named all controls whether all images in the graph are filtered, or just
|
||||
// the heads.
|
||||
func (daemon *Daemon) Images(imageFilters filters.Args, all bool, withExtraAttrs bool) ([]*types.ImageSummary, error) {
|
||||
|
||||
// TODO @jhowardmsft LCOW. This will need work to enumerate the stores for all platforms.
|
||||
platform := runtime.GOOS
|
||||
if platform == "windows" && system.LCOWSupported() {
|
||||
platform = "linux"
|
||||
}
|
||||
|
||||
var (
|
||||
allImages map[image.ID]*image.Image
|
||||
err error
|
||||
|
@ -62,9 +75,9 @@ func (daemon *Daemon) Images(imageFilters filters.Args, all bool, withExtraAttrs
|
|||
}
|
||||
}
|
||||
if danglingOnly {
|
||||
allImages = daemon.imageStore.Heads()
|
||||
allImages = daemon.stores[platform].imageStore.Heads()
|
||||
} else {
|
||||
allImages = daemon.imageStore.Map()
|
||||
allImages = daemon.stores[platform].imageStore.Map()
|
||||
}
|
||||
|
||||
var beforeFilter, sinceFilter *image.Image
|
||||
|
@ -117,7 +130,7 @@ func (daemon *Daemon) Images(imageFilters filters.Args, all bool, withExtraAttrs
|
|||
layerID := img.RootFS.ChainID()
|
||||
var size int64
|
||||
if layerID != "" {
|
||||
l, err := daemon.layerStore.Get(layerID)
|
||||
l, err := daemon.stores[platform].layerStore.Get(layerID)
|
||||
if err != nil {
|
||||
// The layer may have been deleted between the call to `Map()` or
|
||||
// `Heads()` and the call to `Get()`, so we just ignore this error
|
||||
|
@ -128,7 +141,7 @@ func (daemon *Daemon) Images(imageFilters filters.Args, all bool, withExtraAttrs
|
|||
}
|
||||
|
||||
size, err = l.Size()
|
||||
layer.ReleaseAndLog(daemon.layerStore, l)
|
||||
layer.ReleaseAndLog(daemon.stores[platform].layerStore, l)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -136,7 +149,7 @@ func (daemon *Daemon) Images(imageFilters filters.Args, all bool, withExtraAttrs
|
|||
|
||||
newImage := newImage(img, size)
|
||||
|
||||
for _, ref := range daemon.referenceStore.References(id.Digest()) {
|
||||
for _, ref := range daemon.stores[platform].referenceStore.References(id.Digest()) {
|
||||
if imageFilters.Include("reference") {
|
||||
var found bool
|
||||
var matchErr error
|
||||
|
@ -158,7 +171,7 @@ func (daemon *Daemon) Images(imageFilters filters.Args, all bool, withExtraAttrs
|
|||
}
|
||||
}
|
||||
if newImage.RepoDigests == nil && newImage.RepoTags == nil {
|
||||
if all || len(daemon.imageStore.Children(id)) == 0 {
|
||||
if all || len(daemon.stores[platform].imageStore.Children(id)) == 0 {
|
||||
|
||||
if imageFilters.Include("dangling") && !danglingOnly {
|
||||
//dangling=false case, so dangling image is not needed
|
||||
|
@ -180,7 +193,7 @@ func (daemon *Daemon) Images(imageFilters filters.Args, all bool, withExtraAttrs
|
|||
// lazily init variables
|
||||
if imagesMap == nil {
|
||||
allContainers = daemon.List()
|
||||
allLayers = daemon.layerStore.Map()
|
||||
allLayers = daemon.stores[platform].layerStore.Map()
|
||||
imagesMap = make(map[*image.Image]*types.ImageSummary)
|
||||
layerRefs = make(map[layer.ChainID]int)
|
||||
}
|
||||
|
@ -243,7 +256,16 @@ func (daemon *Daemon) Images(imageFilters filters.Args, all bool, withExtraAttrs
|
|||
// The existing image(s) is not destroyed.
|
||||
// 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.
|
||||
func (daemon *Daemon) SquashImage(id, parent string) (string, error) {
|
||||
img, err := daemon.imageStore.Get(image.ID(id))
|
||||
|
||||
var (
|
||||
img *image.Image
|
||||
err error
|
||||
)
|
||||
for _, ds := range daemon.stores {
|
||||
if img, err = ds.imageStore.Get(image.ID(id)); err == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -251,7 +273,7 @@ func (daemon *Daemon) SquashImage(id, parent string) (string, error) {
|
|||
var parentImg *image.Image
|
||||
var parentChainID layer.ChainID
|
||||
if len(parent) != 0 {
|
||||
parentImg, err = daemon.imageStore.Get(image.ID(parent))
|
||||
parentImg, err = daemon.stores[img.Platform()].imageStore.Get(image.ID(parent))
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "error getting specified parent layer")
|
||||
}
|
||||
|
@ -261,11 +283,11 @@ func (daemon *Daemon) SquashImage(id, parent string) (string, error) {
|
|||
parentImg = &image.Image{RootFS: rootFS}
|
||||
}
|
||||
|
||||
l, err := daemon.layerStore.Get(img.RootFS.ChainID())
|
||||
l, err := daemon.stores[img.Platform()].layerStore.Get(img.RootFS.ChainID())
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "error getting image layer")
|
||||
}
|
||||
defer daemon.layerStore.Release(l)
|
||||
defer daemon.stores[img.Platform()].layerStore.Release(l)
|
||||
|
||||
ts, err := l.TarStreamFrom(parentChainID)
|
||||
if err != nil {
|
||||
|
@ -273,17 +295,11 @@ func (daemon *Daemon) SquashImage(id, parent string) (string, error) {
|
|||
}
|
||||
defer ts.Close()
|
||||
|
||||
// To support LCOW, Windows needs to pass the platform into the store when registering the layer.
|
||||
platform := layer.Platform("")
|
||||
if runtime.GOOS == "windows" {
|
||||
platform = l.Platform()
|
||||
}
|
||||
|
||||
newL, err := daemon.layerStore.Register(ts, parentChainID, platform)
|
||||
newL, err := daemon.stores[img.Platform()].layerStore.Register(ts, parentChainID, layer.Platform(img.Platform()))
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "error registering layer")
|
||||
}
|
||||
defer daemon.layerStore.Release(newL)
|
||||
defer daemon.stores[img.Platform()].layerStore.Release(newL)
|
||||
|
||||
var newImage image.Image
|
||||
newImage = *img
|
||||
|
@ -320,7 +336,7 @@ func (daemon *Daemon) SquashImage(id, parent string) (string, error) {
|
|||
return "", errors.Wrap(err, "error marshalling image config")
|
||||
}
|
||||
|
||||
newImgID, err := daemon.imageStore.Create(b)
|
||||
newImgID, err := daemon.stores[img.Platform()].imageStore.Create(b)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "error creating new image after squash")
|
||||
}
|
||||
|
|
|
@ -91,11 +91,11 @@ func (daemon *Daemon) ImportImage(src string, repository, tag string, msg string
|
|||
// but for Linux images, there's no reason it couldn't. However it
|
||||
// would need another CLI flag as there's no meta-data indicating
|
||||
// the OS of the thing being imported.
|
||||
l, err := daemon.layerStore.Register(inflatedLayerData, "", "")
|
||||
l, err := daemon.stores[runtime.GOOS].layerStore.Register(inflatedLayerData, "", "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer layer.ReleaseAndLog(daemon.layerStore, l)
|
||||
defer layer.ReleaseAndLog(daemon.stores[runtime.GOOS].layerStore, l) // TODO LCOW @jhowardmsft as for above comment
|
||||
|
||||
created := time.Now().UTC()
|
||||
imgConfig, err := json.Marshal(&image.Image{
|
||||
|
@ -103,7 +103,7 @@ func (daemon *Daemon) ImportImage(src string, repository, tag string, msg string
|
|||
DockerVersion: dockerversion.Version,
|
||||
Config: config,
|
||||
Architecture: runtime.GOARCH,
|
||||
OS: runtime.GOOS,
|
||||
OS: runtime.GOOS, // TODO LCOW @jhowardmsft as for above commment
|
||||
Created: created,
|
||||
Comment: msg,
|
||||
},
|
||||
|
@ -120,14 +120,16 @@ func (daemon *Daemon) ImportImage(src string, repository, tag string, msg string
|
|||
return err
|
||||
}
|
||||
|
||||
id, err := daemon.imageStore.Create(imgConfig)
|
||||
// TODO @jhowardmsft LCOW - Again, assume the OS of the host for now
|
||||
id, err := daemon.stores[runtime.GOOS].imageStore.Create(imgConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// FIXME: connect with commit code and call refstore directly
|
||||
if newRef != nil {
|
||||
if err := daemon.TagImageWithReference(id, newRef); err != nil {
|
||||
// TODO @jhowardmsft LCOW - Again, assume the OS of the host for now
|
||||
if err := daemon.TagImageWithReference(id, runtime.GOOS, newRef); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
|
@ -77,15 +78,32 @@ func (daemon *Daemon) SystemInfo() (*types.Info, error) {
|
|||
securityOptions = append(securityOptions, "name=userns")
|
||||
}
|
||||
|
||||
imageCount := 0
|
||||
drivers := ""
|
||||
for p, ds := range daemon.stores {
|
||||
imageCount += len(ds.imageStore.Map())
|
||||
drivers += daemon.GraphDriverName(p)
|
||||
if len(daemon.stores) > 1 {
|
||||
drivers += fmt.Sprintf(" (%s) ", p)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO @jhowardmsft LCOW support. For now, hard-code the platform shown for the driver status
|
||||
p := runtime.GOOS
|
||||
if p == "windows" && system.LCOWSupported() {
|
||||
p = "linux"
|
||||
}
|
||||
|
||||
drivers = strings.TrimSpace(drivers)
|
||||
v := &types.Info{
|
||||
ID: daemon.ID,
|
||||
Containers: int(cRunning + cPaused + cStopped),
|
||||
ContainersRunning: int(cRunning),
|
||||
ContainersPaused: int(cPaused),
|
||||
ContainersStopped: int(cStopped),
|
||||
Images: len(daemon.imageStore.Map()),
|
||||
Driver: daemon.GraphDriverName(),
|
||||
DriverStatus: daemon.layerStore.DriverStatus(),
|
||||
Images: imageCount,
|
||||
Driver: drivers,
|
||||
DriverStatus: daemon.stores[p].layerStore.DriverStatus(),
|
||||
Plugins: daemon.showPluginsInfo(),
|
||||
IPv4Forwarding: !sysInfo.IPv4ForwardingDisabled,
|
||||
BridgeNfIptables: !sysInfo.BridgeNFCallIPTablesDisabled,
|
||||
|
|
|
@ -170,6 +170,7 @@ func (daemon *Daemon) getInspectData(container *container.Container) (*types.Con
|
|||
Name: container.Name,
|
||||
RestartCount: container.RestartCount,
|
||||
Driver: container.Driver,
|
||||
Platform: container.Platform,
|
||||
MountLabel: container.MountLabel,
|
||||
ProcessLabel: container.ProcessLabel,
|
||||
ExecIDs: container.GetExecIDs(),
|
||||
|
|
|
@ -317,7 +317,7 @@ func (daemon *Daemon) foldFilter(config *types.ContainerListOptions) (*listConte
|
|||
if psFilters.Include("ancestor") {
|
||||
ancestorFilter = true
|
||||
psFilters.WalkValues("ancestor", func(ancestor string) error {
|
||||
id, err := daemon.GetImageID(ancestor)
|
||||
id, platform, err := daemon.GetImageIDAndPlatform(ancestor)
|
||||
if err != nil {
|
||||
logrus.Warnf("Error while looking up for image %v", ancestor)
|
||||
return nil
|
||||
|
@ -327,7 +327,7 @@ func (daemon *Daemon) foldFilter(config *types.ContainerListOptions) (*listConte
|
|||
return nil
|
||||
}
|
||||
// Then walk down the graph and put the imageIds in imagesFilter
|
||||
populateImageFilterByParents(imagesFilter, id, daemon.imageStore.Children)
|
||||
populateImageFilterByParents(imagesFilter, id, daemon.stores[platform].imageStore.Children)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
@ -558,7 +558,7 @@ func (daemon *Daemon) transformContainer(container *container.Container, ctx *li
|
|||
|
||||
image := container.Config.Image // if possible keep the original ref
|
||||
if image != container.ImageID.String() {
|
||||
id, err := daemon.GetImageID(image)
|
||||
id, _, err := daemon.GetImageIDAndPlatform(image)
|
||||
if _, isDNE := err.(ErrImageDoesNotExist); err != nil && !isDNE {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package daemon
|
|||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
|
@ -14,6 +15,7 @@ import (
|
|||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/layer"
|
||||
"github.com/docker/docker/pkg/directory"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
"github.com/docker/docker/runconfig"
|
||||
"github.com/docker/docker/volume"
|
||||
"github.com/docker/libnetwork"
|
||||
|
@ -157,6 +159,12 @@ func (daemon *Daemon) VolumesPrune(ctx context.Context, pruneFilters filters.Arg
|
|||
|
||||
// ImagesPrune removes unused images
|
||||
func (daemon *Daemon) ImagesPrune(ctx context.Context, pruneFilters filters.Args) (*types.ImagesPruneReport, error) {
|
||||
// TODO @jhowardmsft LCOW Support: This will need revisiting later.
|
||||
platform := runtime.GOOS
|
||||
if platform == "windows" && system.LCOWSupported() {
|
||||
platform = "linux"
|
||||
}
|
||||
|
||||
if !atomic.CompareAndSwapInt32(&daemon.pruneRunning, 0, 1) {
|
||||
return nil, errPruneRunning
|
||||
}
|
||||
|
@ -186,9 +194,9 @@ func (daemon *Daemon) ImagesPrune(ctx context.Context, pruneFilters filters.Args
|
|||
|
||||
var allImages map[image.ID]*image.Image
|
||||
if danglingOnly {
|
||||
allImages = daemon.imageStore.Heads()
|
||||
allImages = daemon.stores[platform].imageStore.Heads()
|
||||
} else {
|
||||
allImages = daemon.imageStore.Map()
|
||||
allImages = daemon.stores[platform].imageStore.Map()
|
||||
}
|
||||
allContainers := daemon.List()
|
||||
imageRefs := map[string]bool{}
|
||||
|
@ -202,7 +210,7 @@ func (daemon *Daemon) ImagesPrune(ctx context.Context, pruneFilters filters.Args
|
|||
}
|
||||
|
||||
// Filter intermediary images and get their unique size
|
||||
allLayers := daemon.layerStore.Map()
|
||||
allLayers := daemon.stores[platform].layerStore.Map()
|
||||
topImages := map[image.ID]*image.Image{}
|
||||
for id, img := range allImages {
|
||||
select {
|
||||
|
@ -210,7 +218,7 @@ func (daemon *Daemon) ImagesPrune(ctx context.Context, pruneFilters filters.Args
|
|||
return nil, ctx.Err()
|
||||
default:
|
||||
dgst := digest.Digest(id)
|
||||
if len(daemon.referenceStore.References(dgst)) == 0 && len(daemon.imageStore.Children(id)) != 0 {
|
||||
if len(daemon.stores[platform].referenceStore.References(dgst)) == 0 && len(daemon.stores[platform].imageStore.Children(id)) != 0 {
|
||||
continue
|
||||
}
|
||||
if !until.IsZero() && img.Created.After(until) {
|
||||
|
@ -241,7 +249,7 @@ deleteImagesLoop:
|
|||
}
|
||||
|
||||
deletedImages := []types.ImageDeleteResponseItem{}
|
||||
refs := daemon.referenceStore.References(dgst)
|
||||
refs := daemon.stores[platform].referenceStore.References(dgst)
|
||||
if len(refs) > 0 {
|
||||
shouldDelete := !danglingOnly
|
||||
if !shouldDelete {
|
||||
|
|
|
@ -207,7 +207,7 @@ func (daemon *Daemon) Cleanup(container *container.Container) {
|
|||
if err := daemon.conditionalUnmountOnCleanup(container); err != nil {
|
||||
// FIXME: remove once reference counting for graphdrivers has been refactored
|
||||
// Ensure that all the mounts are gone
|
||||
if mountid, err := daemon.layerStore.GetMountID(container.ID); err == nil {
|
||||
if mountid, err := daemon.stores[container.Platform].layerStore.GetMountID(container.ID); err == nil {
|
||||
daemon.cleanupMountsByID(mountid)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ func (daemon *Daemon) getLibcontainerdCreateOptions(container *container.Contain
|
|||
layerOpts.LayerFolderPath = m["dir"]
|
||||
|
||||
// Generate the layer paths of the layer options
|
||||
img, err := daemon.imageStore.Get(container.ImageID)
|
||||
img, err := daemon.stores[container.Platform].imageStore.Get(container.ImageID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to graph.Get on ImageID %s - %s", container.ImageID, err)
|
||||
}
|
||||
|
@ -49,9 +49,9 @@ func (daemon *Daemon) getLibcontainerdCreateOptions(container *container.Contain
|
|||
max := len(img.RootFS.DiffIDs)
|
||||
for i := 1; i <= max; i++ {
|
||||
img.RootFS.DiffIDs = img.RootFS.DiffIDs[:i]
|
||||
layerPath, err := layer.GetLayerPath(daemon.layerStore, img.RootFS.ChainID())
|
||||
layerPath, err := layer.GetLayerPath(daemon.stores[container.Platform].layerStore, img.RootFS.ChainID())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get layer path from graphdriver %s for ImageID %s - %s", daemon.layerStore, img.RootFS.ChainID(), err)
|
||||
return nil, fmt.Errorf("failed to get layer path from graphdriver %s for ImageID %s - %s", daemon.stores[container.Platform].layerStore, img.RootFS.ChainID(), err)
|
||||
}
|
||||
// Reverse order, expecting parent most first
|
||||
layerOpts.LayerPaths = append([]string{layerPath}, layerOpts.LayerPaths...)
|
||||
|
|
|
@ -26,15 +26,17 @@ type Store interface {
|
|||
type FSMetadataStore struct {
|
||||
sync.RWMutex
|
||||
basePath string
|
||||
platform string
|
||||
}
|
||||
|
||||
// NewFSMetadataStore creates a new filesystem-based metadata store.
|
||||
func NewFSMetadataStore(basePath string) (*FSMetadataStore, error) {
|
||||
func NewFSMetadataStore(basePath, platform string) (*FSMetadataStore, error) {
|
||||
if err := os.MkdirAll(basePath, 0700); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &FSMetadataStore{
|
||||
basePath: basePath,
|
||||
platform: platform,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ package metadata
|
|||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/layer"
|
||||
|
@ -15,7 +16,7 @@ func TestV1IDService(t *testing.T) {
|
|||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
metadataStore, err := NewFSMetadataStore(tmpDir)
|
||||
metadataStore, err := NewFSMetadataStore(tmpDir, runtime.GOOS)
|
||||
if err != nil {
|
||||
t.Fatalf("could not create metadata store: %v", err)
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"math/rand"
|
||||
"os"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/layer"
|
||||
|
@ -19,7 +20,7 @@ func TestV2MetadataService(t *testing.T) {
|
|||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
metadataStore, err := NewFSMetadataStore(tmpDir)
|
||||
metadataStore, err := NewFSMetadataStore(tmpDir, runtime.GOOS)
|
||||
if err != nil {
|
||||
t.Fatalf("could not create metadata store: %v", err)
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
|
@ -22,7 +23,7 @@ const maxDownloadAttempts = 5
|
|||
// registers and downloads those, taking into account dependencies between
|
||||
// layers.
|
||||
type LayerDownloadManager struct {
|
||||
layerStore layer.Store
|
||||
layerStores map[string]layer.Store
|
||||
tm TransferManager
|
||||
waitDuration time.Duration
|
||||
}
|
||||
|
@ -33,9 +34,9 @@ func (ldm *LayerDownloadManager) SetConcurrency(concurrency int) {
|
|||
}
|
||||
|
||||
// NewLayerDownloadManager returns a new LayerDownloadManager.
|
||||
func NewLayerDownloadManager(layerStore layer.Store, concurrencyLimit int, options ...func(*LayerDownloadManager)) *LayerDownloadManager {
|
||||
func NewLayerDownloadManager(layerStores map[string]layer.Store, concurrencyLimit int, options ...func(*LayerDownloadManager)) *LayerDownloadManager {
|
||||
manager := LayerDownloadManager{
|
||||
layerStore: layerStore,
|
||||
layerStores: layerStores,
|
||||
tm: NewTransferManager(concurrencyLimit),
|
||||
waitDuration: time.Second,
|
||||
}
|
||||
|
@ -104,6 +105,11 @@ func (ldm *LayerDownloadManager) Download(ctx context.Context, initialRootFS ima
|
|||
downloadsByKey = make(map[string]*downloadTransfer)
|
||||
)
|
||||
|
||||
// Assume that the platform is the host OS if blank
|
||||
if platform == "" {
|
||||
platform = layer.Platform(runtime.GOOS)
|
||||
}
|
||||
|
||||
rootFS := initialRootFS
|
||||
for _, descriptor := range layers {
|
||||
key := descriptor.Key()
|
||||
|
@ -115,13 +121,13 @@ func (ldm *LayerDownloadManager) Download(ctx context.Context, initialRootFS ima
|
|||
if err == nil {
|
||||
getRootFS := rootFS
|
||||
getRootFS.Append(diffID)
|
||||
l, err := ldm.layerStore.Get(getRootFS.ChainID())
|
||||
l, err := ldm.layerStores[string(platform)].Get(getRootFS.ChainID())
|
||||
if err == nil {
|
||||
// Layer already exists.
|
||||
logrus.Debugf("Layer already exists: %s", descriptor.ID())
|
||||
progress.Update(progressOutput, descriptor.ID(), "Already exists")
|
||||
if topLayer != nil {
|
||||
layer.ReleaseAndLog(ldm.layerStore, topLayer)
|
||||
layer.ReleaseAndLog(ldm.layerStores[string(platform)], topLayer)
|
||||
}
|
||||
topLayer = l
|
||||
missingLayer = false
|
||||
|
@ -165,7 +171,7 @@ func (ldm *LayerDownloadManager) Download(ctx context.Context, initialRootFS ima
|
|||
if topDownload == nil {
|
||||
return rootFS, func() {
|
||||
if topLayer != nil {
|
||||
layer.ReleaseAndLog(ldm.layerStore, topLayer)
|
||||
layer.ReleaseAndLog(ldm.layerStores[string(platform)], topLayer)
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
|
@ -176,7 +182,7 @@ func (ldm *LayerDownloadManager) Download(ctx context.Context, initialRootFS ima
|
|||
|
||||
defer func() {
|
||||
if topLayer != nil {
|
||||
layer.ReleaseAndLog(ldm.layerStore, topLayer)
|
||||
layer.ReleaseAndLog(ldm.layerStores[string(platform)], topLayer)
|
||||
}
|
||||
}()
|
||||
|
||||
|
@ -216,7 +222,7 @@ func (ldm *LayerDownloadManager) makeDownloadFunc(descriptor DownloadDescriptor,
|
|||
return func(progressChan chan<- progress.Progress, start <-chan struct{}, inactive chan<- struct{}) Transfer {
|
||||
d := &downloadTransfer{
|
||||
Transfer: NewTransfer(),
|
||||
layerStore: ldm.layerStore,
|
||||
layerStore: ldm.layerStores[string(platform)],
|
||||
}
|
||||
|
||||
go func() {
|
||||
|
@ -380,7 +386,7 @@ func (ldm *LayerDownloadManager) makeDownloadFuncFromDownload(descriptor Downloa
|
|||
return func(progressChan chan<- progress.Progress, start <-chan struct{}, inactive chan<- struct{}) Transfer {
|
||||
d := &downloadTransfer{
|
||||
Transfer: NewTransfer(),
|
||||
layerStore: ldm.layerStore,
|
||||
layerStore: ldm.layerStores[string(platform)],
|
||||
}
|
||||
|
||||
go func() {
|
||||
|
|
|
@ -46,6 +46,9 @@ type store struct {
|
|||
// referencesByIDCache is a cache of references indexed by ID, to speed
|
||||
// up References.
|
||||
referencesByIDCache map[digest.Digest]map[string]reference.Named
|
||||
// platform is the container target platform for this store (which may be
|
||||
// different to the host operating system
|
||||
platform string
|
||||
}
|
||||
|
||||
// Repository maps tags to digests. The key is a stringified Reference,
|
||||
|
@ -70,7 +73,7 @@ func (a lexicalAssociations) Less(i, j int) bool {
|
|||
|
||||
// NewReferenceStore creates a new reference store, tied to a file path where
|
||||
// the set of references are serialized in JSON format.
|
||||
func NewReferenceStore(jsonPath string) (Store, error) {
|
||||
func NewReferenceStore(jsonPath, platform string) (Store, error) {
|
||||
abspath, err := filepath.Abs(jsonPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -80,6 +83,7 @@ func NewReferenceStore(jsonPath string) (Store, error) {
|
|||
jsonPath: abspath,
|
||||
Repositories: make(map[string]repository),
|
||||
referencesByIDCache: make(map[digest.Digest]map[string]reference.Named),
|
||||
platform: platform,
|
||||
}
|
||||
// Load the json file if it exists, otherwise create it.
|
||||
if err := store.reload(); os.IsNotExist(err) {
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
|
@ -40,7 +41,7 @@ func TestLoad(t *testing.T) {
|
|||
}
|
||||
jsonFile.Close()
|
||||
|
||||
store, err := NewReferenceStore(jsonFile.Name())
|
||||
store, err := NewReferenceStore(jsonFile.Name(), runtime.GOOS)
|
||||
if err != nil {
|
||||
t.Fatalf("error creating tag store: %v", err)
|
||||
}
|
||||
|
@ -69,7 +70,7 @@ func TestSave(t *testing.T) {
|
|||
jsonFile.Close()
|
||||
defer os.RemoveAll(jsonFile.Name())
|
||||
|
||||
store, err := NewReferenceStore(jsonFile.Name())
|
||||
store, err := NewReferenceStore(jsonFile.Name(), runtime.GOOS)
|
||||
if err != nil {
|
||||
t.Fatalf("error creating tag store: %v", err)
|
||||
}
|
||||
|
@ -111,7 +112,7 @@ func TestAddDeleteGet(t *testing.T) {
|
|||
jsonFile.Close()
|
||||
defer os.RemoveAll(jsonFile.Name())
|
||||
|
||||
store, err := NewReferenceStore(jsonFile.Name())
|
||||
store, err := NewReferenceStore(jsonFile.Name(), runtime.GOOS)
|
||||
if err != nil {
|
||||
t.Fatalf("error creating tag store: %v", err)
|
||||
}
|
||||
|
@ -328,7 +329,7 @@ func TestInvalidTags(t *testing.T) {
|
|||
tmpDir, err := ioutil.TempDir("", "tag-store-test")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
store, err := NewReferenceStore(filepath.Join(tmpDir, "repositories.json"))
|
||||
store, err := NewReferenceStore(filepath.Join(tmpDir, "repositories.json"), runtime.GOOS)
|
||||
if err != nil {
|
||||
t.Fatalf("error creating tag store: %v", err)
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue