mirror of
				https://github.com/moby/moby.git
				synced 2022-11-09 12:21:53 -05:00 
			
		
		
		
	Windows: Factoring out unused fields
Signed-off-by: John Howard <jhoward@microsoft.com>
This commit is contained in:
		
							parent
							
								
									33358f80e5
								
							
						
					
					
						commit
						47c56e4353
					
				
					 26 changed files with 649 additions and 544 deletions
				
			
		| 
						 | 
				
			
			@ -1205,12 +1205,8 @@ func (s *Server) getContainersByName(version version.Version, w http.ResponseWri
 | 
			
		|||
		return fmt.Errorf("Missing parameter")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if version.LessThan("1.20") {
 | 
			
		||||
		containerJSONRaw, err := s.daemon.ContainerInspectPre120(vars["name"])
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		return writeJSON(w, http.StatusOK, containerJSONRaw)
 | 
			
		||||
	if version.LessThan("1.20") && runtime.GOOS != "windows" {
 | 
			
		||||
		return getContainersByNameDownlevel(w, s, vars["name"])
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	containerJSON, err := s.daemon.ContainerInspect(vars["name"])
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -121,3 +121,13 @@ func adjustCpuShares(version version.Version, hostConfig *runconfig.HostConfig)
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// getContainersByNameDownlevel performs processing for pre 1.20 APIs. This
 | 
			
		||||
// is only relevant on non-Windows daemons.
 | 
			
		||||
func getContainersByNameDownlevel(w http.ResponseWriter, s *Server, namevar string) error {
 | 
			
		||||
	containerJSONRaw, err := s.daemon.ContainerInspectPre120(namevar)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return writeJSON(w, http.StatusOK, containerJSONRaw)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -60,3 +60,9 @@ func allocateDaemonPort(addr string) error {
 | 
			
		|||
 | 
			
		||||
func adjustCpuShares(version version.Version, hostConfig *runconfig.HostConfig) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// getContainersByNameDownlevel performs processing for pre 1.20 APIs. This
 | 
			
		||||
// is only relevant on non-Windows daemons.
 | 
			
		||||
func getContainersByNameDownlevel(w http.ResponseWriter, s *Server, namevar string) error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -250,7 +250,8 @@ type ContainerJSON struct {
 | 
			
		|||
	Config *runconfig.Config
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// backcompatibility struct along with ContainerConfig
 | 
			
		||||
// backcompatibility struct along with ContainerConfig. Note this is not
 | 
			
		||||
// used by the Windows daemon.
 | 
			
		||||
type ContainerJSONPre120 struct {
 | 
			
		||||
	*ContainerJSONBase
 | 
			
		||||
	Volumes   map[string]string
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,7 +17,7 @@ import (
 | 
			
		|||
// path does not refer to a directory.
 | 
			
		||||
var ErrExtractPointNotDirectory = errors.New("extraction point is not a directory")
 | 
			
		||||
 | 
			
		||||
// ContainerCopy performs a depracated operation of archiving the resource at
 | 
			
		||||
// ContainerCopy performs a deprecated operation of archiving the resource at
 | 
			
		||||
// the specified path in the conatiner identified by the given name.
 | 
			
		||||
func (daemon *Daemon) ContainerCopy(name string, res string) (io.ReadCloser, error) {
 | 
			
		||||
	container, err := daemon.Get(name)
 | 
			
		||||
| 
						 | 
				
			
			@ -25,7 +25,7 @@ func (daemon *Daemon) ContainerCopy(name string, res string) (io.ReadCloser, err
 | 
			
		|||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if res[0] == '/' {
 | 
			
		||||
	if res[0] == '/' || res[0] == '\\' {
 | 
			
		||||
		res = res[1:]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -90,7 +90,7 @@ func (container *Container) StatPath(path string) (stat *types.ContainerPathStat
 | 
			
		|||
	// Consider the given path as an absolute path in the container.
 | 
			
		||||
	absPath := path
 | 
			
		||||
	if !filepath.IsAbs(absPath) {
 | 
			
		||||
		absPath = archive.PreserveTrailingDotOrSeparator(filepath.Join("/", path), path)
 | 
			
		||||
		absPath = archive.PreserveTrailingDotOrSeparator(filepath.Join(string(os.PathSeparator), path), path)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resolvedPath, err := container.GetResourcePath(absPath)
 | 
			
		||||
| 
						 | 
				
			
			@ -157,7 +157,7 @@ func (container *Container) ArchivePath(path string) (content io.ReadCloser, sta
 | 
			
		|||
	// Consider the given path as an absolute path in the container.
 | 
			
		||||
	absPath := path
 | 
			
		||||
	if !filepath.IsAbs(absPath) {
 | 
			
		||||
		absPath = archive.PreserveTrailingDotOrSeparator(filepath.Join("/", path), path)
 | 
			
		||||
		absPath = archive.PreserveTrailingDotOrSeparator(filepath.Join(string(os.PathSeparator), path), path)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resolvedPath, err := container.GetResourcePath(absPath)
 | 
			
		||||
| 
						 | 
				
			
			@ -230,7 +230,7 @@ func (container *Container) ExtractToDir(path string, noOverwriteDirNonDir bool,
 | 
			
		|||
	// Consider the given path as an absolute path in the container.
 | 
			
		||||
	absPath := path
 | 
			
		||||
	if !filepath.IsAbs(absPath) {
 | 
			
		||||
		absPath = archive.PreserveTrailingDotOrSeparator(filepath.Join("/", path), path)
 | 
			
		||||
		absPath = archive.PreserveTrailingDotOrSeparator(filepath.Join(string(os.PathSeparator), path), path)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resolvedPath, err := container.GetResourcePath(absPath)
 | 
			
		||||
| 
						 | 
				
			
			@ -261,19 +261,14 @@ func (container *Container) ExtractToDir(path string, noOverwriteDirNonDir bool,
 | 
			
		|||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	absPath = filepath.Join("/", baseRel)
 | 
			
		||||
	absPath = filepath.Join(string(os.PathSeparator), baseRel)
 | 
			
		||||
 | 
			
		||||
	// Need to check if the path is in a volume. If it is, it cannot be in a
 | 
			
		||||
	// read-only volume. If it is not in a volume, the container cannot be
 | 
			
		||||
	// configured with a read-only rootfs.
 | 
			
		||||
	var toVolume bool
 | 
			
		||||
	for _, mnt := range container.MountPoints {
 | 
			
		||||
		if toVolume = mnt.hasResource(absPath); toVolume {
 | 
			
		||||
			if mnt.RW {
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
			return ErrVolumeReadonly
 | 
			
		||||
		}
 | 
			
		||||
	toVolume, err := checkIfPathIsInAVolume(container, absPath)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !toVolume && container.hostConfig.ReadonlyRootfs {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										19
									
								
								daemon/archive_unix.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								daemon/archive_unix.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,19 @@
 | 
			
		|||
// +build !windows
 | 
			
		||||
 | 
			
		||||
package daemon
 | 
			
		||||
 | 
			
		||||
// checkIfPathIsInAVolume checks if the path is in a volume. If it is, it
 | 
			
		||||
// cannot be in a read-only volume. If it  is not in a volume, the container
 | 
			
		||||
// cannot be configured with a read-only rootfs.
 | 
			
		||||
func checkIfPathIsInAVolume(container *Container, absPath string) (bool, error) {
 | 
			
		||||
	var toVolume bool
 | 
			
		||||
	for _, mnt := range container.MountPoints {
 | 
			
		||||
		if toVolume = mnt.hasResource(absPath); toVolume {
 | 
			
		||||
			if mnt.RW {
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
			return false, ErrVolumeReadonly
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return toVolume, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										10
									
								
								daemon/archive_windows.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								daemon/archive_windows.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,10 @@
 | 
			
		|||
package daemon
 | 
			
		||||
 | 
			
		||||
// checkIfPathIsInAVolume checks if the path is in a volume. If it is, it
 | 
			
		||||
// cannot be in a read-only volume. If it  is not in a volume, the container
 | 
			
		||||
// cannot be configured with a read-only rootfs.
 | 
			
		||||
//
 | 
			
		||||
// This is a no-op on Windows which does not support volumes.
 | 
			
		||||
func checkIfPathIsInAVolume(container *Container, absPath string) (bool, error) {
 | 
			
		||||
	return false, nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -17,11 +17,9 @@ type CommonConfig struct {
 | 
			
		|||
	AutoRestart    bool
 | 
			
		||||
	Bridge         bridgeConfig // Bridge holds bridge network specific configuration.
 | 
			
		||||
	Context        map[string][]string
 | 
			
		||||
	CorsHeaders    string
 | 
			
		||||
	DisableBridge  bool
 | 
			
		||||
	Dns            []string
 | 
			
		||||
	DnsSearch      []string
 | 
			
		||||
	EnableCors     bool
 | 
			
		||||
	ExecDriver     string
 | 
			
		||||
	ExecOptions    []string
 | 
			
		||||
	ExecRoot       string
 | 
			
		||||
| 
						 | 
				
			
			@ -51,8 +49,6 @@ func (config *Config) InstallCommonFlags(cmd *flag.FlagSet, usageFn func(string)
 | 
			
		|||
	cmd.StringVar(&config.GraphDriver, []string{"s", "-storage-driver"}, "", usageFn("Storage driver to use"))
 | 
			
		||||
	cmd.StringVar(&config.ExecDriver, []string{"e", "-exec-driver"}, defaultExec, usageFn("Exec driver to use"))
 | 
			
		||||
	cmd.IntVar(&config.Mtu, []string{"#mtu", "-mtu"}, 0, usageFn("Set the containers network MTU"))
 | 
			
		||||
	cmd.BoolVar(&config.EnableCors, []string{"#api-enable-cors", "#-api-enable-cors"}, false, usageFn("Enable CORS headers in the remote API, this is deprecated by --api-cors-header"))
 | 
			
		||||
	cmd.StringVar(&config.CorsHeaders, []string{"-api-cors-header"}, "", usageFn("Set CORS headers in the remote API"))
 | 
			
		||||
	// FIXME: why the inconsistency between "hosts" and "sockets"?
 | 
			
		||||
	cmd.Var(opts.NewListOptsRef(&config.Dns, opts.ValidateIPAddress), []string{"#dns", "-dns"}, usageFn("DNS server to use"))
 | 
			
		||||
	cmd.Var(opts.NewListOptsRef(&config.DnsSearch, opts.ValidateDNSSearch), []string{"-dns-search"}, usageFn("DNS search domains to use"))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,6 +22,8 @@ type Config struct {
 | 
			
		|||
 | 
			
		||||
	// Fields below here are platform specific.
 | 
			
		||||
 | 
			
		||||
	CorsHeaders          string
 | 
			
		||||
	EnableCors           bool
 | 
			
		||||
	EnableSelinuxSupport bool
 | 
			
		||||
	SocketGroup          string
 | 
			
		||||
	Ulimits              map[string]*ulimit.Ulimit
 | 
			
		||||
| 
						 | 
				
			
			@ -71,6 +73,8 @@ func (config *Config) InstallFlags(cmd *flag.FlagSet, usageFn func(string) strin
 | 
			
		|||
	cmd.BoolVar(&config.Bridge.InterContainerCommunication, []string{"#icc", "-icc"}, true, usageFn("Enable inter-container communication"))
 | 
			
		||||
	cmd.Var(opts.NewIpOpt(&config.Bridge.DefaultIP, "0.0.0.0"), []string{"#ip", "-ip"}, usageFn("Default IP when binding container ports"))
 | 
			
		||||
	cmd.BoolVar(&config.Bridge.EnableUserlandProxy, []string{"-userland-proxy"}, true, usageFn("Use userland proxy for loopback traffic"))
 | 
			
		||||
	cmd.BoolVar(&config.EnableCors, []string{"#api-enable-cors", "#-api-enable-cors"}, false, usageFn("Enable CORS headers in the remote API, this is deprecated by --api-cors-header"))
 | 
			
		||||
	cmd.StringVar(&config.CorsHeaders, []string{"-api-cors-header"}, "", usageFn("Set CORS headers in the remote API"))
 | 
			
		||||
 | 
			
		||||
	config.attachExperimentalFlags(cmd, usageFn)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -64,28 +64,18 @@ type CommonContainer struct {
 | 
			
		|||
	Config                   *runconfig.Config
 | 
			
		||||
	ImageID                  string `json:"Image"`
 | 
			
		||||
	NetworkSettings          *network.Settings
 | 
			
		||||
	ResolvConfPath           string
 | 
			
		||||
	HostnamePath             string
 | 
			
		||||
	HostsPath                string
 | 
			
		||||
	LogPath                  string
 | 
			
		||||
	Name                     string
 | 
			
		||||
	Driver                   string
 | 
			
		||||
	ExecDriver               string
 | 
			
		||||
	MountLabel, ProcessLabel string
 | 
			
		||||
	RestartCount             int
 | 
			
		||||
	UpdateDns                bool
 | 
			
		||||
	HasBeenStartedBefore     bool
 | 
			
		||||
 | 
			
		||||
	MountPoints map[string]*mountPoint
 | 
			
		||||
	Volumes     map[string]string // Deprecated since 1.7, kept for backwards compatibility
 | 
			
		||||
	VolumesRW   map[string]bool   // Deprecated since 1.7, kept for backwards compatibility
 | 
			
		||||
 | 
			
		||||
	hostConfig *runconfig.HostConfig
 | 
			
		||||
	command    *execdriver.Command
 | 
			
		||||
 | 
			
		||||
	monitor      *containerMonitor
 | 
			
		||||
	execCommands *execStore
 | 
			
		||||
	daemon       *Daemon
 | 
			
		||||
	hostConfig               *runconfig.HostConfig
 | 
			
		||||
	command                  *execdriver.Command
 | 
			
		||||
	monitor                  *containerMonitor
 | 
			
		||||
	execCommands             *execStore
 | 
			
		||||
	daemon                   *Daemon
 | 
			
		||||
	// logDriver for closing
 | 
			
		||||
	logDriver logger.Logger
 | 
			
		||||
	logCopier *logger.Copier
 | 
			
		||||
| 
						 | 
				
			
			@ -1076,94 +1066,6 @@ func copyEscapable(dst io.Writer, src io.ReadCloser) (written int64, err error)
 | 
			
		|||
	return written, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (container *Container) networkMounts() []execdriver.Mount {
 | 
			
		||||
	var mounts []execdriver.Mount
 | 
			
		||||
	if container.ResolvConfPath != "" {
 | 
			
		||||
		label.SetFileLabel(container.ResolvConfPath, container.MountLabel)
 | 
			
		||||
		mounts = append(mounts, execdriver.Mount{
 | 
			
		||||
			Source:      container.ResolvConfPath,
 | 
			
		||||
			Destination: "/etc/resolv.conf",
 | 
			
		||||
			Writable:    !container.hostConfig.ReadonlyRootfs,
 | 
			
		||||
			Private:     true,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	if container.HostnamePath != "" {
 | 
			
		||||
		label.SetFileLabel(container.HostnamePath, container.MountLabel)
 | 
			
		||||
		mounts = append(mounts, execdriver.Mount{
 | 
			
		||||
			Source:      container.HostnamePath,
 | 
			
		||||
			Destination: "/etc/hostname",
 | 
			
		||||
			Writable:    !container.hostConfig.ReadonlyRootfs,
 | 
			
		||||
			Private:     true,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	if container.HostsPath != "" {
 | 
			
		||||
		label.SetFileLabel(container.HostsPath, container.MountLabel)
 | 
			
		||||
		mounts = append(mounts, execdriver.Mount{
 | 
			
		||||
			Source:      container.HostsPath,
 | 
			
		||||
			Destination: "/etc/hosts",
 | 
			
		||||
			Writable:    !container.hostConfig.ReadonlyRootfs,
 | 
			
		||||
			Private:     true,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	return mounts
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (container *Container) addBindMountPoint(name, source, destination string, rw bool) {
 | 
			
		||||
	container.MountPoints[destination] = &mountPoint{
 | 
			
		||||
		Name:        name,
 | 
			
		||||
		Source:      source,
 | 
			
		||||
		Destination: destination,
 | 
			
		||||
		RW:          rw,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (container *Container) addLocalMountPoint(name, destination string, rw bool) {
 | 
			
		||||
	container.MountPoints[destination] = &mountPoint{
 | 
			
		||||
		Name:        name,
 | 
			
		||||
		Driver:      volume.DefaultDriverName,
 | 
			
		||||
		Destination: destination,
 | 
			
		||||
		RW:          rw,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (container *Container) addMountPointWithVolume(destination string, vol volume.Volume, rw bool) {
 | 
			
		||||
	container.MountPoints[destination] = &mountPoint{
 | 
			
		||||
		Name:        vol.Name(),
 | 
			
		||||
		Driver:      vol.DriverName(),
 | 
			
		||||
		Destination: destination,
 | 
			
		||||
		RW:          rw,
 | 
			
		||||
		Volume:      vol,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (container *Container) isDestinationMounted(destination string) bool {
 | 
			
		||||
	return container.MountPoints[destination] != nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (container *Container) prepareMountPoints() error {
 | 
			
		||||
	for _, config := range container.MountPoints {
 | 
			
		||||
		if len(config.Driver) > 0 {
 | 
			
		||||
			v, err := createVolume(config.Name, config.Driver)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			config.Volume = v
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (container *Container) removeMountPoints() error {
 | 
			
		||||
	for _, m := range container.MountPoints {
 | 
			
		||||
		if m.Volume != nil {
 | 
			
		||||
			if err := removeVolume(m.Volume); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (container *Container) shouldRestart() bool {
 | 
			
		||||
	return container.hostConfig.RestartPolicy.Name == "always" ||
 | 
			
		||||
		(container.hostConfig.RestartPolicy.Name == "on-failure" && container.ExitCode != 0)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,12 +27,14 @@ import (
 | 
			
		|||
	"github.com/docker/docker/pkg/ulimit"
 | 
			
		||||
	"github.com/docker/docker/runconfig"
 | 
			
		||||
	"github.com/docker/docker/utils"
 | 
			
		||||
	"github.com/docker/docker/volume"
 | 
			
		||||
	"github.com/docker/libnetwork"
 | 
			
		||||
	"github.com/docker/libnetwork/netlabel"
 | 
			
		||||
	"github.com/docker/libnetwork/options"
 | 
			
		||||
	"github.com/docker/libnetwork/types"
 | 
			
		||||
	"github.com/opencontainers/runc/libcontainer/configs"
 | 
			
		||||
	"github.com/opencontainers/runc/libcontainer/devices"
 | 
			
		||||
	"github.com/opencontainers/runc/libcontainer/label"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const DefaultPathEnv = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
 | 
			
		||||
| 
						 | 
				
			
			@ -41,9 +43,15 @@ type Container struct {
 | 
			
		|||
	CommonContainer
 | 
			
		||||
 | 
			
		||||
	// Fields below here are platform specific.
 | 
			
		||||
 | 
			
		||||
	AppArmorProfile string
 | 
			
		||||
	activeLinks     map[string]*links.Link
 | 
			
		||||
	AppArmorProfile string
 | 
			
		||||
	HostnamePath    string
 | 
			
		||||
	HostsPath       string
 | 
			
		||||
	MountPoints     map[string]*mountPoint
 | 
			
		||||
	ResolvConfPath  string
 | 
			
		||||
	UpdateDns       bool
 | 
			
		||||
	Volumes         map[string]string // Deprecated since 1.7, kept for backwards compatibility
 | 
			
		||||
	VolumesRW       map[string]bool   // Deprecated since 1.7, kept for backwards compatibility
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func killProcessDirectly(container *Container) error {
 | 
			
		||||
| 
						 | 
				
			
			@ -1150,3 +1158,91 @@ func (container *Container) PrepareStorage() error {
 | 
			
		|||
func (container *Container) CleanupStorage() error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (container *Container) networkMounts() []execdriver.Mount {
 | 
			
		||||
	var mounts []execdriver.Mount
 | 
			
		||||
	if container.ResolvConfPath != "" {
 | 
			
		||||
		label.SetFileLabel(container.ResolvConfPath, container.MountLabel)
 | 
			
		||||
		mounts = append(mounts, execdriver.Mount{
 | 
			
		||||
			Source:      container.ResolvConfPath,
 | 
			
		||||
			Destination: "/etc/resolv.conf",
 | 
			
		||||
			Writable:    !container.hostConfig.ReadonlyRootfs,
 | 
			
		||||
			Private:     true,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	if container.HostnamePath != "" {
 | 
			
		||||
		label.SetFileLabel(container.HostnamePath, container.MountLabel)
 | 
			
		||||
		mounts = append(mounts, execdriver.Mount{
 | 
			
		||||
			Source:      container.HostnamePath,
 | 
			
		||||
			Destination: "/etc/hostname",
 | 
			
		||||
			Writable:    !container.hostConfig.ReadonlyRootfs,
 | 
			
		||||
			Private:     true,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	if container.HostsPath != "" {
 | 
			
		||||
		label.SetFileLabel(container.HostsPath, container.MountLabel)
 | 
			
		||||
		mounts = append(mounts, execdriver.Mount{
 | 
			
		||||
			Source:      container.HostsPath,
 | 
			
		||||
			Destination: "/etc/hosts",
 | 
			
		||||
			Writable:    !container.hostConfig.ReadonlyRootfs,
 | 
			
		||||
			Private:     true,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	return mounts
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (container *Container) addBindMountPoint(name, source, destination string, rw bool) {
 | 
			
		||||
	container.MountPoints[destination] = &mountPoint{
 | 
			
		||||
		Name:        name,
 | 
			
		||||
		Source:      source,
 | 
			
		||||
		Destination: destination,
 | 
			
		||||
		RW:          rw,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (container *Container) addLocalMountPoint(name, destination string, rw bool) {
 | 
			
		||||
	container.MountPoints[destination] = &mountPoint{
 | 
			
		||||
		Name:        name,
 | 
			
		||||
		Driver:      volume.DefaultDriverName,
 | 
			
		||||
		Destination: destination,
 | 
			
		||||
		RW:          rw,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (container *Container) addMountPointWithVolume(destination string, vol volume.Volume, rw bool) {
 | 
			
		||||
	container.MountPoints[destination] = &mountPoint{
 | 
			
		||||
		Name:        vol.Name(),
 | 
			
		||||
		Driver:      vol.DriverName(),
 | 
			
		||||
		Destination: destination,
 | 
			
		||||
		RW:          rw,
 | 
			
		||||
		Volume:      vol,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (container *Container) isDestinationMounted(destination string) bool {
 | 
			
		||||
	return container.MountPoints[destination] != nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (container *Container) prepareMountPoints() error {
 | 
			
		||||
	for _, config := range container.MountPoints {
 | 
			
		||||
		if len(config.Driver) > 0 {
 | 
			
		||||
			v, err := createVolume(config.Name, config.Driver)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			config.Volume = v
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (container *Container) removeMountPoints() error {
 | 
			
		||||
	for _, m := range container.MountPoints {
 | 
			
		||||
		if m.Volume != nil {
 | 
			
		||||
			if err := removeVolume(m.Volume); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,18 +22,6 @@ type Container struct {
 | 
			
		|||
	CommonContainer
 | 
			
		||||
 | 
			
		||||
	// Fields below here are platform specific.
 | 
			
		||||
 | 
			
		||||
	// TODO Windows. Further factoring out of unused fields will be necessary.
 | 
			
		||||
 | 
			
		||||
	// ---- START OF TEMPORARY DECLARATION ----
 | 
			
		||||
	// TODO Windows. Temporarily keeping fields in to assist in compilation
 | 
			
		||||
	// of the daemon on Windows without affecting many other files in a single
 | 
			
		||||
	// PR, thus making code review significantly harder. These lines will be
 | 
			
		||||
	// removed in subsequent PRs.
 | 
			
		||||
 | 
			
		||||
	AppArmorProfile string
 | 
			
		||||
	// ---- END OF TEMPORARY DECLARATION ----
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func killProcessDirectly(container *Container) error {
 | 
			
		||||
| 
						 | 
				
			
			@ -213,3 +201,13 @@ func (container *Container) CleanupStorage() error {
 | 
			
		|||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TODO Windows. This can be further factored out. Used in daemon.go
 | 
			
		||||
func (container *Container) prepareMountPoints() error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TODO Windows. This can be further factored out. Used in delete.go
 | 
			
		||||
func (container *Container) removeMountPoints() error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,15 +2,11 @@ package daemon
 | 
			
		|||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/Sirupsen/logrus"
 | 
			
		||||
	"github.com/docker/docker/graph"
 | 
			
		||||
	"github.com/docker/docker/image"
 | 
			
		||||
	"github.com/docker/docker/pkg/parsers"
 | 
			
		||||
	"github.com/docker/docker/pkg/stringid"
 | 
			
		||||
	"github.com/docker/docker/runconfig"
 | 
			
		||||
	"github.com/opencontainers/runc/libcontainer/label"
 | 
			
		||||
)
 | 
			
		||||
| 
						 | 
				
			
			@ -96,47 +92,10 @@ func (daemon *Daemon) Create(config *runconfig.Config, hostConfig *runconfig.Hos
 | 
			
		|||
	}
 | 
			
		||||
	defer container.Unmount()
 | 
			
		||||
 | 
			
		||||
	for spec := range config.Volumes {
 | 
			
		||||
		var (
 | 
			
		||||
			name, destination string
 | 
			
		||||
			parts             = strings.Split(spec, ":")
 | 
			
		||||
		)
 | 
			
		||||
		switch len(parts) {
 | 
			
		||||
		case 2:
 | 
			
		||||
			name, destination = parts[0], filepath.Clean(parts[1])
 | 
			
		||||
		default:
 | 
			
		||||
			name = stringid.GenerateRandomID()
 | 
			
		||||
			destination = filepath.Clean(parts[0])
 | 
			
		||||
		}
 | 
			
		||||
		// Skip volumes for which we already have something mounted on that
 | 
			
		||||
		// destination because of a --volume-from.
 | 
			
		||||
		if container.isDestinationMounted(destination) {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		path, err := container.GetResourcePath(destination)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		stat, err := os.Stat(path)
 | 
			
		||||
		if err == nil && !stat.IsDir() {
 | 
			
		||||
			return nil, nil, fmt.Errorf("cannot mount volume over existing file, file exists %s", path)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		v, err := createVolume(name, config.VolumeDriver)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, nil, err
 | 
			
		||||
		}
 | 
			
		||||
		if err := label.Relabel(v.Path(), container.MountLabel, "z"); err != nil {
 | 
			
		||||
			return nil, nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if err := container.copyImagePathContent(v, destination); err != nil {
 | 
			
		||||
			return nil, nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		container.addMountPointWithVolume(destination, v, true)
 | 
			
		||||
	if err := createContainerPlatformSpecificSettings(container, config); err != nil {
 | 
			
		||||
		return nil, nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := container.ToDisk(); err != nil {
 | 
			
		||||
		logrus.Errorf("Error saving new container to disk: %v", err)
 | 
			
		||||
		return nil, nil, err
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										60
									
								
								daemon/create_unix.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								daemon/create_unix.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,60 @@
 | 
			
		|||
// +build !windows
 | 
			
		||||
 | 
			
		||||
package daemon
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/docker/docker/pkg/stringid"
 | 
			
		||||
	"github.com/docker/docker/runconfig"
 | 
			
		||||
	"github.com/opencontainers/runc/libcontainer/label"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// createContainerPlatformSpecificSettings performs platform specific container create functionality
 | 
			
		||||
func createContainerPlatformSpecificSettings(container *Container, config *runconfig.Config) error {
 | 
			
		||||
	for spec := range config.Volumes {
 | 
			
		||||
		var (
 | 
			
		||||
			name, destination string
 | 
			
		||||
			parts             = strings.Split(spec, ":")
 | 
			
		||||
		)
 | 
			
		||||
		switch len(parts) {
 | 
			
		||||
		case 2:
 | 
			
		||||
			name, destination = parts[0], filepath.Clean(parts[1])
 | 
			
		||||
		default:
 | 
			
		||||
			name = stringid.GenerateRandomID()
 | 
			
		||||
			destination = filepath.Clean(parts[0])
 | 
			
		||||
		}
 | 
			
		||||
		// Skip volumes for which we already have something mounted on that
 | 
			
		||||
		// destination because of a --volume-from.
 | 
			
		||||
		if container.isDestinationMounted(destination) {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		path, err := container.GetResourcePath(destination)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		stat, err := os.Stat(path)
 | 
			
		||||
		if err == nil && !stat.IsDir() {
 | 
			
		||||
			return fmt.Errorf("cannot mount volume over existing file, file exists %s", path)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		v, err := createVolume(name, config.VolumeDriver)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		if err := label.Relabel(v.Path(), container.MountLabel, "z"); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if err := container.copyImagePathContent(v, destination); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		container.addMountPointWithVolume(destination, v, true)
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										10
									
								
								daemon/create_windows.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								daemon/create_windows.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,10 @@
 | 
			
		|||
package daemon
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/docker/docker/runconfig"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// createContainerPlatformSpecificSettings performs platform specific container create functionality
 | 
			
		||||
func createContainerPlatformSpecificSettings(container *Container, config *runconfig.Config) error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -144,19 +144,17 @@ func (daemon *Daemon) containerRoot(id string) string {
 | 
			
		|||
// Load reads the contents of a container from disk
 | 
			
		||||
// This is typically done at startup.
 | 
			
		||||
func (daemon *Daemon) load(id string) (*Container, error) {
 | 
			
		||||
	container := &Container{
 | 
			
		||||
		CommonContainer: daemon.newBaseContainer(id),
 | 
			
		||||
	}
 | 
			
		||||
	container := daemon.newBaseContainer(id)
 | 
			
		||||
 | 
			
		||||
	if err := container.FromDisk(); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if container.ID != id {
 | 
			
		||||
		return container, fmt.Errorf("Container %s is stored at %s", container.ID, id)
 | 
			
		||||
		return &container, fmt.Errorf("Container %s is stored at %s", container.ID, id)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return container, nil
 | 
			
		||||
	return &container, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Register makes a container object usable by the daemon as <container.ID>
 | 
			
		||||
| 
						 | 
				
			
			@ -478,11 +476,7 @@ func (daemon *Daemon) newContainer(name string, config *runconfig.Config, imgID
 | 
			
		|||
	base.Driver = daemon.driver.String()
 | 
			
		||||
	base.ExecDriver = daemon.execDriver.Name()
 | 
			
		||||
 | 
			
		||||
	container := &Container{
 | 
			
		||||
		CommonContainer: base,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return container, err
 | 
			
		||||
	return &base, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func GetFullContainerName(name string) (string, error) {
 | 
			
		||||
| 
						 | 
				
			
			@ -947,18 +941,6 @@ func (daemon *Daemon) setHostConfig(container *Container, hostConfig *runconfig.
 | 
			
		|||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (daemon *Daemon) newBaseContainer(id string) CommonContainer {
 | 
			
		||||
	return CommonContainer{
 | 
			
		||||
		ID:           id,
 | 
			
		||||
		State:        NewState(),
 | 
			
		||||
		MountPoints:  make(map[string]*mountPoint),
 | 
			
		||||
		Volumes:      make(map[string]string),
 | 
			
		||||
		VolumesRW:    make(map[string]bool),
 | 
			
		||||
		execCommands: newExecStore(),
 | 
			
		||||
		root:         daemon.containerRoot(id),
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func setDefaultMtu(config *Config) {
 | 
			
		||||
	// do nothing if the config does not have the default 0 value.
 | 
			
		||||
	if config.Mtu != 0 {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -539,3 +539,17 @@ func (daemon *Daemon) RegisterLinks(container *Container, hostConfig *runconfig.
 | 
			
		|||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (daemon *Daemon) newBaseContainer(id string) Container {
 | 
			
		||||
	return Container{
 | 
			
		||||
		CommonContainer: CommonContainer{
 | 
			
		||||
			ID:           id,
 | 
			
		||||
			State:        NewState(),
 | 
			
		||||
			execCommands: newExecStore(),
 | 
			
		||||
			root:         daemon.containerRoot(id),
 | 
			
		||||
		},
 | 
			
		||||
		MountPoints: make(map[string]*mountPoint),
 | 
			
		||||
		Volumes:     make(map[string]string),
 | 
			
		||||
		VolumesRW:   make(map[string]bool),
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -169,3 +169,14 @@ func (daemon *Daemon) RegisterLinks(container *Container, hostConfig *runconfig.
 | 
			
		|||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (daemon *Daemon) newBaseContainer(id string) Container {
 | 
			
		||||
	return Container{
 | 
			
		||||
		CommonContainer: CommonContainer{
 | 
			
		||||
			ID:           id,
 | 
			
		||||
			State:        NewState(),
 | 
			
		||||
			execCommands: newExecStore(),
 | 
			
		||||
			root:         daemon.containerRoot(id),
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,53 +21,11 @@ func (daemon *Daemon) ContainerInspect(name string) (*types.ContainerJSON, error
 | 
			
		|||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mountPoints := make([]types.MountPoint, 0, len(container.MountPoints))
 | 
			
		||||
	for _, m := range container.MountPoints {
 | 
			
		||||
		mountPoints = append(mountPoints, types.MountPoint{
 | 
			
		||||
			Name:        m.Name,
 | 
			
		||||
			Source:      m.Path(),
 | 
			
		||||
			Destination: m.Destination,
 | 
			
		||||
			Driver:      m.Driver,
 | 
			
		||||
			Mode:        m.Mode,
 | 
			
		||||
			RW:          m.RW,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	mountPoints := addMountPoints(container)
 | 
			
		||||
 | 
			
		||||
	return &types.ContainerJSON{base, mountPoints, container.Config}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (daemon *Daemon) ContainerInspectPre120(name string) (*types.ContainerJSONPre120, error) {
 | 
			
		||||
	container, err := daemon.Get(name)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	container.Lock()
 | 
			
		||||
	defer container.Unlock()
 | 
			
		||||
 | 
			
		||||
	base, err := daemon.getInspectData(container)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	volumes := make(map[string]string)
 | 
			
		||||
	volumesRW := make(map[string]bool)
 | 
			
		||||
	for _, m := range container.MountPoints {
 | 
			
		||||
		volumes[m.Destination] = m.Path()
 | 
			
		||||
		volumesRW[m.Destination] = m.RW
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	config := &types.ContainerConfig{
 | 
			
		||||
		container.Config,
 | 
			
		||||
		container.hostConfig.Memory,
 | 
			
		||||
		container.hostConfig.MemorySwap,
 | 
			
		||||
		container.hostConfig.CPUShares,
 | 
			
		||||
		container.hostConfig.CpusetCpus,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &types.ContainerJSONPre120{base, volumes, volumesRW, config}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (daemon *Daemon) getInspectData(container *Container) (*types.ContainerJSONBase, error) {
 | 
			
		||||
	// make a copy to play with
 | 
			
		||||
	hostConfig := *container.hostConfig
 | 
			
		||||
| 
						 | 
				
			
			@ -104,9 +62,6 @@ func (daemon *Daemon) getInspectData(container *Container) (*types.ContainerJSON
 | 
			
		|||
		State:           containerState,
 | 
			
		||||
		Image:           container.ImageID,
 | 
			
		||||
		NetworkSettings: container.NetworkSettings,
 | 
			
		||||
		ResolvConfPath:  container.ResolvConfPath,
 | 
			
		||||
		HostnamePath:    container.HostnamePath,
 | 
			
		||||
		HostsPath:       container.HostsPath,
 | 
			
		||||
		LogPath:         container.LogPath,
 | 
			
		||||
		Name:            container.Name,
 | 
			
		||||
		RestartCount:    container.RestartCount,
 | 
			
		||||
| 
						 | 
				
			
			@ -114,11 +69,13 @@ func (daemon *Daemon) getInspectData(container *Container) (*types.ContainerJSON
 | 
			
		|||
		ExecDriver:      container.ExecDriver,
 | 
			
		||||
		MountLabel:      container.MountLabel,
 | 
			
		||||
		ProcessLabel:    container.ProcessLabel,
 | 
			
		||||
		AppArmorProfile: container.AppArmorProfile,
 | 
			
		||||
		ExecIDs:         container.GetExecIDs(),
 | 
			
		||||
		HostConfig:      &hostConfig,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Now set any platform-specific fields
 | 
			
		||||
	contJSONBase = setPlatformSpecificContainerFields(container, contJSONBase)
 | 
			
		||||
 | 
			
		||||
	contJSONBase.GraphDriver.Name = container.Driver
 | 
			
		||||
	graphDriverData, err := daemon.driver.GetMetadata(container.ID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										62
									
								
								daemon/inspect_unix.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								daemon/inspect_unix.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,62 @@
 | 
			
		|||
// +build !windows
 | 
			
		||||
 | 
			
		||||
package daemon
 | 
			
		||||
 | 
			
		||||
import "github.com/docker/docker/api/types"
 | 
			
		||||
 | 
			
		||||
// This sets platform-specific fields
 | 
			
		||||
func setPlatformSpecificContainerFields(container *Container, contJSONBase *types.ContainerJSONBase) *types.ContainerJSONBase {
 | 
			
		||||
	contJSONBase.AppArmorProfile = container.AppArmorProfile
 | 
			
		||||
	contJSONBase.ResolvConfPath = container.ResolvConfPath
 | 
			
		||||
	contJSONBase.HostnamePath = container.HostnamePath
 | 
			
		||||
	contJSONBase.HostsPath = container.HostsPath
 | 
			
		||||
 | 
			
		||||
	return contJSONBase
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (daemon *Daemon) ContainerInspectPre120(name string) (*types.ContainerJSONPre120, error) {
 | 
			
		||||
	container, err := daemon.Get(name)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	container.Lock()
 | 
			
		||||
	defer container.Unlock()
 | 
			
		||||
 | 
			
		||||
	base, err := daemon.getInspectData(container)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	volumes := make(map[string]string)
 | 
			
		||||
	volumesRW := make(map[string]bool)
 | 
			
		||||
	for _, m := range container.MountPoints {
 | 
			
		||||
		volumes[m.Destination] = m.Path()
 | 
			
		||||
		volumesRW[m.Destination] = m.RW
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	config := &types.ContainerConfig{
 | 
			
		||||
		container.Config,
 | 
			
		||||
		container.hostConfig.Memory,
 | 
			
		||||
		container.hostConfig.MemorySwap,
 | 
			
		||||
		container.hostConfig.CPUShares,
 | 
			
		||||
		container.hostConfig.CpusetCpus,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &types.ContainerJSONPre120{base, volumes, volumesRW, config}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func addMountPoints(container *Container) []types.MountPoint {
 | 
			
		||||
	mountPoints := make([]types.MountPoint, 0, len(container.MountPoints))
 | 
			
		||||
	for _, m := range container.MountPoints {
 | 
			
		||||
		mountPoints = append(mountPoints, types.MountPoint{
 | 
			
		||||
			Name:        m.Name,
 | 
			
		||||
			Source:      m.Path(),
 | 
			
		||||
			Destination: m.Destination,
 | 
			
		||||
			Driver:      m.Driver,
 | 
			
		||||
			Mode:        m.Mode,
 | 
			
		||||
			RW:          m.RW,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	return mountPoints
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										12
									
								
								daemon/inspect_windows.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								daemon/inspect_windows.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,12 @@
 | 
			
		|||
package daemon
 | 
			
		||||
 | 
			
		||||
import "github.com/docker/docker/api/types"
 | 
			
		||||
 | 
			
		||||
// This sets platform-specific fields
 | 
			
		||||
func setPlatformSpecificContainerFields(container *Container, contJSONBase *types.ContainerJSONBase) *types.ContainerJSONBase {
 | 
			
		||||
	return contJSONBase
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func addMountPoints(container *Container) []types.MountPoint {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -8,20 +8,17 @@ import (
 | 
			
		|||
	"path/filepath"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/Sirupsen/logrus"
 | 
			
		||||
	"github.com/docker/docker/pkg/chrootarchive"
 | 
			
		||||
	"github.com/docker/docker/pkg/system"
 | 
			
		||||
	"github.com/docker/docker/runconfig"
 | 
			
		||||
	"github.com/docker/docker/volume"
 | 
			
		||||
	"github.com/docker/docker/volume/drivers"
 | 
			
		||||
	"github.com/docker/docker/volume/local"
 | 
			
		||||
	"github.com/opencontainers/runc/libcontainer/label"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ErrVolumeReadonly is used to signal an error when trying to copy data into
 | 
			
		||||
// a volume mount that is not writable.
 | 
			
		||||
var ErrVolumeReadonly = errors.New("mounted volume is marked read-only")
 | 
			
		||||
 | 
			
		||||
// TODO Windows. Further platform refactoring can still be done in volumes*.go
 | 
			
		||||
 | 
			
		||||
type mountPoint struct {
 | 
			
		||||
	Name        string
 | 
			
		||||
	Destination string
 | 
			
		||||
| 
						 | 
				
			
			@ -70,73 +67,6 @@ func (m *mountPoint) Path() string {
 | 
			
		|||
	return m.Source
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// BackwardsCompatible decides whether this mount point can be
 | 
			
		||||
// used in old versions of Docker or not.
 | 
			
		||||
// Only bind mounts and local volumes can be used in old versions of Docker.
 | 
			
		||||
func (m *mountPoint) BackwardsCompatible() bool {
 | 
			
		||||
	return len(m.Source) > 0 || m.Driver == volume.DefaultDriverName
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func parseBindMount(spec string, mountLabel string, config *runconfig.Config) (*mountPoint, error) {
 | 
			
		||||
	bind := &mountPoint{
 | 
			
		||||
		RW: true,
 | 
			
		||||
	}
 | 
			
		||||
	arr := strings.Split(spec, ":")
 | 
			
		||||
 | 
			
		||||
	switch len(arr) {
 | 
			
		||||
	case 2:
 | 
			
		||||
		bind.Destination = arr[1]
 | 
			
		||||
	case 3:
 | 
			
		||||
		bind.Destination = arr[1]
 | 
			
		||||
		mode := arr[2]
 | 
			
		||||
		isValid, isRw := volume.ValidateMountMode(mode)
 | 
			
		||||
		if !isValid {
 | 
			
		||||
			return nil, fmt.Errorf("invalid mode for volumes-from: %s", mode)
 | 
			
		||||
		}
 | 
			
		||||
		bind.RW = isRw
 | 
			
		||||
		// Mode field is used by SELinux to decide whether to apply label
 | 
			
		||||
		bind.Mode = mode
 | 
			
		||||
	default:
 | 
			
		||||
		return nil, fmt.Errorf("Invalid volume specification: %s", spec)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	name, source, err := parseVolumeSource(arr[0])
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(source) == 0 {
 | 
			
		||||
		bind.Driver = config.VolumeDriver
 | 
			
		||||
		if len(bind.Driver) == 0 {
 | 
			
		||||
			bind.Driver = volume.DefaultDriverName
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		bind.Source = filepath.Clean(source)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bind.Name = name
 | 
			
		||||
	bind.Destination = filepath.Clean(bind.Destination)
 | 
			
		||||
	return bind, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func parseVolumesFrom(spec string) (string, string, error) {
 | 
			
		||||
	if len(spec) == 0 {
 | 
			
		||||
		return "", "", fmt.Errorf("malformed volumes-from specification: %s", spec)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	specParts := strings.SplitN(spec, ":", 2)
 | 
			
		||||
	id := specParts[0]
 | 
			
		||||
	mode := "rw"
 | 
			
		||||
 | 
			
		||||
	if len(specParts) == 2 {
 | 
			
		||||
		mode = specParts[1]
 | 
			
		||||
		if isValid, _ := volume.ValidateMountMode(mode); !isValid {
 | 
			
		||||
			return "", "", fmt.Errorf("invalid mode for volumes-from: %s", mode)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return id, mode, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func copyExistingContents(source, destination string) error {
 | 
			
		||||
	volList, err := ioutil.ReadDir(source)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
| 
						 | 
				
			
			@ -156,211 +86,3 @@ func copyExistingContents(source, destination string) error {
 | 
			
		|||
	}
 | 
			
		||||
	return copyOwnership(source, destination)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// registerMountPoints initializes the container mount points with the configured volumes and bind mounts.
 | 
			
		||||
// It follows the next sequence to decide what to mount in each final destination:
 | 
			
		||||
//
 | 
			
		||||
// 1. Select the previously configured mount points for the containers, if any.
 | 
			
		||||
// 2. Select the volumes mounted from another containers. Overrides previously configured mount point destination.
 | 
			
		||||
// 3. Select the bind mounts set by the client. Overrides previously configured mount point destinations.
 | 
			
		||||
func (daemon *Daemon) registerMountPoints(container *Container, hostConfig *runconfig.HostConfig) error {
 | 
			
		||||
	binds := map[string]bool{}
 | 
			
		||||
	mountPoints := map[string]*mountPoint{}
 | 
			
		||||
 | 
			
		||||
	// 1. Read already configured mount points.
 | 
			
		||||
	for name, point := range container.MountPoints {
 | 
			
		||||
		mountPoints[name] = point
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 2. Read volumes from other containers.
 | 
			
		||||
	for _, v := range hostConfig.VolumesFrom {
 | 
			
		||||
		containerID, mode, err := parseVolumesFrom(v)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		c, err := daemon.Get(containerID)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for _, m := range c.MountPoints {
 | 
			
		||||
			cp := &mountPoint{
 | 
			
		||||
				Name:        m.Name,
 | 
			
		||||
				Source:      m.Source,
 | 
			
		||||
				RW:          m.RW && volume.ReadWrite(mode),
 | 
			
		||||
				Driver:      m.Driver,
 | 
			
		||||
				Destination: m.Destination,
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if len(cp.Source) == 0 {
 | 
			
		||||
				v, err := createVolume(cp.Name, cp.Driver)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
				cp.Volume = v
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			mountPoints[cp.Destination] = cp
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 3. Read bind mounts
 | 
			
		||||
	for _, b := range hostConfig.Binds {
 | 
			
		||||
		// #10618
 | 
			
		||||
		bind, err := parseBindMount(b, container.MountLabel, container.Config)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if binds[bind.Destination] {
 | 
			
		||||
			return fmt.Errorf("Duplicate bind mount %s", bind.Destination)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if len(bind.Name) > 0 && len(bind.Driver) > 0 {
 | 
			
		||||
			// create the volume
 | 
			
		||||
			v, err := createVolume(bind.Name, bind.Driver)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			bind.Volume = v
 | 
			
		||||
			bind.Source = v.Path()
 | 
			
		||||
			// Since this is just a named volume and not a typical bind, set to shared mode `z`
 | 
			
		||||
			if bind.Mode == "" {
 | 
			
		||||
				bind.Mode = "z"
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if err := label.Relabel(bind.Source, container.MountLabel, bind.Mode); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		binds[bind.Destination] = true
 | 
			
		||||
		mountPoints[bind.Destination] = bind
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Keep backwards compatible structures
 | 
			
		||||
	bcVolumes := map[string]string{}
 | 
			
		||||
	bcVolumesRW := map[string]bool{}
 | 
			
		||||
	for _, m := range mountPoints {
 | 
			
		||||
		if m.BackwardsCompatible() {
 | 
			
		||||
			bcVolumes[m.Destination] = m.Path()
 | 
			
		||||
			bcVolumesRW[m.Destination] = m.RW
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	container.Lock()
 | 
			
		||||
	container.MountPoints = mountPoints
 | 
			
		||||
	container.Volumes = bcVolumes
 | 
			
		||||
	container.VolumesRW = bcVolumesRW
 | 
			
		||||
	container.Unlock()
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TODO Windows. Factor out as not relevant (as Windows daemon support not in pre-1.7)
 | 
			
		||||
// verifyVolumesInfo ports volumes configured for the containers pre docker 1.7.
 | 
			
		||||
// It reads the container configuration and creates valid mount points for the old volumes.
 | 
			
		||||
func (daemon *Daemon) verifyVolumesInfo(container *Container) error {
 | 
			
		||||
	// Inspect old structures only when we're upgrading from old versions
 | 
			
		||||
	// to versions >= 1.7 and the MountPoints has not been populated with volumes data.
 | 
			
		||||
	if len(container.MountPoints) == 0 && len(container.Volumes) > 0 {
 | 
			
		||||
		for destination, hostPath := range container.Volumes {
 | 
			
		||||
			vfsPath := filepath.Join(daemon.root, "vfs", "dir")
 | 
			
		||||
			rw := container.VolumesRW != nil && container.VolumesRW[destination]
 | 
			
		||||
 | 
			
		||||
			if strings.HasPrefix(hostPath, vfsPath) {
 | 
			
		||||
				id := filepath.Base(hostPath)
 | 
			
		||||
				if err := migrateVolume(id, hostPath); err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
				container.addLocalMountPoint(id, destination, rw)
 | 
			
		||||
			} else { // Bind mount
 | 
			
		||||
				id, source, err := parseVolumeSource(hostPath)
 | 
			
		||||
				// We should not find an error here coming
 | 
			
		||||
				// from the old configuration, but who knows.
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
				container.addBindMountPoint(id, source, destination, rw)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	} else if len(container.MountPoints) > 0 {
 | 
			
		||||
		// Volumes created with a Docker version >= 1.7. We verify integrity in case of data created
 | 
			
		||||
		// with Docker 1.7 RC versions that put the information in
 | 
			
		||||
		// DOCKER_ROOT/volumes/VOLUME_ID rather than DOCKER_ROOT/volumes/VOLUME_ID/_container_data.
 | 
			
		||||
		l, err := getVolumeDriver(volume.DefaultDriverName)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for _, m := range container.MountPoints {
 | 
			
		||||
			if m.Driver != volume.DefaultDriverName {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			dataPath := l.(*local.Root).DataPath(m.Name)
 | 
			
		||||
			volumePath := filepath.Dir(dataPath)
 | 
			
		||||
 | 
			
		||||
			d, err := ioutil.ReadDir(volumePath)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				// If the volume directory doesn't exist yet it will be recreated,
 | 
			
		||||
				// so we only return the error when there is a different issue.
 | 
			
		||||
				if !os.IsNotExist(err) {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
				// Do not check when the volume directory does not exist.
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			if validVolumeLayout(d) {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if err := os.Mkdir(dataPath, 0755); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// Move data inside the data directory
 | 
			
		||||
			for _, f := range d {
 | 
			
		||||
				oldp := filepath.Join(volumePath, f.Name())
 | 
			
		||||
				newp := filepath.Join(dataPath, f.Name())
 | 
			
		||||
				if err := os.Rename(oldp, newp); err != nil {
 | 
			
		||||
					logrus.Errorf("Unable to move %s to %s\n", oldp, newp)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return container.ToDisk()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func createVolume(name, driverName string) (volume.Volume, error) {
 | 
			
		||||
	vd, err := getVolumeDriver(driverName)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return vd.Create(name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func removeVolume(v volume.Volume) error {
 | 
			
		||||
	vd, err := getVolumeDriver(v.DriverName())
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	return vd.Remove(v)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getVolumeDriver(name string) (volume.Driver, error) {
 | 
			
		||||
	if name == "" {
 | 
			
		||||
		name = volume.DefaultDriverName
 | 
			
		||||
	}
 | 
			
		||||
	return volumedrivers.Lookup(name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func parseVolumeSource(spec string) (string, string, error) {
 | 
			
		||||
	if !filepath.IsAbs(spec) {
 | 
			
		||||
		return spec, "", nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return "", spec, nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,15 +3,21 @@
 | 
			
		|||
package daemon
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"sort"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/Sirupsen/logrus"
 | 
			
		||||
	"github.com/docker/docker/daemon/execdriver"
 | 
			
		||||
	"github.com/docker/docker/pkg/system"
 | 
			
		||||
	"github.com/docker/docker/runconfig"
 | 
			
		||||
	"github.com/docker/docker/volume"
 | 
			
		||||
	"github.com/docker/docker/volume/drivers"
 | 
			
		||||
	"github.com/docker/docker/volume/local"
 | 
			
		||||
	"github.com/opencontainers/runc/libcontainer/label"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// copyOwnership copies the permissions and uid:gid of the source file
 | 
			
		||||
| 
						 | 
				
			
			@ -49,6 +55,48 @@ func (container *Container) setupMounts() ([]execdriver.Mount, error) {
 | 
			
		|||
	return append(mounts, container.networkMounts()...), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func parseBindMount(spec string, mountLabel string, config *runconfig.Config) (*mountPoint, error) {
 | 
			
		||||
	bind := &mountPoint{
 | 
			
		||||
		RW: true,
 | 
			
		||||
	}
 | 
			
		||||
	arr := strings.Split(spec, ":")
 | 
			
		||||
 | 
			
		||||
	switch len(arr) {
 | 
			
		||||
	case 2:
 | 
			
		||||
		bind.Destination = arr[1]
 | 
			
		||||
	case 3:
 | 
			
		||||
		bind.Destination = arr[1]
 | 
			
		||||
		mode := arr[2]
 | 
			
		||||
		isValid, isRw := volume.ValidateMountMode(mode)
 | 
			
		||||
		if !isValid {
 | 
			
		||||
			return nil, fmt.Errorf("invalid mode for volumes-from: %s", mode)
 | 
			
		||||
		}
 | 
			
		||||
		bind.RW = isRw
 | 
			
		||||
		// Mode field is used by SELinux to decide whether to apply label
 | 
			
		||||
		bind.Mode = mode
 | 
			
		||||
	default:
 | 
			
		||||
		return nil, fmt.Errorf("Invalid volume specification: %s", spec)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	name, source, err := parseVolumeSource(arr[0])
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(source) == 0 {
 | 
			
		||||
		bind.Driver = config.VolumeDriver
 | 
			
		||||
		if len(bind.Driver) == 0 {
 | 
			
		||||
			bind.Driver = volume.DefaultDriverName
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		bind.Source = filepath.Clean(source)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bind.Name = name
 | 
			
		||||
	bind.Destination = filepath.Clean(bind.Destination)
 | 
			
		||||
	return bind, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func sortMounts(m []execdriver.Mount) []execdriver.Mount {
 | 
			
		||||
	sort.Sort(mounts(m))
 | 
			
		||||
	return m
 | 
			
		||||
| 
						 | 
				
			
			@ -118,3 +166,235 @@ func validVolumeLayout(files []os.FileInfo) bool {
 | 
			
		|||
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// verifyVolumesInfo ports volumes configured for the containers pre docker 1.7.
 | 
			
		||||
// It reads the container configuration and creates valid mount points for the old volumes.
 | 
			
		||||
func (daemon *Daemon) verifyVolumesInfo(container *Container) error {
 | 
			
		||||
	// Inspect old structures only when we're upgrading from old versions
 | 
			
		||||
	// to versions >= 1.7 and the MountPoints has not been populated with volumes data.
 | 
			
		||||
	if len(container.MountPoints) == 0 && len(container.Volumes) > 0 {
 | 
			
		||||
		for destination, hostPath := range container.Volumes {
 | 
			
		||||
			vfsPath := filepath.Join(daemon.root, "vfs", "dir")
 | 
			
		||||
			rw := container.VolumesRW != nil && container.VolumesRW[destination]
 | 
			
		||||
 | 
			
		||||
			if strings.HasPrefix(hostPath, vfsPath) {
 | 
			
		||||
				id := filepath.Base(hostPath)
 | 
			
		||||
				if err := migrateVolume(id, hostPath); err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
				container.addLocalMountPoint(id, destination, rw)
 | 
			
		||||
			} else { // Bind mount
 | 
			
		||||
				id, source, err := parseVolumeSource(hostPath)
 | 
			
		||||
				// We should not find an error here coming
 | 
			
		||||
				// from the old configuration, but who knows.
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
				container.addBindMountPoint(id, source, destination, rw)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	} else if len(container.MountPoints) > 0 {
 | 
			
		||||
		// Volumes created with a Docker version >= 1.7. We verify integrity in case of data created
 | 
			
		||||
		// with Docker 1.7 RC versions that put the information in
 | 
			
		||||
		// DOCKER_ROOT/volumes/VOLUME_ID rather than DOCKER_ROOT/volumes/VOLUME_ID/_container_data.
 | 
			
		||||
		l, err := getVolumeDriver(volume.DefaultDriverName)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for _, m := range container.MountPoints {
 | 
			
		||||
			if m.Driver != volume.DefaultDriverName {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			dataPath := l.(*local.Root).DataPath(m.Name)
 | 
			
		||||
			volumePath := filepath.Dir(dataPath)
 | 
			
		||||
 | 
			
		||||
			d, err := ioutil.ReadDir(volumePath)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				// If the volume directory doesn't exist yet it will be recreated,
 | 
			
		||||
				// so we only return the error when there is a different issue.
 | 
			
		||||
				if !os.IsNotExist(err) {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
				// Do not check when the volume directory does not exist.
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			if validVolumeLayout(d) {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if err := os.Mkdir(dataPath, 0755); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// Move data inside the data directory
 | 
			
		||||
			for _, f := range d {
 | 
			
		||||
				oldp := filepath.Join(volumePath, f.Name())
 | 
			
		||||
				newp := filepath.Join(dataPath, f.Name())
 | 
			
		||||
				if err := os.Rename(oldp, newp); err != nil {
 | 
			
		||||
					logrus.Errorf("Unable to move %s to %s\n", oldp, newp)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return container.ToDisk()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func parseVolumesFrom(spec string) (string, string, error) {
 | 
			
		||||
	if len(spec) == 0 {
 | 
			
		||||
		return "", "", fmt.Errorf("malformed volumes-from specification: %s", spec)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	specParts := strings.SplitN(spec, ":", 2)
 | 
			
		||||
	id := specParts[0]
 | 
			
		||||
	mode := "rw"
 | 
			
		||||
 | 
			
		||||
	if len(specParts) == 2 {
 | 
			
		||||
		mode = specParts[1]
 | 
			
		||||
		if isValid, _ := volume.ValidateMountMode(mode); !isValid {
 | 
			
		||||
			return "", "", fmt.Errorf("invalid mode for volumes-from: %s", mode)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return id, mode, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// registerMountPoints initializes the container mount points with the configured volumes and bind mounts.
 | 
			
		||||
// It follows the next sequence to decide what to mount in each final destination:
 | 
			
		||||
//
 | 
			
		||||
// 1. Select the previously configured mount points for the containers, if any.
 | 
			
		||||
// 2. Select the volumes mounted from another containers. Overrides previously configured mount point destination.
 | 
			
		||||
// 3. Select the bind mounts set by the client. Overrides previously configured mount point destinations.
 | 
			
		||||
func (daemon *Daemon) registerMountPoints(container *Container, hostConfig *runconfig.HostConfig) error {
 | 
			
		||||
	binds := map[string]bool{}
 | 
			
		||||
	mountPoints := map[string]*mountPoint{}
 | 
			
		||||
 | 
			
		||||
	// 1. Read already configured mount points.
 | 
			
		||||
	for name, point := range container.MountPoints {
 | 
			
		||||
		mountPoints[name] = point
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 2. Read volumes from other containers.
 | 
			
		||||
	for _, v := range hostConfig.VolumesFrom {
 | 
			
		||||
		containerID, mode, err := parseVolumesFrom(v)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		c, err := daemon.Get(containerID)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for _, m := range c.MountPoints {
 | 
			
		||||
			cp := &mountPoint{
 | 
			
		||||
				Name:        m.Name,
 | 
			
		||||
				Source:      m.Source,
 | 
			
		||||
				RW:          m.RW && volume.ReadWrite(mode),
 | 
			
		||||
				Driver:      m.Driver,
 | 
			
		||||
				Destination: m.Destination,
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if len(cp.Source) == 0 {
 | 
			
		||||
				v, err := createVolume(cp.Name, cp.Driver)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
				cp.Volume = v
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			mountPoints[cp.Destination] = cp
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 3. Read bind mounts
 | 
			
		||||
	for _, b := range hostConfig.Binds {
 | 
			
		||||
		// #10618
 | 
			
		||||
		bind, err := parseBindMount(b, container.MountLabel, container.Config)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if binds[bind.Destination] {
 | 
			
		||||
			return fmt.Errorf("Duplicate bind mount %s", bind.Destination)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if len(bind.Name) > 0 && len(bind.Driver) > 0 {
 | 
			
		||||
			// create the volume
 | 
			
		||||
			v, err := createVolume(bind.Name, bind.Driver)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			bind.Volume = v
 | 
			
		||||
			bind.Source = v.Path()
 | 
			
		||||
			// Since this is just a named volume and not a typical bind, set to shared mode `z`
 | 
			
		||||
			if bind.Mode == "" {
 | 
			
		||||
				bind.Mode = "z"
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if err := label.Relabel(bind.Source, container.MountLabel, bind.Mode); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		binds[bind.Destination] = true
 | 
			
		||||
		mountPoints[bind.Destination] = bind
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Keep backwards compatible structures
 | 
			
		||||
	bcVolumes := map[string]string{}
 | 
			
		||||
	bcVolumesRW := map[string]bool{}
 | 
			
		||||
	for _, m := range mountPoints {
 | 
			
		||||
		if m.BackwardsCompatible() {
 | 
			
		||||
			bcVolumes[m.Destination] = m.Path()
 | 
			
		||||
			bcVolumesRW[m.Destination] = m.RW
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	container.Lock()
 | 
			
		||||
	container.MountPoints = mountPoints
 | 
			
		||||
	container.Volumes = bcVolumes
 | 
			
		||||
	container.VolumesRW = bcVolumesRW
 | 
			
		||||
	container.Unlock()
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func createVolume(name, driverName string) (volume.Volume, error) {
 | 
			
		||||
	vd, err := getVolumeDriver(driverName)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return vd.Create(name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func removeVolume(v volume.Volume) error {
 | 
			
		||||
	vd, err := getVolumeDriver(v.DriverName())
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	return vd.Remove(v)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getVolumeDriver(name string) (volume.Driver, error) {
 | 
			
		||||
	if name == "" {
 | 
			
		||||
		name = volume.DefaultDriverName
 | 
			
		||||
	}
 | 
			
		||||
	return volumedrivers.Lookup(name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func parseVolumeSource(spec string) (string, string, error) {
 | 
			
		||||
	if !filepath.IsAbs(spec) {
 | 
			
		||||
		return spec, "", nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return "", spec, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// BackwardsCompatible decides whether this mount point can be
 | 
			
		||||
// used in old versions of Docker or not.
 | 
			
		||||
// Only bind mounts and local volumes can be used in old versions of Docker.
 | 
			
		||||
func (m *mountPoint) BackwardsCompatible() bool {
 | 
			
		||||
	return len(m.Source) > 0 || m.Driver == volume.DefaultDriverName
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,9 +3,8 @@
 | 
			
		|||
package daemon
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"os"
 | 
			
		||||
 | 
			
		||||
	"github.com/docker/docker/daemon/execdriver"
 | 
			
		||||
	"github.com/docker/docker/runconfig"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Not supported on Windows
 | 
			
		||||
| 
						 | 
				
			
			@ -17,10 +16,13 @@ func (container *Container) setupMounts() ([]execdriver.Mount, error) {
 | 
			
		|||
	return nil, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func migrateVolume(id, vfs string) error {
 | 
			
		||||
// verifyVolumesInfo ports volumes configured for the containers pre docker 1.7.
 | 
			
		||||
// As the Windows daemon was not supported before 1.7, this is a no-op
 | 
			
		||||
func (daemon *Daemon) verifyVolumesInfo(container *Container) error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func validVolumeLayout(files []os.FileInfo) bool {
 | 
			
		||||
	return true
 | 
			
		||||
// TODO Windows: This can be further factored out. Called from daemon\daemon.go
 | 
			
		||||
func (daemon *Daemon) registerMountPoints(container *Container, hostConfig *runconfig.HostConfig) error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -212,10 +212,8 @@ func (cli *DaemonCli) CmdDaemon(args ...string) error {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	serverConfig := &apiserver.ServerConfig{
 | 
			
		||||
		Logging:     true,
 | 
			
		||||
		EnableCors:  cli.EnableCors,
 | 
			
		||||
		CorsHeaders: cli.CorsHeaders,
 | 
			
		||||
		Version:     dockerversion.VERSION,
 | 
			
		||||
		Logging: true,
 | 
			
		||||
		Version: dockerversion.VERSION,
 | 
			
		||||
	}
 | 
			
		||||
	serverConfig = setPlatformServerConfig(serverConfig, cli.Config)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,6 +17,9 @@ import (
 | 
			
		|||
 | 
			
		||||
func setPlatformServerConfig(serverConfig *apiserver.ServerConfig, daemonCfg *daemon.Config) *apiserver.ServerConfig {
 | 
			
		||||
	serverConfig.SocketGroup = daemonCfg.SocketGroup
 | 
			
		||||
	serverConfig.EnableCors = daemonCfg.EnableCors
 | 
			
		||||
	serverConfig.CorsHeaders = daemonCfg.CorsHeaders
 | 
			
		||||
 | 
			
		||||
	return serverConfig
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue