1// +build linux 2 3/* 4 Copyright The containerd Authors. 5 6 Licensed under the Apache License, Version 2.0 (the "License"); 7 you may not use this file except in compliance with the License. 8 You may obtain a copy of the License at 9 10 http://www.apache.org/licenses/LICENSE-2.0 11 12 Unless required by applicable law or agreed to in writing, software 13 distributed under the License is distributed on an "AS IS" BASIS, 14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 See the License for the specific language governing permissions and 16 limitations under the License. 17*/ 18 19package integration 20 21import ( 22 "context" 23 "testing" 24 "time" 25 26 "github.com/stretchr/testify/assert" 27 "github.com/stretchr/testify/require" 28 runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" 29) 30 31func TestSharedPidMultiProcessContainerStop(t *testing.T) { 32 for name, sbConfig := range map[string]*runtime.PodSandboxConfig{ 33 "hostpid": PodSandboxConfig("sandbox", "host-pid-container-stop", WithHostPid), 34 "podpid": PodSandboxConfig("sandbox", "pod-pid-container-stop", WithPodPid), 35 } { 36 t.Run(name, func(t *testing.T) { 37 t.Log("Create a shared pid sandbox") 38 sb, err := runtimeService.RunPodSandbox(sbConfig, *runtimeHandler) 39 require.NoError(t, err) 40 defer func() { 41 assert.NoError(t, runtimeService.StopPodSandbox(sb)) 42 assert.NoError(t, runtimeService.RemovePodSandbox(sb)) 43 }() 44 45 var ( 46 testImage = GetImage(BusyBox) 47 containerName = "test-container" 48 ) 49 t.Logf("Pull test image %q", testImage) 50 img, err := imageService.PullImage(&runtime.ImageSpec{Image: testImage}, nil, sbConfig) 51 require.NoError(t, err) 52 defer func() { 53 assert.NoError(t, imageService.RemoveImage(&runtime.ImageSpec{Image: img})) 54 }() 55 56 t.Log("Create a multi-process container") 57 cnConfig := ContainerConfig( 58 containerName, 59 testImage, 60 WithCommand("sh", "-c", "sleep 10000 & sleep 10000"), 61 ) 62 cn, err := runtimeService.CreateContainer(sb, cnConfig, sbConfig) 63 require.NoError(t, err) 64 65 t.Log("Start the container") 66 require.NoError(t, runtimeService.StartContainer(cn)) 67 68 t.Log("Stop the container") 69 require.NoError(t, runtimeService.StopContainer(cn, 0)) 70 71 t.Log("The container state should be exited") 72 s, err := runtimeService.ContainerStatus(cn) 73 require.NoError(t, err) 74 assert.Equal(t, s.GetState(), runtime.ContainerState_CONTAINER_EXITED) 75 }) 76 } 77} 78 79func TestContainerStopCancellation(t *testing.T) { 80 t.Log("Create a pod sandbox") 81 sbConfig := PodSandboxConfig("sandbox", "cancel-container-stop") 82 sb, err := runtimeService.RunPodSandbox(sbConfig, *runtimeHandler) 83 require.NoError(t, err) 84 defer func() { 85 assert.NoError(t, runtimeService.StopPodSandbox(sb)) 86 assert.NoError(t, runtimeService.RemovePodSandbox(sb)) 87 }() 88 89 var ( 90 testImage = GetImage(BusyBox) 91 containerName = "test-container" 92 ) 93 t.Logf("Pull test image %q", testImage) 94 img, err := imageService.PullImage(&runtime.ImageSpec{Image: testImage}, nil, sbConfig) 95 require.NoError(t, err) 96 defer func() { 97 assert.NoError(t, imageService.RemoveImage(&runtime.ImageSpec{Image: img})) 98 }() 99 100 t.Log("Create a container which traps sigterm") 101 cnConfig := ContainerConfig( 102 containerName, 103 testImage, 104 WithCommand("sh", "-c", `trap "echo ignore sigterm" TERM; sleep 1000`), 105 ) 106 cn, err := runtimeService.CreateContainer(sb, cnConfig, sbConfig) 107 require.NoError(t, err) 108 109 t.Log("Start the container") 110 require.NoError(t, runtimeService.StartContainer(cn)) 111 112 t.Log("Stop the container with 3s timeout, but 1s context timeout") 113 // Note that with container pid namespace, the sleep process 114 // is pid 1, and SIGTERM sent by `StopContainer` will be ignored. 115 rawClient, err := RawRuntimeClient() 116 require.NoError(t, err) 117 ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) 118 defer cancel() 119 _, err = rawClient.StopContainer(ctx, &runtime.StopContainerRequest{ 120 ContainerId: cn, 121 Timeout: 3, 122 }) 123 assert.Error(t, err) 124 125 t.Log("The container should still be running even after 5 seconds") 126 assert.NoError(t, Consistently(func() (bool, error) { 127 s, err := runtimeService.ContainerStatus(cn) 128 if err != nil { 129 return false, err 130 } 131 return s.GetState() == runtime.ContainerState_CONTAINER_RUNNING, nil 132 }, 100*time.Millisecond, 5*time.Second)) 133 134 t.Log("Stop the container with 1s timeout, without shorter context timeout") 135 assert.NoError(t, runtimeService.StopContainer(cn, 1)) 136 137 t.Log("The container state should be exited") 138 s, err := runtimeService.ContainerStatus(cn) 139 require.NoError(t, err) 140 assert.Equal(t, s.GetState(), runtime.ContainerState_CONTAINER_EXITED) 141} 142