Browse Source

Merge pull request #18347 from tiborvass/container_package

Move Container to its own package (carry of 17969)
Michael Crosby 9 years ago
parent
commit
168b490062
60 changed files with 1600 additions and 1237 deletions
  1. 8 9
      builder/builder.go
  2. 5 4
      builder/dockerfile/internals.go
  3. 69 0
      container/archive.go
  4. 92 85
      container/container.go
  5. 36 0
      container/container_unit_test.go
  6. 642 0
      container/container_unix.go
  7. 59 0
      container/container_windows.go
  8. 42 26
      container/monitor.go
  9. 33 23
      container/state.go
  10. 4 4
      container/state_test.go
  11. 1 1
      container/state_unix.go
  12. 1 1
      container/state_windows.go
  13. 20 79
      daemon/archive.go
  14. 3 1
      daemon/archive_unix.go
  15. 3 1
      daemon/archive_windows.go
  16. 2 1
      daemon/attach.go
  17. 4 3
      daemon/commit.go
  18. 9 0
      daemon/container_operations.go
  19. 138 503
      daemon/container_operations_unix.go
  20. 31 73
      daemon/container_operations_windows.go
  21. 0 136
      daemon/container_unit_test.go
  22. 5 4
      daemon/create.go
  23. 5 4
      daemon/create_unix.go
  24. 5 4
      daemon/create_windows.go
  25. 63 55
      daemon/daemon.go
  26. 122 12
      daemon/daemon_test.go
  27. 10 9
      daemon/daemon_unix.go
  28. 7 6
      daemon/daemon_windows.go
  29. 8 7
      daemon/daemonbuilder/builder.go
  30. 7 6
      daemon/delete.go
  31. 6 5
      daemon/delete_test.go
  32. 5 1
      daemon/events.go
  33. 22 22
      daemon/exec.go
  34. 2 1
      daemon/exec_unix.go
  35. 2 1
      daemon/exec_windows.go
  36. 3 2
      daemon/export.go
  37. 4 2
      daemon/history.go
  38. 2 1
      daemon/image_delete.go
  39. 5 4
      daemon/inspect.go
  40. 8 7
      daemon/inspect_unix.go
  41. 6 3
      daemon/inspect_windows.go
  42. 4 3
      daemon/kill.go
  43. 11 10
      daemon/list.go
  44. 3 1
      daemon/list_unix.go
  45. 7 3
      daemon/list_windows.go
  46. 9 8
      daemon/logs.go
  47. 3 2
      daemon/mounts.go
  48. 1 1
      daemon/network.go
  49. 3 2
      daemon/pause.go
  50. 5 7
      daemon/rename.go
  51. 2 1
      daemon/restart.go
  52. 22 32
      daemon/start.go
  53. 8 7
      daemon/stats_collector_unix.go
  54. 8 4
      daemon/stats_collector_windows.go
  55. 3 2
      daemon/stop.go
  56. 3 2
      daemon/unpause.go
  57. 2 1
      daemon/volumes.go
  58. 4 43
      daemon/volumes_unix.go
  59. 2 1
      daemon/volumes_windows.go
  60. 1 1
      opts/opts_windows.go

+ 8 - 9
builder/builder.go

@@ -9,6 +9,7 @@ import (
 	"os"
 
 	// TODO: remove dependency on daemon
+	"github.com/docker/docker/container"
 	"github.com/docker/docker/daemon"
 	"github.com/docker/docker/image"
 	"github.com/docker/docker/runconfig"
@@ -115,13 +116,11 @@ type Docker interface {
 	// Pull tells Docker to pull image referenced by `name`.
 	Pull(name string) (*image.Image, error)
 
-	// TODO: move daemon.Container to its own package
-
 	// Container looks up a Docker container referenced by `id`.
-	Container(id string) (*daemon.Container, error)
+	Container(id string) (*container.Container, error)
 	// Create creates a new Docker container and returns potential warnings
 	// TODO: put warnings in the error
-	Create(*runconfig.Config, *runconfig.HostConfig) (*daemon.Container, []string, error)
+	Create(*runconfig.Config, *runconfig.HostConfig) (*container.Container, []string, error)
 	// Remove removes a container specified by `id`.
 	Remove(id string, cfg *daemon.ContainerRmConfig) error
 	// Commit creates a new Docker image from an existing Docker container.
@@ -131,7 +130,7 @@ type Docker interface {
 	// TODO: make an Extract method instead of passing `decompress`
 	// TODO: do not pass a FileInfo, instead refactor the archive package to export a Walk function that can be used
 	// with Context.Walk
-	Copy(c *daemon.Container, destPath string, src FileInfo, decompress bool) error
+	Copy(c *container.Container, destPath string, src FileInfo, decompress bool) error
 
 	// Retain retains an image avoiding it to be removed or overwritten until a corresponding Release() call.
 	// TODO: remove
@@ -140,13 +139,13 @@ type Docker interface {
 	// TODO: remove
 	Release(sessionID string, activeImages []string)
 	// Kill stops the container execution abruptly.
-	Kill(c *daemon.Container) error
+	Kill(c *container.Container) error
 	// Mount mounts the root filesystem for the container.
-	Mount(c *daemon.Container) error
+	Mount(c *container.Container) error
 	// Unmount unmounts the root filesystem for the container.
-	Unmount(c *daemon.Container) error
+	Unmount(c *container.Container) error
 	// Start starts a new container
-	Start(c *daemon.Container) error
+	Start(c *container.Container) error
 }
 
 // ImageCache abstracts an image cache store.

+ 5 - 4
builder/dockerfile/internals.go

@@ -22,6 +22,7 @@ import (
 	"github.com/docker/docker/api"
 	"github.com/docker/docker/builder"
 	"github.com/docker/docker/builder/dockerfile/parser"
+	"github.com/docker/docker/container"
 	"github.com/docker/docker/daemon"
 	"github.com/docker/docker/image"
 	"github.com/docker/docker/pkg/archive"
@@ -419,8 +420,8 @@ func (b *Builder) processImageFrom(img *image.Image) error {
 	}
 
 	// The default path will be blank on Windows (set by HCS)
-	if len(b.runConfig.Env) == 0 && daemon.DefaultPathEnv != "" {
-		b.runConfig.Env = append(b.runConfig.Env, "PATH="+daemon.DefaultPathEnv)
+	if len(b.runConfig.Env) == 0 && container.DefaultPathEnv != "" {
+		b.runConfig.Env = append(b.runConfig.Env, "PATH="+container.DefaultPathEnv)
 	}
 
 	// Process ONBUILD triggers if they exist
@@ -492,7 +493,7 @@ func (b *Builder) probeCache() (bool, error) {
 	return true, nil
 }
 
-func (b *Builder) create() (*daemon.Container, error) {
+func (b *Builder) create() (*container.Container, error) {
 	if b.image == "" && !b.noBaseImage {
 		return nil, fmt.Errorf("Please provide a source image with `from` prior to run")
 	}
@@ -542,7 +543,7 @@ func (b *Builder) create() (*daemon.Container, error) {
 	return c, nil
 }
 
-func (b *Builder) run(c *daemon.Container) error {
+func (b *Builder) run(c *container.Container) error {
 	var errCh chan error
 	if b.Verbose {
 		errCh = c.Attach(nil, b.Stdout, b.Stderr)

+ 69 - 0
container/archive.go

@@ -0,0 +1,69 @@
+package container
+
+import (
+	"os"
+	"path/filepath"
+
+	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/pkg/archive"
+)
+
+// ResolvePath resolves the given path in the container to a resource on the
+// host. Returns a resolved path (absolute path to the resource on the host),
+// the absolute path to the resource relative to the container's rootfs, and
+// a error if the path points to outside the container's rootfs.
+func (container *Container) ResolvePath(path string) (resolvedPath, absPath string, err error) {
+	// Consider the given path as an absolute path in the container.
+	absPath = archive.PreserveTrailingDotOrSeparator(filepath.Join(string(filepath.Separator), path), path)
+
+	// Split the absPath into its Directory and Base components. We will
+	// resolve the dir in the scope of the container then append the base.
+	dirPath, basePath := filepath.Split(absPath)
+
+	resolvedDirPath, err := container.GetResourcePath(dirPath)
+	if err != nil {
+		return "", "", err
+	}
+
+	// resolvedDirPath will have been cleaned (no trailing path separators) so
+	// we can manually join it with the base path element.
+	resolvedPath = resolvedDirPath + string(filepath.Separator) + basePath
+
+	return resolvedPath, absPath, nil
+}
+
+// StatPath is the unexported version of StatPath. Locks and mounts should
+// be acquired before calling this method and the given path should be fully
+// resolved to a path on the host corresponding to the given absolute path
+// inside the container.
+func (container *Container) StatPath(resolvedPath, absPath string) (stat *types.ContainerPathStat, err error) {
+	lstat, err := os.Lstat(resolvedPath)
+	if err != nil {
+		return nil, err
+	}
+
+	var linkTarget string
+	if lstat.Mode()&os.ModeSymlink != 0 {
+		// Fully evaluate the symlink in the scope of the container rootfs.
+		hostPath, err := container.GetResourcePath(absPath)
+		if err != nil {
+			return nil, err
+		}
+
+		linkTarget, err = filepath.Rel(container.BaseFS, hostPath)
+		if err != nil {
+			return nil, err
+		}
+
+		// Make it an absolute path.
+		linkTarget = filepath.Join(string(filepath.Separator), linkTarget)
+	}
+
+	return &types.ContainerPathStat{
+		Name:       filepath.Base(absPath),
+		Size:       lstat.Size(),
+		Mode:       lstat.Mode(),
+		Mtime:      lstat.ModTime(),
+		LinkTarget: linkTarget,
+	}, nil
+}

+ 92 - 85
daemon/container.go → container/container.go

@@ -1,8 +1,7 @@
-package daemon
+package container
 
 import (
 	"encoding/json"
-	"errors"
 	"fmt"
 	"io"
 	"os"
@@ -11,8 +10,6 @@ import (
 	"syscall"
 	"time"
 
-	"github.com/opencontainers/runc/libcontainer/label"
-
 	"github.com/Sirupsen/logrus"
 	"github.com/docker/docker/daemon/exec"
 	"github.com/docker/docker/daemon/execdriver"
@@ -26,28 +23,22 @@ import (
 	"github.com/docker/docker/pkg/promise"
 	"github.com/docker/docker/pkg/signal"
 	"github.com/docker/docker/pkg/symlink"
-
 	"github.com/docker/docker/runconfig"
 	"github.com/docker/docker/volume"
+	"github.com/opencontainers/runc/libcontainer/label"
 )
 
 const configFileName = "config.v2.json"
 
-var (
-	// ErrRootFSReadOnly is returned when a container
-	// rootfs is marked readonly.
-	ErrRootFSReadOnly = errors.New("container rootfs is marked read-only")
-)
-
 // CommonContainer holds the fields for a container which are
 // applicable across all platforms supported by the daemon.
 type CommonContainer struct {
 	*runconfig.StreamConfig
 	// embed for Container to support states directly.
 	*State          `json:"State"` // Needed for remote api version <= 1.11
-	root            string         // Path to the "home" of the container, including metadata.
-	basefs          string         // Path to the graphdriver mountpoint
-	rwlayer         layer.RWLayer
+	Root            string         `json:"-"` // Path to the "home" of the container, including metadata.
+	BaseFS          string         `json:"-"` // Path to the graphdriver mountpoint
+	RWLayer         layer.RWLayer  `json:"-"`
 	ID              string
 	Created         time.Time
 	Path            string
@@ -65,32 +56,33 @@ type CommonContainer struct {
 	HasBeenStartedBefore   bool
 	HasBeenManuallyStopped bool // used for unless-stopped restart policy
 	MountPoints            map[string]*volume.MountPoint
-	hostConfig             *runconfig.HostConfig
-	command                *execdriver.Command
+	HostConfig             *runconfig.HostConfig `json:"-"` // do not serialize the host config in the json, otherwise we'll make the container unportable
+	Command                *execdriver.Command   `json:"-"`
 	monitor                *containerMonitor
-	execCommands           *exec.Store
+	ExecCommands           *exec.Store `json:"-"`
 	// logDriver for closing
-	logDriver logger.Logger
-	logCopier *logger.Copier
+	LogDriver logger.Logger  `json:"-"`
+	LogCopier *logger.Copier `json:"-"`
 }
 
-// newBaseContainer creates a new container with its
+// NewBaseContainer creates a new container with its
 // basic configuration.
-func newBaseContainer(id, root string) *Container {
+func NewBaseContainer(id, root string) *Container {
 	return &Container{
 		CommonContainer: CommonContainer{
 			ID:           id,
 			State:        NewState(),
-			execCommands: exec.NewStore(),
-			root:         root,
+			ExecCommands: exec.NewStore(),
+			Root:         root,
 			MountPoints:  make(map[string]*volume.MountPoint),
 			StreamConfig: runconfig.NewStreamConfig(),
 		},
 	}
 }
 
-func (container *Container) fromDisk() error {
-	pth, err := container.jsonPath()
+// FromDisk loads the container configuration stored in the host.
+func (container *Container) FromDisk() error {
+	pth, err := container.ConfigPath()
 	if err != nil {
 		return err
 	}
@@ -114,8 +106,9 @@ func (container *Container) fromDisk() error {
 	return container.readHostConfig()
 }
 
-func (container *Container) toDisk() error {
-	pth, err := container.jsonPath()
+// ToDisk saves the container configuration on disk.
+func (container *Container) ToDisk() error {
+	pth, err := container.ConfigPath()
 	if err != nil {
 		return err
 	}
@@ -133,22 +126,24 @@ func (container *Container) toDisk() error {
 		return err
 	}
 
-	return container.writeHostConfig()
+	return container.WriteHostConfig()
 }
 
-func (container *Container) toDiskLocking() error {
+// ToDiskLocking saves the container configuration on disk in a thread safe way.
+func (container *Container) ToDiskLocking() error {
 	container.Lock()
-	err := container.toDisk()
+	err := container.ToDisk()
 	container.Unlock()
 	return err
 }
 
+// readHostConfig reads the host configuration from disk for the container.
 func (container *Container) readHostConfig() error {
-	container.hostConfig = &runconfig.HostConfig{}
+	container.HostConfig = &runconfig.HostConfig{}
 	// If the hostconfig file does not exist, do not read it.
-	// (We still have to initialize container.hostConfig,
+	// (We still have to initialize container.HostConfig,
 	// but that's OK, since we just did that above.)
-	pth, err := container.hostConfigPath()
+	pth, err := container.HostConfigPath()
 	if err != nil {
 		return err
 	}
@@ -162,17 +157,18 @@ func (container *Container) readHostConfig() error {
 	}
 	defer f.Close()
 
-	if err := json.NewDecoder(f).Decode(&container.hostConfig); err != nil {
+	if err := json.NewDecoder(f).Decode(&container.HostConfig); err != nil {
 		return err
 	}
 
-	initDNSHostConfig(container)
+	container.InitDNSHostConfig()
 
 	return nil
 }
 
-func (container *Container) writeHostConfig() error {
-	pth, err := container.hostConfigPath()
+// WriteHostConfig saves the host configuration on disk for the container.
+func (container *Container) WriteHostConfig() error {
+	pth, err := container.HostConfigPath()
 	if err != nil {
 		return err
 	}
@@ -183,19 +179,19 @@ func (container *Container) writeHostConfig() error {
 	}
 	defer f.Close()
 
-	return json.NewEncoder(f).Encode(&container.hostConfig)
+	return json.NewEncoder(f).Encode(&container.HostConfig)
 }
 
-// GetResourcePath evaluates `path` in the scope of the container's basefs, with proper path
-// sanitisation. Symlinks are all scoped to the basefs of the container, as
-// though the container's basefs was `/`.
+// GetResourcePath evaluates `path` in the scope of the container's BaseFS, with proper path
+// sanitisation. Symlinks are all scoped to the BaseFS of the container, as
+// though the container's BaseFS was `/`.
 //
-// The basefs of a container is the host-facing path which is bind-mounted as
+// The BaseFS of a container is the host-facing path which is bind-mounted as
 // `/` inside the container. This method is essentially used to access a
 // particular path inside the container as though you were a process in that
 // container.
 //
-// NOTE: The returned path is *only* safely scoped inside the container's basefs
+// NOTE: The returned path is *only* safely scoped inside the container's BaseFS
 //       if no component of the returned path changes (such as a component
 //       symlinking to a different path) between using this method and using the
 //       path. See symlink.FollowSymlinkInScope for more details.
@@ -203,11 +199,11 @@ func (container *Container) GetResourcePath(path string) (string, error) {
 	// IMPORTANT - These are paths on the OS where the daemon is running, hence
 	// any filepath operations must be done in an OS agnostic way.
 	cleanPath := filepath.Join(string(os.PathSeparator), path)
-	r, e := symlink.FollowSymlinkInScope(filepath.Join(container.basefs, cleanPath), container.basefs)
+	r, e := symlink.FollowSymlinkInScope(filepath.Join(container.BaseFS, cleanPath), container.BaseFS)
 	return r, e
 }
 
-// Evaluates `path` in the scope of the container's root, with proper path
+// GetRootResourcePath evaluates `path` in the scope of the container's root, with proper path
 // sanitisation. Symlinks are all scoped to the root of the container, as
 // though the container's root was `/`.
 //
@@ -219,11 +215,11 @@ func (container *Container) GetResourcePath(path string) (string, error) {
 //       if no component of the returned path changes (such as a component
 //       symlinking to a different path) between using this method and using the
 //       path. See symlink.FollowSymlinkInScope for more details.
-func (container *Container) getRootResourcePath(path string) (string, error) {
+func (container *Container) GetRootResourcePath(path string) (string, error) {
 	// IMPORTANT - These are paths on the OS where the daemon is running, hence
 	// any filepath operations must be done in an OS agnostic way.
 	cleanPath := filepath.Join(string(os.PathSeparator), path)
-	return symlink.FollowSymlinkInScope(filepath.Join(container.root, cleanPath), container.root)
+	return symlink.FollowSymlinkInScope(filepath.Join(container.Root, cleanPath), container.Root)
 }
 
 // ExitOnNext signals to the monitor that it should not restart the container
@@ -235,23 +231,20 @@ func (container *Container) ExitOnNext() {
 // Resize changes the TTY of the process running inside the container
 // to the given height and width. The container must be running.
 func (container *Container) Resize(h, w int) error {
-	if err := container.command.ProcessConfig.Terminal.Resize(h, w); err != nil {
+	if err := container.Command.ProcessConfig.Terminal.Resize(h, w); err != nil {
 		return err
 	}
 	return nil
 }
 
-func (container *Container) hostConfigPath() (string, error) {
-	return container.getRootResourcePath("hostconfig.json")
-}
-
-func (container *Container) jsonPath() (string, error) {
-	return container.getRootResourcePath(configFileName)
+// HostConfigPath returns the path to the container's JSON hostconfig
+func (container *Container) HostConfigPath() (string, error) {
+	return container.GetRootResourcePath("hostconfig.json")
 }
 
-// This directory is only usable when the container is running
-func (container *Container) rootfsPath() string {
-	return container.basefs
+// ConfigPath returns the path to the container's JSON config
+func (container *Container) ConfigPath() (string, error) {
+	return container.GetRootResourcePath(configFileName)
 }
 
 func validateID(id string) error {
@@ -267,8 +260,9 @@ func (container *Container) exposes(p nat.Port) bool {
 	return exists
 }
 
-func (container *Container) getLogConfig(defaultConfig runconfig.LogConfig) runconfig.LogConfig {
-	cfg := container.hostConfig.LogConfig
+// GetLogConfig returns the log configuration for the container.
+func (container *Container) GetLogConfig(defaultConfig runconfig.LogConfig) runconfig.LogConfig {
+	cfg := container.HostConfig.LogConfig
 	if cfg.Type != "" || len(cfg.Config) > 0 { // container has log driver configured
 		if cfg.Type == "" {
 			cfg.Type = jsonfilelog.Name
@@ -300,7 +294,7 @@ func (container *Container) StartLogger(cfg runconfig.LogConfig) (logger.Logger,
 
 	// Set logging file for "json-logger"
 	if cfg.Type == jsonfilelog.Name {
-		ctx.LogPath, err = container.getRootResourcePath(fmt.Sprintf("%s-json.log", container.ID))
+		ctx.LogPath, err = container.GetRootResourcePath(fmt.Sprintf("%s-json.log", container.ID))
 		if err != nil {
 			return nil, err
 		}
@@ -308,33 +302,39 @@ func (container *Container) StartLogger(cfg runconfig.LogConfig) (logger.Logger,
 	return c(ctx)
 }
 
-func (container *Container) getProcessLabel() string {
+// GetProcessLabel returns the process label for the container.
+func (container *Container) GetProcessLabel() string {
 	// even if we have a process label return "" if we are running
 	// in privileged mode
-	if container.hostConfig.Privileged {
+	if container.HostConfig.Privileged {
 		return ""
 	}
 	return container.ProcessLabel
 }
 
-func (container *Container) getMountLabel() string {
-	if container.hostConfig.Privileged {
+// GetMountLabel returns the mounting label for the container.
+// This label is empty if the container is privileged.
+func (container *Container) GetMountLabel() string {
+	if container.HostConfig.Privileged {
 		return ""
 	}
 	return container.MountLabel
 }
 
-func (container *Container) getExecIDs() []string {
-	return container.execCommands.List()
+// GetExecIDs returns the list of exec commands running on the container.
+func (container *Container) GetExecIDs() []string {
+	return container.ExecCommands.List()
 }
 
 // Attach connects to the container's TTY, delegating to standard
 // streams or websockets depending on the configuration.
 func (container *Container) Attach(stdin io.ReadCloser, stdout io.Writer, stderr io.Writer) chan error {
-	return attach(container.StreamConfig, container.Config.OpenStdin, container.Config.StdinOnce, container.Config.Tty, stdin, stdout, stderr)
+	return AttachStreams(container.StreamConfig, container.Config.OpenStdin, container.Config.StdinOnce, container.Config.Tty, stdin, stdout, stderr)
 }
 
-func attach(streamConfig *runconfig.StreamConfig, openStdin, stdinOnce, tty bool, stdin io.ReadCloser, stdout io.Writer, stderr io.Writer) chan error {
+// AttachStreams connects streams to a TTY.
+// Used by exec too. Should this move somewhere else?
+func AttachStreams(streamConfig *runconfig.StreamConfig, openStdin, stdinOnce, tty bool, stdin io.ReadCloser, stdout io.Writer, stderr io.Writer) chan error {
 	var (
 		cStdout, cStderr io.ReadCloser
 		cStdin           io.WriteCloser
@@ -479,13 +479,16 @@ func copyEscapable(dst io.Writer, src io.ReadCloser) (written int64, err error)
 	return written, err
 }
 
-func (container *Container) shouldRestart() bool {
-	return container.hostConfig.RestartPolicy.Name == "always" ||
-		(container.hostConfig.RestartPolicy.Name == "unless-stopped" && !container.HasBeenManuallyStopped) ||
-		(container.hostConfig.RestartPolicy.Name == "on-failure" && container.ExitCode != 0)
+// ShouldRestart decides whether the daemon should restart the container or not.
+// This is based on the container's restart policy.
+func (container *Container) ShouldRestart() bool {
+	return container.HostConfig.RestartPolicy.Name == "always" ||
+		(container.HostConfig.RestartPolicy.Name == "unless-stopped" && !container.HasBeenManuallyStopped) ||
+		(container.HostConfig.RestartPolicy.Name == "on-failure" && container.ExitCode != 0)
 }
 
-func (container *Container) addBindMountPoint(name, source, destination string, rw bool) {
+// AddBindMountPoint adds a new bind mount point configuration to the container.
+func (container *Container) AddBindMountPoint(name, source, destination string, rw bool) {
 	container.MountPoints[destination] = &volume.MountPoint{
 		Name:        name,
 		Source:      source,
@@ -494,7 +497,8 @@ func (container *Container) addBindMountPoint(name, source, destination string,
 	}
 }
 
-func (container *Container) addLocalMountPoint(name, destination string, rw bool) {
+// AddLocalMountPoint adds a new local mount point configuration to the container.
+func (container *Container) AddLocalMountPoint(name, destination string, rw bool) {
 	container.MountPoints[destination] = &volume.MountPoint{
 		Name:        name,
 		Driver:      volume.DefaultDriverName,
@@ -503,7 +507,8 @@ func (container *Container) addLocalMountPoint(name, destination string, rw bool
 	}
 }
 
-func (container *Container) addMountPointWithVolume(destination string, vol volume.Volume, rw bool) {
+// AddMountPointWithVolume adds a new mount point configured with a volume to the container.
+func (container *Container) AddMountPointWithVolume(destination string, vol volume.Volume, rw bool) {
 	container.MountPoints[destination] = &volume.MountPoint{
 		Name:        vol.Name(),
 		Driver:      vol.DriverName(),
@@ -513,11 +518,13 @@ func (container *Container) addMountPointWithVolume(destination string, vol volu
 	}
 }
 
-func (container *Container) isDestinationMounted(destination string) bool {
+// IsDestinationMounted checkes whether a path is mounted on the container or not.
+func (container *Container) IsDestinationMounted(destination string) bool {
 	return container.MountPoints[destination] != nil
 }
 
-func (container *Container) stopSignal() int {
+// StopSignal returns the signal used to stop the container.
+func (container *Container) StopSignal() int {
 	var stopSignal syscall.Signal
 	if container.Config.StopSignal != "" {
 		stopSignal, _ = signal.ParseSignal(container.Config.StopSignal)
@@ -529,7 +536,7 @@ func (container *Container) stopSignal() int {
 	return int(stopSignal)
 }
 
-// initDNSHostConfig ensures that the dns fields are never nil.
+// InitDNSHostConfig ensures that the dns fields are never nil.
 // New containers don't ever have those fields nil,
 // but pre created containers can still have those nil values.
 // The non-recommended host configuration in the start api can
@@ -537,16 +544,16 @@ func (container *Container) stopSignal() int {
 // we remove that behavior for good.
 // See https://github.com/docker/docker/pull/17779
 // for a more detailed explanation on why we don't want that.
-func initDNSHostConfig(container *Container) {
-	if container.hostConfig.DNS == nil {
-		container.hostConfig.DNS = make([]string, 0)
+func (container *Container) InitDNSHostConfig() {
+	if container.HostConfig.DNS == nil {
+		container.HostConfig.DNS = make([]string, 0)
 	}
 
-	if container.hostConfig.DNSSearch == nil {
-		container.hostConfig.DNSSearch = make([]string, 0)
+	if container.HostConfig.DNSSearch == nil {
+		container.HostConfig.DNSSearch = make([]string, 0)
 	}
 
-	if container.hostConfig.DNSOptions == nil {
-		container.hostConfig.DNSOptions = make([]string, 0)
+	if container.HostConfig.DNSOptions == nil {
+		container.HostConfig.DNSOptions = make([]string, 0)
 	}
 }

+ 36 - 0
container/container_unit_test.go

@@ -0,0 +1,36 @@
+package container
+
+import (
+	"testing"
+
+	"github.com/docker/docker/pkg/signal"
+	"github.com/docker/docker/runconfig"
+)
+
+func TestContainerStopSignal(t *testing.T) {
+	c := &Container{
+		CommonContainer: CommonContainer{
+			Config: &runconfig.Config{},
+		},
+	}
+
+	def, err := signal.ParseSignal(signal.DefaultStopSignal)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	s := c.StopSignal()
+	if s != int(def) {
+		t.Fatalf("Expected %v, got %v", def, s)
+	}
+
+	c = &Container{
+		CommonContainer: CommonContainer{
+			Config: &runconfig.Config{StopSignal: "SIGKILL"},
+		},
+	}
+	s = c.StopSignal()
+	if s != 9 {
+		t.Fatalf("Expected 9, got %v", s)
+	}
+}

+ 642 - 0
container/container_unix.go

@@ -0,0 +1,642 @@
+// +build linux freebsd
+
+package container
+
+import (
+	"fmt"
+	"io/ioutil"
+	"net"
+	"os"
+	"path/filepath"
+	"strconv"
+	"strings"
+	"syscall"
+
+	"github.com/Sirupsen/logrus"
+	"github.com/docker/docker/daemon/execdriver"
+	"github.com/docker/docker/daemon/network"
+	derr "github.com/docker/docker/errors"
+	"github.com/docker/docker/pkg/chrootarchive"
+	"github.com/docker/docker/pkg/nat"
+	"github.com/docker/docker/pkg/symlink"
+	"github.com/docker/docker/pkg/system"
+	"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/label"
+)
+
+const (
+	// DefaultPathEnv is unix style list of directories to search for
+	// executables. Each directory is separated from the next by a colon
+	// ':' character .
+	DefaultPathEnv = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
+
+	// DefaultSHMSize is the default size (64MB) of the SHM which will be mounted in the container
+	DefaultSHMSize int64 = 67108864
+)
+
+// Container holds the fields specific to unixen implementations. See
+// CommonContainer for standard fields common to all containers.
+type Container struct {
+	CommonContainer
+
+	// Fields below here are platform specific.
+	AppArmorProfile string
+	HostnamePath    string
+	HostsPath       string
+	ShmPath         string
+	MqueuePath      string
+	ResolvConfPath  string
+}
+
+// CreateDaemonEnvironment returns the list of all environment variables given the list of
+// environment variables related to links.
+// Sets PATH, HOSTNAME and if container.Config.Tty is set: TERM.
+// The defaults set here do not override the values in container.Config.Env
+func (container *Container) CreateDaemonEnvironment(linkedEnv []string) []string {
+	// if a domain name was specified, append it to the hostname (see #7851)
+	fullHostname := container.Config.Hostname
+	if container.Config.Domainname != "" {
+		fullHostname = fmt.Sprintf("%s.%s", fullHostname, container.Config.Domainname)
+	}
+	// Setup environment
+	env := []string{
+		"PATH=" + DefaultPathEnv,
+		"HOSTNAME=" + fullHostname,
+		// Note: we don't set HOME here because it'll get autoset intelligently
+		// based on the value of USER inside dockerinit, but only if it isn't
+		// set already (ie, that can be overridden by setting HOME via -e or ENV
+		// in a Dockerfile).
+	}
+	if container.Config.Tty {
+		env = append(env, "TERM=xterm")
+	}
+	env = append(env, linkedEnv...)
+	// because the env on the container can override certain default values
+	// we need to replace the 'env' keys where they match and append anything
+	// else.
+	env = utils.ReplaceOrAppendEnvValues(env, container.Config.Env)
+
+	return env
+}
+
+// TrySetNetworkMount attempts to set the network mounts given a provided destination and
+// the path to use for it; return true if the given destination was a network mount file
+func (container *Container) TrySetNetworkMount(destination string, path string) bool {
+	if destination == "/etc/resolv.conf" {
+		container.ResolvConfPath = path
+		return true
+	}
+	if destination == "/etc/hostname" {
+		container.HostnamePath = path
+		return true
+	}
+	if destination == "/etc/hosts" {
+		container.HostsPath = path
+		return true
+	}
+
+	return false
+}
+
+// BuildHostnameFile writes the container's hostname file.
+func (container *Container) BuildHostnameFile() error {
+	hostnamePath, err := container.GetRootResourcePath("hostname")
+	if err != nil {
+		return err
+	}
+	container.HostnamePath = hostnamePath
+
+	if container.Config.Domainname != "" {
+		return ioutil.WriteFile(container.HostnamePath, []byte(fmt.Sprintf("%s.%s\n", container.Config.Hostname, container.Config.Domainname)), 0644)
+	}
+	return ioutil.WriteFile(container.HostnamePath, []byte(container.Config.Hostname+"\n"), 0644)
+}
+
+// GetEndpointInNetwork returns the container's endpoint to the provided network.
+func (container *Container) GetEndpointInNetwork(n libnetwork.Network) (libnetwork.Endpoint, error) {
+	endpointName := strings.TrimPrefix(container.Name, "/")
+	return n.EndpointByName(endpointName)
+}
+
+func (container *Container) buildPortMapInfo(ep libnetwork.Endpoint) error {
+	if ep == nil {
+		return derr.ErrorCodeEmptyEndpoint
+	}
+
+	networkSettings := container.NetworkSettings
+	if networkSettings == nil {
+		return derr.ErrorCodeEmptyNetwork
+	}
+
+	driverInfo, err := ep.DriverInfo()
+	if err != nil {
+		return err
+	}
+
+	if driverInfo == nil {
+		// It is not an error for epInfo to be nil
+		return nil
+	}
+
+	if networkSettings.Ports == nil {
+		networkSettings.Ports = nat.PortMap{}
+	}
+
+	if expData, ok := driverInfo[netlabel.ExposedPorts]; ok {
+		if exposedPorts, ok := expData.([]types.TransportPort); ok {
+			for _, tp := range exposedPorts {
+				natPort, err := nat.NewPort(tp.Proto.String(), strconv.Itoa(int(tp.Port)))
+				if err != nil {
+					return derr.ErrorCodeParsingPort.WithArgs(tp.Port, err)
+				}
+				networkSettings.Ports[natPort] = nil
+			}
+		}
+	}
+
+	mapData, ok := driverInfo[netlabel.PortMap]
+	if !ok {
+		return nil
+	}
+
+	if portMapping, ok := mapData.([]types.PortBinding); ok {
+		for _, pp := range portMapping {
+			natPort, err := nat.NewPort(pp.Proto.String(), strconv.Itoa(int(pp.Port)))
+			if err != nil {
+				return err
+			}
+			natBndg := nat.PortBinding{HostIP: pp.HostIP.String(), HostPort: strconv.Itoa(int(pp.HostPort))}
+			networkSettings.Ports[natPort] = append(networkSettings.Ports[natPort], natBndg)
+		}
+	}
+
+	return nil
+}
+
+// BuildEndpointInfo sets endpoint-related fields on container.NetworkSettings based on the provided network and endpoint.
+func (container *Container) BuildEndpointInfo(n libnetwork.Network, ep libnetwork.Endpoint) error {
+	if ep == nil {
+		return derr.ErrorCodeEmptyEndpoint
+	}
+
+	networkSettings := container.NetworkSettings
+	if networkSettings == nil {
+		return derr.ErrorCodeEmptyNetwork
+	}
+
+	epInfo := ep.Info()
+	if epInfo == nil {
+		// It is not an error to get an empty endpoint info
+		return nil
+	}
+
+	if _, ok := networkSettings.Networks[n.Name()]; !ok {
+		networkSettings.Networks[n.Name()] = new(network.EndpointSettings)
+	}
+	networkSettings.Networks[n.Name()].EndpointID = ep.ID()
+
+	iface := epInfo.Iface()
+	if iface == nil {
+		return nil
+	}
+
+	if iface.MacAddress() != nil {
+		networkSettings.Networks[n.Name()].MacAddress = iface.MacAddress().String()
+	}
+
+	if iface.Address() != nil {
+		ones, _ := iface.Address().Mask.Size()
+		networkSettings.Networks[n.Name()].IPAddress = iface.Address().IP.String()
+		networkSettings.Networks[n.Name()].IPPrefixLen = ones
+	}
+
+	if iface.AddressIPv6() != nil && iface.AddressIPv6().IP.To16() != nil {
+		onesv6, _ := iface.AddressIPv6().Mask.Size()
+		networkSettings.Networks[n.Name()].GlobalIPv6Address = iface.AddressIPv6().IP.String()
+		networkSettings.Networks[n.Name()].GlobalIPv6PrefixLen = onesv6
+	}
+
+	return nil
+}
+
+// UpdateJoinInfo updates network settings when container joins network n with endpoint ep.
+func (container *Container) UpdateJoinInfo(n libnetwork.Network, ep libnetwork.Endpoint) error {
+	if err := container.buildPortMapInfo(ep); err != nil {
+		return err
+	}
+
+	epInfo := ep.Info()
+	if epInfo == nil {
+		// It is not an error to get an empty endpoint info
+		return nil
+	}
+	if epInfo.Gateway() != nil {
+		container.NetworkSettings.Networks[n.Name()].Gateway = epInfo.Gateway().String()
+	}
+	if epInfo.GatewayIPv6().To16() != nil {
+		container.NetworkSettings.Networks[n.Name()].IPv6Gateway = epInfo.GatewayIPv6().String()
+	}
+
+	return nil
+}
+
+// UpdateSandboxNetworkSettings updates the sandbox ID and Key.
+func (container *Container) UpdateSandboxNetworkSettings(sb libnetwork.Sandbox) error {
+	container.NetworkSettings.SandboxID = sb.ID()
+	container.NetworkSettings.SandboxKey = sb.Key()
+	return nil
+}
+
+// BuildCreateEndpointOptions builds endpoint options from a given network.
+func (container *Container) BuildCreateEndpointOptions(n libnetwork.Network) ([]libnetwork.EndpointOption, error) {
+	var (
+		portSpecs     = make(nat.PortSet)
+		bindings      = make(nat.PortMap)
+		pbList        []types.PortBinding
+		exposeList    []types.TransportPort
+		createOptions []libnetwork.EndpointOption
+	)
+
+	if n.Name() == "bridge" || container.NetworkSettings.IsAnonymousEndpoint {
+		createOptions = append(createOptions, libnetwork.CreateOptionAnonymous())
+	}
+
+	// Other configs are applicable only for the endpoint in the network
+	// to which container was connected to on docker run.
+	if n.Name() != container.HostConfig.NetworkMode.NetworkName() &&
+		!(n.Name() == "bridge" && container.HostConfig.NetworkMode.IsDefault()) {
+		return createOptions, nil
+	}
+
+	if container.Config.ExposedPorts != nil {
+		portSpecs = container.Config.ExposedPorts
+	}
+
+	if container.HostConfig.PortBindings != nil {
+		for p, b := range container.HostConfig.PortBindings {
+			bindings[p] = []nat.PortBinding{}
+			for _, bb := range b {
+				bindings[p] = append(bindings[p], nat.PortBinding{
+					HostIP:   bb.HostIP,
+					HostPort: bb.HostPort,
+				})
+			}
+		}
+	}
+
+	ports := make([]nat.Port, len(portSpecs))
+	var i int
+	for p := range portSpecs {
+		ports[i] = p
+		i++
+	}
+	nat.SortPortMap(ports, bindings)
+	for _, port := range ports {
+		expose := types.TransportPort{}
+		expose.Proto = types.ParseProtocol(port.Proto())
+		expose.Port = uint16(port.Int())
+		exposeList = append(exposeList, expose)
+
+		pb := types.PortBinding{Port: expose.Port, Proto: expose.Proto}
+		binding := bindings[port]
+		for i := 0; i < len(binding); i++ {
+			pbCopy := pb.GetCopy()
+			newP, err := nat.NewPort(nat.SplitProtoPort(binding[i].HostPort))
+			var portStart, portEnd int
+			if err == nil {
+				portStart, portEnd, err = newP.Range()
+			}
+			if err != nil {
+				return nil, derr.ErrorCodeHostPort.WithArgs(binding[i].HostPort, err)
+			}
+			pbCopy.HostPort = uint16(portStart)
+			pbCopy.HostPortEnd = uint16(portEnd)
+			pbCopy.HostIP = net.ParseIP(binding[i].HostIP)
+			pbList = append(pbList, pbCopy)
+		}
+
+		if container.HostConfig.PublishAllPorts && len(binding) == 0 {
+			pbList = append(pbList, pb)
+		}
+	}
+
+	createOptions = append(createOptions,
+		libnetwork.CreateOptionPortMapping(pbList),
+		libnetwork.CreateOptionExposedPorts(exposeList))
+
+	if container.Config.MacAddress != "" {
+		mac, err := net.ParseMAC(container.Config.MacAddress)
+		if err != nil {
+			return nil, err
+		}
+
+		genericOption := options.Generic{
+			netlabel.MacAddress: mac,
+		}
+
+		createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(genericOption))
+	}
+
+	return createOptions, nil
+}
+
+// SetupWorkingDirectory sets up the container's working directory as set in container.Config.WorkingDir
+func (container *Container) SetupWorkingDirectory() error {
+	if container.Config.WorkingDir == "" {
+		return nil
+	}
+	container.Config.WorkingDir = filepath.Clean(container.Config.WorkingDir)
+
+	pth, err := container.GetResourcePath(container.Config.WorkingDir)
+	if err != nil {
+		return err
+	}
+
+	pthInfo, err := os.Stat(pth)
+	if err != nil {
+		if !os.IsNotExist(err) {
+			return err
+		}
+
+		if err := system.MkdirAll(pth, 0755); err != nil {
+			return err
+		}
+	}
+	if pthInfo != nil && !pthInfo.IsDir() {
+		return derr.ErrorCodeNotADir.WithArgs(container.Config.WorkingDir)
+	}
+	return nil
+}
+
+// appendNetworkMounts appends any network mounts to the array of mount points passed in
+func appendNetworkMounts(container *Container, volumeMounts []volume.MountPoint) ([]volume.MountPoint, error) {
+	for _, mnt := range container.NetworkMounts() {
+		dest, err := container.GetResourcePath(mnt.Destination)
+		if err != nil {
+			return nil, err
+		}
+		volumeMounts = append(volumeMounts, volume.MountPoint{Destination: dest})
+	}
+	return volumeMounts, nil
+}
+
+// NetworkMounts returns the list of network mounts.
+func (container *Container) NetworkMounts() []execdriver.Mount {
+	var mounts []execdriver.Mount
+	shared := container.HostConfig.NetworkMode.IsContainer()
+	if container.ResolvConfPath != "" {
+		if _, err := os.Stat(container.ResolvConfPath); err != nil {
+			logrus.Warnf("ResolvConfPath set to %q, but can't stat this filename (err = %v); skipping", container.ResolvConfPath, err)
+		} else {
+			label.Relabel(container.ResolvConfPath, container.MountLabel, shared)
+			writable := !container.HostConfig.ReadonlyRootfs
+			if m, exists := container.MountPoints["/etc/resolv.conf"]; exists {
+				writable = m.RW
+			}
+			mounts = append(mounts, execdriver.Mount{
+				Source:      container.ResolvConfPath,
+				Destination: "/etc/resolv.conf",
+				Writable:    writable,
+				Private:     true,
+			})
+		}
+	}
+	if container.HostnamePath != "" {
+		if _, err := os.Stat(container.HostnamePath); err != nil {
+			logrus.Warnf("HostnamePath set to %q, but can't stat this filename (err = %v); skipping", container.HostnamePath, err)
+		} else {
+			label.Relabel(container.HostnamePath, container.MountLabel, shared)
+			writable := !container.HostConfig.ReadonlyRootfs
+			if m, exists := container.MountPoints["/etc/hostname"]; exists {
+				writable = m.RW
+			}
+			mounts = append(mounts, execdriver.Mount{
+				Source:      container.HostnamePath,
+				Destination: "/etc/hostname",
+				Writable:    writable,
+				Private:     true,
+			})
+		}
+	}
+	if container.HostsPath != "" {
+		if _, err := os.Stat(container.HostsPath); err != nil {
+			logrus.Warnf("HostsPath set to %q, but can't stat this filename (err = %v); skipping", container.HostsPath, err)
+		} else {
+			label.Relabel(container.HostsPath, container.MountLabel, shared)
+			writable := !container.HostConfig.ReadonlyRootfs
+			if m, exists := container.MountPoints["/etc/hosts"]; exists {
+				writable = m.RW
+			}
+			mounts = append(mounts, execdriver.Mount{
+				Source:      container.HostsPath,
+				Destination: "/etc/hosts",
+				Writable:    writable,
+				Private:     true,
+			})
+		}
+	}
+	return mounts
+}
+
+// CopyImagePathContent copies files in destination to the volume.
+func (container *Container) CopyImagePathContent(v volume.Volume, destination string) error {
+	rootfs, err := symlink.FollowSymlinkInScope(filepath.Join(container.BaseFS, destination), container.BaseFS)
+	if err != nil {
+		return err
+	}
+
+	if _, err = ioutil.ReadDir(rootfs); err != nil {
+		if os.IsNotExist(err) {
+			return nil
+		}
+		return err
+	}
+
+	path, err := v.Mount()
+	if err != nil {
+		return err
+	}
+
+	if err := copyExistingContents(rootfs, path); err != nil {
+		return err
+	}
+
+	return v.Unmount()
+}
+
+// ShmResourcePath returns path to shm
+func (container *Container) ShmResourcePath() (string, error) {
+	return container.GetRootResourcePath("shm")
+}
+
+// MqueueResourcePath returns path to mqueue
+func (container *Container) MqueueResourcePath() (string, error) {
+	return container.GetRootResourcePath("mqueue")
+}
+
+// HasMountFor checks if path is a mountpoint
+func (container *Container) HasMountFor(path string) bool {
+	_, exists := container.MountPoints[path]
+	return exists
+}
+
+// UnmountIpcMounts uses the provided unmount function to unmount shm and mqueue if they were mounted
+func (container *Container) UnmountIpcMounts(unmount func(pth string) error) {
+	if container.HostConfig.IpcMode.IsContainer() || container.HostConfig.IpcMode.IsHost() {
+		return
+	}
+
+	var warnings []string
+
+	if !container.HasMountFor("/dev/shm") {
+		shmPath, err := container.ShmResourcePath()
+		if err != nil {
+			logrus.Error(err)
+			warnings = append(warnings, err.Error())
+		} else if shmPath != "" {
+			if err := unmount(shmPath); err != nil {
+				warnings = append(warnings, fmt.Sprintf("failed to umount %s: %v", shmPath, err))
+			}
+
+		}
+	}
+
+	if !container.HasMountFor("/dev/mqueue") {
+		mqueuePath, err := container.MqueueResourcePath()
+		if err != nil {
+			logrus.Error(err)
+			warnings = append(warnings, err.Error())
+		} else if mqueuePath != "" {
+			if err := unmount(mqueuePath); err != nil {
+				warnings = append(warnings, fmt.Sprintf("failed to umount %s: %v", mqueuePath, err))
+			}
+		}
+	}
+
+	if len(warnings) > 0 {
+		logrus.Warnf("failed to cleanup ipc mounts:\n%v", strings.Join(warnings, "\n"))
+	}
+}
+
+// IpcMounts returns the list of IPC mounts
+func (container *Container) IpcMounts() []execdriver.Mount {
+	var mounts []execdriver.Mount
+
+	if !container.HasMountFor("/dev/shm") {
+		label.SetFileLabel(container.ShmPath, container.MountLabel)
+		mounts = append(mounts, execdriver.Mount{
+			Source:      container.ShmPath,
+			Destination: "/dev/shm",
+			Writable:    true,
+			Private:     true,
+		})
+	}
+
+	if !container.HasMountFor("/dev/mqueue") {
+		label.SetFileLabel(container.MqueuePath, container.MountLabel)
+		mounts = append(mounts, execdriver.Mount{
+			Source:      container.MqueuePath,
+			Destination: "/dev/mqueue",
+			Writable:    true,
+			Private:     true,
+		})
+	}
+	return mounts
+}
+
+func detachMounted(path string) error {
+	return syscall.Unmount(path, syscall.MNT_DETACH)
+}
+
+// UnmountVolumes unmounts all volumes
+func (container *Container) UnmountVolumes(forceSyscall bool) error {
+	var (
+		volumeMounts []volume.MountPoint
+		err          error
+	)
+
+	for _, mntPoint := range container.MountPoints {
+		dest, err := container.GetResourcePath(mntPoint.Destination)
+		if err != nil {
+			return err
+		}
+
+		volumeMounts = append(volumeMounts, volume.MountPoint{Destination: dest, Volume: mntPoint.Volume})
+	}
+
+	// Append any network mounts to the list (this is a no-op on Windows)
+	if volumeMounts, err = appendNetworkMounts(container, volumeMounts); err != nil {
+		return err
+	}
+
+	for _, volumeMount := range volumeMounts {
+		if forceSyscall {
+			if err := detachMounted(volumeMount.Destination); err != nil {
+				logrus.Warnf("%s unmountVolumes: Failed to do lazy umount %v", container.ID, err)
+			}
+		}
+
+		if volumeMount.Volume != nil {
+			if err := volumeMount.Volume.Unmount(); err != nil {
+				return err
+			}
+		}
+	}
+
+	return nil
+}
+
+// copyExistingContents copies from the source to the destination and
+// ensures the ownership is appropriately set.
+func copyExistingContents(source, destination string) error {
+	volList, err := ioutil.ReadDir(source)
+	if err != nil {
+		return err
+	}
+	if len(volList) > 0 {
+		srcList, err := ioutil.ReadDir(destination)
+		if err != nil {
+			return err
+		}
+		if len(srcList) == 0 {
+			// If the source volume is empty copy files from the root into the volume
+			if err := chrootarchive.CopyWithTar(source, destination); err != nil {
+				return err
+			}
+		}
+	}
+	return copyOwnership(source, destination)
+}
+
+// copyOwnership copies the permissions and uid:gid of the source file
+// to the destination file
+func copyOwnership(source, destination string) error {
+	stat, err := system.Stat(source)
+	if err != nil {
+		return err
+	}
+
+	if err := os.Chown(destination, int(stat.UID()), int(stat.GID())); err != nil {
+		return err
+	}
+
+	return os.Chmod(destination, os.FileMode(stat.Mode()))
+}
+
+// TmpfsMounts returns the list of tmpfs mounts
+func (container *Container) TmpfsMounts() []execdriver.Mount {
+	var mounts []execdriver.Mount
+	for dest, data := range container.HostConfig.Tmpfs {
+		mounts = append(mounts, execdriver.Mount{
+			Source:      "tmpfs",
+			Destination: dest,
+			Data:        data,
+		})
+	}
+	return mounts
+}

+ 59 - 0
container/container_windows.go

@@ -0,0 +1,59 @@
+// +build windows
+
+package container
+
+import (
+	"github.com/docker/docker/daemon/execdriver"
+	"github.com/docker/docker/volume"
+)
+
+// DefaultPathEnv is deliberately empty on Windows as the default path will be set by
+// the container. Docker has no context of what the default path should be.
+const DefaultPathEnv = ""
+
+// Container holds fields specific to the Windows implementation. See
+// CommonContainer for standard fields common to all containers.
+type Container struct {
+	CommonContainer
+
+	// Fields below here are platform specific.
+}
+
+// CreateDaemonEnvironment creates a new environment variable slice for this container.
+func (container *Container) CreateDaemonEnvironment(linkedEnv []string) []string {
+	// On Windows, nothing to link. Just return the container environment.
+	return container.Config.Env
+}
+
+// SetupWorkingDirectory initializes the container working directory.
+// This is a NOOP In windows.
+func (container *Container) SetupWorkingDirectory() error {
+	return nil
+}
+
+// UnmountIpcMounts unmount Ipc related mounts.
+// This is a NOOP on windows.
+func (container *Container) UnmountIpcMounts(unmount func(pth string) error) {
+}
+
+// IpcMounts returns the list of Ipc related mounts.
+func (container *Container) IpcMounts() []execdriver.Mount {
+	return nil
+}
+
+// UnmountVolumes explicitely unmounts volumes from the container.
+func (container *Container) UnmountVolumes(forceSyscall bool) error {
+	return nil
+}
+
+// TmpfsMounts returns the list of tmpfs mounts
+func (container *Container) TmpfsMounts() []execdriver.Mount {
+	return nil
+}
+
+// appendNetworkMounts appends any network mounts to the array of mount points passed in.
+// Windows does not support network mounts (not to be confused with SMB network mounts), so
+// this is a no-op.
+func appendNetworkMounts(container *Container, volumeMounts []volume.MountPoint) ([]volume.MountPoint, error) {
+	return volumeMounts, nil
+}

+ 42 - 26
daemon/monitor.go → container/monitor.go

@@ -1,4 +1,4 @@
-package daemon
+package container
 
 import (
 	"io"
@@ -11,6 +11,7 @@ import (
 	"github.com/Sirupsen/logrus"
 	"github.com/docker/docker/daemon/execdriver"
 	derr "github.com/docker/docker/errors"
+	"github.com/docker/docker/pkg/promise"
 	"github.com/docker/docker/pkg/stringid"
 	"github.com/docker/docker/runconfig"
 	"github.com/docker/docker/utils"
@@ -21,8 +22,8 @@ const (
 	loggerCloseTimeout   = 10 * time.Second
 )
 
-// containerSupervisor defines the interface that a supervisor must implement
-type containerSupervisor interface {
+// supervisor defines the interface that a supervisor must implement
+type supervisor interface {
 	// LogContainerEvent generates events related to a given container
 	LogContainerEvent(*Container, string)
 	// Cleanup ensures that the container is properly unmounted
@@ -44,7 +45,7 @@ type containerMonitor struct {
 	mux sync.Mutex
 
 	// supervisor keeps track of the container and the events it generates
-	supervisor containerSupervisor
+	supervisor supervisor
 
 	// container is the container being monitored
 	container *Container
@@ -76,17 +77,32 @@ type containerMonitor struct {
 	lastStartTime time.Time
 }
 
-// newContainerMonitor returns an initialized containerMonitor for the provided container
-// honoring the provided restart policy
-func (daemon *Daemon) newContainerMonitor(container *Container, policy runconfig.RestartPolicy) *containerMonitor {
-	return &containerMonitor{
-		supervisor:    daemon,
+// StartMonitor initializes a containerMonitor for this container with the provided supervisor and restart policy
+// and starts the container's process.
+func (container *Container) StartMonitor(s supervisor, policy runconfig.RestartPolicy) error {
+	container.monitor = &containerMonitor{
+		supervisor:    s,
 		container:     container,
 		restartPolicy: policy,
 		timeIncrement: defaultTimeIncrement,
 		stopChan:      make(chan struct{}),
 		startSignal:   make(chan struct{}),
 	}
+
+	return container.monitor.wait()
+}
+
+// wait starts the container and wait until
+// we either receive an error from the initial start of the container's
+// process or until the process is running in the container
+func (m *containerMonitor) wait() error {
+	select {
+	case <-m.startSignal:
+	case err := <-promise.Go(m.start):
+		return err
+	}
+
+	return nil
 }
 
 // Stop signals to the container monitor that it should stop monitoring the container
@@ -113,7 +129,7 @@ func (m *containerMonitor) Close() error {
 	// FIXME: here is race condition between two RUN instructions in Dockerfile
 	// because they share same runconfig and change image. Must be fixed
 	// in builder/builder.go
-	if err := m.container.toDisk(); err != nil {
+	if err := m.container.ToDisk(); err != nil {
 		logrus.Errorf("Error dumping container %s state to disk: %s", m.container.ID, err)
 
 		return err
@@ -123,7 +139,7 @@ func (m *containerMonitor) Close() error {
 }
 
 // Start starts the containers process and monitors it according to the restart policy
-func (m *containerMonitor) Start() error {
+func (m *containerMonitor) start() error {
 	var (
 		err        error
 		exitStatus execdriver.ExitStatus
@@ -137,7 +153,7 @@ func (m *containerMonitor) Start() error {
 		if afterRun {
 			m.container.Lock()
 			defer m.container.Unlock()
-			m.container.setStopped(&exitStatus)
+			m.container.SetStopped(&exitStatus)
 		}
 		m.Close()
 	}()
@@ -202,7 +218,7 @@ func (m *containerMonitor) Start() error {
 		m.resetMonitor(err == nil && exitStatus.ExitCode == 0)
 
 		if m.shouldRestart(exitStatus.ExitCode) {
-			m.container.setRestarting(&exitStatus)
+			m.container.SetRestarting(&exitStatus)
 			m.logEvent("die")
 			m.resetContainer(true)
 
@@ -295,7 +311,7 @@ func (m *containerMonitor) callback(processConfig *execdriver.ProcessConfig, pid
 	}()
 
 	if processConfig.Tty {
-		// The callback is called after the process Start()
+		// The callback is called after the process start()
 		// so we are in the parent process. In TTY mode, stdin/out/err is the PtySlave
 		// which we close here.
 		if c, ok := processConfig.Stdout.(io.Closer); ok {
@@ -303,7 +319,7 @@ func (m *containerMonitor) callback(processConfig *execdriver.ProcessConfig, pid
 		}
 	}
 
-	m.container.setRunning(pid)
+	m.container.SetRunning(pid)
 
 	// signal that the process has started
 	// close channel only if not closed
@@ -313,7 +329,7 @@ func (m *containerMonitor) callback(processConfig *execdriver.ProcessConfig, pid
 		close(m.startSignal)
 	}
 
-	if err := m.container.toDiskLocking(); err != nil {
+	if err := m.container.ToDiskLocking(); err != nil {
 		logrus.Errorf("Error saving container to disk: %v", err)
 	}
 	return nil
@@ -333,8 +349,8 @@ func (m *containerMonitor) resetContainer(lock bool) {
 		logrus.Errorf("%s: %s", container.ID, err)
 	}
 
-	if container.command != nil && container.command.ProcessConfig.Terminal != nil {
-		if err := container.command.ProcessConfig.Terminal.Close(); err != nil {
+	if container.Command != nil && container.Command.ProcessConfig.Terminal != nil {
+		if err := container.Command.ProcessConfig.Terminal.Close(); err != nil {
 			logrus.Errorf("%s: Error closing terminal: %s", container.ID, err)
 		}
 	}
@@ -344,11 +360,11 @@ func (m *containerMonitor) resetContainer(lock bool) {
 		container.NewInputPipes()
 	}
 
-	if container.logDriver != nil {
-		if container.logCopier != nil {
+	if container.LogDriver != nil {
+		if container.LogCopier != nil {
 			exit := make(chan struct{})
 			go func() {
-				container.logCopier.Wait()
+				container.LogCopier.Wait()
 				close(exit)
 			}()
 			select {
@@ -357,14 +373,14 @@ func (m *containerMonitor) resetContainer(lock bool) {
 			case <-exit:
 			}
 		}
-		container.logDriver.Close()
-		container.logCopier = nil
-		container.logDriver = nil
+		container.LogDriver.Close()
+		container.LogCopier = nil
+		container.LogDriver = nil
 	}
 
-	c := container.command.ProcessConfig.Cmd
+	c := container.Command.ProcessConfig.Cmd
 
-	container.command.ProcessConfig.Cmd = exec.Cmd{
+	container.Command.ProcessConfig.Cmd = exec.Cmd{
 		Stdin:       c.Stdin,
 		Stdout:      c.Stdout,
 		Stderr:      c.Stderr,

+ 33 - 23
daemon/state.go → container/state.go

@@ -1,4 +1,4 @@
-package daemon
+package container
 
 import (
 	"fmt"
@@ -21,7 +21,7 @@ type State struct {
 	Paused            bool
 	Restarting        bool
 	OOMKilled         bool
-	removalInProgress bool // Not need for this to be persistent on disk.
+	RemovalInProgress bool // Not need for this to be persistent on disk.
 	Dead              bool
 	Pid               int
 	ExitCode          int
@@ -51,7 +51,7 @@ func (s *State) String() string {
 		return fmt.Sprintf("Up %s", units.HumanDuration(time.Now().UTC().Sub(s.StartedAt)))
 	}
 
-	if s.removalInProgress {
+	if s.RemovalInProgress {
 		return "Removal In Progress"
 	}
 
@@ -93,7 +93,8 @@ func (s *State) StateString() string {
 	return "exited"
 }
 
-func isValidStateString(s string) bool {
+// IsValidStateString checks if the provided string is a valid container state or not.
+func IsValidStateString(s string) bool {
 	if s != "paused" &&
 		s != "restarting" &&
 		s != "running" &&
@@ -121,7 +122,7 @@ func wait(waitChan <-chan struct{}, timeout time.Duration) error {
 // waitRunning waits until state is running. If state is already
 // running it returns immediately. If you want wait forever you must
 // supply negative timeout. Returns pid, that was passed to
-// setRunning.
+// SetRunning.
 func (s *State) waitRunning(timeout time.Duration) (int, error) {
 	s.Lock()
 	if s.Running {
@@ -139,7 +140,7 @@ func (s *State) waitRunning(timeout time.Duration) (int, error) {
 
 // WaitStop waits until state is stopped. If state already stopped it returns
 // immediately. If you want wait forever you must supply negative timeout.
-// Returns exit code, that was passed to setStoppedLocking
+// Returns exit code, that was passed to SetStoppedLocking
 func (s *State) WaitStop(timeout time.Duration) (int, error) {
 	s.Lock()
 	if !s.Running {
@@ -178,7 +179,8 @@ func (s *State) getExitCode() int {
 	return res
 }
 
-func (s *State) setRunning(pid int) {
+// SetRunning sets the state of the container to "running".
+func (s *State) SetRunning(pid int) {
 	s.Error = ""
 	s.Running = true
 	s.Paused = false
@@ -190,13 +192,15 @@ func (s *State) setRunning(pid int) {
 	s.waitChan = make(chan struct{})
 }
 
-func (s *State) setStoppedLocking(exitStatus *execdriver.ExitStatus) {
+// SetStoppedLocking locks the container state is sets it to "stopped".
+func (s *State) SetStoppedLocking(exitStatus *execdriver.ExitStatus) {
 	s.Lock()
-	s.setStopped(exitStatus)
+	s.SetStopped(exitStatus)
 	s.Unlock()
 }
 
-func (s *State) setStopped(exitStatus *execdriver.ExitStatus) {
+// SetStopped sets the container state to "stopped" without locking.
+func (s *State) SetStopped(exitStatus *execdriver.ExitStatus) {
 	s.Running = false
 	s.Restarting = false
 	s.Pid = 0
@@ -206,15 +210,17 @@ func (s *State) setStopped(exitStatus *execdriver.ExitStatus) {
 	s.waitChan = make(chan struct{})
 }
 
-// setRestarting is when docker handles the auto restart of containers when they are
+// SetRestartingLocking is when docker handles the auto restart of containers when they are
 // in the middle of a stop and being restarted again
-func (s *State) setRestartingLocking(exitStatus *execdriver.ExitStatus) {
+func (s *State) SetRestartingLocking(exitStatus *execdriver.ExitStatus) {
 	s.Lock()
-	s.setRestarting(exitStatus)
+	s.SetRestarting(exitStatus)
 	s.Unlock()
 }
 
-func (s *State) setRestarting(exitStatus *execdriver.ExitStatus) {
+// SetRestarting sets the container state to "restarting".
+// It also sets the container PID to 0.
+func (s *State) SetRestarting(exitStatus *execdriver.ExitStatus) {
 	// we should consider the container running when it is restarting because of
 	// all the checks in docker around rm/stop/etc
 	s.Running = true
@@ -226,37 +232,41 @@ func (s *State) setRestarting(exitStatus *execdriver.ExitStatus) {
 	s.waitChan = make(chan struct{})
 }
 
-// setError sets the container's error state. This is useful when we want to
+// SetError sets the container's error state. This is useful when we want to
 // know the error that occurred when container transits to another state
 // when inspecting it
-func (s *State) setError(err error) {
+func (s *State) SetError(err error) {
 	s.Error = err.Error()
 }
 
-func (s *State) isPaused() bool {
+// IsPaused returns whether the container is paused or not.
+func (s *State) IsPaused() bool {
 	s.Lock()
 	res := s.Paused
 	s.Unlock()
 	return res
 }
 
-func (s *State) setRemovalInProgress() error {
+// SetRemovalInProgress sets the container state as being removed.
+func (s *State) SetRemovalInProgress() error {
 	s.Lock()
 	defer s.Unlock()
-	if s.removalInProgress {
+	if s.RemovalInProgress {
 		return derr.ErrorCodeAlreadyRemoving
 	}
-	s.removalInProgress = true
+	s.RemovalInProgress = true
 	return nil
 }
 
-func (s *State) resetRemovalInProgress() {
+// ResetRemovalInProgress make the RemovalInProgress state to false.
+func (s *State) ResetRemovalInProgress() {
 	s.Lock()
-	s.removalInProgress = false
+	s.RemovalInProgress = false
 	s.Unlock()
 }
 
-func (s *State) setDead() {
+// SetDead sets the container state to "dead"
+func (s *State) SetDead() {
 	s.Lock()
 	s.Dead = true
 	s.Unlock()

+ 4 - 4
daemon/state_test.go → container/state_test.go

@@ -1,4 +1,4 @@
-package daemon
+package container
 
 import (
 	"sync/atomic"
@@ -19,7 +19,7 @@ func TestStateRunStop(t *testing.T) {
 			close(started)
 		}()
 		s.Lock()
-		s.setRunning(i + 100)
+		s.SetRunning(i + 100)
 		s.Unlock()
 
 		if !s.IsRunning() {
@@ -52,7 +52,7 @@ func TestStateRunStop(t *testing.T) {
 			atomic.StoreInt64(&exit, int64(exitCode))
 			close(stopped)
 		}()
-		s.setStoppedLocking(&execdriver.ExitStatus{ExitCode: i})
+		s.SetStoppedLocking(&execdriver.ExitStatus{ExitCode: i})
 		if s.IsRunning() {
 			t.Fatal("State is running")
 		}
@@ -93,7 +93,7 @@ func TestStateTimeoutWait(t *testing.T) {
 	}
 
 	s.Lock()
-	s.setRunning(49)
+	s.SetRunning(49)
 	s.Unlock()
 
 	stopped := make(chan struct{})

+ 1 - 1
daemon/state_unix.go → container/state_unix.go

@@ -1,6 +1,6 @@
 // +build linux freebsd
 
-package daemon
+package container
 
 import "github.com/docker/docker/daemon/execdriver"
 

+ 1 - 1
daemon/state_windows.go → container/state_windows.go

@@ -1,4 +1,4 @@
-package daemon
+package container
 
 import "github.com/docker/docker/daemon/execdriver"
 

+ 20 - 79
daemon/archive.go

@@ -8,6 +8,7 @@ import (
 	"strings"
 
 	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/container"
 	"github.com/docker/docker/pkg/archive"
 	"github.com/docker/docker/pkg/chrootarchive"
 	"github.com/docker/docker/pkg/ioutils"
@@ -71,69 +72,9 @@ func (daemon *Daemon) ContainerExtractToDir(name, path string, noOverwriteDirNon
 	return daemon.containerExtractToDir(container, path, noOverwriteDirNonDir, content)
 }
 
-// resolvePath resolves the given path in the container to a resource on the
-// host. Returns a resolved path (absolute path to the resource on the host),
-// the absolute path to the resource relative to the container's rootfs, and
-// a error if the path points to outside the container's rootfs.
-func (container *Container) resolvePath(path string) (resolvedPath, absPath string, err error) {
-	// Consider the given path as an absolute path in the container.
-	absPath = archive.PreserveTrailingDotOrSeparator(filepath.Join(string(filepath.Separator), path), path)
-
-	// Split the absPath into its Directory and Base components. We will
-	// resolve the dir in the scope of the container then append the base.
-	dirPath, basePath := filepath.Split(absPath)
-
-	resolvedDirPath, err := container.GetResourcePath(dirPath)
-	if err != nil {
-		return "", "", err
-	}
-
-	// resolvedDirPath will have been cleaned (no trailing path separators) so
-	// we can manually join it with the base path element.
-	resolvedPath = resolvedDirPath + string(filepath.Separator) + basePath
-
-	return resolvedPath, absPath, nil
-}
-
-// statPath is the unexported version of StatPath. Locks and mounts should
-// be acquired before calling this method and the given path should be fully
-// resolved to a path on the host corresponding to the given absolute path
-// inside the container.
-func (container *Container) statPath(resolvedPath, absPath string) (stat *types.ContainerPathStat, err error) {
-	lstat, err := os.Lstat(resolvedPath)
-	if err != nil {
-		return nil, err
-	}
-
-	var linkTarget string
-	if lstat.Mode()&os.ModeSymlink != 0 {
-		// Fully evaluate the symlink in the scope of the container rootfs.
-		hostPath, err := container.GetResourcePath(absPath)
-		if err != nil {
-			return nil, err
-		}
-
-		linkTarget, err = filepath.Rel(container.basefs, hostPath)
-		if err != nil {
-			return nil, err
-		}
-
-		// Make it an absolute path.
-		linkTarget = filepath.Join(string(filepath.Separator), linkTarget)
-	}
-
-	return &types.ContainerPathStat{
-		Name:       filepath.Base(absPath),
-		Size:       lstat.Size(),
-		Mode:       lstat.Mode(),
-		Mtime:      lstat.ModTime(),
-		LinkTarget: linkTarget,
-	}, nil
-}
-
 // containerStatPath stats the filesystem resource at the specified path in this
 // container. Returns stat info about the resource.
-func (daemon *Daemon) containerStatPath(container *Container, path string) (stat *types.ContainerPathStat, err error) {
+func (daemon *Daemon) containerStatPath(container *container.Container, path string) (stat *types.ContainerPathStat, err error) {
 	container.Lock()
 	defer container.Unlock()
 
@@ -143,23 +84,23 @@ func (daemon *Daemon) containerStatPath(container *Container, path string) (stat
 	defer daemon.Unmount(container)
 
 	err = daemon.mountVolumes(container)
-	defer container.unmountVolumes(true)
+	defer container.UnmountVolumes(true)
 	if err != nil {
 		return nil, err
 	}
 
-	resolvedPath, absPath, err := container.resolvePath(path)
+	resolvedPath, absPath, err := container.ResolvePath(path)
 	if err != nil {
 		return nil, err
 	}
 
-	return container.statPath(resolvedPath, absPath)
+	return container.StatPath(resolvedPath, absPath)
 }
 
 // containerArchivePath creates an archive of the filesystem resource at the specified
 // path in this container. Returns a tar archive of the resource and stat info
 // about the resource.
-func (daemon *Daemon) containerArchivePath(container *Container, path string) (content io.ReadCloser, stat *types.ContainerPathStat, err error) {
+func (daemon *Daemon) containerArchivePath(container *container.Container, path string) (content io.ReadCloser, stat *types.ContainerPathStat, err error) {
 	container.Lock()
 
 	defer func() {
@@ -178,7 +119,7 @@ func (daemon *Daemon) containerArchivePath(container *Container, path string) (c
 	defer func() {
 		if err != nil {
 			// unmount any volumes
-			container.unmountVolumes(true)
+			container.UnmountVolumes(true)
 			// unmount the container's rootfs
 			daemon.Unmount(container)
 		}
@@ -188,12 +129,12 @@ func (daemon *Daemon) containerArchivePath(container *Container, path string) (c
 		return nil, nil, err
 	}
 
-	resolvedPath, absPath, err := container.resolvePath(path)
+	resolvedPath, absPath, err := container.ResolvePath(path)
 	if err != nil {
 		return nil, nil, err
 	}
 
-	stat, err = container.statPath(resolvedPath, absPath)
+	stat, err = container.StatPath(resolvedPath, absPath)
 	if err != nil {
 		return nil, nil, err
 	}
@@ -213,7 +154,7 @@ func (daemon *Daemon) containerArchivePath(container *Container, path string) (c
 
 	content = ioutils.NewReadCloserWrapper(data, func() error {
 		err := data.Close()
-		container.unmountVolumes(true)
+		container.UnmountVolumes(true)
 		daemon.Unmount(container)
 		container.Unlock()
 		return err
@@ -230,7 +171,7 @@ func (daemon *Daemon) containerArchivePath(container *Container, path string) (c
 // noOverwriteDirNonDir is true then it will be an error if unpacking the
 // given content would cause an existing directory to be replaced with a non-
 // directory and vice versa.
-func (daemon *Daemon) containerExtractToDir(container *Container, path string, noOverwriteDirNonDir bool, content io.Reader) (err error) {
+func (daemon *Daemon) containerExtractToDir(container *container.Container, path string, noOverwriteDirNonDir bool, content io.Reader) (err error) {
 	container.Lock()
 	defer container.Unlock()
 
@@ -240,14 +181,14 @@ func (daemon *Daemon) containerExtractToDir(container *Container, path string, n
 	defer daemon.Unmount(container)
 
 	err = daemon.mountVolumes(container)
-	defer container.unmountVolumes(true)
+	defer container.UnmountVolumes(true)
 	if err != nil {
 		return err
 	}
 
 	// The destination path needs to be resolved to a host path, with all
 	// symbolic links followed in the scope of the container's rootfs. Note
-	// that we do not use `container.resolvePath(path)` here because we need
+	// that we do not use `container.ResolvePath(path)` here because we need
 	// to also evaluate the last path element if it is a symlink. This is so
 	// that you can extract an archive to a symlink that points to a directory.
 
@@ -283,14 +224,14 @@ func (daemon *Daemon) containerExtractToDir(container *Container, path string, n
 	// a volume file path.
 	var baseRel string
 	if strings.HasPrefix(resolvedPath, `\\?\Volume{`) {
-		if strings.HasPrefix(resolvedPath, container.basefs) {
-			baseRel = resolvedPath[len(container.basefs):]
+		if strings.HasPrefix(resolvedPath, container.BaseFS) {
+			baseRel = resolvedPath[len(container.BaseFS):]
 			if baseRel[:1] == `\` {
 				baseRel = baseRel[1:]
 			}
 		}
 	} else {
-		baseRel, err = filepath.Rel(container.basefs, resolvedPath)
+		baseRel, err = filepath.Rel(container.BaseFS, resolvedPath)
 	}
 	if err != nil {
 		return err
@@ -303,7 +244,7 @@ func (daemon *Daemon) containerExtractToDir(container *Container, path string, n
 		return err
 	}
 
-	if !toVolume && container.hostConfig.ReadonlyRootfs {
+	if !toVolume && container.HostConfig.ReadonlyRootfs {
 		return ErrRootFSReadOnly
 	}
 
@@ -323,7 +264,7 @@ func (daemon *Daemon) containerExtractToDir(container *Container, path string, n
 	return nil
 }
 
-func (daemon *Daemon) containerCopy(container *Container, resource string) (rc io.ReadCloser, err error) {
+func (daemon *Daemon) containerCopy(container *container.Container, resource string) (rc io.ReadCloser, err error) {
 	container.Lock()
 
 	defer func() {
@@ -342,7 +283,7 @@ func (daemon *Daemon) containerCopy(container *Container, resource string) (rc i
 	defer func() {
 		if err != nil {
 			// unmount any volumes
-			container.unmountVolumes(true)
+			container.UnmountVolumes(true)
 			// unmount the container's rootfs
 			daemon.Unmount(container)
 		}
@@ -379,7 +320,7 @@ func (daemon *Daemon) containerCopy(container *Container, resource string) (rc i
 
 	reader := ioutils.NewReadCloserWrapper(archive, func() error {
 		err := archive.Close()
-		container.unmountVolumes(true)
+		container.UnmountVolumes(true)
 		daemon.Unmount(container)
 		container.Unlock()
 		return err

+ 3 - 1
daemon/archive_unix.go

@@ -2,10 +2,12 @@
 
 package daemon
 
+import "github.com/docker/docker/container"
+
 // 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) {
+func checkIfPathIsInAVolume(container *container.Container, absPath string) (bool, error) {
 	var toVolume bool
 	for _, mnt := range container.MountPoints {
 		if toVolume = mnt.HasResource(absPath); toVolume {

+ 3 - 1
daemon/archive_windows.go

@@ -1,11 +1,13 @@
 package daemon
 
+import "github.com/docker/docker/container"
+
 // 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 read-only volumes, or
 // extracting to a mount point inside a volume. TODO Windows: FIXME Post-TP4
-func checkIfPathIsInAVolume(container *Container, absPath string) (bool, error) {
+func checkIfPathIsInAVolume(container *container.Container, absPath string) (bool, error) {
 	return false, nil
 }

+ 2 - 1
daemon/attach.go

@@ -5,6 +5,7 @@ import (
 	"time"
 
 	"github.com/Sirupsen/logrus"
+	"github.com/docker/docker/container"
 	"github.com/docker/docker/daemon/logger"
 	"github.com/docker/docker/pkg/stdcopy"
 )
@@ -66,7 +67,7 @@ func (daemon *Daemon) ContainerWsAttachWithLogs(prefixOrName string, c *Containe
 	return daemon.attachWithLogs(container, c.InStream, c.OutStream, c.ErrStream, c.Logs, c.Stream)
 }
 
-func (daemon *Daemon) attachWithLogs(container *Container, stdin io.ReadCloser, stdout, stderr io.Writer, logs, stream bool) error {
+func (daemon *Daemon) attachWithLogs(container *container.Container, stdin io.ReadCloser, stdout, stderr io.Writer, logs, stream bool) error {
 	if logs {
 		logDriver, err := daemon.getLogger(container)
 		if err != nil {

+ 4 - 3
daemon/commit.go

@@ -8,6 +8,7 @@ import (
 	"time"
 
 	"github.com/docker/distribution/reference"
+	"github.com/docker/docker/container"
 	"github.com/docker/docker/dockerversion"
 	"github.com/docker/docker/image"
 	"github.com/docker/docker/layer"
@@ -42,7 +43,7 @@ func (daemon *Daemon) Commit(name string, c *ContainerCommitConfig) (string, err
 		return "", fmt.Errorf("Windows does not support commit of a running container")
 	}
 
-	if c.Pause && !container.isPaused() {
+	if c.Pause && !container.IsPaused() {
 		daemon.containerPause(container)
 		defer daemon.containerUnpause(container)
 	}
@@ -145,12 +146,12 @@ func (daemon *Daemon) Commit(name string, c *ContainerCommitConfig) (string, err
 	return id.String(), nil
 }
 
-func (daemon *Daemon) exportContainerRw(container *Container) (archive.Archive, error) {
+func (daemon *Daemon) exportContainerRw(container *container.Container) (archive.Archive, error) {
 	if err := daemon.Mount(container); err != nil {
 		return nil, err
 	}
 
-	archive, err := container.rwlayer.TarStream()
+	archive, err := container.RWLayer.TarStream()
 	if err != nil {
 		return nil, err
 	}

+ 9 - 0
daemon/container_operations.go

@@ -0,0 +1,9 @@
+package daemon
+
+import "errors"
+
+var (
+	// ErrRootFSReadOnly is returned when a container
+	// rootfs is marked readonly.
+	ErrRootFSReadOnly = errors.New("container rootfs is marked read-only")
+)

File diff suppressed because it is too large
+ 138 - 503
daemon/container_operations_unix.go


+ 31 - 73
daemon/container_windows.go → daemon/container_operations_windows.go

@@ -5,62 +5,37 @@ package daemon
 import (
 	"strings"
 
+	"github.com/docker/docker/container"
 	"github.com/docker/docker/daemon/execdriver"
 	derr "github.com/docker/docker/errors"
 	"github.com/docker/docker/layer"
-	"github.com/docker/docker/volume"
 	"github.com/docker/libnetwork"
 )
 
-// DefaultPathEnv is deliberately empty on Windows as the default path will be set by
-// the container. Docker has no context of what the default path should be.
-const DefaultPathEnv = ""
-
-// Container holds fields specific to the Windows implementation. See
-// CommonContainer for standard fields common to all containers.
-type Container struct {
-	CommonContainer
-
-	// Fields below here are platform specific.
-}
-
-func killProcessDirectly(container *Container) error {
-	return nil
-}
-
-func (daemon *Daemon) setupLinkedContainers(container *Container) ([]string, error) {
+func (daemon *Daemon) setupLinkedContainers(container *container.Container) ([]string, error) {
 	return nil, nil
 }
 
-func (container *Container) createDaemonEnvironment(linkedEnv []string) []string {
-	// On Windows, nothing to link. Just return the container environment.
-	return container.Config.Env
-}
-
-func (daemon *Daemon) initializeNetworking(container *Container) error {
+func (daemon *Daemon) initializeNetworking(container *container.Container) error {
 	return nil
 }
 
 // ConnectToNetwork connects a container to the network
-func (daemon *Daemon) ConnectToNetwork(container *Container, idOrName string) error {
+func (daemon *Daemon) ConnectToNetwork(container *container.Container, idOrName string) error {
 	return nil
 }
 
-// DisconnectFromNetwork disconnects a container from, the network
-func (container *Container) DisconnectFromNetwork(n libnetwork.Network) error {
+// DisconnectFromNetwork disconnects a container from the network.
+func (daemon *Daemon) DisconnectFromNetwork(container *container.Container, n libnetwork.Network) error {
 	return nil
 }
 
-func (container *Container) setupWorkingDirectory() error {
-	return nil
-}
-
-func (daemon *Daemon) populateCommand(c *Container, env []string) error {
+func (daemon *Daemon) populateCommand(c *container.Container, env []string) error {
 	en := &execdriver.Network{
 		Interface: nil,
 	}
 
-	parts := strings.SplitN(string(c.hostConfig.NetworkMode), ":", 2)
+	parts := strings.SplitN(string(c.HostConfig.NetworkMode), ":", 2)
 	switch parts[0] {
 	case "none":
 	case "default", "": // empty string to support existing containers
@@ -68,7 +43,7 @@ func (daemon *Daemon) populateCommand(c *Container, env []string) error {
 			en.Interface = &execdriver.NetworkInterface{
 				MacAddress:   c.Config.MacAddress,
 				Bridge:       daemon.configStore.Bridge.VirtualSwitchName,
-				PortBindings: c.hostConfig.PortBindings,
+				PortBindings: c.HostConfig.PortBindings,
 
 				// TODO Windows. Include IPAddress. There already is a
 				// property IPAddress on execDrive.CommonNetworkInterface,
@@ -77,13 +52,13 @@ func (daemon *Daemon) populateCommand(c *Container, env []string) error {
 			}
 		}
 	default:
-		return derr.ErrorCodeInvalidNetworkMode.WithArgs(c.hostConfig.NetworkMode)
+		return derr.ErrorCodeInvalidNetworkMode.WithArgs(c.HostConfig.NetworkMode)
 	}
 
 	// TODO Windows. More resource controls to be implemented later.
 	resources := &execdriver.Resources{
 		CommonResources: execdriver.CommonResources{
-			CPUShares: c.hostConfig.CPUShares,
+			CPUShares: c.HostConfig.CPUShares,
 		},
 	}
 
@@ -93,7 +68,7 @@ func (daemon *Daemon) populateCommand(c *Container, env []string) error {
 			Arguments:  c.Args,
 			Tty:        c.Config.Tty,
 		},
-		ConsoleSize: c.hostConfig.ConsoleSize,
+		ConsoleSize: c.HostConfig.ConsoleSize,
 	}
 
 	processConfig.Env = env
@@ -123,23 +98,23 @@ func (daemon *Daemon) populateCommand(c *Container, env []string) error {
 	}
 	layerFolder := m["dir"]
 
-	c.command = &execdriver.Command{
+	c.Command = &execdriver.Command{
 		CommonCommand: execdriver.CommonCommand{
 			ID:            c.ID,
-			Rootfs:        c.rootfsPath(),
+			Rootfs:        c.BaseFS,
 			InitPath:      "/.dockerinit",
 			WorkingDir:    c.Config.WorkingDir,
 			Network:       en,
-			MountLabel:    c.getMountLabel(),
+			MountLabel:    c.GetMountLabel(),
 			Resources:     resources,
 			ProcessConfig: processConfig,
-			ProcessLabel:  c.getProcessLabel(),
+			ProcessLabel:  c.GetProcessLabel(),
 		},
 		FirstStart:  !c.HasBeenStartedBefore,
 		LayerFolder: layerFolder,
 		LayerPaths:  layerPaths,
 		Hostname:    c.Config.Hostname,
-		Isolation:   c.hostConfig.Isolation,
+		Isolation:   c.HostConfig.Isolation,
 		ArgsEscaped: c.Config.ArgsEscaped,
 	}
 
@@ -147,7 +122,7 @@ func (daemon *Daemon) populateCommand(c *Container, env []string) error {
 }
 
 // getSize returns real size & virtual size
-func (daemon *Daemon) getSize(container *Container) (int64, int64) {
+func (daemon *Daemon) getSize(container *container.Container) (int64, int64) {
 	// TODO Windows
 	return 0, 0
 }
@@ -158,40 +133,32 @@ func (daemon *Daemon) setNetworkNamespaceKey(containerID string, pid int) error
 }
 
 // allocateNetwork is a no-op on Windows.
-func (daemon *Daemon) allocateNetwork(container *Container) error {
+func (daemon *Daemon) allocateNetwork(container *container.Container) error {
 	return nil
 }
 
-func (daemon *Daemon) updateNetwork(container *Container) error {
+func (daemon *Daemon) updateNetwork(container *container.Container) error {
 	return nil
 }
 
-func (daemon *Daemon) releaseNetwork(container *Container) {
-}
-
-// appendNetworkMounts appends any network mounts to the array of mount points passed in.
-// Windows does not support network mounts (not to be confused with SMB network mounts), so
-// this is a no-op.
-func appendNetworkMounts(container *Container, volumeMounts []volume.MountPoint) ([]volume.MountPoint, error) {
-	return volumeMounts, nil
+func (daemon *Daemon) releaseNetwork(container *container.Container) {
 }
 
-func (daemon *Daemon) setupIpcDirs(container *Container) error {
+func (daemon *Daemon) setupIpcDirs(container *container.Container) error {
 	return nil
 }
 
-func (container *Container) unmountIpcMounts(unmount func(pth string) error) {
-}
-
-func detachMounted(path string) error {
-	return nil
-}
-
-func (container *Container) ipcMounts() []execdriver.Mount {
+// TODO Windows: Fix Post-TP4. This is a hack to allow docker cp to work
+// against containers which have volumes. You will still be able to cp
+// to somewhere on the container drive, but not to any mounted volumes
+// inside the container. Without this fix, docker cp is broken to any
+// container which has a volume, regardless of where the file is inside the
+// container.
+func (daemon *Daemon) mountVolumes(container *container.Container) error {
 	return nil
 }
 
-func (container *Container) tmpfsMounts() []execdriver.Mount {
+func detachMounted(path string) error {
 	return nil
 }
 
@@ -199,15 +166,6 @@ func getDefaultRouteMtu() (int, error) {
 	return -1, errSystemNotSupported
 }
 
-// TODO Windows: Fix Post-TP4. This is a hack to allow docker cp to work
-// against containers which have volumes. You will still be able to cp
-// to somewhere on the container drive, but not to any mounted volumes
-// inside the container. Without this fix, docker cp is broken to any
-// container which has a volume, regardless of where the file is inside the
-// container.
-func (daemon *Daemon) mountVolumes(container *Container) error {
-	return nil
-}
-func (container *Container) unmountVolumes(forceSyscall bool) error {
+func killProcessDirectly(container *container.Container) error {
 	return nil
 }

+ 0 - 136
daemon/container_unit_test.go

@@ -1,136 +0,0 @@
-package daemon
-
-import (
-	"io/ioutil"
-	"os"
-	"path/filepath"
-	"testing"
-
-	"github.com/docker/docker/pkg/signal"
-	"github.com/docker/docker/runconfig"
-	"github.com/docker/docker/volume"
-	"github.com/docker/docker/volume/drivers"
-)
-
-func TestGetFullName(t *testing.T) {
-	name, err := GetFullContainerName("testing")
-	if err != nil {
-		t.Fatal(err)
-	}
-	if name != "/testing" {
-		t.Fatalf("Expected /testing got %s", name)
-	}
-	if _, err := GetFullContainerName(""); err == nil {
-		t.Fatal("Error should not be nil")
-	}
-}
-
-func TestValidContainerNames(t *testing.T) {
-	invalidNames := []string{"-rm", "&sdfsfd", "safd%sd"}
-	validNames := []string{"word-word", "word_word", "1weoid"}
-
-	for _, name := range invalidNames {
-		if validContainerNamePattern.MatchString(name) {
-			t.Fatalf("%q is not a valid container name and was returned as valid.", name)
-		}
-	}
-
-	for _, name := range validNames {
-		if !validContainerNamePattern.MatchString(name) {
-			t.Fatalf("%q is a valid container name and was returned as invalid.", name)
-		}
-	}
-}
-
-func TestContainerStopSignal(t *testing.T) {
-	c := &Container{
-		CommonContainer: CommonContainer{
-			Config: &runconfig.Config{},
-		},
-	}
-
-	def, err := signal.ParseSignal(signal.DefaultStopSignal)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	s := c.stopSignal()
-	if s != int(def) {
-		t.Fatalf("Expected %v, got %v", def, s)
-	}
-
-	c = &Container{
-		CommonContainer: CommonContainer{
-			Config: &runconfig.Config{StopSignal: "SIGKILL"},
-		},
-	}
-	s = c.stopSignal()
-	if s != 9 {
-		t.Fatalf("Expected 9, got %v", s)
-	}
-}
-
-func TestContainerInitDNS(t *testing.T) {
-	tmp, err := ioutil.TempDir("", "docker-container-test-")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer os.RemoveAll(tmp)
-
-	containerID := "d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e"
-	containerPath := filepath.Join(tmp, containerID)
-	if err := os.MkdirAll(containerPath, 0755); err != nil {
-		t.Fatal(err)
-	}
-
-	config := `{"State":{"Running":true,"Paused":false,"Restarting":false,"OOMKilled":false,"Dead":false,"Pid":2464,"ExitCode":0,
-"Error":"","StartedAt":"2015-05-26T16:48:53.869308965Z","FinishedAt":"0001-01-01T00:00:00Z"},
-"ID":"d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e","Created":"2015-05-26T16:48:53.7987917Z","Path":"top",
-"Args":[],"Config":{"Hostname":"d59df5276e7b","Domainname":"","User":"","Memory":0,"MemorySwap":0,"CpuShares":0,"Cpuset":"",
-"AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"PortSpecs":null,"ExposedPorts":null,"Tty":true,"OpenStdin":true,
-"StdinOnce":false,"Env":null,"Cmd":["top"],"Image":"ubuntu:latest","Volumes":null,"WorkingDir":"","Entrypoint":null,
-"NetworkDisabled":false,"MacAddress":"","OnBuild":null,"Labels":{}},"Image":"07f8e8c5e66084bef8f848877857537ffe1c47edd01a93af27e7161672ad0e95",
-"NetworkSettings":{"IPAddress":"172.17.0.1","IPPrefixLen":16,"MacAddress":"02:42:ac:11:00:01","LinkLocalIPv6Address":"fe80::42:acff:fe11:1",
-"LinkLocalIPv6PrefixLen":64,"GlobalIPv6Address":"","GlobalIPv6PrefixLen":0,"Gateway":"172.17.42.1","IPv6Gateway":"","Bridge":"docker0","Ports":{}},
-"ResolvConfPath":"/var/lib/docker/containers/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e/resolv.conf",
-"HostnamePath":"/var/lib/docker/containers/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e/hostname",
-"HostsPath":"/var/lib/docker/containers/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e/hosts",
-"LogPath":"/var/lib/docker/containers/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e-json.log",
-"Name":"/ubuntu","Driver":"aufs","MountLabel":"","ProcessLabel":"","AppArmorProfile":"","RestartCount":0,
-"UpdateDns":false,"Volumes":{},"VolumesRW":{},"AppliedVolumesFrom":null}`
-
-	if err = ioutil.WriteFile(filepath.Join(containerPath, configFileName), []byte(config), 0644); err != nil {
-		t.Fatal(err)
-	}
-
-	hostConfig := `{"Binds":[],"ContainerIDFile":"","Memory":0,"MemorySwap":0,"CpuShares":0,"CpusetCpus":"",
-"Privileged":false,"PortBindings":{},"Links":null,"PublishAllPorts":false,"Dns":null,"DnsOptions":null,"DnsSearch":null,"ExtraHosts":null,"VolumesFrom":null,
-"Devices":[],"NetworkMode":"bridge","IpcMode":"","PidMode":"","CapAdd":null,"CapDrop":null,"RestartPolicy":{"Name":"no","MaximumRetryCount":0},
-"SecurityOpt":null,"ReadonlyRootfs":false,"Ulimits":null,"LogConfig":{"Type":"","Config":null},"CgroupParent":""}`
-	if err = ioutil.WriteFile(filepath.Join(containerPath, "hostconfig.json"), []byte(hostConfig), 0644); err != nil {
-		t.Fatal(err)
-	}
-
-	daemon, err := initDaemonWithVolumeStore(tmp)
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer volumedrivers.Unregister(volume.DefaultDriverName)
-
-	c, err := daemon.load(containerID)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	if c.hostConfig.DNS == nil {
-		t.Fatal("Expected container DNS to not be nil")
-	}
-
-	if c.hostConfig.DNSSearch == nil {
-		t.Fatal("Expected container DNSSearch to not be nil")
-	}
-
-	if c.hostConfig.DNSOptions == nil {
-		t.Fatal("Expected container DNSOptions to not be nil")
-	}
-}

+ 5 - 4
daemon/create.go

@@ -3,6 +3,7 @@ package daemon
 import (
 	"github.com/Sirupsen/logrus"
 	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/container"
 	derr "github.com/docker/docker/errors"
 	"github.com/docker/docker/image"
 	"github.com/docker/docker/pkg/idtools"
@@ -48,9 +49,9 @@ func (daemon *Daemon) ContainerCreate(params *ContainerCreateConfig) (types.Cont
 }
 
 // Create creates a new container from the given configuration with a given name.
-func (daemon *Daemon) create(params *ContainerCreateConfig) (retC *Container, retErr error) {
+func (daemon *Daemon) create(params *ContainerCreateConfig) (retC *container.Container, retErr error) {
 	var (
-		container *Container
+		container *container.Container
 		img       *image.Image
 		imgID     image.ID
 		err       error
@@ -86,7 +87,7 @@ func (daemon *Daemon) create(params *ContainerCreateConfig) (retC *Container, re
 	if err != nil {
 		return nil, err
 	}
-	if err := idtools.MkdirAs(container.root, 0700, rootUID, rootGID); err != nil {
+	if err := idtools.MkdirAs(container.Root, 0700, rootUID, rootGID); err != nil {
 		return nil, err
 	}
 
@@ -105,7 +106,7 @@ func (daemon *Daemon) create(params *ContainerCreateConfig) (retC *Container, re
 		return nil, err
 	}
 
-	if err := container.toDiskLocking(); err != nil {
+	if err := container.ToDiskLocking(); err != nil {
 		logrus.Errorf("Error saving new container to disk: %v", err)
 		return nil, err
 	}

+ 5 - 4
daemon/create_unix.go

@@ -6,6 +6,7 @@ import (
 	"os"
 	"path/filepath"
 
+	"github.com/docker/docker/container"
 	derr "github.com/docker/docker/errors"
 	"github.com/docker/docker/image"
 	"github.com/docker/docker/pkg/stringid"
@@ -15,7 +16,7 @@ import (
 )
 
 // createContainerPlatformSpecificSettings performs platform specific container create functionality
-func (daemon *Daemon) createContainerPlatformSpecificSettings(container *Container, config *runconfig.Config, hostConfig *runconfig.HostConfig, img *image.Image) error {
+func (daemon *Daemon) createContainerPlatformSpecificSettings(container *container.Container, config *runconfig.Config, hostConfig *runconfig.HostConfig, img *image.Image) error {
 	if err := daemon.Mount(container); err != nil {
 		return err
 	}
@@ -27,7 +28,7 @@ func (daemon *Daemon) createContainerPlatformSpecificSettings(container *Contain
 
 		// Skip volumes for which we already have something mounted on that
 		// destination because of a --volume-from.
-		if container.isDestinationMounted(destination) {
+		if container.IsDestinationMounted(destination) {
 			continue
 		}
 		path, err := container.GetResourcePath(destination)
@@ -61,12 +62,12 @@ func (daemon *Daemon) createContainerPlatformSpecificSettings(container *Contain
 
 		// never attempt to copy existing content in a container FS to a shared volume
 		if v.DriverName() == volume.DefaultDriverName {
-			if err := container.copyImagePathContent(v, destination); err != nil {
+			if err := container.CopyImagePathContent(v, destination); err != nil {
 				return err
 			}
 		}
 
-		container.addMountPointWithVolume(destination, v, true)
+		container.AddMountPointWithVolume(destination, v, true)
 	}
 	return nil
 }

+ 5 - 4
daemon/create_windows.go

@@ -3,6 +3,7 @@ package daemon
 import (
 	"fmt"
 
+	"github.com/docker/docker/container"
 	"github.com/docker/docker/image"
 	"github.com/docker/docker/pkg/stringid"
 	"github.com/docker/docker/runconfig"
@@ -10,7 +11,7 @@ import (
 )
 
 // createContainerPlatformSpecificSettings performs platform specific container create functionality
-func (daemon *Daemon) createContainerPlatformSpecificSettings(container *Container, config *runconfig.Config, hostConfig *runconfig.HostConfig, img *image.Image) error {
+func (daemon *Daemon) createContainerPlatformSpecificSettings(container *container.Container, config *runconfig.Config, hostConfig *runconfig.HostConfig, img *image.Image) error {
 	for spec := range config.Volumes {
 
 		mp, err := volume.ParseMountSpec(spec, hostConfig.VolumeDriver)
@@ -25,7 +26,7 @@ func (daemon *Daemon) createContainerPlatformSpecificSettings(container *Contain
 
 		// Skip volumes for which we already have something mounted on that
 		// destination because of a --volume-from.
-		if container.isDestinationMounted(mp.Destination) {
+		if container.IsDestinationMounted(mp.Destination) {
 			continue
 		}
 
@@ -71,13 +72,13 @@ func (daemon *Daemon) createContainerPlatformSpecificSettings(container *Contain
 		//
 		//	// never attempt to copy existing content in a container FS to a shared volume
 		//	if v.DriverName() == volume.DefaultDriverName {
-		//		if err := container.copyImagePathContent(v, mp.Destination); err != nil {
+		//		if err := container.CopyImagePathContent(v, mp.Destination); err != nil {
 		//			return err
 		//		}
 		//	}
 
 		// Add it to container.MountPoints
-		container.addMountPointWithVolume(mp.Destination, v, mp.RW)
+		container.AddMountPointWithVolume(mp.Destination, v, mp.RW)
 	}
 	return nil
 }

+ 63 - 55
daemon/daemon.go

@@ -23,6 +23,7 @@ import (
 	"github.com/docker/docker/api"
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/cliconfig"
+	"github.com/docker/docker/container"
 	"github.com/docker/docker/daemon/events"
 	"github.com/docker/docker/daemon/exec"
 	"github.com/docker/docker/daemon/execdriver"
@@ -84,17 +85,17 @@ func (e ErrImageDoesNotExist) Error() string {
 }
 
 type contStore struct {
-	s map[string]*Container
+	s map[string]*container.Container
 	sync.Mutex
 }
 
-func (c *contStore) Add(id string, cont *Container) {
+func (c *contStore) Add(id string, cont *container.Container) {
 	c.Lock()
 	c.s[id] = cont
 	c.Unlock()
 }
 
-func (c *contStore) Get(id string) *Container {
+func (c *contStore) Get(id string) *container.Container {
 	c.Lock()
 	res := c.s[id]
 	c.Unlock()
@@ -107,7 +108,7 @@ func (c *contStore) Delete(id string) {
 	c.Unlock()
 }
 
-func (c *contStore) List() []*Container {
+func (c *contStore) List() []*container.Container {
 	containers := new(History)
 	c.Lock()
 	for _, cont := range c.s {
@@ -155,7 +156,7 @@ type Daemon struct {
 //  - A partial container ID prefix (e.g. short ID) of any length that is
 //    unique enough to only return a single container object
 //  If none of these searches succeed, an error is returned
-func (daemon *Daemon) Get(prefixOrName string) (*Container, error) {
+func (daemon *Daemon) Get(prefixOrName string) (*container.Container, error) {
 	if containerByID := daemon.containers.Get(prefixOrName); containerByID != nil {
 		// prefix is an exact match to a full container ID
 		return containerByID, nil
@@ -188,7 +189,7 @@ func (daemon *Daemon) Exists(id string) bool {
 // IsPaused returns a bool indicating if the specified container is paused.
 func (daemon *Daemon) IsPaused(id string) bool {
 	c, _ := daemon.Get(id)
-	return c.State.isPaused()
+	return c.State.IsPaused()
 }
 
 func (daemon *Daemon) containerRoot(id string) string {
@@ -197,10 +198,10 @@ 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) {
+func (daemon *Daemon) load(id string) (*container.Container, error) {
 	container := daemon.newBaseContainer(id)
 
-	if err := container.fromDisk(); err != nil {
+	if err := container.FromDisk(); err != nil {
 		return nil, err
 	}
 
@@ -212,7 +213,7 @@ func (daemon *Daemon) load(id string) (*Container, error) {
 }
 
 // Register makes a container object usable by the daemon as <container.ID>
-func (daemon *Daemon) Register(container *Container) error {
+func (daemon *Daemon) Register(container *container.Container) error {
 	if daemon.Exists(container.ID) {
 		return fmt.Errorf("Container is already loaded")
 	}
@@ -238,7 +239,7 @@ func (daemon *Daemon) Register(container *Container) error {
 	if container.IsRunning() {
 		logrus.Debugf("killing old running container %s", container.ID)
 		// Set exit code to 128 + SIGKILL (9) to properly represent unsuccessful exit
-		container.setStoppedLocking(&execdriver.ExitStatus{ExitCode: 137})
+		container.SetStoppedLocking(&execdriver.ExitStatus{ExitCode: 137})
 		// use the current driver and ensure that the container is dead x.x
 		cmd := &execdriver.Command{
 			CommonCommand: execdriver.CommonCommand{
@@ -247,10 +248,10 @@ func (daemon *Daemon) Register(container *Container) error {
 		}
 		daemon.execDriver.Terminate(cmd)
 
-		container.unmountIpcMounts(mount.Unmount)
+		container.UnmountIpcMounts(mount.Unmount)
 
 		daemon.Unmount(container)
-		if err := container.toDiskLocking(); err != nil {
+		if err := container.ToDiskLocking(); err != nil {
 			logrus.Errorf("Error saving stopped state to disk: %v", err)
 		}
 	}
@@ -262,7 +263,7 @@ func (daemon *Daemon) Register(container *Container) error {
 	return nil
 }
 
-func (daemon *Daemon) ensureName(container *Container) error {
+func (daemon *Daemon) ensureName(container *container.Container) error {
 	if container.Name == "" {
 		name, err := daemon.generateNewName(container.ID)
 		if err != nil {
@@ -270,7 +271,7 @@ func (daemon *Daemon) ensureName(container *Container) error {
 		}
 		container.Name = name
 
-		if err := container.toDiskLocking(); err != nil {
+		if err := container.ToDiskLocking(); err != nil {
 			logrus.Errorf("Error saving container name to disk: %v", err)
 		}
 	}
@@ -279,7 +280,7 @@ func (daemon *Daemon) ensureName(container *Container) error {
 
 func (daemon *Daemon) restore() error {
 	type cr struct {
-		container  *Container
+		container  *container.Container
 		registered bool
 	}
 
@@ -336,7 +337,7 @@ func (daemon *Daemon) restore() error {
 	for _, c := range containers {
 		group.Add(1)
 
-		go func(container *Container, registered bool) {
+		go func(container *container.Container, registered bool) {
 			defer group.Done()
 
 			if !registered {
@@ -355,7 +356,7 @@ func (daemon *Daemon) restore() error {
 
 			// check the restart policy on the containers and restart any container with
 			// the restart policy of "always"
-			if daemon.configStore.AutoRestart && container.shouldRestart() {
+			if daemon.configStore.AutoRestart && container.ShouldRestart() {
 				logrus.Debugf("Starting container %s", container.ID)
 
 				if err := daemon.containerStart(container); err != nil {
@@ -474,7 +475,7 @@ func (daemon *Daemon) getEntrypointAndArgs(configEntrypoint *stringutils.StrSlic
 	return cmdSlice[0], cmdSlice[1:]
 }
 
-func (daemon *Daemon) newContainer(name string, config *runconfig.Config, imgID image.ID) (*Container, error) {
+func (daemon *Daemon) newContainer(name string, config *runconfig.Config, imgID image.ID) (*container.Container, error) {
 	var (
 		id             string
 		err            error
@@ -493,7 +494,7 @@ func (daemon *Daemon) newContainer(name string, config *runconfig.Config, imgID
 	base.Path = entrypoint
 	base.Args = args //FIXME: de-duplicate from config
 	base.Config = config
-	base.hostConfig = &runconfig.HostConfig{}
+	base.HostConfig = &runconfig.HostConfig{}
 	base.ImageID = imgID
 	base.NetworkSettings = &network.Settings{IsAnonymousEndpoint: noExplicitName}
 	base.Name = name
@@ -516,7 +517,7 @@ func GetFullContainerName(name string) (string, error) {
 }
 
 // GetByName returns a container given a name.
-func (daemon *Daemon) GetByName(name string) (*Container, error) {
+func (daemon *Daemon) GetByName(name string) (*container.Container, error) {
 	fullName, err := GetFullContainerName(name)
 	if err != nil {
 		return nil, err
@@ -576,12 +577,12 @@ func (daemon *Daemon) GetLabels(id string) map[string]string {
 // children returns all child containers of the container with the
 // given name. The containers are returned as a map from the container
 // name to a pointer to Container.
-func (daemon *Daemon) children(name string) (map[string]*Container, error) {
+func (daemon *Daemon) children(name string) (map[string]*container.Container, error) {
 	name, err := GetFullContainerName(name)
 	if err != nil {
 		return nil, err
 	}
-	children := make(map[string]*Container)
+	children := make(map[string]*container.Container)
 
 	err = daemon.containerGraphDB.Walk(name, func(p string, e *graphdb.Entity) error {
 		c, err := daemon.Get(e.ID())
@@ -609,7 +610,7 @@ func (daemon *Daemon) parents(name string) ([]string, error) {
 	return daemon.containerGraphDB.Parents(name)
 }
 
-func (daemon *Daemon) registerLink(parent, child *Container, alias string) error {
+func (daemon *Daemon) registerLink(parent, child *container.Container, alias string) error {
 	fullName := filepath.Join(parent.Name, alias)
 	if !daemon.containerGraphDB.Exists(fullName) {
 		_, err := daemon.containerGraphDB.Set(fullName, child.ID)
@@ -830,7 +831,7 @@ func NewDaemon(config *Config, registryService *registry.Service) (daemon *Daemo
 
 	d.ID = trustKey.PublicKey().KeyID()
 	d.repository = daemonRepo
-	d.containers = &contStore{s: make(map[string]*Container)}
+	d.containers = &contStore{s: make(map[string]*container.Container)}
 	d.execCommands = exec.NewStore()
 	d.tagStore = tagStore
 	d.distributionPool = distributionPool
@@ -861,9 +862,9 @@ func NewDaemon(config *Config, registryService *registry.Service) (daemon *Daemo
 	return d, nil
 }
 
-func (daemon *Daemon) shutdownContainer(c *Container) error {
+func (daemon *Daemon) shutdownContainer(c *container.Container) error {
 	// TODO(windows): Handle docker restart with paused containers
-	if c.isPaused() {
+	if c.IsPaused() {
 		// To terminate a process in freezer cgroup, we should send
 		// SIGTERM to this process then unfreeze it, and the process will
 		// force to terminate immediately.
@@ -906,20 +907,20 @@ func (daemon *Daemon) Shutdown() error {
 	if daemon.containers != nil {
 		group := sync.WaitGroup{}
 		logrus.Debug("starting clean shutdown of all containers...")
-		for _, container := range daemon.List() {
-			if !container.IsRunning() {
+		for _, cont := range daemon.List() {
+			if !cont.IsRunning() {
 				continue
 			}
-			logrus.Debugf("stopping %s", container.ID)
+			logrus.Debugf("stopping %s", cont.ID)
 			group.Add(1)
-			go func(c *Container) {
+			go func(c *container.Container) {
 				defer group.Done()
 				if err := daemon.shutdownContainer(c); err != nil {
 					logrus.Errorf("Stop container error: %v", err)
 					return
 				}
 				logrus.Debugf("container stopped %s", c.ID)
-			}(container)
+			}(cont)
 		}
 		group.Wait()
 	}
@@ -948,9 +949,9 @@ func (daemon *Daemon) Shutdown() error {
 	return nil
 }
 
-// Mount sets container.basefs
+// Mount sets container.BaseFS
 // (is it not set coming in? why is it unset?)
-func (daemon *Daemon) Mount(container *Container) error {
+func (daemon *Daemon) Mount(container *container.Container) error {
 	var layerID layer.ChainID
 	if container.ImageID != "" {
 		img, err := daemon.imageStore.Get(container.ImageID)
@@ -959,7 +960,7 @@ func (daemon *Daemon) Mount(container *Container) error {
 		}
 		layerID = img.RootFS.ChainID()
 	}
-	rwlayer, err := daemon.layerStore.Mount(container.ID, layerID, container.getMountLabel(), daemon.setupInitLayer)
+	rwlayer, err := daemon.layerStore.Mount(container.ID, layerID, container.GetMountLabel(), daemon.setupInitLayer)
 	if err != nil {
 		return err
 	}
@@ -969,56 +970,56 @@ func (daemon *Daemon) Mount(container *Container) error {
 	}
 	logrus.Debugf("container mounted via layerStore: %v", dir)
 
-	if container.basefs != dir {
+	if container.BaseFS != dir {
 		// The mount path reported by the graph driver should always be trusted on Windows, since the
 		// volume path for a given mounted layer may change over time.  This should only be an error
 		// on non-Windows operating systems.
-		if container.basefs != "" && runtime.GOOS != "windows" {
+		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.driver, container.ID, container.basefs, dir)
+				daemon.driver, container.ID, container.BaseFS, dir)
 		}
 	}
-	container.basefs = dir // TODO: combine these fields
-	container.rwlayer = rwlayer
+	container.BaseFS = dir // TODO: combine these fields
+	container.RWLayer = rwlayer
 	return nil
 }
 
 // Unmount unsets the container base filesystem
-func (daemon *Daemon) Unmount(container *Container) {
+func (daemon *Daemon) Unmount(container *container.Container) {
 	if err := daemon.layerStore.Unmount(container.ID); err != nil {
 		logrus.Errorf("Error unmounting container %s: %s", container.ID, err)
 	}
 }
 
 // Run uses the execution driver to run a given container
-func (daemon *Daemon) Run(c *Container, pipes *execdriver.Pipes, startCallback execdriver.DriverCallback) (execdriver.ExitStatus, error) {
+func (daemon *Daemon) Run(c *container.Container, pipes *execdriver.Pipes, startCallback execdriver.DriverCallback) (execdriver.ExitStatus, error) {
 	hooks := execdriver.Hooks{
 		Start: startCallback,
 	}
 	hooks.PreStart = append(hooks.PreStart, func(processConfig *execdriver.ProcessConfig, pid int, chOOM <-chan struct{}) error {
 		return daemon.setNetworkNamespaceKey(c.ID, pid)
 	})
-	return daemon.execDriver.Run(c.command, pipes, hooks)
+	return daemon.execDriver.Run(c.Command, pipes, hooks)
 }
 
-func (daemon *Daemon) kill(c *Container, sig int) error {
-	return daemon.execDriver.Kill(c.command, sig)
+func (daemon *Daemon) kill(c *container.Container, sig int) error {
+	return daemon.execDriver.Kill(c.Command, sig)
 }
 
-func (daemon *Daemon) stats(c *Container) (*execdriver.ResourceStats, error) {
+func (daemon *Daemon) stats(c *container.Container) (*execdriver.ResourceStats, error) {
 	return daemon.execDriver.Stats(c.ID)
 }
 
-func (daemon *Daemon) subscribeToContainerStats(c *Container) chan interface{} {
+func (daemon *Daemon) subscribeToContainerStats(c *container.Container) chan interface{} {
 	return daemon.statsCollector.collect(c)
 }
 
-func (daemon *Daemon) unsubscribeToContainerStats(c *Container, ch chan interface{}) {
+func (daemon *Daemon) unsubscribeToContainerStats(c *container.Container, ch chan interface{}) {
 	daemon.statsCollector.unsubscribe(c, ch)
 }
 
-func (daemon *Daemon) changes(container *Container) ([]archive.Change, error) {
+func (daemon *Daemon) changes(container *container.Container) ([]archive.Change, error) {
 	return daemon.layerStore.Changes(container.ID)
 }
 
@@ -1343,7 +1344,7 @@ func tempDir(rootDir string, rootUID, rootGID int) (string, error) {
 	return tmpDir, idtools.MkdirAllAs(tmpDir, 0700, rootUID, rootGID)
 }
 
-func (daemon *Daemon) setHostConfig(container *Container, hostConfig *runconfig.HostConfig) error {
+func (daemon *Daemon) setHostConfig(container *container.Container, hostConfig *runconfig.HostConfig) error {
 	container.Lock()
 	if err := parseSecurityOpt(container, hostConfig); err != nil {
 		container.Unlock()
@@ -1365,8 +1366,8 @@ func (daemon *Daemon) setHostConfig(container *Container, hostConfig *runconfig.
 		return err
 	}
 
-	container.hostConfig = hostConfig
-	container.toDisk()
+	container.HostConfig = hostConfig
+	container.ToDisk()
 	return nil
 }
 
@@ -1462,7 +1463,7 @@ func (daemon *Daemon) IsShuttingDown() bool {
 }
 
 // GetContainerStats collects all the stats published by a container
-func (daemon *Daemon) GetContainerStats(container *Container) (*execdriver.ResourceStats, error) {
+func (daemon *Daemon) GetContainerStats(container *container.Container) (*execdriver.ResourceStats, error) {
 	stats, err := daemon.stats(container)
 	if err != nil {
 		return nil, err
@@ -1478,7 +1479,7 @@ func (daemon *Daemon) GetContainerStats(container *Container) (*execdriver.Resou
 	return stats, nil
 }
 
-func (daemon *Daemon) getNetworkStats(c *Container) ([]*libcontainer.NetworkInterface, error) {
+func (daemon *Daemon) getNetworkStats(c *container.Container) ([]*libcontainer.NetworkInterface, error) {
 	var list []*libcontainer.NetworkInterface
 
 	sb, err := daemon.netController.SandboxByID(c.NetworkSettings.SandboxID)
@@ -1501,8 +1502,8 @@ func (daemon *Daemon) getNetworkStats(c *Container) ([]*libcontainer.NetworkInte
 
 // newBaseContainer creates a new container with its initial
 // configuration based on the root storage from the daemon.
-func (daemon *Daemon) newBaseContainer(id string) *Container {
-	return newBaseContainer(id, daemon.containerRoot(id))
+func (daemon *Daemon) newBaseContainer(id string) *container.Container {
+	return container.NewBaseContainer(id, daemon.containerRoot(id))
 }
 
 func convertLnNetworkStats(name string, stats *lntypes.InterfaceStatistics) *libcontainer.NetworkInterface {
@@ -1517,3 +1518,10 @@ func convertLnNetworkStats(name string, stats *lntypes.InterfaceStatistics) *lib
 	n.TxDropped = stats.TxDropped
 	return n
 }
+
+func validateID(id string) error {
+	if id == "" {
+		return derr.ErrorCodeEmptyID
+	}
+	return nil
+}

+ 122 - 12
daemon/daemon_test.go

@@ -1,13 +1,17 @@
 package daemon
 
 import (
+	"io/ioutil"
 	"os"
 	"path"
+	"path/filepath"
 	"testing"
 
+	"github.com/docker/docker/container"
 	"github.com/docker/docker/pkg/graphdb"
 	"github.com/docker/docker/pkg/truncindex"
 	"github.com/docker/docker/runconfig"
+	"github.com/docker/docker/volume"
 	volumedrivers "github.com/docker/docker/volume/drivers"
 	"github.com/docker/docker/volume/local"
 	"github.com/docker/docker/volume/store"
@@ -18,43 +22,43 @@ import (
 //
 
 func TestGet(t *testing.T) {
-	c1 := &Container{
-		CommonContainer: CommonContainer{
+	c1 := &container.Container{
+		CommonContainer: container.CommonContainer{
 			ID:   "5a4ff6a163ad4533d22d69a2b8960bf7fafdcba06e72d2febdba229008b0bf57",
 			Name: "tender_bardeen",
 		},
 	}
 
-	c2 := &Container{
-		CommonContainer: CommonContainer{
+	c2 := &container.Container{
+		CommonContainer: container.CommonContainer{
 			ID:   "3cdbd1aa394fd68559fd1441d6eff2ab7c1e6363582c82febfaa8045df3bd8de",
 			Name: "drunk_hawking",
 		},
 	}
 
-	c3 := &Container{
-		CommonContainer: CommonContainer{
+	c3 := &container.Container{
+		CommonContainer: container.CommonContainer{
 			ID:   "3cdbd1aa394fd68559fd1441d6eff2abfafdcba06e72d2febdba229008b0bf57",
 			Name: "3cdbd1aa",
 		},
 	}
 
-	c4 := &Container{
-		CommonContainer: CommonContainer{
+	c4 := &container.Container{
+		CommonContainer: container.CommonContainer{
 			ID:   "75fb0b800922abdbef2d27e60abcdfaf7fb0698b2a96d22d3354da361a6ff4a5",
 			Name: "5a4ff6a163ad4533d22d69a2b8960bf7fafdcba06e72d2febdba229008b0bf57",
 		},
 	}
 
-	c5 := &Container{
-		CommonContainer: CommonContainer{
+	c5 := &container.Container{
+		CommonContainer: container.CommonContainer{
 			ID:   "d22d69a2b8960bf7fafdcba06e72d2febdba960bf7fafdcba06e72d2f9008b060b",
 			Name: "d22d69a2b896",
 		},
 	}
 
 	store := &contStore{
-		s: map[string]*Container{
+		s: map[string]*container.Container{
 			c1.ID: c1,
 			c2.ID: c2,
 			c3.ID: c3,
@@ -136,7 +140,7 @@ func initDaemonWithVolumeStore(tmp string) (*Daemon, error) {
 }
 
 func TestParseSecurityOpt(t *testing.T) {
-	container := &Container{}
+	container := &container.Container{}
 	config := &runconfig.HostConfig{}
 
 	// test apparmor
@@ -190,3 +194,109 @@ func TestNetworkOptions(t *testing.T) {
 		t.Fatalf("Expected networkOptions error, got nil")
 	}
 }
+
+func TestGetFullName(t *testing.T) {
+	name, err := GetFullContainerName("testing")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if name != "/testing" {
+		t.Fatalf("Expected /testing got %s", name)
+	}
+	if _, err := GetFullContainerName(""); err == nil {
+		t.Fatal("Error should not be nil")
+	}
+}
+
+func TestValidContainerNames(t *testing.T) {
+	invalidNames := []string{"-rm", "&sdfsfd", "safd%sd"}
+	validNames := []string{"word-word", "word_word", "1weoid"}
+
+	for _, name := range invalidNames {
+		if validContainerNamePattern.MatchString(name) {
+			t.Fatalf("%q is not a valid container name and was returned as valid.", name)
+		}
+	}
+
+	for _, name := range validNames {
+		if !validContainerNamePattern.MatchString(name) {
+			t.Fatalf("%q is a valid container name and was returned as invalid.", name)
+		}
+	}
+}
+
+func TestContainerInitDNS(t *testing.T) {
+	tmp, err := ioutil.TempDir("", "docker-container-test-")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(tmp)
+
+	containerID := "d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e"
+	containerPath := filepath.Join(tmp, containerID)
+	if err := os.MkdirAll(containerPath, 0755); err != nil {
+		t.Fatal(err)
+	}
+
+	config := `{"State":{"Running":true,"Paused":false,"Restarting":false,"OOMKilled":false,"Dead":false,"Pid":2464,"ExitCode":0,
+"Error":"","StartedAt":"2015-05-26T16:48:53.869308965Z","FinishedAt":"0001-01-01T00:00:00Z"},
+"ID":"d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e","Created":"2015-05-26T16:48:53.7987917Z","Path":"top",
+"Args":[],"Config":{"Hostname":"d59df5276e7b","Domainname":"","User":"","Memory":0,"MemorySwap":0,"CpuShares":0,"Cpuset":"",
+"AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"PortSpecs":null,"ExposedPorts":null,"Tty":true,"OpenStdin":true,
+"StdinOnce":false,"Env":null,"Cmd":["top"],"Image":"ubuntu:latest","Volumes":null,"WorkingDir":"","Entrypoint":null,
+"NetworkDisabled":false,"MacAddress":"","OnBuild":null,"Labels":{}},"Image":"07f8e8c5e66084bef8f848877857537ffe1c47edd01a93af27e7161672ad0e95",
+"NetworkSettings":{"IPAddress":"172.17.0.1","IPPrefixLen":16,"MacAddress":"02:42:ac:11:00:01","LinkLocalIPv6Address":"fe80::42:acff:fe11:1",
+"LinkLocalIPv6PrefixLen":64,"GlobalIPv6Address":"","GlobalIPv6PrefixLen":0,"Gateway":"172.17.42.1","IPv6Gateway":"","Bridge":"docker0","Ports":{}},
+"ResolvConfPath":"/var/lib/docker/containers/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e/resolv.conf",
+"HostnamePath":"/var/lib/docker/containers/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e/hostname",
+"HostsPath":"/var/lib/docker/containers/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e/hosts",
+"LogPath":"/var/lib/docker/containers/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e/d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e-json.log",
+"Name":"/ubuntu","Driver":"aufs","MountLabel":"","ProcessLabel":"","AppArmorProfile":"","RestartCount":0,
+"UpdateDns":false,"Volumes":{},"VolumesRW":{},"AppliedVolumesFrom":null}`
+
+	// Container struct only used to retrieve path to config file
+	container := &container.Container{CommonContainer: container.CommonContainer{Root: containerPath}}
+	configPath, err := container.ConfigPath()
+	if err != nil {
+		t.Fatal(err)
+	}
+	if err = ioutil.WriteFile(configPath, []byte(config), 0644); err != nil {
+		t.Fatal(err)
+	}
+
+	hostConfig := `{"Binds":[],"ContainerIDFile":"","Memory":0,"MemorySwap":0,"CpuShares":0,"CpusetCpus":"",
+"Privileged":false,"PortBindings":{},"Links":null,"PublishAllPorts":false,"Dns":null,"DnsOptions":null,"DnsSearch":null,"ExtraHosts":null,"VolumesFrom":null,
+"Devices":[],"NetworkMode":"bridge","IpcMode":"","PidMode":"","CapAdd":null,"CapDrop":null,"RestartPolicy":{"Name":"no","MaximumRetryCount":0},
+"SecurityOpt":null,"ReadonlyRootfs":false,"Ulimits":null,"LogConfig":{"Type":"","Config":null},"CgroupParent":""}`
+
+	hostConfigPath, err := container.HostConfigPath()
+	if err != nil {
+		t.Fatal(err)
+	}
+	if err = ioutil.WriteFile(hostConfigPath, []byte(hostConfig), 0644); err != nil {
+		t.Fatal(err)
+	}
+
+	daemon, err := initDaemonWithVolumeStore(tmp)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer volumedrivers.Unregister(volume.DefaultDriverName)
+
+	c, err := daemon.load(containerID)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if c.HostConfig.DNS == nil {
+		t.Fatal("Expected container DNS to not be nil")
+	}
+
+	if c.HostConfig.DNSSearch == nil {
+		t.Fatal("Expected container DNSSearch to not be nil")
+	}
+
+	if c.HostConfig.DNSOptions == nil {
+		t.Fatal("Expected container DNSOptions to not be nil")
+	}
+}

+ 10 - 9
daemon/daemon_unix.go

@@ -12,6 +12,7 @@ import (
 	"syscall"
 
 	"github.com/Sirupsen/logrus"
+	"github.com/docker/docker/container"
 	"github.com/docker/docker/daemon/graphdriver"
 	derr "github.com/docker/docker/errors"
 	"github.com/docker/docker/image"
@@ -57,7 +58,7 @@ func getBlkioWeightDevices(config *runconfig.HostConfig) ([]*blkiodev.WeightDevi
 	return BlkioWeightDevices, nil
 }
 
-func parseSecurityOpt(container *Container, config *runconfig.HostConfig) error {
+func parseSecurityOpt(container *container.Container, config *runconfig.HostConfig) error {
 	var (
 		labelOpts []string
 		err       error
@@ -128,7 +129,7 @@ func (daemon *Daemon) adaptContainerSettings(hostConfig *runconfig.HostConfig, a
 		hostConfig.MemorySwap = hostConfig.Memory * 2
 	}
 	if hostConfig.ShmSize == nil {
-		shmSize := DefaultSHMSize
+		shmSize := container.DefaultSHMSize
 		hostConfig.ShmSize = &shmSize
 	}
 	var err error
@@ -575,7 +576,7 @@ func setupInitLayer(initLayer string, rootUID, rootGID int) error {
 }
 
 // registerLinks writes the links to a file.
-func (daemon *Daemon) registerLinks(container *Container, hostConfig *runconfig.HostConfig) error {
+func (daemon *Daemon) registerLinks(container *container.Container, hostConfig *runconfig.HostConfig) error {
 	if hostConfig == nil || hostConfig.Links == nil {
 		return nil
 	}
@@ -590,14 +591,14 @@ func (daemon *Daemon) registerLinks(container *Container, hostConfig *runconfig.
 			//An error from daemon.Get() means this name could not be found
 			return fmt.Errorf("Could not get container for %s", name)
 		}
-		for child.hostConfig.NetworkMode.IsContainer() {
-			parts := strings.SplitN(string(child.hostConfig.NetworkMode), ":", 2)
+		for child.HostConfig.NetworkMode.IsContainer() {
+			parts := strings.SplitN(string(child.HostConfig.NetworkMode), ":", 2)
 			child, err = daemon.Get(parts[1])
 			if err != nil {
 				return fmt.Errorf("Could not get container for %s", parts[1])
 			}
 		}
-		if child.hostConfig.NetworkMode.IsHost() {
+		if child.HostConfig.NetworkMode.IsHost() {
 			return runconfig.ErrConflictHostNetworkAndLinks
 		}
 		if err := daemon.registerLink(container, child, alias); err != nil {
@@ -608,7 +609,7 @@ func (daemon *Daemon) registerLinks(container *Container, hostConfig *runconfig.
 	// After we load all the links into the daemon
 	// set them to nil on the hostconfig
 	hostConfig.Links = nil
-	if err := container.writeHostConfig(); err != nil {
+	if err := container.WriteHostConfig(); err != nil {
 		return err
 	}
 
@@ -617,13 +618,13 @@ func (daemon *Daemon) registerLinks(container *Container, hostConfig *runconfig.
 
 // conditionalMountOnStart is a platform specific helper function during the
 // container start to call mount.
-func (daemon *Daemon) conditionalMountOnStart(container *Container) error {
+func (daemon *Daemon) conditionalMountOnStart(container *container.Container) error {
 	return daemon.Mount(container)
 }
 
 // conditionalUnmountOnCleanup is a platform specific helper function called
 // during the cleanup of a container to unmount.
-func (daemon *Daemon) conditionalUnmountOnCleanup(container *Container) {
+func (daemon *Daemon) conditionalUnmountOnCleanup(container *container.Container) {
 	daemon.Unmount(container)
 }
 

+ 7 - 6
daemon/daemon_windows.go

@@ -10,6 +10,7 @@ import (
 
 	"github.com/Sirupsen/logrus"
 	"github.com/docker/distribution/reference"
+	"github.com/docker/docker/container"
 	"github.com/docker/docker/daemon/graphdriver"
 	"github.com/docker/docker/dockerversion"
 	"github.com/docker/docker/image"
@@ -34,7 +35,7 @@ func getBlkioWeightDevices(config *runconfig.HostConfig) ([]*blkiodev.WeightDevi
 	return nil, nil
 }
 
-func parseSecurityOpt(container *Container, config *runconfig.HostConfig) error {
+func parseSecurityOpt(container *container.Container, config *runconfig.HostConfig) error {
 	return nil
 }
 
@@ -115,7 +116,7 @@ func (daemon *Daemon) initNetworkController(config *Config) (libnetwork.NetworkC
 
 // registerLinks sets up links between containers and writes the
 // configuration out for persistence. As of Windows TP4, links are not supported.
-func (daemon *Daemon) registerLinks(container *Container, hostConfig *runconfig.HostConfig) error {
+func (daemon *Daemon) registerLinks(container *container.Container, hostConfig *runconfig.HostConfig) error {
 	return nil
 }
 
@@ -125,9 +126,9 @@ func (daemon *Daemon) cleanupMounts() error {
 
 // conditionalMountOnStart is a platform specific helper function during the
 // container start to call mount.
-func (daemon *Daemon) conditionalMountOnStart(container *Container) error {
+func (daemon *Daemon) conditionalMountOnStart(container *container.Container) error {
 	// We do not mount if a Hyper-V container
-	if !container.hostConfig.Isolation.IsHyperV() {
+	if !container.HostConfig.Isolation.IsHyperV() {
 		if err := daemon.Mount(container); err != nil {
 			return err
 		}
@@ -137,9 +138,9 @@ func (daemon *Daemon) conditionalMountOnStart(container *Container) error {
 
 // conditionalUnmountOnCleanup is a platform specific helper function called
 // during the cleanup of a container to unmount.
-func (daemon *Daemon) conditionalUnmountOnCleanup(container *Container) {
+func (daemon *Daemon) conditionalUnmountOnCleanup(container *container.Container) {
 	// We do not unmount if a Hyper-V container
-	if !container.hostConfig.Isolation.IsHyperV() {
+	if !container.HostConfig.Isolation.IsHyperV() {
 		daemon.Unmount(container)
 	}
 }

+ 8 - 7
daemon/daemonbuilder/builder.go

@@ -13,6 +13,7 @@ import (
 	"github.com/docker/docker/api"
 	"github.com/docker/docker/builder"
 	"github.com/docker/docker/cliconfig"
+	"github.com/docker/docker/container"
 	"github.com/docker/docker/daemon"
 	"github.com/docker/docker/image"
 	"github.com/docker/docker/pkg/archive"
@@ -80,12 +81,12 @@ func (d Docker) Pull(name string) (*image.Image, error) {
 }
 
 // Container looks up a Docker container referenced by `id`.
-func (d Docker) Container(id string) (*daemon.Container, error) {
+func (d Docker) Container(id string) (*container.Container, error) {
 	return d.Daemon.Get(id)
 }
 
 // Create creates a new Docker container and returns potential warnings
-func (d Docker) Create(cfg *runconfig.Config, hostCfg *runconfig.HostConfig) (*daemon.Container, []string, error) {
+func (d Docker) Create(cfg *runconfig.Config, hostCfg *runconfig.HostConfig) (*container.Container, []string, error) {
 	ccr, err := d.Daemon.ContainerCreate(&daemon.ContainerCreateConfig{
 		Name:            "",
 		Config:          cfg,
@@ -129,7 +130,7 @@ func (d Docker) Release(sessionID string, activeImages []string) {
 // specified by a container object.
 // TODO: make sure callers don't unnecessarily convert destPath with filepath.FromSlash (Copy does it already).
 // Copy should take in abstract paths (with slashes) and the implementation should convert it to OS-specific paths.
-func (d Docker) Copy(c *daemon.Container, destPath string, src builder.FileInfo, decompress bool) error {
+func (d Docker) Copy(c *container.Container, destPath string, src builder.FileInfo, decompress bool) error {
 	srcPath := src.Path()
 	destExists := true
 	rootUID, rootGID := d.Daemon.GetRemappedUIDGID()
@@ -212,23 +213,23 @@ func (d Docker) GetCachedImage(imgID string, cfg *runconfig.Config) (string, err
 }
 
 // Kill stops the container execution abruptly.
-func (d Docker) Kill(container *daemon.Container) error {
+func (d Docker) Kill(container *container.Container) error {
 	return d.Daemon.Kill(container)
 }
 
 // Mount mounts the root filesystem for the container.
-func (d Docker) Mount(c *daemon.Container) error {
+func (d Docker) Mount(c *container.Container) error {
 	return d.Daemon.Mount(c)
 }
 
 // Unmount unmounts the root filesystem for the container.
-func (d Docker) Unmount(c *daemon.Container) error {
+func (d Docker) Unmount(c *container.Container) error {
 	d.Daemon.Unmount(c)
 	return nil
 }
 
 // Start starts a container
-func (d Docker) Start(c *daemon.Container) error {
+func (d Docker) Start(c *container.Container) error {
 	return d.Daemon.Start(c)
 }
 

+ 7 - 6
daemon/delete.go

@@ -5,6 +5,7 @@ import (
 	"path"
 
 	"github.com/Sirupsen/logrus"
+	"github.com/docker/docker/container"
 	derr "github.com/docker/docker/errors"
 	"github.com/docker/docker/layer"
 	volumestore "github.com/docker/docker/volume/store"
@@ -26,14 +27,14 @@ func (daemon *Daemon) ContainerRm(name string, config *ContainerRmConfig) error
 	}
 
 	// Container state RemovalInProgress should be used to avoid races.
-	if err = container.setRemovalInProgress(); err != nil {
+	if err = container.SetRemovalInProgress(); err != nil {
 		if err == derr.ErrorCodeAlreadyRemoving {
 			// do not fail when the removal is in progress started by other request.
 			return nil
 		}
 		return derr.ErrorCodeRmState.WithArgs(err)
 	}
-	defer container.resetRemovalInProgress()
+	defer container.ResetRemovalInProgress()
 
 	// check if container wasn't deregistered by previous rm since Get
 	if c := daemon.containers.Get(container.ID); c == nil {
@@ -87,7 +88,7 @@ func (daemon *Daemon) rmLink(name string) error {
 
 // cleanupContainer unregisters a container from the daemon, stops stats
 // collection and cleanly removes contents and metadata from the filesystem.
-func (daemon *Daemon) cleanupContainer(container *Container, forceRemove bool) (err error) {
+func (daemon *Daemon) cleanupContainer(container *container.Container, forceRemove bool) (err error) {
 	if container.IsRunning() {
 		if !forceRemove {
 			return derr.ErrorCodeRmRunning
@@ -106,12 +107,12 @@ func (daemon *Daemon) cleanupContainer(container *Container, forceRemove bool) (
 	}
 
 	// Mark container dead. We don't want anybody to be restarting it.
-	container.setDead()
+	container.SetDead()
 
 	// Save container state to disk. So that if error happens before
 	// container meta file got removed from disk, then a restart of
 	// docker should not make a dead container alive.
-	if err := container.toDiskLocking(); err != nil {
+	if err := container.ToDiskLocking(); err != nil {
 		logrus.Errorf("Error saving dying container to disk: %v", err)
 	}
 
@@ -129,7 +130,7 @@ func (daemon *Daemon) cleanupContainer(container *Container, forceRemove bool) (
 		}
 	}()
 
-	if err = os.RemoveAll(container.root); err != nil {
+	if err = os.RemoveAll(container.Root); err != nil {
 		return derr.ErrorCodeRmFS.WithArgs(container.ID, err)
 	}
 

+ 6 - 5
daemon/delete_test.go

@@ -5,6 +5,7 @@ import (
 	"os"
 	"testing"
 
+	"github.com/docker/docker/container"
 	"github.com/docker/docker/runconfig"
 )
 
@@ -18,19 +19,19 @@ func TestContainerDoubleDelete(t *testing.T) {
 		repository: tmp,
 		root:       tmp,
 	}
-	daemon.containers = &contStore{s: make(map[string]*Container)}
+	daemon.containers = &contStore{s: make(map[string]*container.Container)}
 
-	container := &Container{
-		CommonContainer: CommonContainer{
+	container := &container.Container{
+		CommonContainer: container.CommonContainer{
 			ID:     "test",
-			State:  NewState(),
+			State:  container.NewState(),
 			Config: &runconfig.Config{},
 		},
 	}
 	daemon.containers.Add(container.ID, container)
 
 	// Mark the container as having a delete in progress
-	if err := container.setRemovalInProgress(); err != nil {
+	if err := container.SetRemovalInProgress(); err != nil {
 		t.Fatal(err)
 	}
 

+ 5 - 1
daemon/events.go

@@ -1,7 +1,11 @@
 package daemon
 
+import (
+	"github.com/docker/docker/container"
+)
+
 // LogContainerEvent generates an event related to a container.
-func (daemon *Daemon) LogContainerEvent(container *Container, action string) {
+func (daemon *Daemon) LogContainerEvent(container *container.Container, action string) {
 	daemon.EventsService.Log(
 		action,
 		container.ID,

+ 22 - 22
daemon/exec.go

@@ -6,6 +6,7 @@ import (
 	"time"
 
 	"github.com/Sirupsen/logrus"
+	"github.com/docker/docker/container"
 	"github.com/docker/docker/daemon/exec"
 	"github.com/docker/docker/daemon/execdriver"
 	derr "github.com/docker/docker/errors"
@@ -15,15 +16,15 @@ import (
 	"github.com/docker/docker/runconfig"
 )
 
-func (d *Daemon) registerExecCommand(container *Container, config *exec.Config) {
+func (d *Daemon) registerExecCommand(container *container.Container, config *exec.Config) {
 	// Storing execs in container in order to kill them gracefully whenever the container is stopped or removed.
-	container.execCommands.Add(config.ID, config)
+	container.ExecCommands.Add(config.ID, config)
 	// Storing execs in daemon for easy access via remote API.
 	d.execCommands.Add(config.ID, config)
 }
 
 // ExecExists looks up the exec instance and returns a bool if it exists or not.
-// It will also return the error produced by `getExecConfig`
+// It will also return the error produced by `getConfig`
 func (d *Daemon) ExecExists(name string) (bool, error) {
 	if _, err := d.getExecConfig(name); err != nil {
 		return false, err
@@ -47,7 +48,7 @@ func (d *Daemon) getExecConfig(name string) (*exec.Config, error) {
 			if !container.IsRunning() {
 				return nil, derr.ErrorCodeContainerNotRunning.WithArgs(container.ID, container.State.String())
 			}
-			if container.isPaused() {
+			if container.IsPaused() {
 				return nil, derr.ErrorCodeExecPaused.WithArgs(container.ID)
 			}
 			return ec, nil
@@ -57,12 +58,12 @@ func (d *Daemon) getExecConfig(name string) (*exec.Config, error) {
 	return nil, derr.ErrorCodeNoExecID.WithArgs(name)
 }
 
-func (d *Daemon) unregisterExecCommand(container *Container, execConfig *exec.Config) {
-	container.execCommands.Delete(execConfig.ID)
+func (d *Daemon) unregisterExecCommand(container *container.Container, execConfig *exec.Config) {
+	container.ExecCommands.Delete(execConfig.ID)
 	d.execCommands.Delete(execConfig.ID)
 }
 
-func (d *Daemon) getActiveContainer(name string) (*Container, error) {
+func (d *Daemon) getActiveContainer(name string) (*container.Container, error) {
 	container, err := d.Get(name)
 	if err != nil {
 		return nil, err
@@ -71,7 +72,7 @@ func (d *Daemon) getActiveContainer(name string) (*Container, error) {
 	if !container.IsRunning() {
 		return nil, derr.ErrorCodeNotRunning.WithArgs(name)
 	}
-	if container.isPaused() {
+	if container.IsPaused() {
 		return nil, derr.ErrorCodeExecPaused.WithArgs(name)
 	}
 	return container, nil
@@ -131,9 +132,9 @@ func (d *Daemon) ContainerExecStart(name string, stdin io.ReadCloser, stdout io.
 	ec.Running = true
 	ec.Unlock()
 
-	container := d.containers.Get(ec.ContainerID)
-	logrus.Debugf("starting exec command %s in container %s", ec.ID, container.ID)
-	d.LogContainerEvent(container, "exec_start: "+ec.ProcessConfig.Entrypoint+" "+strings.Join(ec.ProcessConfig.Arguments, " "))
+	c := d.containers.Get(ec.ContainerID)
+	logrus.Debugf("starting exec command %s in container %s", ec.ID, c.ID)
+	d.LogContainerEvent(c, "exec_start: "+ec.ProcessConfig.Entrypoint+" "+strings.Join(ec.ProcessConfig.Arguments, " "))
 
 	if ec.OpenStdin {
 		r, w := io.Pipe()
@@ -157,8 +158,7 @@ func (d *Daemon) ContainerExecStart(name string, stdin io.ReadCloser, stdout io.
 		ec.NewNopInputPipe()
 	}
 
-	attachErr := attach(ec.StreamConfig, ec.OpenStdin, true, ec.ProcessConfig.Tty, cStdin, cStdout, cStderr)
-
+	attachErr := container.AttachStreams(ec.StreamConfig, ec.OpenStdin, true, ec.ProcessConfig.Tty, cStdin, cStdout, cStderr)
 	execErr := make(chan error)
 
 	// Note, the ExecConfig data will be removed when the container
@@ -166,7 +166,7 @@ func (d *Daemon) ContainerExecStart(name string, stdin io.ReadCloser, stdout io.
 	// the exitStatus) even after the cmd is done running.
 
 	go func() {
-		execErr <- d.containerExec(container, ec)
+		execErr <- d.containerExec(c, ec)
 	}()
 
 	select {
@@ -184,19 +184,19 @@ func (d *Daemon) ContainerExecStart(name string, stdin io.ReadCloser, stdout io.
 		}
 
 		// Maybe the container stopped while we were trying to exec
-		if !container.IsRunning() {
+		if !c.IsRunning() {
 			return derr.ErrorCodeExecContainerStopped
 		}
-		return derr.ErrorCodeExecCantRun.WithArgs(ec.ID, container.ID, err)
+		return derr.ErrorCodeExecCantRun.WithArgs(ec.ID, c.ID, err)
 	}
 }
 
 // Exec calls the underlying exec driver to run
-func (d *Daemon) Exec(c *Container, execConfig *exec.Config, pipes *execdriver.Pipes, startCallback execdriver.DriverCallback) (int, error) {
+func (d *Daemon) Exec(c *container.Container, execConfig *exec.Config, pipes *execdriver.Pipes, startCallback execdriver.DriverCallback) (int, error) {
 	hooks := execdriver.Hooks{
 		Start: startCallback,
 	}
-	exitStatus, err := d.execDriver.Exec(c.command, execConfig.ProcessConfig, pipes, hooks)
+	exitStatus, err := d.execDriver.Exec(c.Command, execConfig.ProcessConfig, pipes, hooks)
 
 	// On err, make sure we don't leave ExitCode at zero
 	if err != nil && exitStatus == 0 {
@@ -238,14 +238,14 @@ func (d *Daemon) execCommandGC() {
 func (d *Daemon) containerExecIds() map[string]struct{} {
 	ids := map[string]struct{}{}
 	for _, c := range d.containers.List() {
-		for _, id := range c.execCommands.List() {
+		for _, id := range c.ExecCommands.List() {
 			ids[id] = struct{}{}
 		}
 	}
 	return ids
 }
 
-func (d *Daemon) containerExec(container *Container, ec *exec.Config) error {
+func (d *Daemon) containerExec(container *container.Container, ec *exec.Config) error {
 	container.Lock()
 	defer container.Unlock()
 
@@ -268,7 +268,7 @@ func (d *Daemon) containerExec(container *Container, ec *exec.Config) error {
 	return ec.Wait(cErr)
 }
 
-func (d *Daemon) monitorExec(container *Container, execConfig *exec.Config, callback execdriver.DriverCallback) error {
+func (d *Daemon) monitorExec(container *container.Container, execConfig *exec.Config, callback execdriver.DriverCallback) error {
 	pipes := execdriver.NewPipes(execConfig.Stdin(), execConfig.Stdout(), execConfig.Stderr(), execConfig.OpenStdin)
 	exitCode, err := d.Exec(container, execConfig, pipes, callback)
 	if err != nil {
@@ -287,6 +287,6 @@ func (d *Daemon) monitorExec(container *Container, execConfig *exec.Config, call
 	}
 	// remove the exec command from the container's store only and not the
 	// daemon's store so that the exec command can be inspected.
-	container.execCommands.Delete(execConfig.ID)
+	container.ExecCommands.Delete(execConfig.ID)
 	return err
 }

+ 2 - 1
daemon/exec_unix.go

@@ -3,13 +3,14 @@
 package daemon
 
 import (
+	"github.com/docker/docker/container"
 	"github.com/docker/docker/daemon/execdriver"
 	"github.com/docker/docker/runconfig"
 )
 
 // setPlatformSpecificExecProcessConfig sets platform-specific fields in the
 // ProcessConfig structure.
-func setPlatformSpecificExecProcessConfig(config *runconfig.ExecConfig, container *Container, pc *execdriver.ProcessConfig) {
+func setPlatformSpecificExecProcessConfig(config *runconfig.ExecConfig, container *container.Container, pc *execdriver.ProcessConfig) {
 	user := config.User
 	if len(user) == 0 {
 		user = container.Config.User

+ 2 - 1
daemon/exec_windows.go

@@ -1,11 +1,12 @@
 package daemon
 
 import (
+	"github.com/docker/docker/container"
 	"github.com/docker/docker/daemon/execdriver"
 	"github.com/docker/docker/runconfig"
 )
 
 // setPlatformSpecificExecProcessConfig sets platform-specific fields in the
 // ProcessConfig structure. This is a no-op on Windows
-func setPlatformSpecificExecProcessConfig(config *runconfig.ExecConfig, container *Container, pc *execdriver.ProcessConfig) {
+func setPlatformSpecificExecProcessConfig(config *runconfig.ExecConfig, container *container.Container, pc *execdriver.ProcessConfig) {
 }

+ 3 - 2
daemon/export.go

@@ -3,6 +3,7 @@ package daemon
 import (
 	"io"
 
+	"github.com/docker/docker/container"
 	derr "github.com/docker/docker/errors"
 	"github.com/docker/docker/pkg/archive"
 	"github.com/docker/docker/pkg/ioutils"
@@ -29,13 +30,13 @@ func (daemon *Daemon) ContainerExport(name string, out io.Writer) error {
 	return nil
 }
 
-func (daemon *Daemon) containerExport(container *Container) (archive.Archive, error) {
+func (daemon *Daemon) containerExport(container *container.Container) (archive.Archive, error) {
 	if err := daemon.Mount(container); err != nil {
 		return nil, err
 	}
 
 	uidMaps, gidMaps := daemon.GetUIDGIDMaps()
-	archive, err := archive.TarWithOptions(container.basefs, &archive.TarOptions{
+	archive, err := archive.TarWithOptions(container.BaseFS, &archive.TarOptions{
 		Compression: archive.Uncompressed,
 		UIDMaps:     uidMaps,
 		GIDMaps:     gidMaps,

+ 4 - 2
daemon/history.go

@@ -2,11 +2,13 @@ package daemon
 
 import (
 	"sort"
+
+	"github.com/docker/docker/container"
 )
 
 // History is a convenience type for storing a list of containers,
 // ordered by creation date.
-type History []*Container
+type History []*container.Container
 
 func (history *History) Len() int {
 	return len(*history)
@@ -23,7 +25,7 @@ func (history *History) Swap(i, j int) {
 }
 
 // Add the given container to history.
-func (history *History) Add(container *Container) {
+func (history *History) Add(container *container.Container) {
 	*history = append(*history, container)
 }
 

+ 2 - 1
daemon/image_delete.go

@@ -6,6 +6,7 @@ import (
 
 	"github.com/docker/distribution/reference"
 	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/container"
 	derr "github.com/docker/docker/errors"
 	"github.com/docker/docker/image"
 	"github.com/docker/docker/pkg/stringid"
@@ -133,7 +134,7 @@ func isImageIDPrefix(imageID, possiblePrefix string) bool {
 
 // getContainerUsingImage returns a container that was created using the given
 // imageID. Returns nil if there is no such container.
-func (daemon *Daemon) getContainerUsingImage(imageID image.ID) *Container {
+func (daemon *Daemon) getContainerUsingImage(imageID image.ID) *container.Container {
 	for _, container := range daemon.List() {
 		if container.ImageID == imageID {
 			return container

+ 5 - 4
daemon/inspect.go

@@ -6,6 +6,7 @@ import (
 
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types/versions/v1p20"
+	"github.com/docker/docker/container"
 	"github.com/docker/docker/daemon/exec"
 	"github.com/docker/docker/daemon/network"
 	"github.com/docker/docker/layer"
@@ -85,7 +86,7 @@ func (daemon *Daemon) containerInspect120(name string) (*v1p20.ContainerJSON, er
 		MacAddress:      container.Config.MacAddress,
 		NetworkDisabled: container.Config.NetworkDisabled,
 		ExposedPorts:    container.Config.ExposedPorts,
-		VolumeDriver:    container.hostConfig.VolumeDriver,
+		VolumeDriver:    container.HostConfig.VolumeDriver,
 	}
 	networkSettings := daemon.getBackwardsCompatibleNetworkSettings(container.NetworkSettings)
 
@@ -97,9 +98,9 @@ func (daemon *Daemon) containerInspect120(name string) (*v1p20.ContainerJSON, er
 	}, nil
 }
 
-func (daemon *Daemon) getInspectData(container *Container, size bool) (*types.ContainerJSONBase, error) {
+func (daemon *Daemon) getInspectData(container *container.Container, size bool) (*types.ContainerJSONBase, error) {
 	// make a copy to play with
-	hostConfig := *container.hostConfig
+	hostConfig := *container.HostConfig
 
 	if children, err := daemon.children(container.Name); err == nil {
 		for linkAlias, child := range children {
@@ -143,7 +144,7 @@ func (daemon *Daemon) getInspectData(container *Container, size bool) (*types.Co
 		Driver:       container.Driver,
 		MountLabel:   container.MountLabel,
 		ProcessLabel: container.ProcessLabel,
-		ExecIDs:      container.getExecIDs(),
+		ExecIDs:      container.GetExecIDs(),
 		HostConfig:   &hostConfig,
 	}
 

+ 8 - 7
daemon/inspect_unix.go

@@ -5,10 +5,11 @@ package daemon
 import (
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types/versions/v1p19"
+	"github.com/docker/docker/container"
 )
 
 // This sets platform-specific fields
-func setPlatformSpecificContainerFields(container *Container, contJSONBase *types.ContainerJSONBase) *types.ContainerJSONBase {
+func setPlatformSpecificContainerFields(container *container.Container, contJSONBase *types.ContainerJSONBase) *types.ContainerJSONBase {
 	contJSONBase.AppArmorProfile = container.AppArmorProfile
 	contJSONBase.ResolvConfPath = container.ResolvConfPath
 	contJSONBase.HostnamePath = container.HostnamePath
@@ -44,11 +45,11 @@ func (daemon *Daemon) containerInspectPre120(name string) (*v1p19.ContainerJSON,
 		MacAddress:      container.Config.MacAddress,
 		NetworkDisabled: container.Config.NetworkDisabled,
 		ExposedPorts:    container.Config.ExposedPorts,
-		VolumeDriver:    container.hostConfig.VolumeDriver,
-		Memory:          container.hostConfig.Memory,
-		MemorySwap:      container.hostConfig.MemorySwap,
-		CPUShares:       container.hostConfig.CPUShares,
-		CPUSet:          container.hostConfig.CpusetCpus,
+		VolumeDriver:    container.HostConfig.VolumeDriver,
+		Memory:          container.HostConfig.Memory,
+		MemorySwap:      container.HostConfig.MemorySwap,
+		CPUShares:       container.HostConfig.CPUShares,
+		CPUSet:          container.HostConfig.CpusetCpus,
 	}
 	networkSettings := daemon.getBackwardsCompatibleNetworkSettings(container.NetworkSettings)
 
@@ -61,7 +62,7 @@ func (daemon *Daemon) containerInspectPre120(name string) (*v1p19.ContainerJSON,
 	}, nil
 }
 
-func addMountPoints(container *Container) []types.MountPoint {
+func addMountPoints(container *container.Container) []types.MountPoint {
 	mountPoints := make([]types.MountPoint, 0, len(container.MountPoints))
 	for _, m := range container.MountPoints {
 		mountPoints = append(mountPoints, types.MountPoint{

+ 6 - 3
daemon/inspect_windows.go

@@ -1,13 +1,16 @@
 package daemon
 
-import "github.com/docker/docker/api/types"
+import (
+	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/container"
+)
 
 // This sets platform-specific fields
-func setPlatformSpecificContainerFields(container *Container, contJSONBase *types.ContainerJSONBase) *types.ContainerJSONBase {
+func setPlatformSpecificContainerFields(container *container.Container, contJSONBase *types.ContainerJSONBase) *types.ContainerJSONBase {
 	return contJSONBase
 }
 
-func addMountPoints(container *Container) []types.MountPoint {
+func addMountPoints(container *container.Container) []types.MountPoint {
 	mountPoints := make([]types.MountPoint, 0, len(container.MountPoints))
 	for _, m := range container.MountPoints {
 		mountPoints = append(mountPoints, types.MountPoint{

+ 4 - 3
daemon/kill.go

@@ -7,6 +7,7 @@ import (
 	"time"
 
 	"github.com/Sirupsen/logrus"
+	"github.com/docker/docker/container"
 	derr "github.com/docker/docker/errors"
 	"github.com/docker/docker/pkg/signal"
 )
@@ -37,7 +38,7 @@ func (daemon *Daemon) ContainerKill(name string, sig uint64) error {
 // to send the signal. An error is returned if the container is paused
 // or not running, or if there is a problem returned from the
 // underlying kill command.
-func (daemon *Daemon) killWithSignal(container *Container, sig int) error {
+func (daemon *Daemon) killWithSignal(container *container.Container, sig int) error {
 	logrus.Debugf("Sending %d to %s", sig, container.ID)
 	container.Lock()
 	defer container.Unlock()
@@ -69,7 +70,7 @@ func (daemon *Daemon) killWithSignal(container *Container, sig int) error {
 }
 
 // Kill forcefully terminates a container.
-func (daemon *Daemon) Kill(container *Container) error {
+func (daemon *Daemon) Kill(container *container.Container) error {
 	if !container.IsRunning() {
 		return derr.ErrorCodeNotRunning.WithArgs(container.ID)
 	}
@@ -105,7 +106,7 @@ func (daemon *Daemon) Kill(container *Container) error {
 }
 
 // killPossibleDeadProcess is a wrapper aroung killSig() suppressing "no such process" error.
-func (daemon *Daemon) killPossiblyDeadProcess(container *Container, sig int) error {
+func (daemon *Daemon) killPossiblyDeadProcess(container *container.Container, sig int) error {
 	err := daemon.killWithSignal(container, sig)
 	if err == syscall.ESRCH {
 		logrus.Debugf("Cannot kill process (pid=%d) with signal %d: no such process.", container.GetPID(), sig)

+ 11 - 10
daemon/list.go

@@ -8,6 +8,7 @@ import (
 
 	"github.com/Sirupsen/logrus"
 	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/container"
 	"github.com/docker/docker/image"
 	"github.com/docker/docker/pkg/graphdb"
 	"github.com/docker/docker/pkg/nat"
@@ -19,7 +20,7 @@ type iterationAction int
 
 // containerReducer represents a reducer for a container.
 // Returns the object to serialize by the api.
-type containerReducer func(*Container, *listContext) (*types.Container, error)
+type containerReducer func(*container.Container, *listContext) (*types.Container, error)
 
 const (
 	// includeContainer is the action to include a container in the reducer.
@@ -34,7 +35,7 @@ const (
 var errStopIteration = errors.New("container list iteration stopped")
 
 // List returns an array of all containers registered in the daemon.
-func (daemon *Daemon) List() []*Container {
+func (daemon *Daemon) List() []*container.Container {
 	return daemon.containers.List()
 }
 
@@ -71,10 +72,10 @@ type listContext struct {
 	exitAllowed []int
 	// beforeFilter is a filter to ignore containers that appear before the one given
 	// this is used for --filter=before= and --before=, the latter is deprecated.
-	beforeFilter *Container
+	beforeFilter *container.Container
 	// sinceFilter is a filter to stop the filtering when the iterator arrive to the given container
 	// this is used for --filter=since= and --since=, the latter is deprecated.
-	sinceFilter *Container
+	sinceFilter *container.Container
 	// ContainersConfig is the filters set by the user
 	*ContainersConfig
 }
@@ -110,7 +111,7 @@ func (daemon *Daemon) reduceContainers(config *ContainersConfig, reducer contain
 }
 
 // reducePsContainer is the basic representation for a container as expected by the ps command.
-func (daemon *Daemon) reducePsContainer(container *Container, ctx *listContext, reducer containerReducer) (*types.Container, error) {
+func (daemon *Daemon) reducePsContainer(container *container.Container, ctx *listContext, reducer containerReducer) (*types.Container, error) {
 	container.Lock()
 	defer container.Unlock()
 
@@ -148,7 +149,7 @@ func (daemon *Daemon) foldFilter(config *ContainersConfig) (*listContext, error)
 	}
 
 	err = psFilters.WalkValues("status", func(value string) error {
-		if !isValidStateString(value) {
+		if !container.IsValidStateString(value) {
 			return fmt.Errorf("Unrecognised filter value for status: %s", value)
 		}
 
@@ -159,7 +160,7 @@ func (daemon *Daemon) foldFilter(config *ContainersConfig) (*listContext, error)
 		return nil, err
 	}
 
-	var beforeContFilter, sinceContFilter *Container
+	var beforeContFilter, sinceContFilter *container.Container
 	err = psFilters.WalkValues("before", func(value string) error {
 		beforeContFilter, err = daemon.Get(value)
 		return err
@@ -230,7 +231,7 @@ func (daemon *Daemon) foldFilter(config *ContainersConfig) (*listContext, error)
 
 // includeContainerInList decides whether a containers should be include in the output or not based in the filter.
 // It also decides if the iteration should be stopped or not.
-func includeContainerInList(container *Container, ctx *listContext) iterationAction {
+func includeContainerInList(container *container.Container, ctx *listContext) iterationAction {
 	// Do not include container if it's stopped and we're not filters
 	if !container.Running && !ctx.All && ctx.Limit <= 0 && ctx.beforeFilter == nil && ctx.sinceFilter == nil {
 		return excludeContainer
@@ -309,7 +310,7 @@ func includeContainerInList(container *Container, ctx *listContext) iterationAct
 }
 
 // transformContainer generates the container type expected by the docker ps command.
-func (daemon *Daemon) transformContainer(container *Container, ctx *listContext) (*types.Container, error) {
+func (daemon *Daemon) transformContainer(container *container.Container, ctx *listContext) (*types.Container, error) {
 	newC := &types.Container{
 		ID:      container.ID,
 		Names:   ctx.names[container.ID],
@@ -349,7 +350,7 @@ func (daemon *Daemon) transformContainer(container *Container, ctx *listContext)
 	}
 	newC.Created = container.Created.Unix()
 	newC.Status = container.State.String()
-	newC.HostConfig.NetworkMode = string(container.hostConfig.NetworkMode)
+	newC.HostConfig.NetworkMode = string(container.HostConfig.NetworkMode)
 
 	newC.Ports = []types.Port{}
 	for port, bindings := range container.NetworkSettings.Ports {

+ 3 - 1
daemon/list_unix.go

@@ -2,8 +2,10 @@
 
 package daemon
 
+import "github.com/docker/docker/container"
+
 // excludeByIsolation is a platform specific helper function to support PS
 // filtering by Isolation. This is a Windows-only concept, so is a no-op on Unix.
-func excludeByIsolation(container *Container, ctx *listContext) iterationAction {
+func excludeByIsolation(container *container.Container, ctx *listContext) iterationAction {
 	return includeContainer
 }

+ 7 - 3
daemon/list_windows.go

@@ -1,11 +1,15 @@
 package daemon
 
-import "strings"
+import (
+	"strings"
+
+	"github.com/docker/docker/container"
+)
 
 // excludeByIsolation is a platform specific helper function to support PS
 // filtering by Isolation. This is a Windows-only concept, so is a no-op on Unix.
-func excludeByIsolation(container *Container, ctx *listContext) iterationAction {
-	i := strings.ToLower(string(container.hostConfig.Isolation))
+func excludeByIsolation(container *container.Container, ctx *listContext) iterationAction {
+	i := strings.ToLower(string(container.HostConfig.Isolation))
 	if i == "" {
 		i = "default"
 	}

+ 9 - 8
daemon/logs.go

@@ -6,6 +6,7 @@ import (
 	"time"
 
 	"github.com/Sirupsen/logrus"
+	"github.com/docker/docker/container"
 	"github.com/docker/docker/daemon/logger"
 	"github.com/docker/docker/daemon/logger/jsonfilelog"
 	derr "github.com/docker/docker/errors"
@@ -99,11 +100,11 @@ func (daemon *Daemon) ContainerLogs(containerName string, config *ContainerLogsC
 	}
 }
 
-func (daemon *Daemon) getLogger(container *Container) (logger.Logger, error) {
-	if container.logDriver != nil && container.IsRunning() {
-		return container.logDriver, nil
+func (daemon *Daemon) getLogger(container *container.Container) (logger.Logger, error) {
+	if container.LogDriver != nil && container.IsRunning() {
+		return container.LogDriver, nil
 	}
-	cfg := container.getLogConfig(daemon.defaultLogConfig)
+	cfg := container.GetLogConfig(daemon.defaultLogConfig)
 	if err := logger.ValidateLogOpts(cfg.Type, cfg.Config); err != nil {
 		return nil, err
 	}
@@ -111,8 +112,8 @@ func (daemon *Daemon) getLogger(container *Container) (logger.Logger, error) {
 }
 
 // StartLogging initializes and starts the container logging stream.
-func (daemon *Daemon) StartLogging(container *Container) error {
-	cfg := container.getLogConfig(daemon.defaultLogConfig)
+func (daemon *Daemon) StartLogging(container *container.Container) error {
+	cfg := container.GetLogConfig(daemon.defaultLogConfig)
 	if cfg.Type == "none" {
 		return nil // do not start logging routines
 	}
@@ -126,9 +127,9 @@ func (daemon *Daemon) StartLogging(container *Container) error {
 	}
 
 	copier := logger.NewCopier(container.ID, map[string]io.Reader{"stdout": container.StdoutPipe(), "stderr": container.StderrPipe()}, l)
-	container.logCopier = copier
+	container.LogCopier = copier
 	copier.Run()
-	container.logDriver = l
+	container.LogDriver = l
 
 	// set LogPath field only for json-file logdriver
 	if jl, ok := l.(*jsonfilelog.JSONFileLogger); ok {

+ 3 - 2
daemon/mounts.go

@@ -3,11 +3,12 @@ package daemon
 import (
 	"strings"
 
+	"github.com/docker/docker/container"
 	derr "github.com/docker/docker/errors"
 	volumestore "github.com/docker/docker/volume/store"
 )
 
-func (daemon *Daemon) prepareMountPoints(container *Container) error {
+func (daemon *Daemon) prepareMountPoints(container *container.Container) error {
 	for _, config := range container.MountPoints {
 		if len(config.Driver) > 0 {
 			v, err := daemon.createVolume(config.Name, config.Driver, nil)
@@ -20,7 +21,7 @@ func (daemon *Daemon) prepareMountPoints(container *Container) error {
 	return nil
 }
 
-func (daemon *Daemon) removeMountPoints(container *Container, rm bool) error {
+func (daemon *Daemon) removeMountPoints(container *container.Container, rm bool) error {
 	var rmErrors []string
 	for _, m := range container.MountPoints {
 		if m.Volume == nil {

+ 1 - 1
daemon/network.go

@@ -144,7 +144,7 @@ func (daemon *Daemon) DisconnectContainerFromNetwork(containerName string, netwo
 	if err != nil {
 		return err
 	}
-	return container.DisconnectFromNetwork(network)
+	return daemon.DisconnectFromNetwork(container, network)
 }
 
 // GetNetworkDriverList returns the list of plugins drivers

+ 3 - 2
daemon/pause.go

@@ -1,6 +1,7 @@
 package daemon
 
 import (
+	"github.com/docker/docker/container"
 	derr "github.com/docker/docker/errors"
 )
 
@@ -20,7 +21,7 @@ func (daemon *Daemon) ContainerPause(name string) error {
 
 // containerPause pauses the container execution without stopping the process.
 // The execution can be resumed by calling containerUnpause.
-func (daemon *Daemon) containerPause(container *Container) error {
+func (daemon *Daemon) containerPause(container *container.Container) error {
 	container.Lock()
 	defer container.Unlock()
 
@@ -34,7 +35,7 @@ func (daemon *Daemon) containerPause(container *Container) error {
 		return derr.ErrorCodeAlreadyPaused.WithArgs(container.ID)
 	}
 
-	if err := daemon.execDriver.Pause(container.command); err != nil {
+	if err := daemon.execDriver.Pause(container.Command); err != nil {
 		return err
 	}
 	container.Paused = true

+ 5 - 7
daemon/rename.go

@@ -13,17 +13,15 @@ import (
 // reserved.
 func (daemon *Daemon) ContainerRename(oldName, newName string) error {
 	var (
-		err       error
-		sid       string
-		sb        libnetwork.Sandbox
-		container *Container
+		sid string
+		sb  libnetwork.Sandbox
 	)
 
 	if oldName == "" || newName == "" {
 		return derr.ErrorCodeEmptyRename
 	}
 
-	container, err = daemon.Get(oldName)
+	container, err := daemon.Get(oldName)
 	if err != nil {
 		return err
 	}
@@ -50,7 +48,7 @@ func (daemon *Daemon) ContainerRename(oldName, newName string) error {
 		return derr.ErrorCodeRenameDelete.WithArgs(oldName, err)
 	}
 
-	if err = container.toDisk(); err != nil {
+	if err = container.ToDisk(); err != nil {
 		return err
 	}
 
@@ -62,7 +60,7 @@ func (daemon *Daemon) ContainerRename(oldName, newName string) error {
 	defer func() {
 		if err != nil {
 			container.Name = oldName
-			if e := container.toDisk(); e != nil {
+			if e := container.ToDisk(); e != nil {
 				logrus.Errorf("%s: Failed in writing to Disk on rename failure: %v", container.ID, e)
 			}
 		}

+ 2 - 1
daemon/restart.go

@@ -1,6 +1,7 @@
 package daemon
 
 import (
+	"github.com/docker/docker/container"
 	derr "github.com/docker/docker/errors"
 )
 
@@ -25,7 +26,7 @@ func (daemon *Daemon) ContainerRestart(name string, seconds int) error {
 // container. When stopping, wait for the given duration in seconds to
 // gracefully stop, before forcefully terminating the container. If
 // given a negative duration, wait forever for a graceful stop.
-func (daemon *Daemon) containerRestart(container *Container, seconds int) error {
+func (daemon *Daemon) containerRestart(container *container.Container, seconds int) error {
 	// Avoid unnecessarily unmounting and then directly mounting
 	// the container when the container stops and then starts
 	// again

+ 22 - 32
daemon/start.go

@@ -4,8 +4,8 @@ import (
 	"runtime"
 
 	"github.com/Sirupsen/logrus"
+	"github.com/docker/docker/container"
 	derr "github.com/docker/docker/errors"
-	"github.com/docker/docker/pkg/promise"
 	"github.com/docker/docker/runconfig"
 )
 
@@ -16,7 +16,7 @@ func (daemon *Daemon) ContainerStart(name string, hostConfig *runconfig.HostConf
 		return err
 	}
 
-	if container.isPaused() {
+	if container.IsPaused() {
 		return derr.ErrorCodeStartPaused
 	}
 
@@ -42,7 +42,7 @@ func (daemon *Daemon) ContainerStart(name string, hostConfig *runconfig.HostConf
 			if err := daemon.setHostConfig(container, hostConfig); err != nil {
 				return err
 			}
-			initDNSHostConfig(container)
+			container.InitDNSHostConfig()
 		}
 	} else {
 		if hostConfig != nil {
@@ -52,7 +52,7 @@ func (daemon *Daemon) ContainerStart(name string, hostConfig *runconfig.HostConf
 
 	// check if hostConfig is in line with the current system settings.
 	// It may happen cgroups are umounted or the like.
-	if _, err = daemon.verifyContainerSettings(container.hostConfig, nil); err != nil {
+	if _, err = daemon.verifyContainerSettings(container.HostConfig, nil); err != nil {
 		return err
 	}
 
@@ -64,7 +64,7 @@ func (daemon *Daemon) ContainerStart(name string, hostConfig *runconfig.HostConf
 }
 
 // Start starts a container
-func (daemon *Daemon) Start(container *Container) error {
+func (daemon *Daemon) Start(container *container.Container) error {
 	return daemon.containerStart(container)
 }
 
@@ -72,7 +72,7 @@ func (daemon *Daemon) Start(container *Container) error {
 // container needs, such as storage and networking, as well as links
 // between containers. The container is left waiting for a signal to
 // begin running.
-func (daemon *Daemon) containerStart(container *Container) (err error) {
+func (daemon *Daemon) containerStart(container *container.Container) (err error) {
 	container.Lock()
 	defer container.Unlock()
 
@@ -80,7 +80,7 @@ func (daemon *Daemon) containerStart(container *Container) (err error) {
 		return nil
 	}
 
-	if container.removalInProgress || container.Dead {
+	if container.RemovalInProgress || container.Dead {
 		return derr.ErrorCodeContainerBeingRemoved
 	}
 
@@ -88,12 +88,12 @@ func (daemon *Daemon) containerStart(container *Container) (err error) {
 	// setup has been cleaned up properly
 	defer func() {
 		if err != nil {
-			container.setError(err)
+			container.SetError(err)
 			// if no one else has set it, make sure we don't leave it at zero
 			if container.ExitCode == 0 {
 				container.ExitCode = 128
 			}
-			container.toDisk()
+			container.ToDisk()
 			daemon.Cleanup(container)
 			daemon.LogContainerEvent(container, "die")
 		}
@@ -105,7 +105,7 @@ func (daemon *Daemon) containerStart(container *Container) (err error) {
 
 	// Make sure NetworkMode has an acceptable value. We do this to ensure
 	// backwards API compatibility.
-	container.hostConfig = runconfig.SetDefaultNetModeIfBlank(container.hostConfig)
+	container.HostConfig = runconfig.SetDefaultNetModeIfBlank(container.HostConfig)
 
 	if err := daemon.initializeNetworking(container); err != nil {
 		return err
@@ -114,15 +114,15 @@ func (daemon *Daemon) containerStart(container *Container) (err error) {
 	if err != nil {
 		return err
 	}
-	if err := container.setupWorkingDirectory(); err != nil {
+	if err := container.SetupWorkingDirectory(); err != nil {
 		return err
 	}
-	env := container.createDaemonEnvironment(linkedEnv)
+	env := container.CreateDaemonEnvironment(linkedEnv)
 	if err := daemon.populateCommand(container, env); err != nil {
 		return err
 	}
 
-	if !container.hostConfig.IpcMode.IsContainer() && !container.hostConfig.IpcMode.IsHost() {
+	if !container.HostConfig.IpcMode.IsContainer() && !container.HostConfig.IpcMode.IsHost() {
 		if err := daemon.setupIpcDirs(container); err != nil {
 			return err
 		}
@@ -132,10 +132,10 @@ func (daemon *Daemon) containerStart(container *Container) (err error) {
 	if err != nil {
 		return err
 	}
-	mounts = append(mounts, container.ipcMounts()...)
-	mounts = append(mounts, container.tmpfsMounts()...)
+	mounts = append(mounts, container.IpcMounts()...)
+	mounts = append(mounts, container.TmpfsMounts()...)
 
-	container.command.Mounts = mounts
+	container.Command.Mounts = mounts
 	if err := daemon.waitForStart(container); err != nil {
 		return err
 	}
@@ -143,34 +143,24 @@ func (daemon *Daemon) containerStart(container *Container) (err error) {
 	return nil
 }
 
-func (daemon *Daemon) waitForStart(container *Container) error {
-	container.monitor = daemon.newContainerMonitor(container, container.hostConfig.RestartPolicy)
-
-	// block until we either receive an error from the initial start of the container's
-	// process or until the process is running in the container
-	select {
-	case <-container.monitor.startSignal:
-	case err := <-promise.Go(container.monitor.Start):
-		return err
-	}
-
-	return nil
+func (daemon *Daemon) waitForStart(container *container.Container) error {
+	return container.StartMonitor(daemon, container.HostConfig.RestartPolicy)
 }
 
 // Cleanup releases any network resources allocated to the container along with any rules
 // around how containers are linked together.  It also unmounts the container's root filesystem.
-func (daemon *Daemon) Cleanup(container *Container) {
+func (daemon *Daemon) Cleanup(container *container.Container) {
 	daemon.releaseNetwork(container)
 
-	container.unmountIpcMounts(detachMounted)
+	container.UnmountIpcMounts(detachMounted)
 
 	daemon.conditionalUnmountOnCleanup(container)
 
-	for _, eConfig := range container.execCommands.Commands() {
+	for _, eConfig := range container.ExecCommands.Commands() {
 		daemon.unregisterExecCommand(container, eConfig)
 	}
 
-	if err := container.unmountVolumes(false); err != nil {
+	if err := container.UnmountVolumes(false); err != nil {
 		logrus.Warnf("%s cleanup: Failed to umount volumes: %v", container.ID, err)
 	}
 }

+ 8 - 7
daemon/stats_collector_unix.go

@@ -11,6 +11,7 @@ import (
 	"time"
 
 	"github.com/Sirupsen/logrus"
+	"github.com/docker/docker/container"
 	"github.com/docker/docker/daemon/execdriver"
 	derr "github.com/docker/docker/errors"
 	"github.com/docker/docker/pkg/pubsub"
@@ -19,7 +20,7 @@ import (
 
 type statsSupervisor interface {
 	// GetContainerStats collects all the stats related to a container
-	GetContainerStats(container *Container) (*execdriver.ResourceStats, error)
+	GetContainerStats(container *container.Container) (*execdriver.ResourceStats, error)
 }
 
 // newStatsCollector returns a new statsCollector that collections
@@ -30,7 +31,7 @@ func (daemon *Daemon) newStatsCollector(interval time.Duration) *statsCollector
 	s := &statsCollector{
 		interval:            interval,
 		supervisor:          daemon,
-		publishers:          make(map[*Container]*pubsub.Publisher),
+		publishers:          make(map[*container.Container]*pubsub.Publisher),
 		clockTicksPerSecond: uint64(system.GetClockTicks()),
 		bufReader:           bufio.NewReaderSize(nil, 128),
 	}
@@ -44,14 +45,14 @@ type statsCollector struct {
 	supervisor          statsSupervisor
 	interval            time.Duration
 	clockTicksPerSecond uint64
-	publishers          map[*Container]*pubsub.Publisher
+	publishers          map[*container.Container]*pubsub.Publisher
 	bufReader           *bufio.Reader
 }
 
 // collect registers the container with the collector and adds it to
 // the event loop for collection on the specified interval returning
 // a channel for the subscriber to receive on.
-func (s *statsCollector) collect(c *Container) chan interface{} {
+func (s *statsCollector) collect(c *container.Container) chan interface{} {
 	s.m.Lock()
 	defer s.m.Unlock()
 	publisher, exists := s.publishers[c]
@@ -64,7 +65,7 @@ func (s *statsCollector) collect(c *Container) chan interface{} {
 
 // stopCollection closes the channels for all subscribers and removes
 // the container from metrics collection.
-func (s *statsCollector) stopCollection(c *Container) {
+func (s *statsCollector) stopCollection(c *container.Container) {
 	s.m.Lock()
 	if publisher, exists := s.publishers[c]; exists {
 		publisher.Close()
@@ -74,7 +75,7 @@ func (s *statsCollector) stopCollection(c *Container) {
 }
 
 // unsubscribe removes a specific subscriber from receiving updates for a container's stats.
-func (s *statsCollector) unsubscribe(c *Container, ch chan interface{}) {
+func (s *statsCollector) unsubscribe(c *container.Container, ch chan interface{}) {
 	s.m.Lock()
 	publisher := s.publishers[c]
 	if publisher != nil {
@@ -88,7 +89,7 @@ func (s *statsCollector) unsubscribe(c *Container, ch chan interface{}) {
 
 func (s *statsCollector) run() {
 	type publishersPair struct {
-		container *Container
+		container *container.Container
 		publisher *pubsub.Publisher
 	}
 	// we cannot determine the capacity here.

+ 8 - 4
daemon/stats_collector_windows.go

@@ -1,6 +1,10 @@
 package daemon
 
-import "time"
+import (
+	"time"
+
+	"github.com/docker/docker/container"
+)
 
 // newStatsCollector returns a new statsCollector for collection stats
 // for a registered container at the specified interval. The collector allows
@@ -17,15 +21,15 @@ type statsCollector struct {
 // collect registers the container with the collector and adds it to
 // the event loop for collection on the specified interval returning
 // a channel for the subscriber to receive on.
-func (s *statsCollector) collect(c *Container) chan interface{} {
+func (s *statsCollector) collect(c *container.Container) chan interface{} {
 	return nil
 }
 
 // stopCollection closes the channels for all subscribers and removes
 // the container from metrics collection.
-func (s *statsCollector) stopCollection(c *Container) {
+func (s *statsCollector) stopCollection(c *container.Container) {
 }
 
 // unsubscribe removes a specific subscriber from receiving updates for a container's stats.
-func (s *statsCollector) unsubscribe(c *Container, ch chan interface{}) {
+func (s *statsCollector) unsubscribe(c *container.Container, ch chan interface{}) {
 }

+ 3 - 2
daemon/stop.go

@@ -4,6 +4,7 @@ import (
 	"time"
 
 	"github.com/Sirupsen/logrus"
+	"github.com/docker/docker/container"
 	derr "github.com/docker/docker/errors"
 )
 
@@ -32,13 +33,13 @@ func (daemon *Daemon) ContainerStop(name string, seconds int) error {
 // process to exit. If a negative duration is given, Stop will wait
 // for the initial signal forever. If the container is not running Stop returns
 // immediately.
-func (daemon *Daemon) containerStop(container *Container, seconds int) error {
+func (daemon *Daemon) containerStop(container *container.Container, seconds int) error {
 	if !container.IsRunning() {
 		return nil
 	}
 
 	// 1. Send a SIGTERM
-	if err := daemon.killPossiblyDeadProcess(container, container.stopSignal()); err != nil {
+	if err := daemon.killPossiblyDeadProcess(container, container.StopSignal()); err != nil {
 		logrus.Infof("Failed to send SIGTERM to the process, force killing")
 		if err := daemon.killPossiblyDeadProcess(container, 9); err != nil {
 			return err

+ 3 - 2
daemon/unpause.go

@@ -1,6 +1,7 @@
 package daemon
 
 import (
+	"github.com/docker/docker/container"
 	derr "github.com/docker/docker/errors"
 )
 
@@ -19,7 +20,7 @@ func (daemon *Daemon) ContainerUnpause(name string) error {
 }
 
 // containerUnpause resumes the container execution after the container is paused.
-func (daemon *Daemon) containerUnpause(container *Container) error {
+func (daemon *Daemon) containerUnpause(container *container.Container) error {
 	container.Lock()
 	defer container.Unlock()
 
@@ -33,7 +34,7 @@ func (daemon *Daemon) containerUnpause(container *Container) error {
 		return derr.ErrorCodeNotPaused.WithArgs(container.ID)
 	}
 
-	if err := daemon.execDriver.Unpause(container.command); err != nil {
+	if err := daemon.execDriver.Unpause(container.Command); err != nil {
 		return err
 	}
 

+ 2 - 1
daemon/volumes.go

@@ -7,6 +7,7 @@ import (
 	"strings"
 
 	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/container"
 	"github.com/docker/docker/daemon/execdriver"
 	derr "github.com/docker/docker/errors"
 	"github.com/docker/docker/runconfig"
@@ -70,7 +71,7 @@ func (m mounts) parts(i int) int {
 // 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.
 // 4. Cleanup old volumes that are about to be reasigned.
-func (daemon *Daemon) registerMountPoints(container *Container, hostConfig *runconfig.HostConfig) error {
+func (daemon *Daemon) registerMountPoints(container *container.Container, hostConfig *runconfig.HostConfig) error {
 	binds := map[string]bool{}
 	mountPoints := map[string]*volume.MountPoint{}
 

+ 4 - 43
daemon/volumes_unix.go

@@ -3,66 +3,27 @@
 package daemon
 
 import (
-	"io/ioutil"
 	"os"
 	"sort"
 
+	"github.com/docker/docker/container"
 	"github.com/docker/docker/daemon/execdriver"
-	"github.com/docker/docker/pkg/chrootarchive"
-	"github.com/docker/docker/pkg/system"
 	"github.com/docker/docker/volume"
 	volumedrivers "github.com/docker/docker/volume/drivers"
 	"github.com/docker/docker/volume/local"
 )
 
-// copyExistingContents copies from the source to the destination and
-// ensures the ownership is appropriately set.
-func copyExistingContents(source, destination string) error {
-	volList, err := ioutil.ReadDir(source)
-	if err != nil {
-		return err
-	}
-	if len(volList) > 0 {
-		srcList, err := ioutil.ReadDir(destination)
-		if err != nil {
-			return err
-		}
-		if len(srcList) == 0 {
-			// If the source volume is empty copy files from the root into the volume
-			if err := chrootarchive.CopyWithTar(source, destination); err != nil {
-				return err
-			}
-		}
-	}
-	return copyOwnership(source, destination)
-}
-
-// copyOwnership copies the permissions and uid:gid of the source file
-// to the destination file
-func copyOwnership(source, destination string) error {
-	stat, err := system.Stat(source)
-	if err != nil {
-		return err
-	}
-
-	if err := os.Chown(destination, int(stat.UID()), int(stat.GID())); err != nil {
-		return err
-	}
-
-	return os.Chmod(destination, os.FileMode(stat.Mode()))
-}
-
 // setupMounts iterates through each of the mount points for a container and
 // calls Setup() on each. It also looks to see if is a network mount such as
 // /etc/resolv.conf, and if it is not, appends it to the array of mounts.
-func (daemon *Daemon) setupMounts(container *Container) ([]execdriver.Mount, error) {
+func (daemon *Daemon) setupMounts(container *container.Container) ([]execdriver.Mount, error) {
 	var mounts []execdriver.Mount
 	for _, m := range container.MountPoints {
 		path, err := m.Setup()
 		if err != nil {
 			return nil, err
 		}
-		if !container.trySetNetworkMount(m.Destination, path) {
+		if !container.TrySetNetworkMount(m.Destination, path) {
 			mounts = append(mounts, execdriver.Mount{
 				Source:      path,
 				Destination: m.Destination,
@@ -72,7 +33,7 @@ func (daemon *Daemon) setupMounts(container *Container) ([]execdriver.Mount, err
 	}
 
 	mounts = sortMounts(mounts)
-	netMounts := container.networkMounts()
+	netMounts := container.NetworkMounts()
 	// if we are going to mount any of the network files from container
 	// metadata, the ownership must be set properly for potential container
 	// remapped root (user namespaces)

+ 2 - 1
daemon/volumes_windows.go

@@ -5,6 +5,7 @@ package daemon
 import (
 	"sort"
 
+	"github.com/docker/docker/container"
 	"github.com/docker/docker/daemon/execdriver"
 	derr "github.com/docker/docker/errors"
 	"github.com/docker/docker/volume"
@@ -14,7 +15,7 @@ import (
 // of the configured mounts on the container to the execdriver mount structure
 // which will ultimately be passed into the exec driver during container creation.
 // It also ensures each of the mounts are lexographically sorted.
-func (daemon *Daemon) setupMounts(container *Container) ([]execdriver.Mount, error) {
+func (daemon *Daemon) setupMounts(container *container.Container) ([]execdriver.Mount, error) {
 	var mnts []execdriver.Mount
 	for _, mount := range container.MountPoints { // type is volume.MountPoint
 		// If there is no source, take it from the volume path

+ 1 - 1
opts/opts_windows.go

@@ -22,7 +22,7 @@ package opts
 // time="2015-11-06T13:38:37.259627400-08:00" level=debug msg="After createRootfs"
 // time="2015-11-06T13:38:37.263626300-08:00" level=debug msg="After setHostConfig"
 // time="2015-11-06T13:38:37.267631200-08:00" level=debug msg="before createContainerPl...."
-// time="2015-11-06T13:38:37.271629500-08:00" level=debug msg=toDiskLocking....
+// time="2015-11-06T13:38:37.271629500-08:00" level=debug msg=ToDiskLocking....
 // time="2015-11-06T13:38:37.275643200-08:00" level=debug msg="loggin event...."
 // time="2015-11-06T13:38:37.277627600-08:00" level=debug msg="logged event...."
 // time="2015-11-06T13:38:37.279631800-08:00" level=debug msg="In defer func"

Some files were not shown because too many files changed in this diff