Expose multiple network interfaces in API.

Part of #686
This commit is contained in:
Victor Marmol 2015-06-04 10:58:32 -07:00
parent 48f14dcde6
commit b923eff11c
8 changed files with 82 additions and 44 deletions

View File

@ -426,8 +426,7 @@ func convertStats(cont *info.ContainerInfo) []v2.ContainerStats {
stat.Memory = val.Memory stat.Memory = val.Memory
} }
if stat.HasNetwork { if stat.HasNetwork {
// TODO(rjnagal): Return stats about all network interfaces. stat.Network.Interfaces = val.Network.Interfaces
stat.Network = append(stat.Network, val.Network)
} }
if stat.HasFilesystem { if stat.HasFilesystem {
stat.Filesystem = val.Filesystem stat.Filesystem = val.Filesystem

View File

@ -261,17 +261,10 @@ func (self *dockerContainerHandler) GetStats() (*info.ContainerStats, error) {
} }
// TODO(rjnagal): Remove the conversion when network stats are read from libcontainer. // TODO(rjnagal): Remove the conversion when network stats are read from libcontainer.
net := stats.Network convertInterfaceStats(&stats.Network.InterfaceStats)
// Ingress for host veth is from the container. for i := range stats.Network.Interfaces {
// Hence tx_bytes stat on the host veth is actually number of bytes received by the container. convertInterfaceStats(&stats.Network.Interfaces[i])
stats.Network.RxBytes = net.TxBytes }
stats.Network.RxPackets = net.TxPackets
stats.Network.RxErrors = net.TxErrors
stats.Network.RxDropped = net.TxDropped
stats.Network.TxBytes = net.RxBytes
stats.Network.TxPackets = net.RxPackets
stats.Network.TxErrors = net.RxErrors
stats.Network.TxDropped = net.RxDropped
// Get filesystem stats. // Get filesystem stats.
err = self.getFsStats(stats) err = self.getFsStats(stats)
@ -282,6 +275,21 @@ func (self *dockerContainerHandler) GetStats() (*info.ContainerStats, error) {
return stats, nil return stats, nil
} }
func convertInterfaceStats(stats *info.InterfaceStats) {
net := stats
// Ingress for host veth is from the container.
// Hence tx_bytes stat on the host veth is actually number of bytes received by the container.
stats.RxBytes = net.TxBytes
stats.RxPackets = net.TxPackets
stats.RxErrors = net.TxErrors
stats.RxDropped = net.TxDropped
stats.TxBytes = net.RxBytes
stats.TxPackets = net.RxPackets
stats.TxErrors = net.RxErrors
stats.TxDropped = net.RxDropped
}
func (self *dockerContainerHandler) ListContainers(listType container.ListType) ([]info.ContainerReference, error) { func (self *dockerContainerHandler) ListContainers(listType container.ListType) ([]info.ContainerReference, error) {
if self.name != "/docker" { if self.name != "/docker" {
return []info.ContainerReference{}, nil return []info.ContainerReference{}, nil

View File

@ -84,15 +84,20 @@ func GetStats(cgroupManager cgroups.Manager, networkInterfaces []string) (*info.
} }
stats := toContainerStats(libcontainerStats) stats := toContainerStats(libcontainerStats)
if len(networkInterfaces) != 0 { // TODO(rjnagal): Use networking stats directly from libcontainer.
// ContainerStats only reports stat for one network device. stats.Network.Interfaces = make([]info.InterfaceStats, len(networkInterfaces))
// TODO(rjnagal): Handle multiple physical network devices. for i := range networkInterfaces {
// TODO(rjnagal): Use networking stats directly from libcontainer. interfaceStats, err := sysinfo.GetNetworkStats(networkInterfaces[i])
stats.Network, err = sysinfo.GetNetworkStats(networkInterfaces[0])
if err != nil { if err != nil {
return stats, err return stats, err
} }
stats.Network.Interfaces[i] = interfaceStats
} }
// For backwards compatability.
if len(networkInterfaces) > 0 {
stats.Network.InterfaceStats = stats.Network.Interfaces[0]
}
return stats, nil return stats, nil
} }
@ -213,15 +218,25 @@ func toContainerStats2(s *cgroups.Stats, ret *info.ContainerStats) {
} }
func toContainerStats3(libcontainerStats *libcontainer.Stats, ret *info.ContainerStats) { func toContainerStats3(libcontainerStats *libcontainer.Stats, ret *info.ContainerStats) {
// TODO(vmarmol): Handle multiple interfaces. ret.Network.Interfaces = make([]info.InterfaceStats, len(libcontainerStats.Interfaces))
ret.Network.RxBytes = libcontainerStats.Interfaces[0].RxBytes for i := range libcontainerStats.Interfaces {
ret.Network.RxPackets = libcontainerStats.Interfaces[0].RxPackets ret.Network.Interfaces[i] = info.InterfaceStats{
ret.Network.RxErrors = libcontainerStats.Interfaces[0].RxErrors Name: libcontainerStats.Interfaces[i].Name,
ret.Network.RxDropped = libcontainerStats.Interfaces[0].RxDropped RxBytes: libcontainerStats.Interfaces[i].RxBytes,
ret.Network.TxBytes = libcontainerStats.Interfaces[0].TxBytes RxPackets: libcontainerStats.Interfaces[i].RxPackets,
ret.Network.TxPackets = libcontainerStats.Interfaces[0].TxPackets RxErrors: libcontainerStats.Interfaces[i].RxErrors,
ret.Network.TxErrors = libcontainerStats.Interfaces[0].TxErrors RxDropped: libcontainerStats.Interfaces[i].RxDropped,
ret.Network.TxDropped = libcontainerStats.Interfaces[0].TxDropped TxBytes: libcontainerStats.Interfaces[i].TxBytes,
TxPackets: libcontainerStats.Interfaces[i].TxPackets,
TxErrors: libcontainerStats.Interfaces[i].TxErrors,
TxDropped: libcontainerStats.Interfaces[i].TxDropped,
}
}
// Add to base struct for backwards compatability.
if len(ret.Network.Interfaces) > 0 {
ret.Network.InterfaceStats = ret.Network.Interfaces[0]
}
} }
func toContainerStats(libcontainerStats *libcontainer.Stats) *info.ContainerStats { func toContainerStats(libcontainerStats *libcontainer.Stats) *info.ContainerStats {

View File

@ -312,7 +312,9 @@ type MemoryStatsMemoryData struct {
Pgmajfault uint64 `json:"pgmajfault"` Pgmajfault uint64 `json:"pgmajfault"`
} }
type NetworkStats struct { type InterfaceStats struct {
// The name of the interface.
Name string `json:"name"`
// Cumulative count of bytes received. // Cumulative count of bytes received.
RxBytes uint64 `json:"rx_bytes"` RxBytes uint64 `json:"rx_bytes"`
// Cumulative count of packets received. // Cumulative count of packets received.
@ -331,6 +333,11 @@ type NetworkStats struct {
TxDropped uint64 `json:"tx_dropped"` TxDropped uint64 `json:"tx_dropped"`
} }
type NetworkStats struct {
InterfaceStats `json:",inline"`
Interfaces []InterfaceStats `json:"interfaces,omitempty"`
}
type FsStats struct { type FsStats struct {
// The block device name associated with the filesystem. // The block device name associated with the filesystem.
Device string `json:"device,omitempty"` Device string `json:"device,omitempty"`

View File

@ -92,8 +92,8 @@ type ContainerStats struct {
HasMemory bool `json:"has_memory"` HasMemory bool `json:"has_memory"`
Memory v1.MemoryStats `json:"memory,omitempty"` Memory v1.MemoryStats `json:"memory,omitempty"`
// Network statistics // Network statistics
HasNetwork bool `json:"has_network"` HasNetwork bool `json:"has_network"`
Network []v1.NetworkStats `json:"network,omitempty"` Network NetworkStats `json:"network,omitempty"`
// Filesystem statistics // Filesystem statistics
HasFilesystem bool `json:"has_filesystem"` HasFilesystem bool `json:"has_filesystem"`
Filesystem []v1.FsStats `json:"filesystem,omitempty"` Filesystem []v1.FsStats `json:"filesystem,omitempty"`
@ -189,3 +189,8 @@ type ProcessInfo struct {
CgroupPath string `json:"cgroup_path"` CgroupPath string `json:"cgroup_path"`
Cmd string `json:"cmd"` Cmd string `json:"cmd"`
} }
type NetworkStats struct {
// Network stats by interface.
Interfaces []v1.InterfaceStats `json:"interfaces,omitempty"`
}

View File

@ -57,14 +57,17 @@ func (p testSubcontainersInfoProvider) SubcontainersInfo(string, *info.Container
}, },
}, },
Network: info.NetworkStats{ Network: info.NetworkStats{
RxBytes: 14, InterfaceStats: info.InterfaceStats{
RxPackets: 15, Name: "eth0",
RxErrors: 16, RxBytes: 14,
RxDropped: 17, RxPackets: 15,
TxBytes: 18, RxErrors: 16,
TxPackets: 19, RxDropped: 17,
TxErrors: 20, TxBytes: 18,
TxDropped: 21, TxPackets: 19,
TxErrors: 20,
TxDropped: 21,
},
}, },
Filesystem: []info.FsStats{ Filesystem: []info.FsStats{
{ {

View File

@ -157,19 +157,19 @@ func GetCacheInfo(sysFs sysfs.SysFs, id int) ([]sysfs.CacheInfo, error) {
return info, nil return info, nil
} }
func GetNetworkStats(name string) (info.NetworkStats, error) { func GetNetworkStats(name string) (info.InterfaceStats, error) {
stats := info.NetworkStats{}
// TODO(rjnagal): Take syfs as an argument. // TODO(rjnagal): Take syfs as an argument.
sysFs, err := sysfs.NewRealSysFs() sysFs, err := sysfs.NewRealSysFs()
if err != nil { if err != nil {
return stats, err return info.InterfaceStats{}, err
} }
return getNetworkStats(name, sysFs) return getNetworkStats(name, sysFs)
} }
func getNetworkStats(name string, sysFs sysfs.SysFs) (info.NetworkStats, error) { func getNetworkStats(name string, sysFs sysfs.SysFs) (info.InterfaceStats, error) {
stats := info.NetworkStats{} var stats info.InterfaceStats
var err error var err error
stats.Name = name
stats.RxBytes, err = sysFs.GetNetworkStatValue(name, "rx_bytes") stats.RxBytes, err = sysFs.GetNetworkStatValue(name, "rx_bytes")
if err != nil { if err != nil {
return stats, err return stats, err

View File

@ -110,7 +110,8 @@ func TestGetCacheInfo(t *testing.T) {
} }
func TestGetNetworkStats(t *testing.T) { func TestGetNetworkStats(t *testing.T) {
expected_stats := info.NetworkStats{ expected_stats := info.InterfaceStats{
Name: "eth0",
RxBytes: 1024, RxBytes: 1024,
RxPackets: 1024, RxPackets: 1024,
RxErrors: 1024, RxErrors: 1024,