Merge pull request #1511 from kevpar/named-pipe-mounts
Support named pipe mounts for Windows containers
This commit is contained in:
commit
09d6426f33
@ -22,6 +22,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
"sort"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/containerd/containerd/containers"
|
"github.com/containerd/containerd/containers"
|
||||||
"github.com/containerd/containerd/oci"
|
"github.com/containerd/containerd/oci"
|
||||||
@ -47,6 +48,20 @@ func WithWindowsNetworkNamespace(path string) oci.SpecOpts {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// namedPipePath returns true if the given path is to a named pipe.
|
||||||
|
func namedPipePath(p string) bool {
|
||||||
|
return strings.HasPrefix(p, `\\.\pipe\`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// cleanMount returns a cleaned version of the mount path. The input is returned
|
||||||
|
// as-is if it is a named pipe path.
|
||||||
|
func cleanMount(p string) string {
|
||||||
|
if namedPipePath(p) {
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
return filepath.Clean(p)
|
||||||
|
}
|
||||||
|
|
||||||
// WithWindowsMounts sorts and adds runtime and CRI mounts to the spec for
|
// WithWindowsMounts sorts and adds runtime and CRI mounts to the spec for
|
||||||
// windows container.
|
// windows container.
|
||||||
func WithWindowsMounts(osi osinterface.OS, config *runtime.ContainerConfig, extra []*runtime.Mount) oci.SpecOpts {
|
func WithWindowsMounts(osi osinterface.OS, config *runtime.ContainerConfig, extra []*runtime.Mount) oci.SpecOpts {
|
||||||
@ -62,7 +77,7 @@ func WithWindowsMounts(osi osinterface.OS, config *runtime.ContainerConfig, extr
|
|||||||
for _, e := range extra {
|
for _, e := range extra {
|
||||||
found := false
|
found := false
|
||||||
for _, c := range criMounts {
|
for _, c := range criMounts {
|
||||||
if filepath.Clean(e.ContainerPath) == filepath.Clean(c.ContainerPath) {
|
if cleanMount(e.ContainerPath) == cleanMount(c.ContainerPath) {
|
||||||
found = true
|
found = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -80,14 +95,14 @@ func WithWindowsMounts(osi osinterface.OS, config *runtime.ContainerConfig, extr
|
|||||||
// mounts overridden by supplied mount;
|
// mounts overridden by supplied mount;
|
||||||
mountSet := make(map[string]struct{})
|
mountSet := make(map[string]struct{})
|
||||||
for _, m := range mounts {
|
for _, m := range mounts {
|
||||||
mountSet[filepath.Clean(m.ContainerPath)] = struct{}{}
|
mountSet[cleanMount(m.ContainerPath)] = struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultMounts := s.Mounts
|
defaultMounts := s.Mounts
|
||||||
s.Mounts = nil
|
s.Mounts = nil
|
||||||
|
|
||||||
for _, m := range defaultMounts {
|
for _, m := range defaultMounts {
|
||||||
dst := filepath.Clean(m.Destination)
|
dst := cleanMount(m.Destination)
|
||||||
if _, ok := mountSet[dst]; ok {
|
if _, ok := mountSet[dst]; ok {
|
||||||
// filter out mount overridden by a supplied mount
|
// filter out mount overridden by a supplied mount
|
||||||
continue
|
continue
|
||||||
@ -100,18 +115,26 @@ func WithWindowsMounts(osi osinterface.OS, config *runtime.ContainerConfig, extr
|
|||||||
dst = mount.GetContainerPath()
|
dst = mount.GetContainerPath()
|
||||||
src = mount.GetHostPath()
|
src = mount.GetHostPath()
|
||||||
)
|
)
|
||||||
// TODO(windows): Support special mount sources, e.g. named pipe.
|
// In the case of a named pipe mount on Windows, don't stat the file
|
||||||
// Create the host path if it doesn't exist.
|
// or do other operations that open it, as that could interfere with
|
||||||
|
// the listening process. filepath.Clean also breaks named pipe
|
||||||
|
// paths, so don't use it.
|
||||||
|
if !namedPipePath(src) {
|
||||||
if _, err := osi.Stat(src); err != nil {
|
if _, err := osi.Stat(src); err != nil {
|
||||||
// If the source doesn't exist, return an error instead
|
// If the source doesn't exist, return an error instead
|
||||||
// of creating the source. This aligns with Docker's
|
// of creating the source. This aligns with Docker's
|
||||||
// behavior on windows.
|
// behavior on windows.
|
||||||
return errors.Wrapf(err, "failed to stat %q", src)
|
return errors.Wrapf(err, "failed to stat %q", src)
|
||||||
}
|
}
|
||||||
src, err := osi.ResolveSymbolicLink(src)
|
var err error
|
||||||
|
src, err = osi.ResolveSymbolicLink(src)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "failed to resolve symlink %q", src)
|
return errors.Wrapf(err, "failed to resolve symlink %q", src)
|
||||||
}
|
}
|
||||||
|
// hcsshim requires clean path, especially '/' -> '\'.
|
||||||
|
src = filepath.Clean(src)
|
||||||
|
dst = filepath.Clean(dst)
|
||||||
|
}
|
||||||
|
|
||||||
var options []string
|
var options []string
|
||||||
// NOTE(random-liu): we don't change all mounts to `ro` when root filesystem
|
// NOTE(random-liu): we don't change all mounts to `ro` when root filesystem
|
||||||
@ -122,9 +145,8 @@ func WithWindowsMounts(osi osinterface.OS, config *runtime.ContainerConfig, extr
|
|||||||
options = append(options, "rw")
|
options = append(options, "rw")
|
||||||
}
|
}
|
||||||
s.Mounts = append(s.Mounts, runtimespec.Mount{
|
s.Mounts = append(s.Mounts, runtimespec.Mount{
|
||||||
// hcsshim requires clean path, especially '/' -> '\'.
|
Source: src,
|
||||||
Source: filepath.Clean(src),
|
Destination: dst,
|
||||||
Destination: filepath.Clean(dst),
|
|
||||||
Options: options,
|
Options: options,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -167,3 +167,23 @@ func TestMountCleanPath(t *testing.T) {
|
|||||||
specCheck(t, testID, testSandboxID, testPid, spec)
|
specCheck(t, testID, testSandboxID, testPid, spec)
|
||||||
checkMount(t, spec.Mounts, "c:\\test\\host-path", "c:\\test\\container-path", "", []string{"rw"}, nil)
|
checkMount(t, spec.Mounts, "c:\\test\\host-path", "c:\\test\\container-path", "", []string{"rw"}, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMountNamedPipe(t *testing.T) {
|
||||||
|
testID := "test-id"
|
||||||
|
testSandboxID := "sandbox-id"
|
||||||
|
testContainerName := "container-name"
|
||||||
|
testPid := uint32(1234)
|
||||||
|
nsPath := "test-cni"
|
||||||
|
c := newTestCRIService()
|
||||||
|
|
||||||
|
containerConfig, sandboxConfig, imageConfig, specCheck := getCreateContainerTestData()
|
||||||
|
containerConfig.Mounts = append(containerConfig.Mounts, &runtime.Mount{
|
||||||
|
ContainerPath: `\\.\pipe\foo`,
|
||||||
|
HostPath: `\\.\pipe\foo`,
|
||||||
|
})
|
||||||
|
spec, err := c.containerSpec(testID, testSandboxID, testPid, nsPath, testContainerName, containerConfig, sandboxConfig, imageConfig, nil, config.Runtime{})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotNil(t, spec)
|
||||||
|
specCheck(t, testID, testSandboxID, testPid, spec)
|
||||||
|
checkMount(t, spec.Mounts, `\\.\pipe\foo`, `\\.\pipe\foo`, "", []string{"rw"}, nil)
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user