diff --git a/pkg/validate/multi_container_linux.go b/pkg/validate/multi_container_linux.go new file mode 100644 index 0000000000..5b3d829010 --- /dev/null +++ b/pkg/validate/multi_container_linux.go @@ -0,0 +1,152 @@ +/* +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 ( + "fmt" + "io/ioutil" + "os" + "strings" + "time" + + "github.com/kubernetes-sigs/cri-tools/pkg/framework" + internalapi "k8s.io/kubernetes/pkg/kubelet/apis/cri" + runtimeapi "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +const ( + httpdContainerPort = 80 + httpdImage = "httpd" +) + +var _ = framework.KubeDescribe("Multiple Containers [Conformance]", func() { + f := framework.NewDefaultCRIFramework() + + var rc internalapi.RuntimeService + var ic internalapi.ImageManagerService + + BeforeEach(func() { + rc = f.CRIClient.CRIRuntimeClient + ic = f.CRIClient.CRIImageClient + }) + + Context("when running multiple containers in a pod", func() { + var podID, httpdContainerID, busyboxContainerID, logDir string + var podConfig *runtimeapi.PodSandboxConfig + + BeforeEach(func() { + By("create a PodSandbox") + podID, podConfig, logDir = createMultiContainerTestPodSandbox(rc) + + By("create a httpd container") + httpdContainerID = createMultiContainerTestHttpdContainer(rc, ic, "httpd", podID, podConfig) + By("start the httpd container") + testStartContainer(rc, httpdContainerID) + + By("create a busybox container") + busyboxContainerID = createMultiContainerTestBusyboxContainer(rc, ic, "busybox", podID, podConfig) + By("start the busybox container") + testStartContainer(rc, busyboxContainerID) + }) + + AfterEach(func() { + By("stop PodSandbox") + Expect(rc.StopPodSandbox(podID)).To(Succeed()) + By("delete PodSandbox") + Expect(rc.RemovePodSandbox(podID)).To(Succeed()) + By("cleanup log path") + Expect(os.RemoveAll(logDir)).To(Succeed()) + }) + + It("should support network", func() { + checkMainPage(rc, podID, 0) + }) + + It("should support container log", func() { + verifyContainerLog := func(path, expected string) func() (bool, error) { + return func() (bool, error) { + content, err := ioutil.ReadFile(path) + if err != nil { + return false, err + } + return strings.Contains(string(content), expected), nil + } + } + httpdStatus, err := rc.ContainerStatus(httpdContainerID) + Expect(err).NotTo(HaveOccurred(), "get httpd container status") + Eventually(verifyContainerLog(httpdStatus.GetLogPath(), + "httpd -D FOREGROUND"), time.Minute, 100*time.Millisecond).Should(BeTrue()) + + busyboxStatus, err := rc.ContainerStatus(busyboxContainerID) + Expect(err).NotTo(HaveOccurred(), "get busybox container status") + Eventually(verifyContainerLog(busyboxStatus.GetLogPath(), + defaultLog), time.Minute, 100*time.Millisecond).Should(BeTrue()) + }) + + It("should support container exec", func() { + Expect(execSyncContainer(rc, httpdContainerID, []string{"echo", "httpd"})).To(Equal("httpd\n")) + Expect(execSyncContainer(rc, busyboxContainerID, []string{"echo", "busybox"})).To(Equal("busybox\n")) + }) + }) +}) + +// createMultiContainerTestPodSandbox creates a sandbox with log directory and a container port for httpd container. +func createMultiContainerTestPodSandbox(c internalapi.RuntimeService) (string, *runtimeapi.PodSandboxConfig, string) { + podSandboxName := "PodSandbox-for-multi-container-test-" + framework.NewUUID() + uid := framework.DefaultUIDPrefix + framework.NewUUID() + namespace := framework.DefaultNamespacePrefix + framework.NewUUID() + logDir, podLogPath := createLogTempDir(podSandboxName) + podConfig := &runtimeapi.PodSandboxConfig{ + Metadata: framework.BuildPodSandboxMetadata(podSandboxName, uid, namespace, framework.DefaultAttempt), + LogDirectory: podLogPath, + PortMappings: []*runtimeapi.PortMapping{ + { + ContainerPort: httpdContainerPort, + }, + }, + } + return framework.RunPodSandbox(c, podConfig), podConfig, logDir +} + +// createMultiContainerTestHttpdContainer creates an httpd container. +func createMultiContainerTestHttpdContainer(rc internalapi.RuntimeService, ic internalapi.ImageManagerService, prefix string, + podID string, podConfig *runtimeapi.PodSandboxConfig) string { + containerName := prefix + framework.NewUUID() + containerConfig := &runtimeapi.ContainerConfig{ + Metadata: framework.BuildContainerMetadata(containerName, framework.DefaultAttempt), + Image: &runtimeapi.ImageSpec{Image: httpdImage}, + Linux: &runtimeapi.LinuxContainerConfig{}, + LogPath: fmt.Sprintf("%s.log", containerName), + } + return framework.CreateContainer(rc, ic, containerConfig, podID, podConfig) +} + +// createMultiContainerTestBusyboxContainer creates a busybox container. +func createMultiContainerTestBusyboxContainer(rc internalapi.RuntimeService, ic internalapi.ImageManagerService, + prefix string, podID string, podConfig *runtimeapi.PodSandboxConfig) string { + containerName := prefix + framework.NewUUID() + containerConfig := &runtimeapi.ContainerConfig{ + Metadata: framework.BuildContainerMetadata(containerName, framework.DefaultAttempt), + Image: &runtimeapi.ImageSpec{Image: framework.DefaultContainerImage}, + Command: []string{"sh", "-c", "echo " + defaultLog + "; sleep 1000"}, + LogPath: fmt.Sprintf("%s.log", containerName), + } + return framework.CreateContainer(rc, ic, containerConfig, podID, podConfig) +} diff --git a/pkg/validate/networking.go b/pkg/validate/networking.go index 177d714452..c79ae9d038 100644 --- a/pkg/validate/networking.go +++ b/pkg/validate/networking.go @@ -103,7 +103,7 @@ var _ = framework.KubeDescribe("Networking", func() { startContainer(rc, containerID) By("check the port mapping with only container port") - checkNginxMainPage(rc, podID, 0) + checkMainPage(rc, podID, 0) }) It("runtime should support port mapping with host port and container port [Conformance]", func() { @@ -124,7 +124,7 @@ var _ = framework.KubeDescribe("Networking", func() { startContainer(rc, containerID) By("check the port mapping with host port and container port") - checkNginxMainPage(rc, "", nginxHostPortForPortMapping) + checkMainPage(rc, "", nginxHostPortForPortMapping) }) }) }) @@ -205,8 +205,8 @@ func createHostNetNginxContainer(rc internalapi.RuntimeService, ic internalapi.I return framework.CreateContainer(rc, ic, containerConfig, podID, podConfig) } -// checkNginxMainPage check if the we can get the main page of nginx via given IP:port. -func checkNginxMainPage(c internalapi.RuntimeService, podID string, hostPort int32) { +// checkMainPage check if the we can get the main page of the pod via given IP:port. +func checkMainPage(c internalapi.RuntimeService, podID string, hostPort int32) { By("get the IP:port needed to be checked") var err error var resp *http.Response diff --git a/pkg/validate/streaming.go b/pkg/validate/streaming.go index ab3bd78662..f81e9a30ea 100644 --- a/pkg/validate/streaming.go +++ b/pkg/validate/streaming.go @@ -343,6 +343,6 @@ func checkPortForward(c internalapi.RuntimeService, portForwardSeverURL string, }() By(fmt.Sprintf("check if we can get nginx main page via localhost:%d", hostPort)) - checkNginxMainPage(c, "", hostPort) + checkMainPage(c, "", hostPort) framework.Logf("Check port forward url %q succeed", portForwardSeverURL) }