-
Notifications
You must be signed in to change notification settings - Fork 285
Support restarting containerd in tests, add restart test case #1188
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
4abfd06
f5ca517
2d35b70
7b098b0
5ec59dc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| // +build functional | ||
|
|
||
| package cri_containerd | ||
|
|
||
| import ( | ||
| "context" | ||
| "testing" | ||
|
|
||
| runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" | ||
| ) | ||
|
|
||
| // CRI will terminate any running containers when it is restarted. | ||
| // Run a container, restart containerd, validate the container is terminated. | ||
| func Test_ContainerdRestart_LCOW(t *testing.T) { | ||
| requireFeatures(t, featureLCOW, featureTerminateOnRestart) | ||
|
|
||
| pullRequiredLCOWImages(t, []string{imageLcowK8sPause, imageLcowAlpine}) | ||
|
|
||
| client := newTestRuntimeClient(t) | ||
| ctx, cancel := context.WithCancel(context.Background()) | ||
| defer cancel() | ||
|
|
||
| sandboxRequest := getRunPodSandboxRequest(t, lcowRuntimeHandler) | ||
|
|
||
| podID := runPodSandbox(t, client, ctx, sandboxRequest) | ||
| defer removePodSandbox(t, client, ctx, podID) | ||
| defer stopPodSandbox(t, client, ctx, podID) | ||
|
|
||
| request := &runtime.CreateContainerRequest{ | ||
| PodSandboxId: podID, | ||
| Config: &runtime.ContainerConfig{ | ||
| Metadata: &runtime.ContainerMetadata{ | ||
| Name: t.Name() + "-Container", | ||
| }, | ||
| Image: &runtime.ImageSpec{ | ||
| Image: imageLcowAlpine, | ||
| }, | ||
| Command: []string{ | ||
| "top", | ||
| }, | ||
| }, | ||
| SandboxConfig: sandboxRequest.Config, | ||
| } | ||
|
|
||
| containerID := createContainer(t, client, ctx, request) | ||
| defer removeContainer(t, client, ctx, containerID) | ||
| startContainer(t, client, ctx, containerID) | ||
| defer stopContainer(t, client, ctx, containerID) | ||
|
|
||
| t.Log("Restart containerd") | ||
| stopContainerd(t) | ||
| startContainerd(t) | ||
| client = newTestRuntimeClient(t) | ||
|
|
||
| containerStatus, err := client.ContainerStatus(ctx, &runtime.ContainerStatusRequest{ContainerId: containerID}) | ||
| if err != nil { | ||
| t.Fatal(err) | ||
| } | ||
| if containerStatus.Status.State != runtime.ContainerState_CONTAINER_EXITED { | ||
| t.Errorf("Container was not terminated on containerd restart. Status is %d", containerStatus.Status.State) | ||
| } | ||
| podStatus, err := client.PodSandboxStatus(ctx, &runtime.PodSandboxStatusRequest{PodSandboxId: podID}) | ||
| if err != nil { | ||
| t.Fatal(err) | ||
| } | ||
| if podStatus.Status.State != runtime.PodSandboxState_SANDBOX_NOTREADY { | ||
| t.Errorf("Pod was not terminated on containerd restart. Status is %d", podStatus.Status.State) | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,90 @@ | ||
| package cri_containerd | ||
|
|
||
| import ( | ||
| "fmt" | ||
| "sync" | ||
| "testing" | ||
| "time" | ||
|
|
||
| "golang.org/x/sys/windows/svc" | ||
| "golang.org/x/sys/windows/svc/mgr" | ||
| ) | ||
|
|
||
| // Implements functionality so tests can start/stop the containerd service. | ||
| // Tests assume containerd will be running when they start, since this | ||
| // matches with the state a dev box will usually be in. A test that stops containerd should | ||
| // therefore ensure it starts it again. | ||
|
|
||
| var ( | ||
| svcMgr *mgr.Mgr | ||
| svcMgrConnectOnce sync.Once | ||
| svcMgrConnectErr error | ||
| ) | ||
|
|
||
| func getSvcMgr() (*mgr.Mgr, error) { | ||
| svcMgrConnectOnce.Do(func() { | ||
| s, err := mgr.Connect() | ||
| if err != nil { | ||
| err = fmt.Errorf("failed to connect to service manager: %w", err) | ||
| } | ||
| svcMgr, svcMgrConnectErr = s, err | ||
| }) | ||
| return svcMgr, svcMgrConnectErr | ||
| } | ||
|
|
||
| func startService(serviceName string) error { | ||
| m, err := getSvcMgr() | ||
| if err != nil { | ||
| return err | ||
| } | ||
| s, err := m.OpenService(serviceName) | ||
| if err != nil { | ||
| return fmt.Errorf("failed to open service %s: %w", serviceName, err) | ||
| } | ||
| if err := s.Start(); err != nil { | ||
| return fmt.Errorf("failed to start service %s: %w", serviceName, err) | ||
| } | ||
| return nil | ||
| } | ||
|
|
||
| func stopService(serviceName string) error { | ||
| m, err := getSvcMgr() | ||
| if err != nil { | ||
| return err | ||
| } | ||
| s, err := m.OpenService(serviceName) | ||
| if err != nil { | ||
| return fmt.Errorf("failed to open service %s: %w", serviceName, err) | ||
| } | ||
| status, err := s.Control(svc.Stop) | ||
| if err != nil { | ||
| return fmt.Errorf("failed to send stop control to service %s: %w", serviceName, err) | ||
| } | ||
| tc := time.NewTimer(10 * time.Second) | ||
| defer tc.Stop() | ||
| for status.State != svc.Stopped { | ||
| time.Sleep(1 * time.Second) | ||
| select { | ||
| case <-tc.C: | ||
| return fmt.Errorf("service %s did not stop in time", serviceName) | ||
| default: | ||
| status, err = s.Query() | ||
| if err != nil { | ||
| return fmt.Errorf("failed to query service %s status: %w", serviceName, err) | ||
| } | ||
| } | ||
| } | ||
| return nil | ||
| } | ||
|
|
||
| func startContainerd(t *testing.T) { | ||
| if err := startService(*flagContainerdServiceName); err != nil { | ||
| t.Fatal(err) | ||
| } | ||
| } | ||
|
|
||
| func stopContainerd(t *testing.T) { | ||
| if err := stopService(*flagContainerdServiceName); err != nil { | ||
| t.Fatal(err) | ||
| } | ||
| } |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Usually,
cri-containerd.test.exeruns 4 tests in parallel (IIRC), This would break other tests that are running in parallel, right?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it? I thought running tests in parallel required you to sprinkle the ones that you'd like to make eligible with t.Parallel
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see. I thought just setting
-test.parallel(which has default value of 4) to value greater than 1 does it.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My understanding is also that tests must explicitly opt into being run in parallel. I agree running in parallel would cause problems given the service is global state.