mirror of
https://github.com/clearlinux/docker.git
synced 2026-08-26 09:36:04 +00:00
Stats API to retrieve nw stats from libnetwork
- Container networking statistics are no longer retrievable from libcontainer after the introduction of libnetwork. This change adds the missing code for docker daemon to retireve the nw stats from Endpoint. Signed-off-by: Alessandro Boch <aboch@docker.com>
This commit is contained in:
committed by
David Calavera
parent
ac6a9ce95f
commit
e698770d40
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/docker/docker/daemon/execdriver"
|
||||
"github.com/docker/libcontainer"
|
||||
"github.com/docker/libcontainer/cgroups"
|
||||
"github.com/docker/libnetwork/sandbox"
|
||||
)
|
||||
|
||||
func (daemon *Daemon) ContainerStats(name string, stream bool, out io.Writer) error {
|
||||
@@ -19,6 +20,10 @@ func (daemon *Daemon) ContainerStats(name string, stream bool, out io.Writer) er
|
||||
var preCpuStats types.CpuStats
|
||||
getStat := func(v interface{}) *types.Stats {
|
||||
update := v.(*execdriver.ResourceStats)
|
||||
// Retrieve the nw statistics from libnetwork and inject them in the Stats
|
||||
if nwStats, err := daemon.getNetworkStats(name); err == nil {
|
||||
update.Stats.Interfaces = nwStats
|
||||
}
|
||||
ss := convertToAPITypes(update.Stats)
|
||||
ss.PreCpuStats = preCpuStats
|
||||
ss.MemoryStats.Limit = uint64(update.MemoryLimit)
|
||||
@@ -118,3 +123,46 @@ func copyBlkioEntry(entries []cgroups.BlkioStatEntry) []types.BlkioStatEntry {
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func (daemon *Daemon) getNetworkStats(name string) ([]*libcontainer.NetworkInterface, error) {
|
||||
var list []*libcontainer.NetworkInterface
|
||||
|
||||
c, err := daemon.Get(name)
|
||||
if err != nil {
|
||||
return list, err
|
||||
}
|
||||
|
||||
nw, err := daemon.netController.NetworkByID(c.NetworkSettings.NetworkID)
|
||||
if err != nil {
|
||||
return list, err
|
||||
}
|
||||
ep, err := nw.EndpointByID(c.NetworkSettings.EndpointID)
|
||||
if err != nil {
|
||||
return list, err
|
||||
}
|
||||
|
||||
stats, err := ep.Statistics()
|
||||
if err != nil {
|
||||
return list, err
|
||||
}
|
||||
|
||||
// Convert libnetwork nw stats into libcontainer nw stats
|
||||
for ifName, ifStats := range stats {
|
||||
list = append(list, convertLnNetworkStats(ifName, ifStats))
|
||||
}
|
||||
|
||||
return list, nil
|
||||
}
|
||||
|
||||
func convertLnNetworkStats(name string, stats *sandbox.InterfaceStatistics) *libcontainer.NetworkInterface {
|
||||
n := &libcontainer.NetworkInterface{Name: name}
|
||||
n.RxBytes = stats.RxBytes
|
||||
n.RxPackets = stats.RxPackets
|
||||
n.RxErrors = stats.RxErrors
|
||||
n.RxDropped = stats.RxDropped
|
||||
n.TxBytes = stats.TxBytes
|
||||
n.TxPackets = stats.TxPackets
|
||||
n.TxErrors = stats.TxErrors
|
||||
n.TxDropped = stats.TxDropped
|
||||
return n
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ package main
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
@@ -33,3 +35,41 @@ func (s *DockerSuite) TestCliStatsNoStreamGetCpu(c *check.C) {
|
||||
c.Fatalf("docker stats with no-stream get cpu usage failed: was %v", cpuPercent)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestApiNetworkStats(c *check.C) {
|
||||
// Run container for 30 secs
|
||||
out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
|
||||
id := strings.TrimSpace(out)
|
||||
err := waitRun(id)
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
// Retrieve the container address
|
||||
contIP := findContainerIP(c, id)
|
||||
numPings := 10
|
||||
|
||||
// Get the container networking stats before and after pinging the container
|
||||
nwStatsPre := getNetworkStats(c, id)
|
||||
_, err = exec.Command("ping", contIP, "-c", strconv.Itoa(numPings)).Output()
|
||||
c.Assert(err, check.IsNil)
|
||||
nwStatsPost := getNetworkStats(c, id)
|
||||
|
||||
// Verify the stats contain at least the expected number of packets (account for ARP)
|
||||
expRxPkts := 1 + nwStatsPre.RxPackets + uint64(numPings)
|
||||
expTxPkts := 1 + nwStatsPre.TxPackets + uint64(numPings)
|
||||
c.Assert(nwStatsPost.TxPackets >= expTxPkts, check.Equals, true,
|
||||
check.Commentf("Reported less TxPackets than expected. Expected >= %d. Found %d", expTxPkts, nwStatsPost.TxPackets))
|
||||
c.Assert(nwStatsPost.RxPackets >= expRxPkts, check.Equals, true,
|
||||
check.Commentf("Reported less Txbytes than expected. Expected >= %d. Found %d", expRxPkts, nwStatsPost.RxPackets))
|
||||
}
|
||||
|
||||
func getNetworkStats(c *check.C, id string) types.Network {
|
||||
var st *types.Stats
|
||||
|
||||
_, body, err := sockRequestRaw("GET", fmt.Sprintf("/containers/%s/stats?stream=false", id), nil, "")
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
err = json.NewDecoder(body).Decode(&st)
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
return st.Network
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user