9a2d0bc3ad
Fixes #22564 When an error occurs on mount, there should not be any call later to unmount. This can throw off refcounting in the underlying driver unexpectedly. Consider these two cases: ``` $ docker run -v foo:/bar busybox true ``` ``` $ docker run -v foo:/bar -w /foo busybox true ``` In the first case, if mounting `foo` fails, the volume driver will not get a call to unmount (this is the incorrect behavior). In the second case, the volume driver will not get a call to unmount (correct behavior). This occurs because in the first case, `/bar` does not exist in the container, and as such there is no call to `volume.Mount()` during the `create` phase. It will error out during the `start` phase. In the second case `/bar` is created before dealing with the volume because of the `-w`. Because of this, when the volume is being setup docker will try to copy the image path contents in the volume, in which case it will attempt to mount the volume and fail. This happens during the `create` phase. This makes it so the container will not be created (or at least fully created) and the user gets the error on `create` instead of `start`. The error handling is different in these two phases. Changed to only send `unmount` if the volume is mounted. While investigating the cause of the reported issue I found some odd behavior in unmount calls so I've cleaned those up a bit here as well. Signed-off-by: Brian Goff <cpuguy83@gmail.com>
118 lines
3.8 KiB
Go
118 lines
3.8 KiB
Go
// +build windows
|
|
|
|
package container
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
containertypes "github.com/docker/docker/api/types/container"
|
|
"github.com/docker/docker/utils"
|
|
)
|
|
|
|
// Container holds fields specific to the Windows implementation. See
|
|
// CommonContainer for standard fields common to all containers.
|
|
type Container struct {
|
|
CommonContainer
|
|
|
|
// Fields below here are platform specific.
|
|
}
|
|
|
|
// ExitStatus provides exit reasons for a container.
|
|
type ExitStatus struct {
|
|
// The exit code with which the container exited.
|
|
ExitCode int
|
|
}
|
|
|
|
// CreateDaemonEnvironment creates a new environment variable slice for this container.
|
|
func (container *Container) CreateDaemonEnvironment(_ bool, linkedEnv []string) []string {
|
|
// because the env on the container can override certain default values
|
|
// we need to replace the 'env' keys where they match and append anything
|
|
// else.
|
|
return utils.ReplaceOrAppendEnvValues(linkedEnv, container.Config.Env)
|
|
}
|
|
|
|
// UnmountIpcMounts unmounts Ipc related mounts.
|
|
// This is a NOOP on windows.
|
|
func (container *Container) UnmountIpcMounts(unmount func(pth string) error) {
|
|
}
|
|
|
|
// IpcMounts returns the list of Ipc related mounts.
|
|
func (container *Container) IpcMounts() []Mount {
|
|
return nil
|
|
}
|
|
|
|
// SecretMount returns the mount for the secret path
|
|
func (container *Container) SecretMount() *Mount {
|
|
return nil
|
|
}
|
|
|
|
// UnmountSecrets unmounts the fs for secrets
|
|
func (container *Container) UnmountSecrets() error {
|
|
return nil
|
|
}
|
|
|
|
// DetachAndUnmount unmounts all volumes.
|
|
// On Windows it only delegates to `UnmountVolumes` since there is nothing to
|
|
// force unmount.
|
|
func (container *Container) DetachAndUnmount(volumeEventLog func(name, action string, attributes map[string]string)) error {
|
|
return container.UnmountVolumes(volumeEventLog)
|
|
}
|
|
|
|
// TmpfsMounts returns the list of tmpfs mounts
|
|
func (container *Container) TmpfsMounts() ([]Mount, error) {
|
|
var mounts []Mount
|
|
return mounts, nil
|
|
}
|
|
|
|
// UpdateContainer updates configuration of a container
|
|
func (container *Container) UpdateContainer(hostConfig *containertypes.HostConfig) error {
|
|
container.Lock()
|
|
defer container.Unlock()
|
|
resources := hostConfig.Resources
|
|
if resources.BlkioWeight != 0 || resources.CPUShares != 0 ||
|
|
resources.CPUPeriod != 0 || resources.CPUQuota != 0 ||
|
|
resources.CpusetCpus != "" || resources.CpusetMems != "" ||
|
|
resources.Memory != 0 || resources.MemorySwap != 0 ||
|
|
resources.MemoryReservation != 0 || resources.KernelMemory != 0 {
|
|
return fmt.Errorf("Resource updating isn't supported on Windows")
|
|
}
|
|
// update HostConfig of container
|
|
if hostConfig.RestartPolicy.Name != "" {
|
|
if container.HostConfig.AutoRemove && !hostConfig.RestartPolicy.IsNone() {
|
|
return fmt.Errorf("Restart policy cannot be updated because AutoRemove is enabled for the container")
|
|
}
|
|
container.HostConfig.RestartPolicy = hostConfig.RestartPolicy
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// cleanResourcePath cleans a resource path by removing C:\ syntax, and prepares
|
|
// to combine with a volume path
|
|
func cleanResourcePath(path string) string {
|
|
if len(path) >= 2 {
|
|
c := path[0]
|
|
if path[1] == ':' && ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z') {
|
|
path = path[2:]
|
|
}
|
|
}
|
|
return filepath.Join(string(os.PathSeparator), path)
|
|
}
|
|
|
|
// BuildHostnameFile writes the container's hostname file.
|
|
func (container *Container) BuildHostnameFile() error {
|
|
return nil
|
|
}
|
|
|
|
// canMountFS determines if the file system for the container
|
|
// can be mounted locally. In the case of Windows, this is not possible
|
|
// for Hyper-V containers during WORKDIR execution for example.
|
|
func (container *Container) canMountFS() bool {
|
|
return !containertypes.Isolation.IsHyperV(container.HostConfig.Isolation)
|
|
}
|
|
|
|
// EnableServiceDiscoveryOnDefaultNetwork Enable service discovery on default network
|
|
func (container *Container) EnableServiceDiscoveryOnDefaultNetwork() bool {
|
|
return true
|
|
}
|