summaryrefslogtreecommitdiffhomepage
path: root/runsc
diff options
context:
space:
mode:
authorFabricio Voznika <fvoznika@google.com>2020-11-05 18:16:11 -0800
committergVisor bot <gvisor-bot@google.com>2020-11-05 18:18:21 -0800
commit62b0e845b7301da7d0c75eb812e9cd75ade05b74 (patch)
tree98fef994113d5887930d94b5b0947572a8204e81 /runsc
parentf27edcc708e412b5c5bbeb0c274837af94c625cc (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.go9
-rw-r--r--runsc/container/container.go7
-rw-r--r--runsc/container/multi_container_test.go70
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)
+ }
+ }
+}