Skip to content

Commit

Permalink
Merge pull request moby#16433 from Microsoft/10662-volumes5
Browse files Browse the repository at this point in the history
Windows: [TP4] Add volume support
  • Loading branch information
tiborvass committed Oct 23, 2015
2 parents 448398c + a7e686a commit e74cf8a
Show file tree
Hide file tree
Showing 47 changed files with 1,693 additions and 714 deletions.
7 changes: 6 additions & 1 deletion api/server/router/local/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,12 @@ func (s *router) postContainersCreate(ctx context.Context, w http.ResponseWriter
version := httputils.VersionFromContext(ctx)
adjustCPUShares := version.LessThan("1.19")

ccr, err := s.daemon.ContainerCreate(name, config, hostConfig, adjustCPUShares)
ccr, err := s.daemon.ContainerCreate(&daemon.ContainerCreateConfig{
Name: name,
Config: config,
HostConfig: hostConfig,
AdjustCPUShares: adjustCPUShares,
})
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion builder/dockerfile/evaluator.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ func platformSupports(command string) error {
return nil
}
switch command {
case "expose", "volume", "user", "stopsignal", "arg":
case "expose", "user", "stopsignal", "arg":
return fmt.Errorf("The daemon on this platform does not support the command '%s'", command)
}
return nil
Expand Down
2 changes: 1 addition & 1 deletion daemon/archive_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ package daemon
func checkIfPathIsInAVolume(container *Container, absPath string) (bool, error) {
var toVolume bool
for _, mnt := range container.MountPoints {
if toVolume = mnt.hasResource(absPath); toVolume {
if toVolume = mnt.HasResource(absPath); toVolume {
if mnt.RW {
break
}
Expand Down
110 changes: 97 additions & 13 deletions daemon/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"io/ioutil"
"os"
"path/filepath"
"strings"
"sync"
"syscall"
"time"
Expand All @@ -30,8 +31,10 @@ import (
"github.com/docker/docker/pkg/promise"
"github.com/docker/docker/pkg/signal"
"github.com/docker/docker/pkg/symlink"
"github.com/docker/docker/pkg/system"
"github.com/docker/docker/runconfig"
"github.com/docker/docker/volume"
"github.com/docker/docker/volume/store"
)

var (
Expand Down Expand Up @@ -72,6 +75,7 @@ type CommonContainer struct {
RestartCount int
HasBeenStartedBefore bool
HasBeenManuallyStopped bool // used for unless-stopped restart policy
MountPoints map[string]*volume.MountPoint
hostConfig *runconfig.HostConfig
command *execdriver.Command
monitor *containerMonitor
Expand Down Expand Up @@ -1108,29 +1112,109 @@ func (container *Container) mountVolumes() error {
return nil
}

func (container *Container) copyImagePathContent(v volume.Volume, destination string) error {
rootfs, err := symlink.FollowSymlinkInScope(filepath.Join(container.basefs, destination), container.basefs)
if err != nil {
return err
func (container *Container) prepareMountPoints() error {
for _, config := range container.MountPoints {
if len(config.Driver) > 0 {
v, err := container.daemon.createVolume(config.Name, config.Driver, nil)
if err != nil {
return err
}
config.Volume = v
}
}
return nil
}

if _, err = ioutil.ReadDir(rootfs); err != nil {
if os.IsNotExist(err) {
return nil
func (container *Container) removeMountPoints(rm bool) error {
var rmErrors []string
for _, m := range container.MountPoints {
if m.Volume == nil {
continue
}
container.daemon.volumes.Decrement(m.Volume)
if rm {
err := container.daemon.volumes.Remove(m.Volume)
// ErrVolumeInUse is ignored because having this
// volume being referenced by other container is
// not an error, but an implementation detail.
// This prevents docker from logging "ERROR: Volume in use"
// where there is another container using the volume.
if err != nil && err != store.ErrVolumeInUse {
rmErrors = append(rmErrors, err.Error())
}
}
return err
}
if len(rmErrors) > 0 {
return derr.ErrorCodeRemovingVolume.WithArgs(strings.Join(rmErrors, "\n"))
}
return nil
}

path, err := v.Mount()
if err != nil {
return err
func (container *Container) unmountVolumes(forceSyscall bool) error {
var (
volumeMounts []volume.MountPoint
err error
)

for _, mntPoint := range container.MountPoints {
dest, err := container.GetResourcePath(mntPoint.Destination)
if err != nil {
return err
}

volumeMounts = append(volumeMounts, volume.MountPoint{Destination: dest, Volume: mntPoint.Volume})
}

if err := copyExistingContents(rootfs, path); err != nil {
// Append any network mounts to the list (this is a no-op on Windows)
if volumeMounts, err = appendNetworkMounts(container, volumeMounts); err != nil {
return err
}

return v.Unmount()
for _, volumeMount := range volumeMounts {
if forceSyscall {
system.UnmountWithSyscall(volumeMount.Destination)
}

if volumeMount.Volume != nil {
if err := volumeMount.Volume.Unmount(); err != nil {
return err
}
}
}

return nil
}

func (container *Container) addBindMountPoint(name, source, destination string, rw bool) {
container.MountPoints[destination] = &volume.MountPoint{
Name: name,
Source: source,
Destination: destination,
RW: rw,
}
}

func (container *Container) addLocalMountPoint(name, destination string, rw bool) {
container.MountPoints[destination] = &volume.MountPoint{
Name: name,
Driver: volume.DefaultDriverName,
Destination: destination,
RW: rw,
}
}

func (container *Container) addMountPointWithVolume(destination string, vol volume.Volume, rw bool) {
container.MountPoints[destination] = &volume.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) stopSignal() int {
Expand Down
116 changes: 23 additions & 93 deletions daemon/container_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@ import (
"github.com/docker/docker/pkg/idtools"
"github.com/docker/docker/pkg/nat"
"github.com/docker/docker/pkg/stringid"
"github.com/docker/docker/pkg/symlink"
"github.com/docker/docker/pkg/system"
"github.com/docker/docker/pkg/ulimit"
"github.com/docker/docker/runconfig"
"github.com/docker/docker/utils"
"github.com/docker/docker/volume"
"github.com/docker/docker/volume/store"
"github.com/docker/libnetwork"
"github.com/docker/libnetwork/drivers/bridge"
"github.com/docker/libnetwork/netlabel"
Expand All @@ -54,9 +54,8 @@ type Container struct {
AppArmorProfile string
HostnamePath string
HostsPath string
ShmPath string
MqueuePath string
MountPoints map[string]*mountPoint
ShmPath string // TODO Windows - Factor this out (GH15862)
MqueuePath string // TODO Windows - Factor this out (GH15862)
ResolvConfPath string

Volumes map[string]string // Deprecated since 1.7, kept for backwards compatibility
Expand Down Expand Up @@ -1201,40 +1200,16 @@ func (container *Container) disconnectFromNetwork(n libnetwork.Network) error {
return nil
}

func (container *Container) unmountVolumes(forceSyscall bool) error {
var volumeMounts []mountPoint

for _, mntPoint := range container.MountPoints {
dest, err := container.GetResourcePath(mntPoint.Destination)
if err != nil {
return err
}

volumeMounts = append(volumeMounts, mountPoint{Destination: dest, Volume: mntPoint.Volume})
}

// appendNetworkMounts appends any network mounts to the array of mount points passed in
func appendNetworkMounts(container *Container, volumeMounts []volume.MountPoint) ([]volume.MountPoint, error) {
for _, mnt := range container.networkMounts() {
dest, err := container.GetResourcePath(mnt.Destination)
if err != nil {
return err
}

volumeMounts = append(volumeMounts, mountPoint{Destination: dest})
}

for _, volumeMount := range volumeMounts {
if forceSyscall {
syscall.Unmount(volumeMount.Destination, 0)
}

if volumeMount.Volume != nil {
if err := volumeMount.Volume.Unmount(); err != nil {
return err
}
return nil, err
}
volumeMounts = append(volumeMounts, volume.MountPoint{Destination: dest})
}

return nil
return volumeMounts, nil
}

func (container *Container) networkMounts() []execdriver.Mount {
Expand Down Expand Up @@ -1294,74 +1269,29 @@ func (container *Container) networkMounts() []execdriver.Mount {
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) copyImagePathContent(v volume.Volume, destination string) error {
rootfs, err := symlink.FollowSymlinkInScope(filepath.Join(container.basefs, destination), container.basefs)
if err != nil {
return err
}
}

func (container *Container) addLocalMountPoint(name, destination string, rw bool) {
container.MountPoints[destination] = &mountPoint{
Name: name,
Driver: volume.DefaultDriverName,
Destination: destination,
RW: rw,
if _, err = ioutil.ReadDir(rootfs); err != nil {
if os.IsNotExist(err) {
return nil
}
return err
}
}

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,
path, err := v.Mount()
if err != nil {
return err
}
}

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 := container.daemon.createVolume(config.Name, config.Driver, nil)
if err != nil {
return err
}
config.Volume = v
}
if err := copyExistingContents(rootfs, path); err != nil {
return err
}
return nil
}

func (container *Container) removeMountPoints(rm bool) error {
var rmErrors []string
for _, m := range container.MountPoints {
if m.Volume == nil {
continue
}
container.daemon.volumes.Decrement(m.Volume)
if rm {
err := container.daemon.volumes.Remove(m.Volume)
// ErrVolumeInUse is ignored because having this
// volume being referenced by othe container is
// not an error, but an implementation detail.
// This prevents docker from logging "ERROR: Volume in use"
// where there is another container using the volume.
if err != nil && err != store.ErrVolumeInUse {
rmErrors = append(rmErrors, err.Error())
}
}
}
if len(rmErrors) > 0 {
return derr.ErrorCodeRemovingVolume.WithArgs(strings.Join(rmErrors, "\n"))
}
return nil
return v.Unmount()
}

func (container *Container) shmPath() (string, error) {
Expand Down
18 changes: 6 additions & 12 deletions daemon/container_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

"github.com/docker/docker/daemon/execdriver"
derr "github.com/docker/docker/errors"
"github.com/docker/docker/volume"
"github.com/docker/libnetwork"
)

Expand Down Expand Up @@ -169,18 +170,11 @@ func (container *Container) updateNetwork() error {
func (container *Container) releaseNetwork() {
}

func (container *Container) unmountVolumes(forceSyscall bool) error {
return nil
}

// prepareMountPoints is a no-op on Windows
func (container *Container) prepareMountPoints() error {
return nil
}

// removeMountPoints is a no-op on Windows.
func (container *Container) removeMountPoints(_ bool) error {
return nil
// appendNetworkMounts appends any network mounts to the array of mount points passed in.
// Windows does not support network mounts (not to be confused with SMB network mounts), so
// this is a no-op.
func appendNetworkMounts(container *Container, volumeMounts []volume.MountPoint) ([]volume.MountPoint, error) {
return volumeMounts, nil
}

func (container *Container) setupIpcDirs() error {
Expand Down
Loading

0 comments on commit e74cf8a

Please sign in to comment.