From 9ed8422e8cf088c83a3a2da4504675bae7428538 Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Tue, 26 Apr 2016 14:57:30 -0700 Subject: [PATCH] Use runc events --stats for collecting stats runc `events --stats` now has stable output so we don't need to bind to libcontainer directly to get stats output for the containers. Signed-off-by: Michael Crosby --- api/grpc/server/server.go | 75 +++++++++++++++++--------------------- runtime/container.go | 22 +++++------ runtime/runtime.go | 10 ----- runtime/stats.go | 77 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 121 insertions(+), 63 deletions(-) create mode 100644 runtime/stats.go diff --git a/api/grpc/server/server.go b/api/grpc/server/server.go index 9429be2..440e0e0 100644 --- a/api/grpc/server/server.go +++ b/api/grpc/server/server.go @@ -17,8 +17,6 @@ import ( "github.com/docker/containerd/runtime" "github.com/docker/containerd/specs" "github.com/docker/containerd/supervisor" - "github.com/opencontainers/runc/libcontainer" - "github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/system" ocs "github.com/opencontainers/runtime-spec/specs-go" "golang.org/x/net/context" @@ -368,75 +366,68 @@ func convertToPb(st *runtime.Stat) *types.StatsResponse { Timestamp: uint64(st.Timestamp.Unix()), CgroupStats: &types.CgroupStats{}, } - lcSt, ok := st.Data.(*libcontainer.Stats) - if !ok { - return pbSt - } - cpuSt := lcSt.CgroupStats.CpuStats systemUsage, _ := getSystemCPUUsage() pbSt.CgroupStats.CpuStats = &types.CpuStats{ CpuUsage: &types.CpuUsage{ - TotalUsage: cpuSt.CpuUsage.TotalUsage, - PercpuUsage: cpuSt.CpuUsage.PercpuUsage, - UsageInKernelmode: cpuSt.CpuUsage.UsageInKernelmode, - UsageInUsermode: cpuSt.CpuUsage.UsageInUsermode, + TotalUsage: st.Cpu.Usage.Total, + PercpuUsage: st.Cpu.Usage.Percpu, + UsageInKernelmode: st.Cpu.Usage.Kernel, + UsageInUsermode: st.Cpu.Usage.User, }, ThrottlingData: &types.ThrottlingData{ - Periods: cpuSt.ThrottlingData.Periods, - ThrottledPeriods: cpuSt.ThrottlingData.ThrottledPeriods, - ThrottledTime: cpuSt.ThrottlingData.ThrottledTime, + Periods: st.Cpu.Throttling.Periods, + ThrottledPeriods: st.Cpu.Throttling.ThrottledPeriods, + ThrottledTime: st.Cpu.Throttling.ThrottledTime, }, SystemUsage: systemUsage, } - memSt := lcSt.CgroupStats.MemoryStats pbSt.CgroupStats.MemoryStats = &types.MemoryStats{ - Cache: memSt.Cache, + Cache: st.Memory.Cache, Usage: &types.MemoryData{ - Usage: memSt.Usage.Usage, - MaxUsage: memSt.Usage.MaxUsage, - Failcnt: memSt.Usage.Failcnt, - Limit: memSt.Usage.Limit, + Usage: st.Memory.Usage.Usage, + MaxUsage: st.Memory.Usage.Max, + Failcnt: st.Memory.Usage.Failcnt, + Limit: st.Memory.Usage.Limit, }, SwapUsage: &types.MemoryData{ - Usage: memSt.SwapUsage.Usage, - MaxUsage: memSt.SwapUsage.MaxUsage, - Failcnt: memSt.SwapUsage.Failcnt, - Limit: memSt.SwapUsage.Limit, + Usage: st.Memory.Swap.Usage, + MaxUsage: st.Memory.Swap.Max, + Failcnt: st.Memory.Swap.Failcnt, + Limit: st.Memory.Swap.Limit, }, KernelUsage: &types.MemoryData{ - Usage: memSt.KernelUsage.Usage, - MaxUsage: memSt.KernelUsage.MaxUsage, - Failcnt: memSt.KernelUsage.Failcnt, - Limit: memSt.KernelUsage.Limit, + Usage: st.Memory.Kernel.Usage, + MaxUsage: st.Memory.Kernel.Max, + Failcnt: st.Memory.Kernel.Failcnt, + Limit: st.Memory.Kernel.Limit, }, } - blkSt := lcSt.CgroupStats.BlkioStats pbSt.CgroupStats.BlkioStats = &types.BlkioStats{ - IoServiceBytesRecursive: convertBlkioEntryToPb(blkSt.IoServiceBytesRecursive), - IoServicedRecursive: convertBlkioEntryToPb(blkSt.IoServicedRecursive), - IoQueuedRecursive: convertBlkioEntryToPb(blkSt.IoQueuedRecursive), - IoServiceTimeRecursive: convertBlkioEntryToPb(blkSt.IoServiceTimeRecursive), - IoWaitTimeRecursive: convertBlkioEntryToPb(blkSt.IoWaitTimeRecursive), - IoMergedRecursive: convertBlkioEntryToPb(blkSt.IoMergedRecursive), - IoTimeRecursive: convertBlkioEntryToPb(blkSt.IoTimeRecursive), - SectorsRecursive: convertBlkioEntryToPb(blkSt.SectorsRecursive), + IoServiceBytesRecursive: convertBlkioEntryToPb(st.Blkio.IoServiceBytesRecursive), + IoServicedRecursive: convertBlkioEntryToPb(st.Blkio.IoServicedRecursive), + IoQueuedRecursive: convertBlkioEntryToPb(st.Blkio.IoQueuedRecursive), + IoServiceTimeRecursive: convertBlkioEntryToPb(st.Blkio.IoServiceTimeRecursive), + IoWaitTimeRecursive: convertBlkioEntryToPb(st.Blkio.IoWaitTimeRecursive), + IoMergedRecursive: convertBlkioEntryToPb(st.Blkio.IoMergedRecursive), + IoTimeRecursive: convertBlkioEntryToPb(st.Blkio.IoTimeRecursive), + SectorsRecursive: convertBlkioEntryToPb(st.Blkio.SectorsRecursive), } pbSt.CgroupStats.HugetlbStats = make(map[string]*types.HugetlbStats) - for k, st := range lcSt.CgroupStats.HugetlbStats { + for k, st := range st.Hugetlb { pbSt.CgroupStats.HugetlbStats[k] = &types.HugetlbStats{ Usage: st.Usage, - MaxUsage: st.MaxUsage, + MaxUsage: st.Max, Failcnt: st.Failcnt, } } pbSt.CgroupStats.PidsStats = &types.PidsStats{ - Current: lcSt.CgroupStats.PidsStats.Current, - Limit: lcSt.CgroupStats.PidsStats.Limit, + Current: st.Pids.Current, + Limit: st.Pids.Limit, } return pbSt } -func convertBlkioEntryToPb(b []cgroups.BlkioStatEntry) []*types.BlkioStatsEntry { +func convertBlkioEntryToPb(b []runtime.BlkioEntry) []*types.BlkioStatsEntry { var pbEs []*types.BlkioStatsEntry for _, e := range b { pbEs = append(pbEs, &types.BlkioStatsEntry{ diff --git a/runtime/container.go b/runtime/container.go index 144298c..5fb11bc 100644 --- a/runtime/container.go +++ b/runtime/container.go @@ -523,7 +523,7 @@ func hostIDFromMap(id uint32, mp []ocs.IDMapping) int { func (c *container) Pids() ([]int, error) { out, err := exec.Command(c.runtime, "ps", "--format=json", c.id).CombinedOutput() if err != nil { - return nil, fmt.Errorf(string(out)) + return nil, fmt.Errorf("%s", out) } var pids []int if err := json.Unmarshal(out, &pids); err != nil { @@ -533,19 +533,19 @@ func (c *container) Pids() ([]int, error) { } func (c *container) Stats() (*Stat, error) { - container, err := c.getLibctContainer() - if err != nil { - return nil, err - } now := time.Now() - stats, err := container.Stats() + out, err := exec.Command(c.runtime, "events", "--stats", c.id).CombinedOutput() if err != nil { + return nil, fmt.Errorf("%s", out) + } + s := struct { + Data *Stat `json:"data"` + }{} + if err := json.Unmarshal(out, &s); err != nil { return nil, err } - return &Stat{ - Timestamp: now, - Data: stats, - }, nil + s.Data.Timestamp = now + return s.Data, nil } func (c *container) OOM() (OOM, error) { @@ -575,7 +575,7 @@ func (c *container) Status() (State, error) { out, err := exec.Command(c.runtime, args...).CombinedOutput() if err != nil { - return "", fmt.Errorf(string(out)) + return "", fmt.Errorf("%s", out) } // We only require the runtime json output to have a top level Status field. diff --git a/runtime/runtime.go b/runtime/runtime.go index fff7b29..ff2094d 100644 --- a/runtime/runtime.go +++ b/runtime/runtime.go @@ -97,13 +97,3 @@ type ProcessState struct { PlatformProcessState } - -type Stat struct { - // Timestamp is the time that the statistics where collected - Timestamp time.Time - // Data is the raw stats - // TODO: it is currently an interface because we don't know what type of exec drivers - // we will have or what the structure should look like at the moment os the containers - // can return what they want and we could marshal to json or whatever. - Data interface{} -} diff --git a/runtime/stats.go b/runtime/stats.go new file mode 100644 index 0000000..de160bf --- /dev/null +++ b/runtime/stats.go @@ -0,0 +1,77 @@ +package runtime + +import "time" + +type Stat struct { + // Timestamp is the time that the statistics where collected + Timestamp time.Time + Cpu Cpu `json:"cpu"` + Memory Memory `json:"memory"` + Pids Pids `json:"pids"` + Blkio Blkio `json:"blkio"` + Hugetlb map[string]Hugetlb `json:"hugetlb"` +} + +type Hugetlb struct { + Usage uint64 `json:"usage,omitempty"` + Max uint64 `json:"max,omitempty"` + Failcnt uint64 `json:"failcnt"` +} + +type BlkioEntry struct { + Major uint64 `json:"major,omitempty"` + Minor uint64 `json:"minor,omitempty"` + Op string `json:"op,omitempty"` + Value uint64 `json:"value,omitempty"` +} + +type Blkio struct { + IoServiceBytesRecursive []BlkioEntry `json:"ioServiceBytesRecursive,omitempty"` + IoServicedRecursive []BlkioEntry `json:"ioServicedRecursive,omitempty"` + IoQueuedRecursive []BlkioEntry `json:"ioQueueRecursive,omitempty"` + IoServiceTimeRecursive []BlkioEntry `json:"ioServiceTimeRecursive,omitempty"` + IoWaitTimeRecursive []BlkioEntry `json:"ioWaitTimeRecursive,omitempty"` + IoMergedRecursive []BlkioEntry `json:"ioMergedRecursive,omitempty"` + IoTimeRecursive []BlkioEntry `json:"ioTimeRecursive,omitempty"` + SectorsRecursive []BlkioEntry `json:"sectorsRecursive,omitempty"` +} + +type Pids struct { + Current uint64 `json:"current,omitempty"` + Limit uint64 `json:"limit,omitempty"` +} + +type Throttling struct { + Periods uint64 `json:"periods,omitempty"` + ThrottledPeriods uint64 `json:"throttledPeriods,omitempty"` + ThrottledTime uint64 `json:"throttledTime,omitempty"` +} + +type CpuUsage struct { + // Units: nanoseconds. + Total uint64 `json:"total,omitempty"` + Percpu []uint64 `json:"percpu,omitempty"` + Kernel uint64 `json:"kernel"` + User uint64 `json:"user"` +} + +type Cpu struct { + Usage CpuUsage `json:"usage,omitempty"` + Throttling Throttling `json:"throttling,omitempty"` +} + +type MemoryEntry struct { + Limit uint64 `json:"limit"` + Usage uint64 `json:"usage,omitempty"` + Max uint64 `json:"max,omitempty"` + Failcnt uint64 `json:"failcnt"` +} + +type Memory struct { + Cache uint64 `json:"cache,omitempty"` + Usage MemoryEntry `json:"usage,omitempty"` + Swap MemoryEntry `json:"swap,omitempty"` + Kernel MemoryEntry `json:"kernel,omitempty"` + KernelTCP MemoryEntry `json:"kernelTCP,omitempty"` + Raw map[string]uint64 `json:"raw,omitempty"` +}