mirror of https://github.com/docker/docs.git
Windows: Factoring out unused fields
Signed-off-by: John Howard <jhoward@microsoft.com>
This commit is contained in:
parent
33358f80e5
commit
47c56e4353
|
@ -1205,12 +1205,8 @@ func (s *Server) getContainersByName(version version.Version, w http.ResponseWri
|
||||||
return fmt.Errorf("Missing parameter")
|
return fmt.Errorf("Missing parameter")
|
||||||
}
|
}
|
||||||
|
|
||||||
if version.LessThan("1.20") {
|
if version.LessThan("1.20") && runtime.GOOS != "windows" {
|
||||||
containerJSONRaw, err := s.daemon.ContainerInspectPre120(vars["name"])
|
return getContainersByNameDownlevel(w, s, vars["name"])
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return writeJSON(w, http.StatusOK, containerJSONRaw)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
containerJSON, err := s.daemon.ContainerInspect(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) {
|
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
|
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 {
|
type ContainerJSONPre120 struct {
|
||||||
*ContainerJSONBase
|
*ContainerJSONBase
|
||||||
Volumes map[string]string
|
Volumes map[string]string
|
||||||
|
|
|
@ -17,7 +17,7 @@ import (
|
||||||
// path does not refer to a directory.
|
// path does not refer to a directory.
|
||||||
var ErrExtractPointNotDirectory = errors.New("extraction point is not 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.
|
// the specified path in the conatiner identified by the given name.
|
||||||
func (daemon *Daemon) ContainerCopy(name string, res string) (io.ReadCloser, error) {
|
func (daemon *Daemon) ContainerCopy(name string, res string) (io.ReadCloser, error) {
|
||||||
container, err := daemon.Get(name)
|
container, err := daemon.Get(name)
|
||||||
|
@ -25,7 +25,7 @@ func (daemon *Daemon) ContainerCopy(name string, res string) (io.ReadCloser, err
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if res[0] == '/' {
|
if res[0] == '/' || res[0] == '\\' {
|
||||||
res = res[1:]
|
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.
|
// Consider the given path as an absolute path in the container.
|
||||||
absPath := path
|
absPath := path
|
||||||
if !filepath.IsAbs(absPath) {
|
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)
|
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.
|
// Consider the given path as an absolute path in the container.
|
||||||
absPath := path
|
absPath := path
|
||||||
if !filepath.IsAbs(absPath) {
|
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)
|
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.
|
// Consider the given path as an absolute path in the container.
|
||||||
absPath := path
|
absPath := path
|
||||||
if !filepath.IsAbs(absPath) {
|
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)
|
resolvedPath, err := container.GetResourcePath(absPath)
|
||||||
|
@ -261,19 +261,14 @@ func (container *Container) ExtractToDir(path string, noOverwriteDirNonDir bool,
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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
|
// 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
|
// read-only volume. If it is not in a volume, the container cannot be
|
||||||
// configured with a read-only rootfs.
|
// configured with a read-only rootfs.
|
||||||
var toVolume bool
|
toVolume, err := checkIfPathIsInAVolume(container, absPath)
|
||||||
for _, mnt := range container.MountPoints {
|
if err != nil {
|
||||||
if toVolume = mnt.hasResource(absPath); toVolume {
|
return err
|
||||||
if mnt.RW {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
return ErrVolumeReadonly
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !toVolume && container.hostConfig.ReadonlyRootfs {
|
if !toVolume && container.hostConfig.ReadonlyRootfs {
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
AutoRestart bool
|
||||||
Bridge bridgeConfig // Bridge holds bridge network specific configuration.
|
Bridge bridgeConfig // Bridge holds bridge network specific configuration.
|
||||||
Context map[string][]string
|
Context map[string][]string
|
||||||
CorsHeaders string
|
|
||||||
DisableBridge bool
|
DisableBridge bool
|
||||||
Dns []string
|
Dns []string
|
||||||
DnsSearch []string
|
DnsSearch []string
|
||||||
EnableCors bool
|
|
||||||
ExecDriver string
|
ExecDriver string
|
||||||
ExecOptions []string
|
ExecOptions []string
|
||||||
ExecRoot 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.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.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.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"?
|
// 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.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"))
|
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.
|
// Fields below here are platform specific.
|
||||||
|
|
||||||
|
CorsHeaders string
|
||||||
|
EnableCors bool
|
||||||
EnableSelinuxSupport bool
|
EnableSelinuxSupport bool
|
||||||
SocketGroup string
|
SocketGroup string
|
||||||
Ulimits map[string]*ulimit.Ulimit
|
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.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.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.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)
|
config.attachExperimentalFlags(cmd, usageFn)
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,28 +64,18 @@ type CommonContainer struct {
|
||||||
Config *runconfig.Config
|
Config *runconfig.Config
|
||||||
ImageID string `json:"Image"`
|
ImageID string `json:"Image"`
|
||||||
NetworkSettings *network.Settings
|
NetworkSettings *network.Settings
|
||||||
ResolvConfPath string
|
|
||||||
HostnamePath string
|
|
||||||
HostsPath string
|
|
||||||
LogPath string
|
LogPath string
|
||||||
Name string
|
Name string
|
||||||
Driver string
|
Driver string
|
||||||
ExecDriver string
|
ExecDriver string
|
||||||
MountLabel, ProcessLabel string
|
MountLabel, ProcessLabel string
|
||||||
RestartCount int
|
RestartCount int
|
||||||
UpdateDns bool
|
|
||||||
HasBeenStartedBefore bool
|
HasBeenStartedBefore bool
|
||||||
|
hostConfig *runconfig.HostConfig
|
||||||
MountPoints map[string]*mountPoint
|
command *execdriver.Command
|
||||||
Volumes map[string]string // Deprecated since 1.7, kept for backwards compatibility
|
monitor *containerMonitor
|
||||||
VolumesRW map[string]bool // Deprecated since 1.7, kept for backwards compatibility
|
execCommands *execStore
|
||||||
|
daemon *Daemon
|
||||||
hostConfig *runconfig.HostConfig
|
|
||||||
command *execdriver.Command
|
|
||||||
|
|
||||||
monitor *containerMonitor
|
|
||||||
execCommands *execStore
|
|
||||||
daemon *Daemon
|
|
||||||
// logDriver for closing
|
// logDriver for closing
|
||||||
logDriver logger.Logger
|
logDriver logger.Logger
|
||||||
logCopier *logger.Copier
|
logCopier *logger.Copier
|
||||||
|
@ -1076,94 +1066,6 @@ func copyEscapable(dst io.Writer, src io.ReadCloser) (written int64, err error)
|
||||||
return written, err
|
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 {
|
func (container *Container) shouldRestart() bool {
|
||||||
return container.hostConfig.RestartPolicy.Name == "always" ||
|
return container.hostConfig.RestartPolicy.Name == "always" ||
|
||||||
(container.hostConfig.RestartPolicy.Name == "on-failure" && container.ExitCode != 0)
|
(container.hostConfig.RestartPolicy.Name == "on-failure" && container.ExitCode != 0)
|
||||||
|
|
|
@ -27,12 +27,14 @@ import (
|
||||||
"github.com/docker/docker/pkg/ulimit"
|
"github.com/docker/docker/pkg/ulimit"
|
||||||
"github.com/docker/docker/runconfig"
|
"github.com/docker/docker/runconfig"
|
||||||
"github.com/docker/docker/utils"
|
"github.com/docker/docker/utils"
|
||||||
|
"github.com/docker/docker/volume"
|
||||||
"github.com/docker/libnetwork"
|
"github.com/docker/libnetwork"
|
||||||
"github.com/docker/libnetwork/netlabel"
|
"github.com/docker/libnetwork/netlabel"
|
||||||
"github.com/docker/libnetwork/options"
|
"github.com/docker/libnetwork/options"
|
||||||
"github.com/docker/libnetwork/types"
|
"github.com/docker/libnetwork/types"
|
||||||
"github.com/opencontainers/runc/libcontainer/configs"
|
"github.com/opencontainers/runc/libcontainer/configs"
|
||||||
"github.com/opencontainers/runc/libcontainer/devices"
|
"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"
|
const DefaultPathEnv = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
||||||
|
@ -41,9 +43,15 @@ type Container struct {
|
||||||
CommonContainer
|
CommonContainer
|
||||||
|
|
||||||
// Fields below here are platform specific.
|
// Fields below here are platform specific.
|
||||||
|
|
||||||
AppArmorProfile string
|
|
||||||
activeLinks map[string]*links.Link
|
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 {
|
func killProcessDirectly(container *Container) error {
|
||||||
|
@ -1150,3 +1158,91 @@ func (container *Container) PrepareStorage() error {
|
||||||
func (container *Container) CleanupStorage() error {
|
func (container *Container) CleanupStorage() error {
|
||||||
return nil
|
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
|
CommonContainer
|
||||||
|
|
||||||
// Fields below here are platform specific.
|
// 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 {
|
func killProcessDirectly(container *Container) error {
|
||||||
|
@ -213,3 +201,13 @@ func (container *Container) CleanupStorage() error {
|
||||||
}
|
}
|
||||||
return nil
|
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 (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
"github.com/docker/docker/graph"
|
"github.com/docker/docker/graph"
|
||||||
"github.com/docker/docker/image"
|
"github.com/docker/docker/image"
|
||||||
"github.com/docker/docker/pkg/parsers"
|
"github.com/docker/docker/pkg/parsers"
|
||||||
"github.com/docker/docker/pkg/stringid"
|
|
||||||
"github.com/docker/docker/runconfig"
|
"github.com/docker/docker/runconfig"
|
||||||
"github.com/opencontainers/runc/libcontainer/label"
|
"github.com/opencontainers/runc/libcontainer/label"
|
||||||
)
|
)
|
||||||
|
@ -96,47 +92,10 @@ func (daemon *Daemon) Create(config *runconfig.Config, hostConfig *runconfig.Hos
|
||||||
}
|
}
|
||||||
defer container.Unmount()
|
defer container.Unmount()
|
||||||
|
|
||||||
for spec := range config.Volumes {
|
if err := createContainerPlatformSpecificSettings(container, config); err != nil {
|
||||||
var (
|
return nil, nil, err
|
||||||
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 := container.ToDisk(); err != nil {
|
if err := container.ToDisk(); err != nil {
|
||||||
logrus.Errorf("Error saving new container to disk: %v", err)
|
logrus.Errorf("Error saving new container to disk: %v", err)
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
// Load reads the contents of a container from disk
|
||||||
// This is typically done at startup.
|
// This is typically done at startup.
|
||||||
func (daemon *Daemon) load(id string) (*Container, error) {
|
func (daemon *Daemon) load(id string) (*Container, error) {
|
||||||
container := &Container{
|
container := daemon.newBaseContainer(id)
|
||||||
CommonContainer: daemon.newBaseContainer(id),
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := container.FromDisk(); err != nil {
|
if err := container.FromDisk(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if container.ID != id {
|
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>
|
// 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.Driver = daemon.driver.String()
|
||||||
base.ExecDriver = daemon.execDriver.Name()
|
base.ExecDriver = daemon.execDriver.Name()
|
||||||
|
|
||||||
container := &Container{
|
return &base, err
|
||||||
CommonContainer: base,
|
|
||||||
}
|
|
||||||
|
|
||||||
return container, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetFullContainerName(name string) (string, error) {
|
func GetFullContainerName(name string) (string, error) {
|
||||||
|
@ -947,18 +941,6 @@ func (daemon *Daemon) setHostConfig(container *Container, hostConfig *runconfig.
|
||||||
return nil
|
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) {
|
func setDefaultMtu(config *Config) {
|
||||||
// do nothing if the config does not have the default 0 value.
|
// do nothing if the config does not have the default 0 value.
|
||||||
if config.Mtu != 0 {
|
if config.Mtu != 0 {
|
||||||
|
|
|
@ -539,3 +539,17 @@ func (daemon *Daemon) RegisterLinks(container *Container, hostConfig *runconfig.
|
||||||
|
|
||||||
return nil
|
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
|
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
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
mountPoints := make([]types.MountPoint, 0, len(container.MountPoints))
|
mountPoints := addMountPoints(container)
|
||||||
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 &types.ContainerJSON{base, mountPoints, container.Config}, nil
|
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) {
|
func (daemon *Daemon) getInspectData(container *Container) (*types.ContainerJSONBase, error) {
|
||||||
// make a copy to play with
|
// make a copy to play with
|
||||||
hostConfig := *container.hostConfig
|
hostConfig := *container.hostConfig
|
||||||
|
@ -104,9 +62,6 @@ func (daemon *Daemon) getInspectData(container *Container) (*types.ContainerJSON
|
||||||
State: containerState,
|
State: containerState,
|
||||||
Image: container.ImageID,
|
Image: container.ImageID,
|
||||||
NetworkSettings: container.NetworkSettings,
|
NetworkSettings: container.NetworkSettings,
|
||||||
ResolvConfPath: container.ResolvConfPath,
|
|
||||||
HostnamePath: container.HostnamePath,
|
|
||||||
HostsPath: container.HostsPath,
|
|
||||||
LogPath: container.LogPath,
|
LogPath: container.LogPath,
|
||||||
Name: container.Name,
|
Name: container.Name,
|
||||||
RestartCount: container.RestartCount,
|
RestartCount: container.RestartCount,
|
||||||
|
@ -114,11 +69,13 @@ func (daemon *Daemon) getInspectData(container *Container) (*types.ContainerJSON
|
||||||
ExecDriver: container.ExecDriver,
|
ExecDriver: container.ExecDriver,
|
||||||
MountLabel: container.MountLabel,
|
MountLabel: container.MountLabel,
|
||||||
ProcessLabel: container.ProcessLabel,
|
ProcessLabel: container.ProcessLabel,
|
||||||
AppArmorProfile: container.AppArmorProfile,
|
|
||||||
ExecIDs: container.GetExecIDs(),
|
ExecIDs: container.GetExecIDs(),
|
||||||
HostConfig: &hostConfig,
|
HostConfig: &hostConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Now set any platform-specific fields
|
||||||
|
contJSONBase = setPlatformSpecificContainerFields(container, contJSONBase)
|
||||||
|
|
||||||
contJSONBase.GraphDriver.Name = container.Driver
|
contJSONBase.GraphDriver.Name = container.Driver
|
||||||
graphDriverData, err := daemon.driver.GetMetadata(container.ID)
|
graphDriverData, err := daemon.driver.GetMetadata(container.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
|
@ -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"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/docker/pkg/chrootarchive"
|
"github.com/docker/docker/pkg/chrootarchive"
|
||||||
"github.com/docker/docker/pkg/system"
|
"github.com/docker/docker/pkg/system"
|
||||||
"github.com/docker/docker/runconfig"
|
|
||||||
"github.com/docker/docker/volume"
|
"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
|
// ErrVolumeReadonly is used to signal an error when trying to copy data into
|
||||||
// a volume mount that is not writable.
|
// a volume mount that is not writable.
|
||||||
var ErrVolumeReadonly = errors.New("mounted volume is marked read-only")
|
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 {
|
type mountPoint struct {
|
||||||
Name string
|
Name string
|
||||||
Destination string
|
Destination string
|
||||||
|
@ -70,73 +67,6 @@ func (m *mountPoint) Path() string {
|
||||||
return m.Source
|
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 {
|
func copyExistingContents(source, destination string) error {
|
||||||
volList, err := ioutil.ReadDir(source)
|
volList, err := ioutil.ReadDir(source)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -156,211 +86,3 @@ func copyExistingContents(source, destination string) error {
|
||||||
}
|
}
|
||||||
return copyOwnership(source, destination)
|
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
|
package daemon
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
"github.com/docker/docker/daemon/execdriver"
|
"github.com/docker/docker/daemon/execdriver"
|
||||||
"github.com/docker/docker/pkg/system"
|
"github.com/docker/docker/pkg/system"
|
||||||
|
"github.com/docker/docker/runconfig"
|
||||||
"github.com/docker/docker/volume"
|
"github.com/docker/docker/volume"
|
||||||
|
"github.com/docker/docker/volume/drivers"
|
||||||
"github.com/docker/docker/volume/local"
|
"github.com/docker/docker/volume/local"
|
||||||
|
"github.com/opencontainers/runc/libcontainer/label"
|
||||||
)
|
)
|
||||||
|
|
||||||
// copyOwnership copies the permissions and uid:gid of the source file
|
// 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
|
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 {
|
func sortMounts(m []execdriver.Mount) []execdriver.Mount {
|
||||||
sort.Sort(mounts(m))
|
sort.Sort(mounts(m))
|
||||||
return m
|
return m
|
||||||
|
@ -118,3 +166,235 @@ func validVolumeLayout(files []os.FileInfo) bool {
|
||||||
|
|
||||||
return true
|
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
|
package daemon
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/docker/docker/daemon/execdriver"
|
"github.com/docker/docker/daemon/execdriver"
|
||||||
|
"github.com/docker/docker/runconfig"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Not supported on Windows
|
// Not supported on Windows
|
||||||
|
@ -17,10 +16,13 @@ func (container *Container) setupMounts() ([]execdriver.Mount, error) {
|
||||||
return nil, nil
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func validVolumeLayout(files []os.FileInfo) bool {
|
// TODO Windows: This can be further factored out. Called from daemon\daemon.go
|
||||||
return true
|
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{
|
serverConfig := &apiserver.ServerConfig{
|
||||||
Logging: true,
|
Logging: true,
|
||||||
EnableCors: cli.EnableCors,
|
Version: dockerversion.VERSION,
|
||||||
CorsHeaders: cli.CorsHeaders,
|
|
||||||
Version: dockerversion.VERSION,
|
|
||||||
}
|
}
|
||||||
serverConfig = setPlatformServerConfig(serverConfig, cli.Config)
|
serverConfig = setPlatformServerConfig(serverConfig, cli.Config)
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,9 @@ import (
|
||||||
|
|
||||||
func setPlatformServerConfig(serverConfig *apiserver.ServerConfig, daemonCfg *daemon.Config) *apiserver.ServerConfig {
|
func setPlatformServerConfig(serverConfig *apiserver.ServerConfig, daemonCfg *daemon.Config) *apiserver.ServerConfig {
|
||||||
serverConfig.SocketGroup = daemonCfg.SocketGroup
|
serverConfig.SocketGroup = daemonCfg.SocketGroup
|
||||||
|
serverConfig.EnableCors = daemonCfg.EnableCors
|
||||||
|
serverConfig.CorsHeaders = daemonCfg.CorsHeaders
|
||||||
|
|
||||||
return serverConfig
|
return serverConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue