diff --git a/Makefile b/Makefile index a21625b7b2..ff43d0004a 100644 --- a/Makefile +++ b/Makefile @@ -55,6 +55,12 @@ clean: find . -name \*~ -delete find . -name \#\* -delete +cross: check-gopath + GOOS=windows $(GO) build -o $(CURDIR)/_output/critest.exe \ + $(PROJECT)/cmd/critest + GOOS=windows $(GO) build -o $(CURDIR)/_output/crictl.exe \ + $(PROJECT)/cmd/crictl + binaries: critest crictl install: check-gopath diff --git a/cmd/crictl/main.go b/cmd/crictl/main.go index ad4bff75dd..66af6654d7 100644 --- a/cmd/crictl/main.go +++ b/cmd/crictl/main.go @@ -18,7 +18,6 @@ package main import ( "fmt" - "net" "os" "sort" "time" @@ -28,6 +27,7 @@ import ( "google.golang.org/grpc" "k8s.io/kubernetes/pkg/kubelet/apis/cri" "k8s.io/kubernetes/pkg/kubelet/remote" + "k8s.io/kubernetes/pkg/kubelet/util" ) const ( @@ -36,7 +36,7 @@ const ( ) var ( - // RuntimeEndpoint is CRI server runtime endpoint (default: "/var/run/dockershim.sock") + // RuntimeEndpoint is CRI server runtime endpoint (default: "unix:///var/run/dockershim.sock") RuntimeEndpoint string // ImageEndpoint is CRI server image endpoint, default same as runtime endpoint ImageEndpoint string @@ -50,10 +50,13 @@ func getRuntimeClientConnection(context *cli.Context) (*grpc.ClientConn, error) if RuntimeEndpoint == "" { return nil, fmt.Errorf("--runtime-endpoint is not set") } - conn, err := grpc.Dial(RuntimeEndpoint, grpc.WithInsecure(), grpc.WithTimeout(Timeout), - grpc.WithDialer(func(addr string, timeout time.Duration) (net.Conn, error) { - return net.DialTimeout("unix", addr, timeout) - })) + + addr, dialer, err := util.GetAddressAndDialer(RuntimeEndpoint) + if err != nil { + return nil, err + } + + conn, err := grpc.Dial(addr, grpc.WithInsecure(), grpc.WithTimeout(Timeout), grpc.WithDialer(dialer)) if err != nil { return nil, fmt.Errorf("failed to connect: %v", err) } @@ -67,10 +70,13 @@ func getImageClientConnection(context *cli.Context) (*grpc.ClientConn, error) { } ImageEndpoint = RuntimeEndpoint } - conn, err := grpc.Dial(ImageEndpoint, grpc.WithInsecure(), grpc.WithTimeout(Timeout), - grpc.WithDialer(func(addr string, timeout time.Duration) (net.Conn, error) { - return net.DialTimeout("unix", addr, timeout) - })) + + addr, dialer, err := util.GetAddressAndDialer(ImageEndpoint) + if err != nil { + return nil, err + } + + conn, err := grpc.Dial(addr, grpc.WithInsecure(), grpc.WithTimeout(Timeout), grpc.WithDialer(dialer)) if err != nil { return nil, fmt.Errorf("failed to connect: %v", err) } @@ -125,7 +131,7 @@ func main() { cli.StringFlag{ Name: "runtime-endpoint, r", EnvVar: "CRI_RUNTIME_ENDPOINT", - Value: "/var/run/dockershim.sock", + Value: "unix:///var/run/dockershim.sock", Usage: "Endpoint of CRI container runtime service", }, cli.StringFlag{ diff --git a/cmd/critest/main.go b/cmd/critest/main.go index 7ff25c8fba..eb872575a1 100644 --- a/cmd/critest/main.go +++ b/cmd/critest/main.go @@ -49,7 +49,7 @@ func main() { cli.StringFlag{ Name: "runtime-endpoint, r", EnvVar: "CRI_RUNTIME_ENDPOINT", - Value: "/var/run/dockershim.sock", + Value: "unix:///var/run/dockershim.sock", Usage: "CRI runtime service address which is tested.", }, cli.StringFlag{ diff --git a/docs/benchmark.md b/docs/benchmark.md index ad85fcdd76..e6043e1641 100644 --- a/docs/benchmark.md +++ b/docs/benchmark.md @@ -32,7 +32,7 @@ This will - Run the benchmark tests using `ginkgo` - Output the test results to STDOUT -critest connects to `/var/run/dockershim.sock` by default. For other runtimes, the endpoint can be set in two ways: +critest connects to `unix:///var/run/dockershim.sock` by default. For other runtimes, the endpoint can be set in two ways: - By setting flags `--runtime-endpoint` and `--image-endpoint` - By setting environment variables `CRI_RUNTIME_ENDPOINT` and `CRI_IMAGE_ENDPOINT` @@ -42,5 +42,5 @@ critest connects to `/var/run/dockershim.sock` by default. For other runtimes, t - `--focus`, `-f`: Only run the tests that match the regular expression. - -`-ginkgo-flags`, `-g`: Space-separated list of arguments to pass to Ginkgo test runner. - `--image-endpoint`, `-i`: Set the endpoint of image service. Same with runtime-endpoint if not specified. -- `--runtime-endpoint`, `-r`: Set the endpoint of runtime service. Default to `/var/run/dockershim.sock`. +- `--runtime-endpoint`, `-r`: Set the endpoint of runtime service. Default to `unix:///var/run/dockershim.sock`. - `--skip`, `-s`: Skip the tests that match the regular expression. diff --git a/docs/crictl.md b/docs/crictl.md index 4174399f47..06e5dc03c6 100644 --- a/docs/crictl.md +++ b/docs/crictl.md @@ -47,7 +47,7 @@ Subcommands includes: - `logs`: Fetch the logs of a container - `help`: Shows a list of commands or help for one command -crictl connects to `/var/run/dockershim.sock` by default. For other runtimes, the endpoint can be set in three ways: +crictl connects to `unix:///var/run/dockershim.sock` by default. For other runtimes, the endpoint can be set in three ways: - By setting flags `--runtime-endpoint` and `--image-endpoint` - By setting environment variables `CRI_RUNTIME_ENDPOINT` and `CRI_IMAGE_ENDPOINT` @@ -55,15 +55,15 @@ crictl connects to `/var/run/dockershim.sock` by default. For other runtimes, th ``` # cat /etc/crictl.yaml -runtime-endpoint: /var/run/dockershim.sock -image-endpoint: /var/run/dockershim.sock +runtime-endpoint: unix:///var/run/dockershim.sock +image-endpoint: unix:///var/run/dockershim.sock timeout: 10 debug: true ``` ## Additional options -- `--runtime-endpoint`, `-r`: CRI server runtime endpoint (default: "/var/run/dockershim.sock").The default server is dockershim. If we want to debug other CRI server such as frakti, we can add flag `--runtime-endpoint=/var/run/frakti.sock` +- `--runtime-endpoint`, `-r`: CRI server runtime endpoint (default: "unix:///var/run/dockershim.sock").The default server is dockershim. If we want to debug other CRI server such as frakti, we can add flag `--runtime-endpoint=/var/run/frakti.sock` - `--image-endpoint`, `-i`: CRI server image endpoint, default same as runtime endpoint. - `--timeout`, `-t`: Timeout of connecting to server (default: 10s) - `--debug`, `-D`: Enable debug output diff --git a/docs/validation.md b/docs/validation.md index 68d9698adb..9114342dc4 100644 --- a/docs/validation.md +++ b/docs/validation.md @@ -34,7 +34,7 @@ This will - Run the tests using `ginkgo` - Output the test results to STDOUT -critest connects to `/var/run/dockershim.sock` by default. For other runtimes, the endpoint can be set in two ways: +critest connects to `unix:///var/run/dockershim.sock` by default. For other runtimes, the endpoint can be set in two ways: - By setting flags `--runtime-endpoint` and `--image-endpoint` - By setting environment variables `CRI_RUNTIME_ENDPOINT` and `CRI_IMAGE_ENDPOINT` @@ -44,5 +44,5 @@ critest connects to `/var/run/dockershim.sock` by default. For other runtimes, t - `--focus`, `-f`: Only run the tests that match the regular expression. - -`-ginkgo-flags`, `-g`: Space-separated list of arguments to pass to Ginkgo test runner. - `--image-endpoint`, `-i`: Set the endpoint of image service. Same with runtime-endpoint if not specified. -- `--runtime-endpoint`, `-r`: Set the endpoint of runtime service. Default to `/var/run/dockershim.sock`. +- `--runtime-endpoint`, `-r`: Set the endpoint of runtime service. Default to `unix:///var/run/dockershim.sock`. - `--skip`, `-s`: Skip the tests that match the regular expression. diff --git a/pkg/framework/test_context.go b/pkg/framework/test_context.go index 9ffc00c991..fd788816c6 100644 --- a/pkg/framework/test_context.go +++ b/pkg/framework/test_context.go @@ -55,9 +55,9 @@ func RegisterFlags() { flag.StringVar(&TestContext.ReportPrefix, "report-prefix", "", "Optional prefix for JUnit XML reports. Default is empty, which doesn't prepend anything to the default name.") flag.StringVar(&TestContext.ReportDir, "report-dir", "", "Path to the directory where the JUnit XML reports should be saved. Default is empty, which doesn't generate these reports.") - flag.StringVar(&TestContext.ImageServiceAddr, "image-service-address", "/var/run/dockershim.sock", "Image service socket for client to connect.") + flag.StringVar(&TestContext.ImageServiceAddr, "image-service-address", "unix:///var/run/dockershim.sock", "Image service socket for client to connect.") flag.DurationVar(&TestContext.ImageServiceTimeout, "image-service-timeout", 300*time.Second, "Timeout when trying to connect to image service.") - flag.StringVar(&TestContext.RuntimeServiceAddr, "runtime-service-address", "/var/run/dockershim.sock", "Runtime service socket for client to connect..") + flag.StringVar(&TestContext.RuntimeServiceAddr, "runtime-service-address", "unix:///var/run/dockershim.sock", "Runtime service socket for client to connect..") flag.DurationVar(&TestContext.RuntimeServiceTimeout, "runtime-service-timeout", 300*time.Second, "Timeout when trying to connect to a runtime service.") flag.IntVar(&TestContext.Number, "number", 5, "Number of PodSandbox/container in listing benchmark test.") } diff --git a/pkg/validate/container.go b/pkg/validate/container.go index f2b39146a9..68506eabcc 100644 --- a/pkg/validate/container.go +++ b/pkg/validate/container.go @@ -22,14 +22,12 @@ import ( "fmt" "io/ioutil" "os" - "path" "path/filepath" "strings" "time" "github.com/docker/docker/pkg/jsonlog" "github.com/kubernetes-incubator/cri-tools/pkg/framework" - "golang.org/x/sys/unix" internalapi "k8s.io/kubernetes/pkg/kubelet/apis/cri" runtimeapi "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime" @@ -225,123 +223,6 @@ var _ = framework.KubeDescribe("Container", func() { }) }) - Context("runtime should support mount propagation", func() { - var podID string - var podConfig *runtimeapi.PodSandboxConfig - - BeforeEach(func() { - podID, podConfig = createPrivilegedPodSandbox(rc, true) - }) - - AfterEach(func() { - By("stop PodSandbox") - rc.StopPodSandbox(podID) - By("delete PodSandbox") - rc.RemovePodSandbox(podID) - }) - - It("mount with 'rprivate' should not support propagation", func() { - By("create host path and flag file") - mntSource, propagationSrcDir, propagationMntPoint, clearHostPath := createHostPathForMountPropagation(podID, runtimeapi.MountPropagation_PROPAGATION_PRIVATE) - defer clearHostPath() // clean up the TempDir - - By("create container with volume") - containerID := createMountPropagationContainer(rc, ic, "mount-propagation-test-", podID, podConfig, mntSource, runtimeapi.MountPropagation_PROPAGATION_PRIVATE) - - By("test start container with volume") - testStartContainer(rc, containerID) - - By("create a propatation mount point in host") - createPropagationMountPoint(propagationSrcDir, propagationMntPoint) - - By("check whether propagationMntPoint contains file or dir in container") - command := []string{"ls", "-A", propagationMntPoint} - output := execSyncContainer(rc, containerID, command) - Expect(len(output)).To(BeZero(), "len(output) should be zero.") - - By("create a directory named containerMntPoint as a mount point in container") - containerMntPoint := path.Join(mntSource, "containerMntPoint") - command = []string{"sh", "-c", "mkdir -p " + containerMntPoint} - execSyncContainer(rc, containerID, command) - - By("mount /etc to the mount point in container") - command = []string{"sh", "-c", "mount --bind /etc " + containerMntPoint} - execSyncContainer(rc, containerID, command) - - By("check whether containerMntPoint contains file or dir in host") - fileInfo, err := ioutil.ReadDir(containerMntPoint) - framework.ExpectNoError(err, "failed to ReadDir %q in Host", containerMntPoint) - Expect(len(fileInfo)).To(BeZero(), "len(fileInfo) should be zero.") - }) - - It("mount with 'rshared' should support propagation from host to container and vice versa", func() { - By("create host path and flag file") - mntSource, propagationSrcDir, propagationMntPoint, clearHostPath := createHostPathForMountPropagation(podID, runtimeapi.MountPropagation_PROPAGATION_BIDIRECTIONAL) - defer clearHostPath() // clean up the TempDir - - By("create container with volume") - containerID := createMountPropagationContainer(rc, ic, "mount-propagation-test-", podID, podConfig, mntSource, runtimeapi.MountPropagation_PROPAGATION_BIDIRECTIONAL) - - By("test start container with volume") - testStartContainer(rc, containerID) - - By("create a propatation mount point in host") - createPropagationMountPoint(propagationSrcDir, propagationMntPoint) - - By("check whether propagationMntPoint contains file or dir in container") - command := []string{"ls", "-A", propagationMntPoint} - output := execSyncContainer(rc, containerID, command) - Expect(len(output)).NotTo(BeZero(), "len(output) should not be zero.") - - By("create a directory named containerMntPoint as a mount point in container") - containerMntPoint := path.Join(mntSource, "containerMntPoint") - command = []string{"sh", "-c", "mkdir -p " + containerMntPoint} - execSyncContainer(rc, containerID, command) - - By("mount /etc to the mount point in container") - command = []string{"sh", "-c", "mount --bind /etc " + containerMntPoint} - execSyncContainer(rc, containerID, command) - - By("check whether containerMntPoint contains file or dir in host") - fileInfo, err := ioutil.ReadDir(containerMntPoint) - framework.ExpectNoError(err, "failed to ReadDir %q in Host", containerMntPoint) - Expect(len(fileInfo)).NotTo(BeZero(), "len(fileInfo) should not be zero.") - }) - - It("mount with 'rslave' should support propagation from host to container", func() { - By("create host path and flag file") - mntSource, propagationSrcDir, propagationMntPoint, clearHostPath := createHostPathForMountPropagation(podID, runtimeapi.MountPropagation_PROPAGATION_HOST_TO_CONTAINER) - defer clearHostPath() // clean up the TempDir - - By("create container with volume") - containerID := createMountPropagationContainer(rc, ic, "mount-propagation-test-", podID, podConfig, mntSource, runtimeapi.MountPropagation_PROPAGATION_HOST_TO_CONTAINER) - - By("test start container with volume") - testStartContainer(rc, containerID) - - By("create a propatation mount point in host") - createPropagationMountPoint(propagationSrcDir, propagationMntPoint) - - By("check whether propagationMntPoint contains file or dir in container") - command := []string{"ls", "-A", propagationMntPoint} - output := execSyncContainer(rc, containerID, command) - Expect(len(output)).NotTo(BeZero(), "len(output) should not be zero.") - - By("create a directory named containerMntPoint as a mount point in container") - containerMntPoint := path.Join(mntSource, "containerMntPoint") - command = []string{"sh", "-c", "mkdir -p " + containerMntPoint} - execSyncContainer(rc, containerID, command) - - By("mount /etc to the mount point in container") - command = []string{"sh", "-c", "mount --bind /etc " + containerMntPoint} - execSyncContainer(rc, containerID, command) - - By("check whether containerMntPoint contains file or dir in host") - fileInfo, err := ioutil.ReadDir(containerMntPoint) - framework.ExpectNoError(err, "failed to ReadDir %q in Host", containerMntPoint) - Expect(len(fileInfo)).To(BeZero(), "len(fileInfo) should be zero.") - }) - }) }) // containerFound returns whether containers is found. @@ -601,87 +482,3 @@ func verifyLogContents(podConfig *runtimeapi.PodSandboxConfig, logPath string, e Expect(string(msg.stream)).To(Equal(string(expectedLogMessage.stream)), "Stream should be %s", string(expectedLogMessage.stream)) } } - -// createHostPath creates the hostPath for mount propagation test. -func createHostPathForMountPropagation(podID string, propagationOpt runtimeapi.MountPropagation) (string, string, string, func()) { - hostPath, err := ioutil.TempDir("", "/test"+podID) - framework.ExpectNoError(err, "failed to create TempDir %q: %v", hostPath, err) - - mntSource := filepath.Join(hostPath, "mnt") - propagationMntPoint := filepath.Join(mntSource, "propagationMnt") - err = os.MkdirAll(propagationMntPoint, 0700) - framework.ExpectNoError(err, "failed to create volume dir %q: %v", propagationMntPoint, err) - - propagationSrcDir := filepath.Join(hostPath, "propagationSrcDir") - err = os.MkdirAll(propagationSrcDir, 0700) - framework.ExpectNoError(err, "failed to create volume dir %q: %v", propagationSrcDir, err) - - _, err = os.Create(filepath.Join(propagationSrcDir, "flagFile")) - framework.ExpectNoError(err, "failed to create volume file \"flagFile\": %v", err) - - switch propagationOpt { - case runtimeapi.MountPropagation_PROPAGATION_PRIVATE: - err := unix.Mount(mntSource, mntSource, "bind", unix.MS_BIND|unix.MS_REC, "") - framework.ExpectNoError(err, "failed to mount \"mntSource\": %v", err) - err = unix.Mount("", mntSource, "", unix.MS_PRIVATE|unix.MS_REC, "") - framework.ExpectNoError(err, "failed to set \"mntSource\" to \"rprivate\": %v", err) - case runtimeapi.MountPropagation_PROPAGATION_HOST_TO_CONTAINER, - runtimeapi.MountPropagation_PROPAGATION_BIDIRECTIONAL: - err := unix.Mount(mntSource, mntSource, "bind", unix.MS_BIND|unix.MS_REC, "") - framework.ExpectNoError(err, "failed to mount \"mntSource\": %v", err) - err = unix.Mount("", mntSource, "", unix.MS_SHARED|unix.MS_REC, "") - framework.ExpectNoError(err, "failed to set \"mntSource\" to \"rprivate\": %v", err) - default: - err := unix.Mount(mntSource, mntSource, "bind", unix.MS_BIND|unix.MS_REC, "") - framework.ExpectNoError(err, "failed to mount \"mntSource\": %v", err) - err = unix.Mount("", mntSource, "", unix.MS_PRIVATE|unix.MS_REC, "") - framework.ExpectNoError(err, "failed to set \"mntSource\" to \"rprivate\": %v", err) - } - - clearHostPath := func() { - By("clean up the TempDir") - err := unix.Unmount(propagationMntPoint, unix.MNT_DETACH) - framework.ExpectNoError(err, "failed to unmount \"propagationMntPoint\": %v", err) - err = unix.Unmount(mntSource, unix.MNT_DETACH) - framework.ExpectNoError(err, "failed to unmount \"mntSource\": %v", err) - - os.RemoveAll(hostPath) - framework.ExpectNoError(err, "failed to remove \"hostPath\": %v", err) - } - - return mntSource, propagationSrcDir, propagationMntPoint, clearHostPath -} - -// createMountPropagationContainer creates a container with volume and Privileged and fails if it gets error. -func createMountPropagationContainer(rc internalapi.RuntimeService, ic internalapi.ImageManagerService, prefix string, podID string, - podConfig *runtimeapi.PodSandboxConfig, hostPath string, PropagationOpt runtimeapi.MountPropagation) string { - By("create a container with volume and name") - containerName := prefix + framework.NewUUID() - containerConfig := &runtimeapi.ContainerConfig{ - Metadata: framework.BuildContainerMetadata(containerName, framework.DefaultAttempt), - Image: &runtimeapi.ImageSpec{Image: framework.DefaultContainerImage}, - Command: []string{"sh", "-c", "top"}, - // Set Privileged in order to executing mount command in container - Linux: &runtimeapi.LinuxContainerConfig{ - SecurityContext: &runtimeapi.LinuxContainerSecurityContext{ - Privileged: true, - }, - }, - Mounts: []*runtimeapi.Mount{ - { - HostPath: hostPath, - ContainerPath: hostPath, - Propagation: PropagationOpt, - }, - }, - } - - return framework.CreateContainer(rc, ic, containerConfig, podID, podConfig) -} - -// createPropagationMountPoint mount "propagationSrcDir" at "propagationMntPoint", -// this will be used to check whether mount can be propagated from host to container or not. -func createPropagationMountPoint(propagationSrcDir, propagationMntPoint string) { - err := unix.Mount(propagationSrcDir, propagationMntPoint, "bind", unix.MS_BIND|unix.MS_REC, "") - framework.ExpectNoError(err, "failed to mount \"propagationMntPoint\": %v", err) -} diff --git a/pkg/validate/container_linux.go b/pkg/validate/container_linux.go new file mode 100644 index 0000000000..f7daa46070 --- /dev/null +++ b/pkg/validate/container_linux.go @@ -0,0 +1,246 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package validate + +import ( + "io/ioutil" + "os" + "path" + "path/filepath" + + "github.com/kubernetes-incubator/cri-tools/pkg/framework" + "golang.org/x/sys/unix" + internalapi "k8s.io/kubernetes/pkg/kubelet/apis/cri" + runtimeapi "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = framework.KubeDescribe("Container Mount Propagation", func() { + f := framework.NewDefaultCRIFramework() + + var rc internalapi.RuntimeService + var ic internalapi.ImageManagerService + + BeforeEach(func() { + rc = f.CRIClient.CRIRuntimeClient + ic = f.CRIClient.CRIImageClient + }) + + Context("runtime should support mount propagation", func() { + var podID string + var podConfig *runtimeapi.PodSandboxConfig + + BeforeEach(func() { + podID, podConfig = createPrivilegedPodSandbox(rc, true) + }) + + AfterEach(func() { + By("stop PodSandbox") + rc.StopPodSandbox(podID) + By("delete PodSandbox") + rc.RemovePodSandbox(podID) + }) + + It("mount with 'rprivate' should not support propagation", func() { + By("create host path and flag file") + mntSource, propagationSrcDir, propagationMntPoint, clearHostPath := createHostPathForMountPropagation(podID, runtimeapi.MountPropagation_PROPAGATION_PRIVATE) + defer clearHostPath() // clean up the TempDir + + By("create container with volume") + containerID := createMountPropagationContainer(rc, ic, "mount-propagation-test-", podID, podConfig, mntSource, runtimeapi.MountPropagation_PROPAGATION_PRIVATE) + + By("test start container with volume") + testStartContainer(rc, containerID) + + By("create a propatation mount point in host") + createPropagationMountPoint(propagationSrcDir, propagationMntPoint) + + By("check whether propagationMntPoint contains file or dir in container") + command := []string{"ls", "-A", propagationMntPoint} + output := execSyncContainer(rc, containerID, command) + Expect(len(output)).To(BeZero(), "len(output) should be zero.") + + By("create a directory named containerMntPoint as a mount point in container") + containerMntPoint := path.Join(mntSource, "containerMntPoint") + command = []string{"sh", "-c", "mkdir -p " + containerMntPoint} + execSyncContainer(rc, containerID, command) + + By("mount /etc to the mount point in container") + command = []string{"sh", "-c", "mount --bind /etc " + containerMntPoint} + execSyncContainer(rc, containerID, command) + + By("check whether containerMntPoint contains file or dir in host") + fileInfo, err := ioutil.ReadDir(containerMntPoint) + framework.ExpectNoError(err, "failed to ReadDir %q in Host", containerMntPoint) + Expect(len(fileInfo)).To(BeZero(), "len(fileInfo) should be zero.") + }) + + It("mount with 'rshared' should support propagation from host to container and vice versa", func() { + By("create host path and flag file") + mntSource, propagationSrcDir, propagationMntPoint, clearHostPath := createHostPathForMountPropagation(podID, runtimeapi.MountPropagation_PROPAGATION_BIDIRECTIONAL) + defer clearHostPath() // clean up the TempDir + + By("create container with volume") + containerID := createMountPropagationContainer(rc, ic, "mount-propagation-test-", podID, podConfig, mntSource, runtimeapi.MountPropagation_PROPAGATION_BIDIRECTIONAL) + + By("test start container with volume") + testStartContainer(rc, containerID) + + By("create a propatation mount point in host") + createPropagationMountPoint(propagationSrcDir, propagationMntPoint) + + By("check whether propagationMntPoint contains file or dir in container") + command := []string{"ls", "-A", propagationMntPoint} + output := execSyncContainer(rc, containerID, command) + Expect(len(output)).NotTo(BeZero(), "len(output) should not be zero.") + + By("create a directory named containerMntPoint as a mount point in container") + containerMntPoint := path.Join(mntSource, "containerMntPoint") + command = []string{"sh", "-c", "mkdir -p " + containerMntPoint} + execSyncContainer(rc, containerID, command) + + By("mount /etc to the mount point in container") + command = []string{"sh", "-c", "mount --bind /etc " + containerMntPoint} + execSyncContainer(rc, containerID, command) + + By("check whether containerMntPoint contains file or dir in host") + fileInfo, err := ioutil.ReadDir(containerMntPoint) + framework.ExpectNoError(err, "failed to ReadDir %q in Host", containerMntPoint) + Expect(len(fileInfo)).NotTo(BeZero(), "len(fileInfo) should not be zero.") + }) + + It("mount with 'rslave' should support propagation from host to container", func() { + By("create host path and flag file") + mntSource, propagationSrcDir, propagationMntPoint, clearHostPath := createHostPathForMountPropagation(podID, runtimeapi.MountPropagation_PROPAGATION_HOST_TO_CONTAINER) + defer clearHostPath() // clean up the TempDir + + By("create container with volume") + containerID := createMountPropagationContainer(rc, ic, "mount-propagation-test-", podID, podConfig, mntSource, runtimeapi.MountPropagation_PROPAGATION_HOST_TO_CONTAINER) + + By("test start container with volume") + testStartContainer(rc, containerID) + + By("create a propatation mount point in host") + createPropagationMountPoint(propagationSrcDir, propagationMntPoint) + + By("check whether propagationMntPoint contains file or dir in container") + command := []string{"ls", "-A", propagationMntPoint} + output := execSyncContainer(rc, containerID, command) + Expect(len(output)).NotTo(BeZero(), "len(output) should not be zero.") + + By("create a directory named containerMntPoint as a mount point in container") + containerMntPoint := path.Join(mntSource, "containerMntPoint") + command = []string{"sh", "-c", "mkdir -p " + containerMntPoint} + execSyncContainer(rc, containerID, command) + + By("mount /etc to the mount point in container") + command = []string{"sh", "-c", "mount --bind /etc " + containerMntPoint} + execSyncContainer(rc, containerID, command) + + By("check whether containerMntPoint contains file or dir in host") + fileInfo, err := ioutil.ReadDir(containerMntPoint) + framework.ExpectNoError(err, "failed to ReadDir %q in Host", containerMntPoint) + Expect(len(fileInfo)).To(BeZero(), "len(fileInfo) should be zero.") + }) + }) +}) + +// createHostPath creates the hostPath for mount propagation test. +func createHostPathForMountPropagation(podID string, propagationOpt runtimeapi.MountPropagation) (string, string, string, func()) { + hostPath, err := ioutil.TempDir("", "/test"+podID) + framework.ExpectNoError(err, "failed to create TempDir %q: %v", hostPath, err) + + mntSource := filepath.Join(hostPath, "mnt") + propagationMntPoint := filepath.Join(mntSource, "propagationMnt") + err = os.MkdirAll(propagationMntPoint, 0700) + framework.ExpectNoError(err, "failed to create volume dir %q: %v", propagationMntPoint, err) + + propagationSrcDir := filepath.Join(hostPath, "propagationSrcDir") + err = os.MkdirAll(propagationSrcDir, 0700) + framework.ExpectNoError(err, "failed to create volume dir %q: %v", propagationSrcDir, err) + + _, err = os.Create(filepath.Join(propagationSrcDir, "flagFile")) + framework.ExpectNoError(err, "failed to create volume file \"flagFile\": %v", err) + + switch propagationOpt { + case runtimeapi.MountPropagation_PROPAGATION_PRIVATE: + err := unix.Mount(mntSource, mntSource, "bind", unix.MS_BIND|unix.MS_REC, "") + framework.ExpectNoError(err, "failed to mount \"mntSource\": %v", err) + err = unix.Mount("", mntSource, "", unix.MS_PRIVATE|unix.MS_REC, "") + framework.ExpectNoError(err, "failed to set \"mntSource\" to \"rprivate\": %v", err) + case runtimeapi.MountPropagation_PROPAGATION_HOST_TO_CONTAINER, + runtimeapi.MountPropagation_PROPAGATION_BIDIRECTIONAL: + err := unix.Mount(mntSource, mntSource, "bind", unix.MS_BIND|unix.MS_REC, "") + framework.ExpectNoError(err, "failed to mount \"mntSource\": %v", err) + err = unix.Mount("", mntSource, "", unix.MS_SHARED|unix.MS_REC, "") + framework.ExpectNoError(err, "failed to set \"mntSource\" to \"rprivate\": %v", err) + default: + err := unix.Mount(mntSource, mntSource, "bind", unix.MS_BIND|unix.MS_REC, "") + framework.ExpectNoError(err, "failed to mount \"mntSource\": %v", err) + err = unix.Mount("", mntSource, "", unix.MS_PRIVATE|unix.MS_REC, "") + framework.ExpectNoError(err, "failed to set \"mntSource\" to \"rprivate\": %v", err) + } + + clearHostPath := func() { + By("clean up the TempDir") + err := unix.Unmount(propagationMntPoint, unix.MNT_DETACH) + framework.ExpectNoError(err, "failed to unmount \"propagationMntPoint\": %v", err) + err = unix.Unmount(mntSource, unix.MNT_DETACH) + framework.ExpectNoError(err, "failed to unmount \"mntSource\": %v", err) + + os.RemoveAll(hostPath) + framework.ExpectNoError(err, "failed to remove \"hostPath\": %v", err) + } + + return mntSource, propagationSrcDir, propagationMntPoint, clearHostPath +} + +// createMountPropagationContainer creates a container with volume and Privileged and fails if it gets error. +func createMountPropagationContainer(rc internalapi.RuntimeService, ic internalapi.ImageManagerService, prefix string, podID string, + podConfig *runtimeapi.PodSandboxConfig, hostPath string, PropagationOpt runtimeapi.MountPropagation) string { + By("create a container with volume and name") + containerName := prefix + framework.NewUUID() + containerConfig := &runtimeapi.ContainerConfig{ + Metadata: framework.BuildContainerMetadata(containerName, framework.DefaultAttempt), + Image: &runtimeapi.ImageSpec{Image: framework.DefaultContainerImage}, + Command: []string{"sh", "-c", "top"}, + // Set Privileged in order to executing mount command in container + Linux: &runtimeapi.LinuxContainerConfig{ + SecurityContext: &runtimeapi.LinuxContainerSecurityContext{ + Privileged: true, + }, + }, + Mounts: []*runtimeapi.Mount{ + { + HostPath: hostPath, + ContainerPath: hostPath, + Propagation: PropagationOpt, + }, + }, + } + + return framework.CreateContainer(rc, ic, containerConfig, podID, podConfig) +} + +// createPropagationMountPoint mount "propagationSrcDir" at "propagationMntPoint", +// this will be used to check whether mount can be propagated from host to container or not. +func createPropagationMountPoint(propagationSrcDir, propagationMntPoint string) { + err := unix.Mount(propagationSrcDir, propagationMntPoint, "bind", unix.MS_BIND|unix.MS_REC, "") + framework.ExpectNoError(err, "failed to mount \"propagationMntPoint\": %v", err) +} diff --git a/pkg/validate/selinux.go b/pkg/validate/selinux_linux.go similarity index 100% rename from pkg/validate/selinux.go rename to pkg/validate/selinux_linux.go