Root.Path for a process-isolated WCOW container must be the Volume GUID
The actual divergence is due to differences in the snapshotter and graphfilter mount behaviour on Windows, but the snapshotter behaviour is better, so we deal with it here rather than changing the snapshotter behaviour. We're relying on the internals of containerd's Windows mount implementation here. Unless this code flow is replaced, future work is to move getBackingDeviceForContainerdMount into containerd's mount implementation. Signed-off-by: Paul "TBBle" Hampson <Paul.Hampson@Pobox.com> Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
This commit is contained in:
parent
ec041193f9
commit
e8f4bfb374
1 changed files with 61 additions and 1 deletions
|
@ -8,6 +8,7 @@ import (
|
|||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/Microsoft/hcsshim"
|
||||
coci "github.com/containerd/containerd/oci"
|
||||
"github.com/containerd/log"
|
||||
containertypes "github.com/docker/docker/api/types/container"
|
||||
|
@ -249,7 +250,24 @@ func (daemon *Daemon) createSpecWindowsFields(c *container.Container, s *specs.S
|
|||
return errors.New("createSpecWindowsFields: BaseFS of container " + c.ID + " is unexpectedly empty")
|
||||
}
|
||||
|
||||
s.Root.Path = c.BaseFS // This is not set for Hyper-V containers
|
||||
if daemon.UsesSnapshotter() {
|
||||
// daemon.Mount() for the snapshotters actually mounts the filesystem to the host
|
||||
// using containerd/mount.All and BaseFS is the directory where this is mounted.
|
||||
// This is consistent with Linux-based graphdriver implementations.
|
||||
// For the windowsfilter graphdriver, the underlying Get() call does not actually mount
|
||||
// the filesystem to a path, and BaseFS is the Volume GUID of the prepared/activated
|
||||
// filesystem.
|
||||
|
||||
// The spec for Root.Path for Windows specifies that for Process-isolated containers,
|
||||
// it must be in the Volume GUID (\\?\\Volume{GUID} style), not a host-mounted directory.
|
||||
backingDevicePath, err := getBackingDeviceForContainerdMount(c.BaseFS)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "createSpecWindowsFields: Failed to get backing device of BaseFS of container %s", c.ID)
|
||||
}
|
||||
s.Root.Path = backingDevicePath
|
||||
} else {
|
||||
s.Root.Path = c.BaseFS // This is not set for Hyper-V containers
|
||||
}
|
||||
if !strings.HasSuffix(s.Root.Path, `\`) {
|
||||
s.Root.Path = s.Root.Path + `\` // Ensure a correctly formatted volume GUID path \\?\Volume{GUID}\
|
||||
}
|
||||
|
@ -275,6 +293,48 @@ func (daemon *Daemon) createSpecWindowsFields(c *container.Container, s *specs.S
|
|||
return nil
|
||||
}
|
||||
|
||||
// getBackingDeviceForContainerdMount extracts the backing device or directory mounted at mountPoint
|
||||
// by containerd's mount.Mount implementation for Windows.
|
||||
func getBackingDeviceForContainerdMount(mountPoint string) (string, error) {
|
||||
// NOTE: This relies on details of the behaviour of containerd's mount implementation for Windows,
|
||||
// and so is somewhat fragile.
|
||||
// TODO: Upstream this into the mount package.
|
||||
// The implementation would be the same, but it'll be better-encapsulated.
|
||||
|
||||
// See containerd/containerd/mount/mount_windows.go
|
||||
// This is mostly just copied from mount.Unmount
|
||||
|
||||
const sourceStreamName = "containerd.io-source"
|
||||
|
||||
mountPoint = filepath.Clean(mountPoint)
|
||||
adsFile := mountPoint + ":" + sourceStreamName
|
||||
var layerPath string
|
||||
|
||||
if _, err := os.Lstat(adsFile); err == nil {
|
||||
layerPathb, err := os.ReadFile(mountPoint + ":" + sourceStreamName)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to retrieve layer source for mount %s: %w", mountPoint, err)
|
||||
}
|
||||
layerPath = string(layerPathb)
|
||||
}
|
||||
|
||||
if layerPath == "" {
|
||||
return "", fmt.Errorf("no layer source for mount %s", mountPoint)
|
||||
}
|
||||
|
||||
home, layerID := filepath.Split(layerPath)
|
||||
di := hcsshim.DriverInfo{
|
||||
HomeDir: home,
|
||||
}
|
||||
|
||||
backingDevice, err := hcsshim.GetLayerMountPath(di, layerID)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to retrieve backing device for layer %s: %w", mountPoint, err)
|
||||
}
|
||||
|
||||
return backingDevice, nil
|
||||
}
|
||||
|
||||
var errInvalidCredentialSpecSecOpt = errdefs.InvalidParameter(fmt.Errorf("invalid credential spec security option - value must be prefixed by 'file://', 'registry://', or 'raw://' followed by a non-empty value"))
|
||||
|
||||
// setWindowsCredentialSpec sets the spec's `Windows.CredentialSpec`
|
||||
|
|
Loading…
Reference in a new issue