diff options
author | Fabricio Voznika <fvoznika@google.com> | 2020-11-05 18:16:11 -0800 |
---|---|---|
committer | gVisor bot <gvisor-bot@google.com> | 2020-11-05 18:18:21 -0800 |
commit | 62b0e845b7301da7d0c75eb812e9cd75ade05b74 (patch) | |
tree | 98fef994113d5887930d94b5b0947572a8204e81 /runsc | |
parent | f27edcc708e412b5c5bbeb0c274837af94c625cc (diff) |
Return failure when `runsc events` queries a stopped container
This was causing gvisor-containerd-shim to crash because the command
suceeded, but there was no stat present.
PiperOrigin-RevId: 340964921
Diffstat (limited to 'runsc')
-rw-r--r-- | runsc/cmd/events.go | 9 | ||||
-rw-r--r-- | runsc/container/container.go | 7 | ||||
-rw-r--r-- | runsc/container/multi_container_test.go | 70 |
3 files changed, 82 insertions, 4 deletions
diff --git a/runsc/cmd/events.go b/runsc/cmd/events.go index 5211ad4ce..3836b7b4e 100644 --- a/runsc/cmd/events.go +++ b/runsc/cmd/events.go @@ -85,7 +85,12 @@ func (evs *Events) Execute(ctx context.Context, f *flag.FlagSet, args ...interfa ev, err := c.Event() if err != nil { log.Warningf("Error getting events for container: %v", err) + if evs.stats { + return subcommands.ExitFailure + } } + log.Debugf("Events: %+v", ev) + // err must be preserved because it is used below when breaking // out of the loop. b, err := json.Marshal(ev) @@ -101,11 +106,9 @@ func (evs *Events) Execute(ctx context.Context, f *flag.FlagSet, args ...interfa if err != nil { return subcommands.ExitFailure } - break + return subcommands.ExitSuccess } time.Sleep(time.Duration(evs.intervalSec) * time.Second) } - - return subcommands.ExitSuccess } diff --git a/runsc/container/container.go b/runsc/container/container.go index 435d866f5..4aa139c88 100644 --- a/runsc/container/container.go +++ b/runsc/container/container.go @@ -587,7 +587,12 @@ func (c *Container) SandboxPid() int { // and wait returns immediately. func (c *Container) Wait() (syscall.WaitStatus, error) { log.Debugf("Wait on container, cid: %s", c.ID) - return c.Sandbox.Wait(c.ID) + ws, err := c.Sandbox.Wait(c.ID) + if err == nil { + // Wait succeeded, container is not running anymore. + c.changeStatus(Stopped) + } + return ws, err } // WaitRootPID waits for process 'pid' in the sandbox's PID namespace and diff --git a/runsc/container/multi_container_test.go b/runsc/container/multi_container_test.go index 8f77c2371..cadc63bf3 100644 --- a/runsc/container/multi_container_test.go +++ b/runsc/container/multi_container_test.go @@ -15,6 +15,7 @@ package container import ( + "encoding/json" "fmt" "io/ioutil" "math" @@ -1766,3 +1767,72 @@ func TestMultiContainerHomeEnvDir(t *testing.T) { }) } } + +func TestMultiContainerEvent(t *testing.T) { + conf := testutil.TestConfig(t) + rootDir, cleanup, err := testutil.SetupRootDir() + if err != nil { + t.Fatalf("error creating root dir: %v", err) + } + defer cleanup() + conf.RootDir = rootDir + + // Setup the containers. + sleep := []string{"/bin/sleep", "100"} + quick := []string{"/bin/true"} + podSpec, ids := createSpecs(sleep, sleep, quick) + containers, cleanup, err := startContainers(conf, podSpec, ids) + if err != nil { + t.Fatalf("error starting containers: %v", err) + } + defer cleanup() + + for _, cont := range containers { + t.Logf("Running containerd %s", cont.ID) + } + + // Wait for last container to stabilize the process count that is checked + // further below. + if ws, err := containers[2].Wait(); err != nil || ws != 0 { + t.Fatalf("Container.Wait, status: %v, err: %v", ws, err) + } + + // Check events for running containers. + for _, cont := range containers[:2] { + evt, err := cont.Event() + if err != nil { + t.Errorf("Container.Events(): %v", err) + } + if want := "stats"; evt.Type != want { + t.Errorf("Wrong event type, want: %s, got :%s", want, evt.Type) + } + if cont.ID != evt.ID { + t.Errorf("Wrong container ID, want: %s, got :%s", cont.ID, evt.ID) + } + // Event.Data is an interface, so it comes from the wire was + // map[string]string. Marshal and unmarshall again to the correc type. + data, err := json.Marshal(evt.Data) + if err != nil { + t.Fatalf("invalid event data: %v", err) + } + var stats boot.Stats + if err := json.Unmarshal(data, &stats); err != nil { + t.Fatalf("invalid event data: %v", err) + } + // One process per remaining container. + if want := uint64(2); stats.Pids.Current != want { + t.Errorf("Wrong number of PIDs, want: %d, got :%d", want, stats.Pids.Current) + } + } + + // Check that stop and destroyed containers return error. + if err := containers[1].Destroy(); err != nil { + t.Fatalf("container.Destroy: %v", err) + } + for _, cont := range containers[1:] { + _, err := cont.Event() + if err == nil { + t.Errorf("Container.Events() should have failed, cid:%s, state: %v", cont.ID, cont.Status) + } + } +} |