Update cadvisor and containerd

This commit is contained in:
Davanum Srinivas
2020-03-24 13:11:42 -04:00
parent d00f9c7c10
commit 4274ea2c89
172 changed files with 8572 additions and 4031 deletions

View File

@@ -16,11 +16,13 @@ package libcontainer
import (
"bufio"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"os"
"path"
"regexp"
"strconv"
"strings"
"time"
@@ -44,6 +46,8 @@ type Handler struct {
pidMetricsCache map[int]*info.CpuSchedstat
}
var whitelistedUlimits = [...]string{"max_open_files"}
func NewHandler(cgroupManager cgroups.Manager, rootFs string, pid int, includedMetrics container.MetricSet) *Handler {
return &Handler{
cgroupManager: cgroupManager,
@@ -103,6 +107,15 @@ func (h *Handler) GetStats() (*info.ContainerStats, error) {
} else {
stats.Network.Tcp6 = t6
}
}
if h.includedMetrics.Has(container.NetworkAdvancedTcpUsageMetrics) {
ta, err := advancedTcpStatsFromProc(h.rootFs, h.pid, "net/netstat", "net/snmp")
if err != nil {
klog.V(4).Infof("Unable to get advanced tcp stats from pid %d: %v", h.pid, err)
} else {
stats.Network.TcpAdvanced = ta
}
}
if h.includedMetrics.Has(container.NetworkUdpUsageMetrics) {
u, err := udpStatsFromProc(h.rootFs, h.pid, "net/udp")
@@ -125,7 +138,7 @@ func (h *Handler) GetStats() (*info.ContainerStats, error) {
if !ok {
klog.V(4).Infof("Could not find cgroups CPU for container %d", h.pid)
} else {
stats.Processes, err = processStatsFromProcs(h.rootFs, path)
stats.Processes, err = processStatsFromProcs(h.rootFs, path, h.pid)
if err != nil {
klog.V(4).Infof("Unable to get Process Stats: %v", err)
}
@@ -143,7 +156,76 @@ func (h *Handler) GetStats() (*info.ContainerStats, error) {
return stats, nil
}
func processStatsFromProcs(rootFs string, cgroupPath string) (info.ProcessStats, error) {
func parseUlimit(value string) (int64, error) {
num, err := strconv.ParseInt(value, 10, 64)
if err != nil {
if strings.EqualFold(value, "unlimited") {
// -1 implies unlimited except for priority and nice; man limits.conf
num = -1
} else {
// Value is not a number or "unlimited"; return an error
return 0, fmt.Errorf("unable to parse limit: %s", value)
}
}
return num, nil
}
func isUlimitWhitelisted(name string) bool {
for _, whitelist := range whitelistedUlimits {
if name == whitelist {
return true
}
}
return false
}
func processLimitsFile(fileData string) []info.UlimitSpec {
limits := strings.Split(fileData, "\n")
ulimits := make([]info.UlimitSpec, 0, len(limits))
for _, lim := range limits {
// Skip any headers/footers
if strings.HasPrefix(lim, "Max") {
// Line format: Max open files 16384 16384 files
fields := regexp.MustCompile("[\\s]{2,}").Split(lim, -1)
name := strings.Replace(strings.ToLower(strings.TrimSpace(fields[0])), " ", "_", -1)
found := isUlimitWhitelisted(name)
if !found {
continue
}
soft := strings.TrimSpace(fields[1])
soft_num, soft_err := parseUlimit(soft)
hard := strings.TrimSpace(fields[2])
hard_num, hard_err := parseUlimit(hard)
// Omit metric if there were any parsing errors
if soft_err == nil && hard_err == nil {
ulimitSpec := info.UlimitSpec{
Name: name,
SoftLimit: int64(soft_num),
HardLimit: int64(hard_num),
}
ulimits = append(ulimits, ulimitSpec)
}
}
}
return ulimits
}
func processRootProcUlimits(rootFs string, rootPid int) []info.UlimitSpec {
filePath := path.Join(rootFs, "/proc", strconv.Itoa(rootPid), "limits")
out, err := ioutil.ReadFile(filePath)
if err != nil {
klog.V(4).Infof("error while listing directory %q to read ulimits: %v", filePath, err)
return []info.UlimitSpec{}
}
return processLimitsFile(string(out))
}
func processStatsFromProcs(rootFs string, cgroupPath string, rootPid int) (info.ProcessStats, error) {
var fdCount, socketCount uint64
filePath := path.Join(cgroupPath, "cgroup.procs")
out, err := ioutil.ReadFile(filePath)
@@ -180,11 +262,13 @@ func processStatsFromProcs(rootFs string, cgroupPath string) (info.ProcessStats,
}
}
}
ulimits := processRootProcUlimits(rootFs, rootPid)
processStats := info.ProcessStats{
ProcessCount: uint64(len(pids)),
FdCount: fdCount,
SocketCount: socketCount,
Ulimits: ulimits,
}
return processStats, nil
@@ -334,6 +418,80 @@ func tcpStatsFromProc(rootFs string, pid int, file string) (info.TcpStat, error)
return tcpStats, nil
}
func advancedTcpStatsFromProc(rootFs string, pid int, file1, file2 string) (info.TcpAdvancedStat, error) {
var advancedStats info.TcpAdvancedStat
var err error
netstatFile := path.Join(rootFs, "proc", strconv.Itoa(pid), file1)
err = scanAdvancedTcpStats(&advancedStats, netstatFile)
if err != nil {
return advancedStats, err
}
snmpFile := path.Join(rootFs, "proc", strconv.Itoa(pid), file2)
err = scanAdvancedTcpStats(&advancedStats, snmpFile)
if err != nil {
return advancedStats, err
}
return advancedStats, nil
}
func scanAdvancedTcpStats(advancedStats *info.TcpAdvancedStat, advancedTcpStatsFile string) error {
data, err := ioutil.ReadFile(advancedTcpStatsFile)
if err != nil {
return fmt.Errorf("failure opening %s: %v", advancedTcpStatsFile, err)
}
reader := strings.NewReader(string(data))
scanner := bufio.NewScanner(reader)
scanner.Split(bufio.ScanLines)
advancedTcpStats := make(map[string]interface{})
for scanner.Scan() {
nameParts := strings.Split(scanner.Text(), " ")
scanner.Scan()
valueParts := strings.Split(scanner.Text(), " ")
// Remove trailing :. and ignore non-tcp
protocol := nameParts[0][:len(nameParts[0])-1]
if protocol != "TcpExt" && protocol != "Tcp" {
continue
}
if len(nameParts) != len(valueParts) {
return fmt.Errorf("mismatch field count mismatch in %s: %s",
advancedTcpStatsFile, protocol)
}
for i := 1; i < len(nameParts); i++ {
if strings.Contains(valueParts[i], "-") {
vInt64, err := strconv.ParseInt(valueParts[i], 10, 64)
if err != nil {
return fmt.Errorf("decode value: %s to int64 error: %s", valueParts[i], err)
}
advancedTcpStats[nameParts[i]] = vInt64
} else {
vUint64, err := strconv.ParseUint(valueParts[i], 10, 64)
if err != nil {
return fmt.Errorf("decode value: %s to uint64 error: %s", valueParts[i], err)
}
advancedTcpStats[nameParts[i]] = vUint64
}
}
}
b, err := json.Marshal(advancedTcpStats)
if err != nil {
return err
}
err = json.Unmarshal(b, advancedStats)
if err != nil {
return err
}
return scanner.Err()
}
func scanTcpStats(tcpStatsFile string) (info.TcpStat, error) {
var stats info.TcpStat
@@ -581,6 +739,17 @@ func setMemoryStats(s *cgroups.Stats, ret *info.ContainerStats) {
ret.Memory.WorkingSet = workingSet
}
func setHugepageStats(s *cgroups.Stats, ret *info.ContainerStats) {
ret.Hugetlb = make(map[string]info.HugetlbStats)
for k, v := range s.HugetlbStats {
ret.Hugetlb[k] = info.HugetlbStats{
Usage: v.Usage,
MaxUsage: v.MaxUsage,
Failcnt: v.Failcnt,
}
}
}
func setNetworkStats(libcontainerStats *libcontainer.Stats, ret *info.ContainerStats) {
ret.Network.Interfaces = make([]info.InterfaceStats, len(libcontainerStats.Interfaces))
for i := range libcontainerStats.Interfaces {
@@ -623,6 +792,9 @@ func newContainerStats(libcontainerStats *libcontainer.Stats, includedMetrics co
setDiskIoStats(s, ret)
}
setMemoryStats(s, ret)
if includedMetrics.Has(container.HugetlbUsageMetrics) {
setHugepageStats(s, ret)
}
}
if len(libcontainerStats.Interfaces) > 0 {
setNetworkStats(libcontainerStats, ret)

View File

@@ -107,6 +107,7 @@ var supportedSubsystems map[string]struct{} = map[string]struct{}{
"cpu": {},
"cpuacct": {},
"memory": {},
"hugetlb": {},
"pids": {},
"cpuset": {},
"blkio": {},