From 149481a57184becf3e9be329d253602654414118 Mon Sep 17 00:00:00 2001 From: haircommander Date: Mon, 20 Aug 2018 18:24:35 -0400 Subject: Fixed segfault in stats where container had netNS none or from container Signed-off-by: haircommander Closes: #1306 Approved by: rhatdan --- libpod/networking_linux.go | 28 +++++++++++++++++++++++++++- libpod/stats.go | 10 ++++++++-- test/e2e/stats_test.go | 23 +++++++++++++++++++++++ 3 files changed, 58 insertions(+), 3 deletions(-) diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go index e5f935e30..77ab97910 100644 --- a/libpod/networking_linux.go +++ b/libpod/networking_linux.go @@ -249,9 +249,35 @@ func (r *Runtime) teardownNetNS(ctr *Container) error { return nil } +func getContainerNetNS(ctr *Container) (string, error) { + if ctr.state.NetNS != nil { + return ctr.state.NetNS.Path(), nil + } + if ctr.config.NetNsCtr != "" { + c, err := ctr.runtime.GetContainer(ctr.config.NetNsCtr) + if err != nil { + return "", err + } + if err = c.syncContainer(); err != nil { + return "", err + } + return c.state.NetNS.Path(), nil + } + return "", nil +} + func getContainerNetIO(ctr *Container) (*netlink.LinkStatistics, error) { var netStats *netlink.LinkStatistics - err := ns.WithNetNSPath(ctr.state.NetNS.Path(), func(_ ns.NetNS) error { + netNSPath, netPathErr := getContainerNetNS(ctr) + if netPathErr != nil { + return nil, netPathErr + } + if netNSPath == "" { + // If netNSPath is empty, it was set as none, and no netNS was set up + // this is a valid state and thus return no error, nor any statistics + return nil, nil + } + err := ns.WithNetNSPath(netNSPath, func(_ ns.NetNS) error { link, err := netlink.LinkByName(ocicni.DefaultInterfaceName) if err != nil { return err diff --git a/libpod/stats.go b/libpod/stats.go index 7830919ba..61e85ed5e 100644 --- a/libpod/stats.go +++ b/libpod/stats.go @@ -66,8 +66,14 @@ func (c *Container) GetContainerStats(previousStats *ContainerStats) (*Container stats.BlockInput, stats.BlockOutput = calculateBlockIO(cgroupStats) stats.CPUNano = cgroupStats.CPU.Usage.Total stats.SystemNano = cgroupStats.CPU.Usage.Kernel - stats.NetInput = netStats.TxBytes - stats.NetOutput = netStats.RxBytes + // Handle case where the container is not in a network namespace + if netStats != nil { + stats.NetInput = netStats.TxBytes + stats.NetOutput = netStats.RxBytes + } else { + stats.NetInput = 0 + stats.NetOutput = 0 + } return stats, nil } diff --git a/test/e2e/stats_test.go b/test/e2e/stats_test.go index ad40cbe5a..8096f58b2 100644 --- a/test/e2e/stats_test.go +++ b/test/e2e/stats_test.go @@ -90,4 +90,27 @@ var _ = Describe("Podman stats", func() { Expect(session.IsJSONOutputValid()).To(BeTrue()) }) + It("podman stats on a container with no net ns", func() { + session := podmanTest.Podman([]string{"run", "-d", "--net", "none", ALPINE, "top"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + session = podmanTest.Podman([]string{"stats", "--no-stream", "-a"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + }) + + It("podman stats on a container that joined another's net ns", func() { + session := podmanTest.RunTopContainer("") + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + cid := session.OutputToString() + + session = podmanTest.Podman([]string{"run", "-d", "--net", fmt.Sprintf("container:%s", cid), ALPINE, "top"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + session = podmanTest.Podman([]string{"stats", "--no-stream", "-a"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + }) }) -- cgit v1.2.3-54-g00ecf