Jelajahi Sumber

Windows: Factoring out unused fields

Signed-off-by: John Howard <jhoward@microsoft.com>
John Howard 10 tahun lalu
induk
melakukan
47c56e4353

+ 2 - 6
api/server/server.go

@@ -1205,12 +1205,8 @@ func (s *Server) getContainersByName(version version.Version, w http.ResponseWri
 		return fmt.Errorf("Missing parameter")
 	}
 
-	if version.LessThan("1.20") {
-		containerJSONRaw, err := s.daemon.ContainerInspectPre120(vars["name"])
-		if err != nil {
-			return err
-		}
-		return writeJSON(w, http.StatusOK, containerJSONRaw)
+	if version.LessThan("1.20") && runtime.GOOS != "windows" {
+		return getContainersByNameDownlevel(w, s, vars["name"])
 	}
 
 	containerJSON, err := s.daemon.ContainerInspect(vars["name"])

+ 10 - 0
api/server/server_linux.go

@@ -121,3 +121,13 @@ func adjustCpuShares(version version.Version, hostConfig *runconfig.HostConfig)
 		}
 	}
 }
+
+// getContainersByNameDownlevel performs processing for pre 1.20 APIs. This
+// is only relevant on non-Windows daemons.
+func getContainersByNameDownlevel(w http.ResponseWriter, s *Server, namevar string) error {
+	containerJSONRaw, err := s.daemon.ContainerInspectPre120(namevar)
+	if err != nil {
+		return err
+	}
+	return writeJSON(w, http.StatusOK, containerJSONRaw)
+}

+ 6 - 0
api/server/server_windows.go

@@ -60,3 +60,9 @@ func allocateDaemonPort(addr string) error {
 
 func adjustCpuShares(version version.Version, hostConfig *runconfig.HostConfig) {
 }
+
+// getContainersByNameDownlevel performs processing for pre 1.20 APIs. This
+// is only relevant on non-Windows daemons.
+func getContainersByNameDownlevel(w http.ResponseWriter, s *Server, namevar string) error {
+	return nil
+}

+ 2 - 1
api/types/types.go

@@ -250,7 +250,8 @@ type ContainerJSON struct {
 	Config *runconfig.Config
 }
 
-// backcompatibility struct along with ContainerConfig
+// backcompatibility struct along with ContainerConfig. Note this is not
+// used by the Windows daemon.
 type ContainerJSONPre120 struct {
 	*ContainerJSONBase
 	Volumes   map[string]string

+ 9 - 14
daemon/archive.go

@@ -17,7 +17,7 @@ import (
 // path does not refer to a directory.
 var ErrExtractPointNotDirectory = errors.New("extraction point is not a directory")
 
-// ContainerCopy performs a depracated operation of archiving the resource at
+// ContainerCopy performs a deprecated operation of archiving the resource at
 // the specified path in the conatiner identified by the given name.
 func (daemon *Daemon) ContainerCopy(name string, res string) (io.ReadCloser, error) {
 	container, err := daemon.Get(name)
@@ -25,7 +25,7 @@ func (daemon *Daemon) ContainerCopy(name string, res string) (io.ReadCloser, err
 		return nil, err
 	}
 
-	if res[0] == '/' {
+	if res[0] == '/' || res[0] == '\\' {
 		res = res[1:]
 	}
 
@@ -90,7 +90,7 @@ func (container *Container) StatPath(path string) (stat *types.ContainerPathStat
 	// Consider the given path as an absolute path in the container.
 	absPath := path
 	if !filepath.IsAbs(absPath) {
-		absPath = archive.PreserveTrailingDotOrSeparator(filepath.Join("/", path), path)
+		absPath = archive.PreserveTrailingDotOrSeparator(filepath.Join(string(os.PathSeparator), path), path)
 	}
 
 	resolvedPath, err := container.GetResourcePath(absPath)
@@ -157,7 +157,7 @@ func (container *Container) ArchivePath(path string) (content io.ReadCloser, sta
 	// Consider the given path as an absolute path in the container.
 	absPath := path
 	if !filepath.IsAbs(absPath) {
-		absPath = archive.PreserveTrailingDotOrSeparator(filepath.Join("/", path), path)
+		absPath = archive.PreserveTrailingDotOrSeparator(filepath.Join(string(os.PathSeparator), path), path)
 	}
 
 	resolvedPath, err := container.GetResourcePath(absPath)
@@ -230,7 +230,7 @@ func (container *Container) ExtractToDir(path string, noOverwriteDirNonDir bool,
 	// Consider the given path as an absolute path in the container.
 	absPath := path
 	if !filepath.IsAbs(absPath) {
-		absPath = archive.PreserveTrailingDotOrSeparator(filepath.Join("/", path), path)
+		absPath = archive.PreserveTrailingDotOrSeparator(filepath.Join(string(os.PathSeparator), path), path)
 	}
 
 	resolvedPath, err := container.GetResourcePath(absPath)
@@ -261,19 +261,14 @@ func (container *Container) ExtractToDir(path string, noOverwriteDirNonDir bool,
 	if err != nil {
 		return err
 	}
-	absPath = filepath.Join("/", baseRel)
+	absPath = filepath.Join(string(os.PathSeparator), baseRel)
 
 	// Need to check if the path is in a volume. If it is, it cannot be in a
 	// read-only volume. If it is not in a volume, the container cannot be
 	// configured with a read-only rootfs.
-	var toVolume bool
-	for _, mnt := range container.MountPoints {
-		if toVolume = mnt.hasResource(absPath); toVolume {
-			if mnt.RW {
-				break
-			}
-			return ErrVolumeReadonly
-		}
+	toVolume, err := checkIfPathIsInAVolume(container, absPath)
+	if err != nil {
+		return err
 	}
 
 	if !toVolume && container.hostConfig.ReadonlyRootfs {

+ 19 - 0
daemon/archive_unix.go

@@ -0,0 +1,19 @@
+// +build !windows
+
+package daemon
+
+// checkIfPathIsInAVolume checks if the path is in a volume. If it is, it
+// cannot be in a read-only volume. If it  is not in a volume, the container
+// cannot be configured with a read-only rootfs.
+func checkIfPathIsInAVolume(container *Container, absPath string) (bool, error) {
+	var toVolume bool
+	for _, mnt := range container.MountPoints {
+		if toVolume = mnt.hasResource(absPath); toVolume {
+			if mnt.RW {
+				break
+			}
+			return false, ErrVolumeReadonly
+		}
+	}
+	return toVolume, nil
+}

+ 10 - 0
daemon/archive_windows.go

@@ -0,0 +1,10 @@
+package daemon
+
+// checkIfPathIsInAVolume checks if the path is in a volume. If it is, it
+// cannot be in a read-only volume. If it  is not in a volume, the container
+// cannot be configured with a read-only rootfs.
+//
+// This is a no-op on Windows which does not support volumes.
+func checkIfPathIsInAVolume(container *Container, absPath string) (bool, error) {
+	return false, nil
+}

+ 0 - 4
daemon/config.go

@@ -17,11 +17,9 @@ type CommonConfig struct {
 	AutoRestart    bool
 	Bridge         bridgeConfig // Bridge holds bridge network specific configuration.
 	Context        map[string][]string
-	CorsHeaders    string
 	DisableBridge  bool
 	Dns            []string
 	DnsSearch      []string
-	EnableCors     bool
 	ExecDriver     string
 	ExecOptions    []string
 	ExecRoot       string
@@ -51,8 +49,6 @@ func (config *Config) InstallCommonFlags(cmd *flag.FlagSet, usageFn func(string)
 	cmd.StringVar(&config.GraphDriver, []string{"s", "-storage-driver"}, "", usageFn("Storage driver to use"))
 	cmd.StringVar(&config.ExecDriver, []string{"e", "-exec-driver"}, defaultExec, usageFn("Exec driver to use"))
 	cmd.IntVar(&config.Mtu, []string{"#mtu", "-mtu"}, 0, usageFn("Set the containers network MTU"))
-	cmd.BoolVar(&config.EnableCors, []string{"#api-enable-cors", "#-api-enable-cors"}, false, usageFn("Enable CORS headers in the remote API, this is deprecated by --api-cors-header"))
-	cmd.StringVar(&config.CorsHeaders, []string{"-api-cors-header"}, "", usageFn("Set CORS headers in the remote API"))
 	// FIXME: why the inconsistency between "hosts" and "sockets"?
 	cmd.Var(opts.NewListOptsRef(&config.Dns, opts.ValidateIPAddress), []string{"#dns", "-dns"}, usageFn("DNS server to use"))
 	cmd.Var(opts.NewListOptsRef(&config.DnsSearch, opts.ValidateDNSSearch), []string{"-dns-search"}, usageFn("DNS search domains to use"))

+ 4 - 0
daemon/config_linux.go

@@ -22,6 +22,8 @@ type Config struct {
 
 	// Fields below here are platform specific.
 
+	CorsHeaders          string
+	EnableCors           bool
 	EnableSelinuxSupport bool
 	SocketGroup          string
 	Ulimits              map[string]*ulimit.Ulimit
@@ -71,6 +73,8 @@ func (config *Config) InstallFlags(cmd *flag.FlagSet, usageFn func(string) strin
 	cmd.BoolVar(&config.Bridge.InterContainerCommunication, []string{"#icc", "-icc"}, true, usageFn("Enable inter-container communication"))
 	cmd.Var(opts.NewIpOpt(&config.Bridge.DefaultIP, "0.0.0.0"), []string{"#ip", "-ip"}, usageFn("Default IP when binding container ports"))
 	cmd.BoolVar(&config.Bridge.EnableUserlandProxy, []string{"-userland-proxy"}, true, usageFn("Use userland proxy for loopback traffic"))
+	cmd.BoolVar(&config.EnableCors, []string{"#api-enable-cors", "#-api-enable-cors"}, false, usageFn("Enable CORS headers in the remote API, this is deprecated by --api-cors-header"))
+	cmd.StringVar(&config.CorsHeaders, []string{"-api-cors-header"}, "", usageFn("Set CORS headers in the remote API"))
 
 	config.attachExperimentalFlags(cmd, usageFn)
 }

+ 5 - 103
daemon/container.go

@@ -64,28 +64,18 @@ type CommonContainer struct {
 	Config                   *runconfig.Config
 	ImageID                  string `json:"Image"`
 	NetworkSettings          *network.Settings
-	ResolvConfPath           string
-	HostnamePath             string
-	HostsPath                string
 	LogPath                  string
 	Name                     string
 	Driver                   string
 	ExecDriver               string
 	MountLabel, ProcessLabel string
 	RestartCount             int
-	UpdateDns                bool
 	HasBeenStartedBefore     bool
-
-	MountPoints map[string]*mountPoint
-	Volumes     map[string]string // Deprecated since 1.7, kept for backwards compatibility
-	VolumesRW   map[string]bool   // Deprecated since 1.7, kept for backwards compatibility
-
-	hostConfig *runconfig.HostConfig
-	command    *execdriver.Command
-
-	monitor      *containerMonitor
-	execCommands *execStore
-	daemon       *Daemon
+	hostConfig               *runconfig.HostConfig
+	command                  *execdriver.Command
+	monitor                  *containerMonitor
+	execCommands             *execStore
+	daemon                   *Daemon
 	// logDriver for closing
 	logDriver logger.Logger
 	logCopier *logger.Copier
@@ -1076,94 +1066,6 @@ func copyEscapable(dst io.Writer, src io.ReadCloser) (written int64, err error)
 	return written, err
 }
 
-func (container *Container) networkMounts() []execdriver.Mount {
-	var mounts []execdriver.Mount
-	if container.ResolvConfPath != "" {
-		label.SetFileLabel(container.ResolvConfPath, container.MountLabel)
-		mounts = append(mounts, execdriver.Mount{
-			Source:      container.ResolvConfPath,
-			Destination: "/etc/resolv.conf",
-			Writable:    !container.hostConfig.ReadonlyRootfs,
-			Private:     true,
-		})
-	}
-	if container.HostnamePath != "" {
-		label.SetFileLabel(container.HostnamePath, container.MountLabel)
-		mounts = append(mounts, execdriver.Mount{
-			Source:      container.HostnamePath,
-			Destination: "/etc/hostname",
-			Writable:    !container.hostConfig.ReadonlyRootfs,
-			Private:     true,
-		})
-	}
-	if container.HostsPath != "" {
-		label.SetFileLabel(container.HostsPath, container.MountLabel)
-		mounts = append(mounts, execdriver.Mount{
-			Source:      container.HostsPath,
-			Destination: "/etc/hosts",
-			Writable:    !container.hostConfig.ReadonlyRootfs,
-			Private:     true,
-		})
-	}
-	return mounts
-}
-
-func (container *Container) addBindMountPoint(name, source, destination string, rw bool) {
-	container.MountPoints[destination] = &mountPoint{
-		Name:        name,
-		Source:      source,
-		Destination: destination,
-		RW:          rw,
-	}
-}
-
-func (container *Container) addLocalMountPoint(name, destination string, rw bool) {
-	container.MountPoints[destination] = &mountPoint{
-		Name:        name,
-		Driver:      volume.DefaultDriverName,
-		Destination: destination,
-		RW:          rw,
-	}
-}
-
-func (container *Container) addMountPointWithVolume(destination string, vol volume.Volume, rw bool) {
-	container.MountPoints[destination] = &mountPoint{
-		Name:        vol.Name(),
-		Driver:      vol.DriverName(),
-		Destination: destination,
-		RW:          rw,
-		Volume:      vol,
-	}
-}
-
-func (container *Container) isDestinationMounted(destination string) bool {
-	return container.MountPoints[destination] != nil
-}
-
-func (container *Container) prepareMountPoints() error {
-	for _, config := range container.MountPoints {
-		if len(config.Driver) > 0 {
-			v, err := createVolume(config.Name, config.Driver)
-			if err != nil {
-				return err
-			}
-			config.Volume = v
-		}
-	}
-	return nil
-}
-
-func (container *Container) removeMountPoints() error {
-	for _, m := range container.MountPoints {
-		if m.Volume != nil {
-			if err := removeVolume(m.Volume); err != nil {
-				return err
-			}
-		}
-	}
-	return nil
-}
-
 func (container *Container) shouldRestart() bool {
 	return container.hostConfig.RestartPolicy.Name == "always" ||
 		(container.hostConfig.RestartPolicy.Name == "on-failure" && container.ExitCode != 0)

+ 98 - 2
daemon/container_unix.go

@@ -27,12 +27,14 @@ import (
 	"github.com/docker/docker/pkg/ulimit"
 	"github.com/docker/docker/runconfig"
 	"github.com/docker/docker/utils"
+	"github.com/docker/docker/volume"
 	"github.com/docker/libnetwork"
 	"github.com/docker/libnetwork/netlabel"
 	"github.com/docker/libnetwork/options"
 	"github.com/docker/libnetwork/types"
 	"github.com/opencontainers/runc/libcontainer/configs"
 	"github.com/opencontainers/runc/libcontainer/devices"
+	"github.com/opencontainers/runc/libcontainer/label"
 )
 
 const DefaultPathEnv = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
@@ -41,9 +43,15 @@ type Container struct {
 	CommonContainer
 
 	// Fields below here are platform specific.
-
-	AppArmorProfile string
 	activeLinks     map[string]*links.Link
+	AppArmorProfile string
+	HostnamePath    string
+	HostsPath       string
+	MountPoints     map[string]*mountPoint
+	ResolvConfPath  string
+	UpdateDns       bool
+	Volumes         map[string]string // Deprecated since 1.7, kept for backwards compatibility
+	VolumesRW       map[string]bool   // Deprecated since 1.7, kept for backwards compatibility
 }
 
 func killProcessDirectly(container *Container) error {
@@ -1150,3 +1158,91 @@ func (container *Container) PrepareStorage() error {
 func (container *Container) CleanupStorage() error {
 	return nil
 }
+
+func (container *Container) networkMounts() []execdriver.Mount {
+	var mounts []execdriver.Mount
+	if container.ResolvConfPath != "" {
+		label.SetFileLabel(container.ResolvConfPath, container.MountLabel)
+		mounts = append(mounts, execdriver.Mount{
+			Source:      container.ResolvConfPath,
+			Destination: "/etc/resolv.conf",
+			Writable:    !container.hostConfig.ReadonlyRootfs,
+			Private:     true,
+		})
+	}
+	if container.HostnamePath != "" {
+		label.SetFileLabel(container.HostnamePath, container.MountLabel)
+		mounts = append(mounts, execdriver.Mount{
+			Source:      container.HostnamePath,
+			Destination: "/etc/hostname",
+			Writable:    !container.hostConfig.ReadonlyRootfs,
+			Private:     true,
+		})
+	}
+	if container.HostsPath != "" {
+		label.SetFileLabel(container.HostsPath, container.MountLabel)
+		mounts = append(mounts, execdriver.Mount{
+			Source:      container.HostsPath,
+			Destination: "/etc/hosts",
+			Writable:    !container.hostConfig.ReadonlyRootfs,
+			Private:     true,
+		})
+	}
+	return mounts
+}
+
+func (container *Container) addBindMountPoint(name, source, destination string, rw bool) {
+	container.MountPoints[destination] = &mountPoint{
+		Name:        name,
+		Source:      source,
+		Destination: destination,
+		RW:          rw,
+	}
+}
+
+func (container *Container) addLocalMountPoint(name, destination string, rw bool) {
+	container.MountPoints[destination] = &mountPoint{
+		Name:        name,
+		Driver:      volume.DefaultDriverName,
+		Destination: destination,
+		RW:          rw,
+	}
+}
+
+func (container *Container) addMountPointWithVolume(destination string, vol volume.Volume, rw bool) {
+	container.MountPoints[destination] = &mountPoint{
+		Name:        vol.Name(),
+		Driver:      vol.DriverName(),
+		Destination: destination,
+		RW:          rw,
+		Volume:      vol,
+	}
+}
+
+func (container *Container) isDestinationMounted(destination string) bool {
+	return container.MountPoints[destination] != nil
+}
+
+func (container *Container) prepareMountPoints() error {
+	for _, config := range container.MountPoints {
+		if len(config.Driver) > 0 {
+			v, err := createVolume(config.Name, config.Driver)
+			if err != nil {
+				return err
+			}
+			config.Volume = v
+		}
+	}
+	return nil
+}
+
+func (container *Container) removeMountPoints() error {
+	for _, m := range container.MountPoints {
+		if m.Volume != nil {
+			if err := removeVolume(m.Volume); err != nil {
+				return err
+			}
+		}
+	}
+	return nil
+}

+ 10 - 12
daemon/container_windows.go

@@ -22,18 +22,6 @@ type Container struct {
 	CommonContainer
 
 	// Fields below here are platform specific.
-
-	// TODO Windows. Further factoring out of unused fields will be necessary.
-
-	// ---- START OF TEMPORARY DECLARATION ----
-	// TODO Windows. Temporarily keeping fields in to assist in compilation
-	// of the daemon on Windows without affecting many other files in a single
-	// PR, thus making code review significantly harder. These lines will be
-	// removed in subsequent PRs.
-
-	AppArmorProfile string
-	// ---- END OF TEMPORARY DECLARATION ----
-
 }
 
 func killProcessDirectly(container *Container) error {
@@ -213,3 +201,13 @@ func (container *Container) CleanupStorage() error {
 	}
 	return nil
 }
+
+// TODO Windows. This can be further factored out. Used in daemon.go
+func (container *Container) prepareMountPoints() error {
+	return nil
+}
+
+// TODO Windows. This can be further factored out. Used in delete.go
+func (container *Container) removeMountPoints() error {
+	return nil
+}

+ 3 - 44
daemon/create.go

@@ -2,15 +2,11 @@ package daemon
 
 import (
 	"fmt"
-	"os"
-	"path/filepath"
-	"strings"
 
 	"github.com/Sirupsen/logrus"
 	"github.com/docker/docker/graph"
 	"github.com/docker/docker/image"
 	"github.com/docker/docker/pkg/parsers"
-	"github.com/docker/docker/pkg/stringid"
 	"github.com/docker/docker/runconfig"
 	"github.com/opencontainers/runc/libcontainer/label"
 )
@@ -96,47 +92,10 @@ func (daemon *Daemon) Create(config *runconfig.Config, hostConfig *runconfig.Hos
 	}
 	defer container.Unmount()
 
-	for spec := range config.Volumes {
-		var (
-			name, destination string
-			parts             = strings.Split(spec, ":")
-		)
-		switch len(parts) {
-		case 2:
-			name, destination = parts[0], filepath.Clean(parts[1])
-		default:
-			name = stringid.GenerateRandomID()
-			destination = filepath.Clean(parts[0])
-		}
-		// Skip volumes for which we already have something mounted on that
-		// destination because of a --volume-from.
-		if container.isDestinationMounted(destination) {
-			continue
-		}
-		path, err := container.GetResourcePath(destination)
-		if err != nil {
-			return nil, nil, err
-		}
-
-		stat, err := os.Stat(path)
-		if err == nil && !stat.IsDir() {
-			return nil, nil, fmt.Errorf("cannot mount volume over existing file, file exists %s", path)
-		}
-
-		v, err := createVolume(name, config.VolumeDriver)
-		if err != nil {
-			return nil, nil, err
-		}
-		if err := label.Relabel(v.Path(), container.MountLabel, "z"); err != nil {
-			return nil, nil, err
-		}
-
-		if err := container.copyImagePathContent(v, destination); err != nil {
-			return nil, nil, err
-		}
-
-		container.addMountPointWithVolume(destination, v, true)
+	if err := createContainerPlatformSpecificSettings(container, config); err != nil {
+		return nil, nil, err
 	}
+
 	if err := container.ToDisk(); err != nil {
 		logrus.Errorf("Error saving new container to disk: %v", err)
 		return nil, nil, err

+ 60 - 0
daemon/create_unix.go

@@ -0,0 +1,60 @@
+// +build !windows
+
+package daemon
+
+import (
+	"fmt"
+	"os"
+	"path/filepath"
+	"strings"
+
+	"github.com/docker/docker/pkg/stringid"
+	"github.com/docker/docker/runconfig"
+	"github.com/opencontainers/runc/libcontainer/label"
+)
+
+// createContainerPlatformSpecificSettings performs platform specific container create functionality
+func createContainerPlatformSpecificSettings(container *Container, config *runconfig.Config) error {
+	for spec := range config.Volumes {
+		var (
+			name, destination string
+			parts             = strings.Split(spec, ":")
+		)
+		switch len(parts) {
+		case 2:
+			name, destination = parts[0], filepath.Clean(parts[1])
+		default:
+			name = stringid.GenerateRandomID()
+			destination = filepath.Clean(parts[0])
+		}
+		// Skip volumes for which we already have something mounted on that
+		// destination because of a --volume-from.
+		if container.isDestinationMounted(destination) {
+			continue
+		}
+		path, err := container.GetResourcePath(destination)
+		if err != nil {
+			return err
+		}
+
+		stat, err := os.Stat(path)
+		if err == nil && !stat.IsDir() {
+			return fmt.Errorf("cannot mount volume over existing file, file exists %s", path)
+		}
+
+		v, err := createVolume(name, config.VolumeDriver)
+		if err != nil {
+			return err
+		}
+		if err := label.Relabel(v.Path(), container.MountLabel, "z"); err != nil {
+			return err
+		}
+
+		if err := container.copyImagePathContent(v, destination); err != nil {
+			return err
+		}
+
+		container.addMountPointWithVolume(destination, v, true)
+	}
+	return nil
+}

+ 10 - 0
daemon/create_windows.go

@@ -0,0 +1,10 @@
+package daemon
+
+import (
+	"github.com/docker/docker/runconfig"
+)
+
+// createContainerPlatformSpecificSettings performs platform specific container create functionality
+func createContainerPlatformSpecificSettings(container *Container, config *runconfig.Config) error {
+	return nil
+}

+ 4 - 22
daemon/daemon.go

@@ -144,19 +144,17 @@ func (daemon *Daemon) containerRoot(id string) string {
 // Load reads the contents of a container from disk
 // This is typically done at startup.
 func (daemon *Daemon) load(id string) (*Container, error) {
-	container := &Container{
-		CommonContainer: daemon.newBaseContainer(id),
-	}
+	container := daemon.newBaseContainer(id)
 
 	if err := container.FromDisk(); err != nil {
 		return nil, err
 	}
 
 	if container.ID != id {
-		return container, fmt.Errorf("Container %s is stored at %s", container.ID, id)
+		return &container, fmt.Errorf("Container %s is stored at %s", container.ID, id)
 	}
 
-	return container, nil
+	return &container, nil
 }
 
 // Register makes a container object usable by the daemon as <container.ID>
@@ -478,11 +476,7 @@ func (daemon *Daemon) newContainer(name string, config *runconfig.Config, imgID
 	base.Driver = daemon.driver.String()
 	base.ExecDriver = daemon.execDriver.Name()
 
-	container := &Container{
-		CommonContainer: base,
-	}
-
-	return container, err
+	return &base, err
 }
 
 func GetFullContainerName(name string) (string, error) {
@@ -947,18 +941,6 @@ func (daemon *Daemon) setHostConfig(container *Container, hostConfig *runconfig.
 	return nil
 }
 
-func (daemon *Daemon) newBaseContainer(id string) CommonContainer {
-	return CommonContainer{
-		ID:           id,
-		State:        NewState(),
-		MountPoints:  make(map[string]*mountPoint),
-		Volumes:      make(map[string]string),
-		VolumesRW:    make(map[string]bool),
-		execCommands: newExecStore(),
-		root:         daemon.containerRoot(id),
-	}
-}
-
 func setDefaultMtu(config *Config) {
 	// do nothing if the config does not have the default 0 value.
 	if config.Mtu != 0 {

+ 14 - 0
daemon/daemon_unix.go

@@ -539,3 +539,17 @@ func (daemon *Daemon) RegisterLinks(container *Container, hostConfig *runconfig.
 
 	return nil
 }
+
+func (daemon *Daemon) newBaseContainer(id string) Container {
+	return Container{
+		CommonContainer: CommonContainer{
+			ID:           id,
+			State:        NewState(),
+			execCommands: newExecStore(),
+			root:         daemon.containerRoot(id),
+		},
+		MountPoints: make(map[string]*mountPoint),
+		Volumes:     make(map[string]string),
+		VolumesRW:   make(map[string]bool),
+	}
+}

+ 11 - 0
daemon/daemon_windows.go

@@ -169,3 +169,14 @@ func (daemon *Daemon) RegisterLinks(container *Container, hostConfig *runconfig.
 	}
 	return nil
 }
+
+func (daemon *Daemon) newBaseContainer(id string) Container {
+	return Container{
+		CommonContainer: CommonContainer{
+			ID:           id,
+			State:        NewState(),
+			execCommands: newExecStore(),
+			root:         daemon.containerRoot(id),
+		},
+	}
+}

+ 4 - 47
daemon/inspect.go

@@ -21,53 +21,11 @@ func (daemon *Daemon) ContainerInspect(name string) (*types.ContainerJSON, error
 		return nil, err
 	}
 
-	mountPoints := make([]types.MountPoint, 0, len(container.MountPoints))
-	for _, m := range container.MountPoints {
-		mountPoints = append(mountPoints, types.MountPoint{
-			Name:        m.Name,
-			Source:      m.Path(),
-			Destination: m.Destination,
-			Driver:      m.Driver,
-			Mode:        m.Mode,
-			RW:          m.RW,
-		})
-	}
+	mountPoints := addMountPoints(container)
 
 	return &types.ContainerJSON{base, mountPoints, container.Config}, nil
 }
 
-func (daemon *Daemon) ContainerInspectPre120(name string) (*types.ContainerJSONPre120, error) {
-	container, err := daemon.Get(name)
-	if err != nil {
-		return nil, err
-	}
-
-	container.Lock()
-	defer container.Unlock()
-
-	base, err := daemon.getInspectData(container)
-	if err != nil {
-		return nil, err
-	}
-
-	volumes := make(map[string]string)
-	volumesRW := make(map[string]bool)
-	for _, m := range container.MountPoints {
-		volumes[m.Destination] = m.Path()
-		volumesRW[m.Destination] = m.RW
-	}
-
-	config := &types.ContainerConfig{
-		container.Config,
-		container.hostConfig.Memory,
-		container.hostConfig.MemorySwap,
-		container.hostConfig.CPUShares,
-		container.hostConfig.CpusetCpus,
-	}
-
-	return &types.ContainerJSONPre120{base, volumes, volumesRW, config}, nil
-}
-
 func (daemon *Daemon) getInspectData(container *Container) (*types.ContainerJSONBase, error) {
 	// make a copy to play with
 	hostConfig := *container.hostConfig
@@ -104,9 +62,6 @@ func (daemon *Daemon) getInspectData(container *Container) (*types.ContainerJSON
 		State:           containerState,
 		Image:           container.ImageID,
 		NetworkSettings: container.NetworkSettings,
-		ResolvConfPath:  container.ResolvConfPath,
-		HostnamePath:    container.HostnamePath,
-		HostsPath:       container.HostsPath,
 		LogPath:         container.LogPath,
 		Name:            container.Name,
 		RestartCount:    container.RestartCount,
@@ -114,11 +69,13 @@ func (daemon *Daemon) getInspectData(container *Container) (*types.ContainerJSON
 		ExecDriver:      container.ExecDriver,
 		MountLabel:      container.MountLabel,
 		ProcessLabel:    container.ProcessLabel,
-		AppArmorProfile: container.AppArmorProfile,
 		ExecIDs:         container.GetExecIDs(),
 		HostConfig:      &hostConfig,
 	}
 
+	// Now set any platform-specific fields
+	contJSONBase = setPlatformSpecificContainerFields(container, contJSONBase)
+
 	contJSONBase.GraphDriver.Name = container.Driver
 	graphDriverData, err := daemon.driver.GetMetadata(container.ID)
 	if err != nil {

+ 62 - 0
daemon/inspect_unix.go

@@ -0,0 +1,62 @@
+// +build !windows
+
+package daemon
+
+import "github.com/docker/docker/api/types"
+
+// This sets platform-specific fields
+func setPlatformSpecificContainerFields(container *Container, contJSONBase *types.ContainerJSONBase) *types.ContainerJSONBase {
+	contJSONBase.AppArmorProfile = container.AppArmorProfile
+	contJSONBase.ResolvConfPath = container.ResolvConfPath
+	contJSONBase.HostnamePath = container.HostnamePath
+	contJSONBase.HostsPath = container.HostsPath
+
+	return contJSONBase
+}
+
+func (daemon *Daemon) ContainerInspectPre120(name string) (*types.ContainerJSONPre120, error) {
+	container, err := daemon.Get(name)
+	if err != nil {
+		return nil, err
+	}
+
+	container.Lock()
+	defer container.Unlock()
+
+	base, err := daemon.getInspectData(container)
+	if err != nil {
+		return nil, err
+	}
+
+	volumes := make(map[string]string)
+	volumesRW := make(map[string]bool)
+	for _, m := range container.MountPoints {
+		volumes[m.Destination] = m.Path()
+		volumesRW[m.Destination] = m.RW
+	}
+
+	config := &types.ContainerConfig{
+		container.Config,
+		container.hostConfig.Memory,
+		container.hostConfig.MemorySwap,
+		container.hostConfig.CPUShares,
+		container.hostConfig.CpusetCpus,
+	}
+
+	return &types.ContainerJSONPre120{base, volumes, volumesRW, config}, nil
+}
+
+func addMountPoints(container *Container) []types.MountPoint {
+	mountPoints := make([]types.MountPoint, 0, len(container.MountPoints))
+	for _, m := range container.MountPoints {
+		mountPoints = append(mountPoints, types.MountPoint{
+			Name:        m.Name,
+			Source:      m.Path(),
+			Destination: m.Destination,
+			Driver:      m.Driver,
+			Mode:        m.Mode,
+			RW:          m.RW,
+		})
+	}
+	return mountPoints
+}

+ 12 - 0
daemon/inspect_windows.go

@@ -0,0 +1,12 @@
+package daemon
+
+import "github.com/docker/docker/api/types"
+
+// This sets platform-specific fields
+func setPlatformSpecificContainerFields(container *Container, contJSONBase *types.ContainerJSONBase) *types.ContainerJSONBase {
+	return contJSONBase
+}
+
+func addMountPoints(container *Container) []types.MountPoint {
+	return nil
+}

+ 2 - 280
daemon/volumes.go

@@ -8,20 +8,17 @@ import (
 	"path/filepath"
 	"strings"
 
-	"github.com/Sirupsen/logrus"
 	"github.com/docker/docker/pkg/chrootarchive"
 	"github.com/docker/docker/pkg/system"
-	"github.com/docker/docker/runconfig"
 	"github.com/docker/docker/volume"
-	"github.com/docker/docker/volume/drivers"
-	"github.com/docker/docker/volume/local"
-	"github.com/opencontainers/runc/libcontainer/label"
 )
 
 // ErrVolumeReadonly is used to signal an error when trying to copy data into
 // a volume mount that is not writable.
 var ErrVolumeReadonly = errors.New("mounted volume is marked read-only")
 
+// TODO Windows. Further platform refactoring can still be done in volumes*.go
+
 type mountPoint struct {
 	Name        string
 	Destination string
@@ -70,73 +67,6 @@ func (m *mountPoint) Path() string {
 	return m.Source
 }
 
-// BackwardsCompatible decides whether this mount point can be
-// used in old versions of Docker or not.
-// Only bind mounts and local volumes can be used in old versions of Docker.
-func (m *mountPoint) BackwardsCompatible() bool {
-	return len(m.Source) > 0 || m.Driver == volume.DefaultDriverName
-}
-
-func parseBindMount(spec string, mountLabel string, config *runconfig.Config) (*mountPoint, error) {
-	bind := &mountPoint{
-		RW: true,
-	}
-	arr := strings.Split(spec, ":")
-
-	switch len(arr) {
-	case 2:
-		bind.Destination = arr[1]
-	case 3:
-		bind.Destination = arr[1]
-		mode := arr[2]
-		isValid, isRw := volume.ValidateMountMode(mode)
-		if !isValid {
-			return nil, fmt.Errorf("invalid mode for volumes-from: %s", mode)
-		}
-		bind.RW = isRw
-		// Mode field is used by SELinux to decide whether to apply label
-		bind.Mode = mode
-	default:
-		return nil, fmt.Errorf("Invalid volume specification: %s", spec)
-	}
-
-	name, source, err := parseVolumeSource(arr[0])
-	if err != nil {
-		return nil, err
-	}
-
-	if len(source) == 0 {
-		bind.Driver = config.VolumeDriver
-		if len(bind.Driver) == 0 {
-			bind.Driver = volume.DefaultDriverName
-		}
-	} else {
-		bind.Source = filepath.Clean(source)
-	}
-
-	bind.Name = name
-	bind.Destination = filepath.Clean(bind.Destination)
-	return bind, nil
-}
-
-func parseVolumesFrom(spec string) (string, string, error) {
-	if len(spec) == 0 {
-		return "", "", fmt.Errorf("malformed volumes-from specification: %s", spec)
-	}
-
-	specParts := strings.SplitN(spec, ":", 2)
-	id := specParts[0]
-	mode := "rw"
-
-	if len(specParts) == 2 {
-		mode = specParts[1]
-		if isValid, _ := volume.ValidateMountMode(mode); !isValid {
-			return "", "", fmt.Errorf("invalid mode for volumes-from: %s", mode)
-		}
-	}
-	return id, mode, nil
-}
-
 func copyExistingContents(source, destination string) error {
 	volList, err := ioutil.ReadDir(source)
 	if err != nil {
@@ -156,211 +86,3 @@ func copyExistingContents(source, destination string) error {
 	}
 	return copyOwnership(source, destination)
 }
-
-// registerMountPoints initializes the container mount points with the configured volumes and bind mounts.
-// It follows the next sequence to decide what to mount in each final destination:
-//
-// 1. Select the previously configured mount points for the containers, if any.
-// 2. Select the volumes mounted from another containers. Overrides previously configured mount point destination.
-// 3. Select the bind mounts set by the client. Overrides previously configured mount point destinations.
-func (daemon *Daemon) registerMountPoints(container *Container, hostConfig *runconfig.HostConfig) error {
-	binds := map[string]bool{}
-	mountPoints := map[string]*mountPoint{}
-
-	// 1. Read already configured mount points.
-	for name, point := range container.MountPoints {
-		mountPoints[name] = point
-	}
-
-	// 2. Read volumes from other containers.
-	for _, v := range hostConfig.VolumesFrom {
-		containerID, mode, err := parseVolumesFrom(v)
-		if err != nil {
-			return err
-		}
-
-		c, err := daemon.Get(containerID)
-		if err != nil {
-			return err
-		}
-
-		for _, m := range c.MountPoints {
-			cp := &mountPoint{
-				Name:        m.Name,
-				Source:      m.Source,
-				RW:          m.RW && volume.ReadWrite(mode),
-				Driver:      m.Driver,
-				Destination: m.Destination,
-			}
-
-			if len(cp.Source) == 0 {
-				v, err := createVolume(cp.Name, cp.Driver)
-				if err != nil {
-					return err
-				}
-				cp.Volume = v
-			}
-
-			mountPoints[cp.Destination] = cp
-		}
-	}
-
-	// 3. Read bind mounts
-	for _, b := range hostConfig.Binds {
-		// #10618
-		bind, err := parseBindMount(b, container.MountLabel, container.Config)
-		if err != nil {
-			return err
-		}
-
-		if binds[bind.Destination] {
-			return fmt.Errorf("Duplicate bind mount %s", bind.Destination)
-		}
-
-		if len(bind.Name) > 0 && len(bind.Driver) > 0 {
-			// create the volume
-			v, err := createVolume(bind.Name, bind.Driver)
-			if err != nil {
-				return err
-			}
-			bind.Volume = v
-			bind.Source = v.Path()
-			// Since this is just a named volume and not a typical bind, set to shared mode `z`
-			if bind.Mode == "" {
-				bind.Mode = "z"
-			}
-		}
-
-		if err := label.Relabel(bind.Source, container.MountLabel, bind.Mode); err != nil {
-			return err
-		}
-		binds[bind.Destination] = true
-		mountPoints[bind.Destination] = bind
-	}
-
-	// Keep backwards compatible structures
-	bcVolumes := map[string]string{}
-	bcVolumesRW := map[string]bool{}
-	for _, m := range mountPoints {
-		if m.BackwardsCompatible() {
-			bcVolumes[m.Destination] = m.Path()
-			bcVolumesRW[m.Destination] = m.RW
-		}
-	}
-
-	container.Lock()
-	container.MountPoints = mountPoints
-	container.Volumes = bcVolumes
-	container.VolumesRW = bcVolumesRW
-	container.Unlock()
-
-	return nil
-}
-
-// TODO Windows. Factor out as not relevant (as Windows daemon support not in pre-1.7)
-// verifyVolumesInfo ports volumes configured for the containers pre docker 1.7.
-// It reads the container configuration and creates valid mount points for the old volumes.
-func (daemon *Daemon) verifyVolumesInfo(container *Container) error {
-	// Inspect old structures only when we're upgrading from old versions
-	// to versions >= 1.7 and the MountPoints has not been populated with volumes data.
-	if len(container.MountPoints) == 0 && len(container.Volumes) > 0 {
-		for destination, hostPath := range container.Volumes {
-			vfsPath := filepath.Join(daemon.root, "vfs", "dir")
-			rw := container.VolumesRW != nil && container.VolumesRW[destination]
-
-			if strings.HasPrefix(hostPath, vfsPath) {
-				id := filepath.Base(hostPath)
-				if err := migrateVolume(id, hostPath); err != nil {
-					return err
-				}
-				container.addLocalMountPoint(id, destination, rw)
-			} else { // Bind mount
-				id, source, err := parseVolumeSource(hostPath)
-				// We should not find an error here coming
-				// from the old configuration, but who knows.
-				if err != nil {
-					return err
-				}
-				container.addBindMountPoint(id, source, destination, rw)
-			}
-		}
-	} else if len(container.MountPoints) > 0 {
-		// Volumes created with a Docker version >= 1.7. We verify integrity in case of data created
-		// with Docker 1.7 RC versions that put the information in
-		// DOCKER_ROOT/volumes/VOLUME_ID rather than DOCKER_ROOT/volumes/VOLUME_ID/_container_data.
-		l, err := getVolumeDriver(volume.DefaultDriverName)
-		if err != nil {
-			return err
-		}
-
-		for _, m := range container.MountPoints {
-			if m.Driver != volume.DefaultDriverName {
-				continue
-			}
-			dataPath := l.(*local.Root).DataPath(m.Name)
-			volumePath := filepath.Dir(dataPath)
-
-			d, err := ioutil.ReadDir(volumePath)
-			if err != nil {
-				// If the volume directory doesn't exist yet it will be recreated,
-				// so we only return the error when there is a different issue.
-				if !os.IsNotExist(err) {
-					return err
-				}
-				// Do not check when the volume directory does not exist.
-				continue
-			}
-			if validVolumeLayout(d) {
-				continue
-			}
-
-			if err := os.Mkdir(dataPath, 0755); err != nil {
-				return err
-			}
-
-			// Move data inside the data directory
-			for _, f := range d {
-				oldp := filepath.Join(volumePath, f.Name())
-				newp := filepath.Join(dataPath, f.Name())
-				if err := os.Rename(oldp, newp); err != nil {
-					logrus.Errorf("Unable to move %s to %s\n", oldp, newp)
-				}
-			}
-		}
-
-		return container.ToDisk()
-	}
-
-	return nil
-}
-
-func createVolume(name, driverName string) (volume.Volume, error) {
-	vd, err := getVolumeDriver(driverName)
-	if err != nil {
-		return nil, err
-	}
-	return vd.Create(name)
-}
-
-func removeVolume(v volume.Volume) error {
-	vd, err := getVolumeDriver(v.DriverName())
-	if err != nil {
-		return nil
-	}
-	return vd.Remove(v)
-}
-
-func getVolumeDriver(name string) (volume.Driver, error) {
-	if name == "" {
-		name = volume.DefaultDriverName
-	}
-	return volumedrivers.Lookup(name)
-}
-
-func parseVolumeSource(spec string) (string, string, error) {
-	if !filepath.IsAbs(spec) {
-		return spec, "", nil
-	}
-
-	return "", spec, nil
-}

+ 280 - 0
daemon/volumes_linux.go

@@ -3,15 +3,21 @@
 package daemon
 
 import (
+	"fmt"
+	"io/ioutil"
 	"os"
 	"path/filepath"
 	"sort"
 	"strings"
 
+	"github.com/Sirupsen/logrus"
 	"github.com/docker/docker/daemon/execdriver"
 	"github.com/docker/docker/pkg/system"
+	"github.com/docker/docker/runconfig"
 	"github.com/docker/docker/volume"
+	"github.com/docker/docker/volume/drivers"
 	"github.com/docker/docker/volume/local"
+	"github.com/opencontainers/runc/libcontainer/label"
 )
 
 // copyOwnership copies the permissions and uid:gid of the source file
@@ -49,6 +55,48 @@ func (container *Container) setupMounts() ([]execdriver.Mount, error) {
 	return append(mounts, container.networkMounts()...), nil
 }
 
+func parseBindMount(spec string, mountLabel string, config *runconfig.Config) (*mountPoint, error) {
+	bind := &mountPoint{
+		RW: true,
+	}
+	arr := strings.Split(spec, ":")
+
+	switch len(arr) {
+	case 2:
+		bind.Destination = arr[1]
+	case 3:
+		bind.Destination = arr[1]
+		mode := arr[2]
+		isValid, isRw := volume.ValidateMountMode(mode)
+		if !isValid {
+			return nil, fmt.Errorf("invalid mode for volumes-from: %s", mode)
+		}
+		bind.RW = isRw
+		// Mode field is used by SELinux to decide whether to apply label
+		bind.Mode = mode
+	default:
+		return nil, fmt.Errorf("Invalid volume specification: %s", spec)
+	}
+
+	name, source, err := parseVolumeSource(arr[0])
+	if err != nil {
+		return nil, err
+	}
+
+	if len(source) == 0 {
+		bind.Driver = config.VolumeDriver
+		if len(bind.Driver) == 0 {
+			bind.Driver = volume.DefaultDriverName
+		}
+	} else {
+		bind.Source = filepath.Clean(source)
+	}
+
+	bind.Name = name
+	bind.Destination = filepath.Clean(bind.Destination)
+	return bind, nil
+}
+
 func sortMounts(m []execdriver.Mount) []execdriver.Mount {
 	sort.Sort(mounts(m))
 	return m
@@ -118,3 +166,235 @@ func validVolumeLayout(files []os.FileInfo) bool {
 
 	return true
 }
+
+// verifyVolumesInfo ports volumes configured for the containers pre docker 1.7.
+// It reads the container configuration and creates valid mount points for the old volumes.
+func (daemon *Daemon) verifyVolumesInfo(container *Container) error {
+	// Inspect old structures only when we're upgrading from old versions
+	// to versions >= 1.7 and the MountPoints has not been populated with volumes data.
+	if len(container.MountPoints) == 0 && len(container.Volumes) > 0 {
+		for destination, hostPath := range container.Volumes {
+			vfsPath := filepath.Join(daemon.root, "vfs", "dir")
+			rw := container.VolumesRW != nil && container.VolumesRW[destination]
+
+			if strings.HasPrefix(hostPath, vfsPath) {
+				id := filepath.Base(hostPath)
+				if err := migrateVolume(id, hostPath); err != nil {
+					return err
+				}
+				container.addLocalMountPoint(id, destination, rw)
+			} else { // Bind mount
+				id, source, err := parseVolumeSource(hostPath)
+				// We should not find an error here coming
+				// from the old configuration, but who knows.
+				if err != nil {
+					return err
+				}
+				container.addBindMountPoint(id, source, destination, rw)
+			}
+		}
+	} else if len(container.MountPoints) > 0 {
+		// Volumes created with a Docker version >= 1.7. We verify integrity in case of data created
+		// with Docker 1.7 RC versions that put the information in
+		// DOCKER_ROOT/volumes/VOLUME_ID rather than DOCKER_ROOT/volumes/VOLUME_ID/_container_data.
+		l, err := getVolumeDriver(volume.DefaultDriverName)
+		if err != nil {
+			return err
+		}
+
+		for _, m := range container.MountPoints {
+			if m.Driver != volume.DefaultDriverName {
+				continue
+			}
+			dataPath := l.(*local.Root).DataPath(m.Name)
+			volumePath := filepath.Dir(dataPath)
+
+			d, err := ioutil.ReadDir(volumePath)
+			if err != nil {
+				// If the volume directory doesn't exist yet it will be recreated,
+				// so we only return the error when there is a different issue.
+				if !os.IsNotExist(err) {
+					return err
+				}
+				// Do not check when the volume directory does not exist.
+				continue
+			}
+			if validVolumeLayout(d) {
+				continue
+			}
+
+			if err := os.Mkdir(dataPath, 0755); err != nil {
+				return err
+			}
+
+			// Move data inside the data directory
+			for _, f := range d {
+				oldp := filepath.Join(volumePath, f.Name())
+				newp := filepath.Join(dataPath, f.Name())
+				if err := os.Rename(oldp, newp); err != nil {
+					logrus.Errorf("Unable to move %s to %s\n", oldp, newp)
+				}
+			}
+		}
+
+		return container.ToDisk()
+	}
+
+	return nil
+}
+
+func parseVolumesFrom(spec string) (string, string, error) {
+	if len(spec) == 0 {
+		return "", "", fmt.Errorf("malformed volumes-from specification: %s", spec)
+	}
+
+	specParts := strings.SplitN(spec, ":", 2)
+	id := specParts[0]
+	mode := "rw"
+
+	if len(specParts) == 2 {
+		mode = specParts[1]
+		if isValid, _ := volume.ValidateMountMode(mode); !isValid {
+			return "", "", fmt.Errorf("invalid mode for volumes-from: %s", mode)
+		}
+	}
+	return id, mode, nil
+}
+
+// registerMountPoints initializes the container mount points with the configured volumes and bind mounts.
+// It follows the next sequence to decide what to mount in each final destination:
+//
+// 1. Select the previously configured mount points for the containers, if any.
+// 2. Select the volumes mounted from another containers. Overrides previously configured mount point destination.
+// 3. Select the bind mounts set by the client. Overrides previously configured mount point destinations.
+func (daemon *Daemon) registerMountPoints(container *Container, hostConfig *runconfig.HostConfig) error {
+	binds := map[string]bool{}
+	mountPoints := map[string]*mountPoint{}
+
+	// 1. Read already configured mount points.
+	for name, point := range container.MountPoints {
+		mountPoints[name] = point
+	}
+
+	// 2. Read volumes from other containers.
+	for _, v := range hostConfig.VolumesFrom {
+		containerID, mode, err := parseVolumesFrom(v)
+		if err != nil {
+			return err
+		}
+
+		c, err := daemon.Get(containerID)
+		if err != nil {
+			return err
+		}
+
+		for _, m := range c.MountPoints {
+			cp := &mountPoint{
+				Name:        m.Name,
+				Source:      m.Source,
+				RW:          m.RW && volume.ReadWrite(mode),
+				Driver:      m.Driver,
+				Destination: m.Destination,
+			}
+
+			if len(cp.Source) == 0 {
+				v, err := createVolume(cp.Name, cp.Driver)
+				if err != nil {
+					return err
+				}
+				cp.Volume = v
+			}
+
+			mountPoints[cp.Destination] = cp
+		}
+	}
+
+	// 3. Read bind mounts
+	for _, b := range hostConfig.Binds {
+		// #10618
+		bind, err := parseBindMount(b, container.MountLabel, container.Config)
+		if err != nil {
+			return err
+		}
+
+		if binds[bind.Destination] {
+			return fmt.Errorf("Duplicate bind mount %s", bind.Destination)
+		}
+
+		if len(bind.Name) > 0 && len(bind.Driver) > 0 {
+			// create the volume
+			v, err := createVolume(bind.Name, bind.Driver)
+			if err != nil {
+				return err
+			}
+			bind.Volume = v
+			bind.Source = v.Path()
+			// Since this is just a named volume and not a typical bind, set to shared mode `z`
+			if bind.Mode == "" {
+				bind.Mode = "z"
+			}
+		}
+
+		if err := label.Relabel(bind.Source, container.MountLabel, bind.Mode); err != nil {
+			return err
+		}
+		binds[bind.Destination] = true
+		mountPoints[bind.Destination] = bind
+	}
+
+	// Keep backwards compatible structures
+	bcVolumes := map[string]string{}
+	bcVolumesRW := map[string]bool{}
+	for _, m := range mountPoints {
+		if m.BackwardsCompatible() {
+			bcVolumes[m.Destination] = m.Path()
+			bcVolumesRW[m.Destination] = m.RW
+		}
+	}
+
+	container.Lock()
+	container.MountPoints = mountPoints
+	container.Volumes = bcVolumes
+	container.VolumesRW = bcVolumesRW
+	container.Unlock()
+
+	return nil
+}
+
+func createVolume(name, driverName string) (volume.Volume, error) {
+	vd, err := getVolumeDriver(driverName)
+	if err != nil {
+		return nil, err
+	}
+	return vd.Create(name)
+}
+
+func removeVolume(v volume.Volume) error {
+	vd, err := getVolumeDriver(v.DriverName())
+	if err != nil {
+		return nil
+	}
+	return vd.Remove(v)
+}
+
+func getVolumeDriver(name string) (volume.Driver, error) {
+	if name == "" {
+		name = volume.DefaultDriverName
+	}
+	return volumedrivers.Lookup(name)
+}
+
+func parseVolumeSource(spec string) (string, string, error) {
+	if !filepath.IsAbs(spec) {
+		return spec, "", nil
+	}
+
+	return "", spec, nil
+}
+
+// BackwardsCompatible decides whether this mount point can be
+// used in old versions of Docker or not.
+// Only bind mounts and local volumes can be used in old versions of Docker.
+func (m *mountPoint) BackwardsCompatible() bool {
+	return len(m.Source) > 0 || m.Driver == volume.DefaultDriverName
+}

+ 7 - 5
daemon/volumes_windows.go

@@ -3,9 +3,8 @@
 package daemon
 
 import (
-	"os"
-
 	"github.com/docker/docker/daemon/execdriver"
+	"github.com/docker/docker/runconfig"
 )
 
 // Not supported on Windows
@@ -17,10 +16,13 @@ func (container *Container) setupMounts() ([]execdriver.Mount, error) {
 	return nil, nil
 }
 
-func migrateVolume(id, vfs string) error {
+// verifyVolumesInfo ports volumes configured for the containers pre docker 1.7.
+// As the Windows daemon was not supported before 1.7, this is a no-op
+func (daemon *Daemon) verifyVolumesInfo(container *Container) error {
 	return nil
 }
 
-func validVolumeLayout(files []os.FileInfo) bool {
-	return true
+// TODO Windows: This can be further factored out. Called from daemon\daemon.go
+func (daemon *Daemon) registerMountPoints(container *Container, hostConfig *runconfig.HostConfig) error {
+	return nil
 }

+ 2 - 4
docker/daemon.go

@@ -212,10 +212,8 @@ func (cli *DaemonCli) CmdDaemon(args ...string) error {
 	}
 
 	serverConfig := &apiserver.ServerConfig{
-		Logging:     true,
-		EnableCors:  cli.EnableCors,
-		CorsHeaders: cli.CorsHeaders,
-		Version:     dockerversion.VERSION,
+		Logging: true,
+		Version: dockerversion.VERSION,
 	}
 	serverConfig = setPlatformServerConfig(serverConfig, cli.Config)
 

+ 3 - 0
docker/daemon_unix.go

@@ -17,6 +17,9 @@ import (
 
 func setPlatformServerConfig(serverConfig *apiserver.ServerConfig, daemonCfg *daemon.Config) *apiserver.ServerConfig {
 	serverConfig.SocketGroup = daemonCfg.SocketGroup
+	serverConfig.EnableCors = daemonCfg.EnableCors
+	serverConfig.CorsHeaders = daemonCfg.CorsHeaders
+
 	return serverConfig
 }