Commit 9a75f8d7 authored by Victor Marmol's avatar Victor Marmol

Update cAdvisor dependency to latest.

Brings in new range-based requests. Fixes #5777.
parent adac4328
......@@ -203,83 +203,83 @@
},
{
"ImportPath": "github.com/google/cadvisor/api",
"Comment": "0.10.1-62-ge78e515",
"Rev": "e78e515723d9eb387e5fd865a811f6263e946a06"
"Comment": "0.10.1-92-g41a0c30",
"Rev": "41a0c30fbf4df4d5d711b752785febb6ed5330a4"
},
{
"ImportPath": "github.com/google/cadvisor/container",
"Comment": "0.10.1-62-ge78e515",
"Rev": "e78e515723d9eb387e5fd865a811f6263e946a06"
"Comment": "0.10.1-92-g41a0c30",
"Rev": "41a0c30fbf4df4d5d711b752785febb6ed5330a4"
},
{
"ImportPath": "github.com/google/cadvisor/events",
"Comment": "0.10.1-62-ge78e515",
"Rev": "e78e515723d9eb387e5fd865a811f6263e946a06"
"Comment": "0.10.1-92-g41a0c30",
"Rev": "41a0c30fbf4df4d5d711b752785febb6ed5330a4"
},
{
"ImportPath": "github.com/google/cadvisor/fs",
"Comment": "0.10.1-62-ge78e515",
"Rev": "e78e515723d9eb387e5fd865a811f6263e946a06"
"Comment": "0.10.1-92-g41a0c30",
"Rev": "41a0c30fbf4df4d5d711b752785febb6ed5330a4"
},
{
"ImportPath": "github.com/google/cadvisor/healthz",
"Comment": "0.10.1-62-ge78e515",
"Rev": "e78e515723d9eb387e5fd865a811f6263e946a06"
"Comment": "0.10.1-92-g41a0c30",
"Rev": "41a0c30fbf4df4d5d711b752785febb6ed5330a4"
},
{
"ImportPath": "github.com/google/cadvisor/http",
"Comment": "0.10.1-62-ge78e515",
"Rev": "e78e515723d9eb387e5fd865a811f6263e946a06"
"Comment": "0.10.1-92-g41a0c30",
"Rev": "41a0c30fbf4df4d5d711b752785febb6ed5330a4"
},
{
"ImportPath": "github.com/google/cadvisor/info/v1",
"Comment": "0.10.1-62-ge78e515",
"Rev": "e78e515723d9eb387e5fd865a811f6263e946a06"
"Comment": "0.10.1-92-g41a0c30",
"Rev": "41a0c30fbf4df4d5d711b752785febb6ed5330a4"
},
{
"ImportPath": "github.com/google/cadvisor/info/v2",
"Comment": "0.10.1-62-ge78e515",
"Rev": "e78e515723d9eb387e5fd865a811f6263e946a06"
"Comment": "0.10.1-92-g41a0c30",
"Rev": "41a0c30fbf4df4d5d711b752785febb6ed5330a4"
},
{
"ImportPath": "github.com/google/cadvisor/manager",
"Comment": "0.10.1-62-ge78e515",
"Rev": "e78e515723d9eb387e5fd865a811f6263e946a06"
"Comment": "0.10.1-92-g41a0c30",
"Rev": "41a0c30fbf4df4d5d711b752785febb6ed5330a4"
},
{
"ImportPath": "github.com/google/cadvisor/metrics",
"Comment": "0.10.1-62-ge78e515",
"Rev": "e78e515723d9eb387e5fd865a811f6263e946a06"
"Comment": "0.10.1-92-g41a0c30",
"Rev": "41a0c30fbf4df4d5d711b752785febb6ed5330a4"
},
{
"ImportPath": "github.com/google/cadvisor/pages",
"Comment": "0.10.1-62-ge78e515",
"Rev": "e78e515723d9eb387e5fd865a811f6263e946a06"
"Comment": "0.10.1-92-g41a0c30",
"Rev": "41a0c30fbf4df4d5d711b752785febb6ed5330a4"
},
{
"ImportPath": "github.com/google/cadvisor/storage",
"Comment": "0.10.1-62-ge78e515",
"Rev": "e78e515723d9eb387e5fd865a811f6263e946a06"
"Comment": "0.10.1-92-g41a0c30",
"Rev": "41a0c30fbf4df4d5d711b752785febb6ed5330a4"
},
{
"ImportPath": "github.com/google/cadvisor/summary",
"Comment": "0.10.1-62-ge78e515",
"Rev": "e78e515723d9eb387e5fd865a811f6263e946a06"
"Comment": "0.10.1-92-g41a0c30",
"Rev": "41a0c30fbf4df4d5d711b752785febb6ed5330a4"
},
{
"ImportPath": "github.com/google/cadvisor/utils",
"Comment": "0.10.1-62-ge78e515",
"Rev": "e78e515723d9eb387e5fd865a811f6263e946a06"
"Comment": "0.10.1-92-g41a0c30",
"Rev": "41a0c30fbf4df4d5d711b752785febb6ed5330a4"
},
{
"ImportPath": "github.com/google/cadvisor/validate",
"Comment": "0.10.1-62-ge78e515",
"Rev": "e78e515723d9eb387e5fd865a811f6263e946a06"
"Comment": "0.10.1-92-g41a0c30",
"Rev": "41a0c30fbf4df4d5d711b752785febb6ed5330a4"
},
{
"ImportPath": "github.com/google/cadvisor/version",
"Comment": "0.10.1-62-ge78e515",
"Rev": "e78e515723d9eb387e5fd865a811f6263e946a06"
"Comment": "0.10.1-92-g41a0c30",
"Rev": "41a0c30fbf4df4d5d711b752785febb6ed5330a4"
},
{
"ImportPath": "github.com/google/gofuzz",
......
......@@ -36,6 +36,8 @@ const (
specApi = "spec"
eventsApi = "events"
storageApi = "storage"
attributesApi = "attributes"
versionApi = "version"
)
// Interface for a cAdvisor API version
......@@ -305,42 +307,69 @@ func (self *version2_0) SupportedRequestTypes() []string {
}
func (self *version2_0) HandleRequest(requestType string, request []string, m manager.Manager, w http.ResponseWriter, r *http.Request) error {
opt, err := getRequestOptions(r)
if err != nil {
return err
}
switch requestType {
case versionApi:
glog.V(2).Infof("Api - Version")
versionInfo, err := m.GetVersionInfo()
if err != nil {
return err
}
return writeResult(versionInfo.CadvisorVersion, w)
case attributesApi:
glog.V(2).Info("Api - Attributes")
machineInfo, err := m.GetMachineInfo()
if err != nil {
return err
}
versionInfo, err := m.GetVersionInfo()
if err != nil {
return err
}
info := v2.GetAttributes(machineInfo, versionInfo)
return writeResult(info, w)
case machineApi:
glog.V(2).Info("Api - Machine")
// TODO(rjnagal): Move machineInfo from v1.
machineInfo, err := m.GetMachineInfo()
if err != nil {
return err
}
return writeResult(machineInfo, w)
case summaryApi:
containerName := getContainerName(request)
glog.V(2).Infof("Api - Summary(%v)", containerName)
glog.V(2).Infof("Api - Summary for container %q, options %+v", containerName, opt)
stats, err := m.GetContainerDerivedStats(containerName)
stats, err := m.GetDerivedStats(containerName, opt)
if err != nil {
return err
}
return writeResult(stats, w)
case statsApi:
name := getContainerName(request)
sr, err := getStatsRequest(name, r)
glog.V(2).Infof("Api - Stats: Looking for stats for container %q, options %+v", name, opt)
conts, err := m.GetRequestedContainersInfo(name, opt)
if err != nil {
return err
}
glog.V(2).Infof("Api - Stats: Looking for stats for container %q, options %+v", name, sr)
query := info.ContainerInfoRequest{
NumStats: sr.Count,
contStats := make(map[string][]v2.ContainerStats, 0)
for name, cont := range conts {
contStats[name] = convertStats(cont)
}
cont, err := m.GetContainerInfo(name, &query)
if err != nil {
return fmt.Errorf("failed to get container %q: %v", name, err)
}
contStats := convertStats(cont)
return writeResult(contStats, w)
case specApi:
containerName := getContainerName(request)
glog.V(2).Infof("Api - Spec(%v)", containerName)
spec, err := m.GetContainerSpec(containerName)
glog.V(2).Infof("Api - Spec for container %q, options %+v", containerName, opt)
specs, err := m.GetContainerSpec(containerName, opt)
if err != nil {
return err
}
specV2 := convertSpec(spec)
return writeResult(specV2, w)
return writeResult(specs, w)
case storageApi:
var err error
fi := []v2.FsInfo{}
......@@ -364,26 +393,6 @@ func (self *version2_0) HandleRequest(requestType string, request []string, m ma
}
}
// Convert container spec from v1 to v2.
func convertSpec(specV1 info.ContainerSpec) v2.ContainerSpec {
specV2 := v2.ContainerSpec{
CreationTime: specV1.CreationTime,
HasCpu: specV1.HasCpu,
HasMemory: specV1.HasMemory,
}
if specV1.HasCpu {
specV2.Cpu.Limit = specV1.Cpu.Limit
specV2.Cpu.MaxLimit = specV1.Cpu.MaxLimit
specV2.Cpu.Mask = specV1.Cpu.Mask
}
if specV1.HasMemory {
specV2.Memory.Limit = specV1.Memory.Limit
specV2.Memory.Reservation = specV1.Memory.Reservation
specV2.Memory.SwapLimit = specV1.Memory.SwapLimit
}
return specV2
}
func convertStats(cont *info.ContainerInfo) []v2.ContainerStats {
stats := []v2.ContainerStats{}
for _, val := range cont.Stats {
......@@ -417,25 +426,35 @@ func convertStats(cont *info.ContainerInfo) []v2.ContainerStats {
return stats
}
func getStatsRequest(id string, r *http.Request) (v2.StatsRequest, error) {
func getRequestOptions(r *http.Request) (v2.RequestOptions, error) {
supportedTypes := map[string]bool{
v2.TypeName: true,
v2.TypeDocker: true,
}
// fill in the defaults.
sr := v2.StatsRequest{
IdType: "name",
opt := v2.RequestOptions{
IdType: v2.TypeName,
Count: 64,
Recursive: false,
}
idType := r.URL.Query().Get("type")
if len(idType) != 0 && idType != "name" {
return sr, fmt.Errorf("unknown 'type' %q for container name %q", idType, id)
if len(idType) != 0 {
if !supportedTypes[idType] {
return opt, fmt.Errorf("unknown 'type' %q", idType)
}
opt.IdType = idType
}
count := r.URL.Query().Get("count")
if len(count) != 0 {
n, err := strconv.ParseUint(count, 10, 32)
if err != nil {
return sr, fmt.Errorf("failed to parse 'count' option: %v", count)
return opt, fmt.Errorf("failed to parse 'count' option: %v", count)
}
sr.Count = int(n)
opt.Count = int(n)
}
recursive := r.URL.Query().Get("recursive")
if recursive == "true" {
opt.Recursive = true
}
// TODO(rjnagal): Add option to specify recursive.
return sr, nil
return opt, nil
}
......@@ -21,6 +21,7 @@ import (
"regexp"
"strconv"
"strings"
"sync"
"github.com/docker/libcontainer/cgroups"
"github.com/docker/libcontainer/cgroups/systemd"
......@@ -43,23 +44,23 @@ var dockerRootDir = flag.String("docker_root", "/var/lib/docker", "Absolute path
// Whether the system is using Systemd.
var useSystemd bool
func init() {
useSystemd = systemd.UseSystemd()
if !useSystemd {
// Second attempt at checking for systemd, check for a "name=systemd" cgroup.
mnt, err := cgroups.FindCgroupMountpoint("cpu")
if err == nil {
// systemd presence does not mean systemd controls cgroups.
// If system.slice cgroup exists, then systemd is taking control.
// This breaks if user creates system.slice manually :)
useSystemd = utils.FileExists(mnt + "/system.slice")
}
}
}
var check = sync.Once{}
func UseSystemd() bool {
// init would run and initialize useSystemd before we can call this method.
check.Do(func() {
// run and initialize useSystemd
useSystemd = systemd.UseSystemd()
if !useSystemd {
// Second attempt at checking for systemd, check for a "name=systemd" cgroup.
mnt, err := cgroups.FindCgroupMountpoint("cpu")
if err == nil {
// systemd presence does not mean systemd controls cgroups.
// If system.slice cgroup exists, then systemd is taking control.
// This breaks if user creates system.slice manually :)
useSystemd = utils.FileExists(mnt + "/system.slice")
}
}
})
return useSystemd
}
......@@ -108,7 +109,7 @@ func ContainerNameToDockerId(name string) string {
id := path.Base(name)
// Turn systemd cgroup name into Docker ID.
if useSystemd {
if UseSystemd() {
id = strings.TrimPrefix(id, "docker-")
id = strings.TrimSuffix(id, ".scope")
}
......@@ -119,7 +120,7 @@ func ContainerNameToDockerId(name string) string {
// Returns a full container name for the specified Docker ID.
func FullContainerName(dockerId string) string {
// Add the full container name.
if useSystemd {
if UseSystemd() {
return path.Join("/system.slice", fmt.Sprintf("docker-%s.scope", dockerId))
} else {
return path.Join("/docker", dockerId)
......@@ -207,7 +208,7 @@ func Register(factory info.MachineInfoFactory, fsInfo fs.FsInfo) error {
}
}
if useSystemd {
if UseSystemd() {
glog.Infof("System is using systemd")
}
......
......@@ -234,25 +234,28 @@ type LoadStats struct {
NrIoWait uint64 `json:"nr_io_wait"`
}
// CPU usage time statistics.
type CpuUsage struct {
// Total CPU usage.
// Units: nanoseconds
Total uint64 `json:"total"`
// Per CPU/core usage of the container.
// Unit: nanoseconds.
PerCpu []uint64 `json:"per_cpu_usage,omitempty"`
// Time spent in user space.
// Unit: nanoseconds
User uint64 `json:"user"`
// Time spent in kernel space.
// Unit: nanoseconds
System uint64 `json:"system"`
}
// All CPU usage metrics are cumulative from the creation of the container
type CpuStats struct {
Usage struct {
// Total CPU usage.
// Units: nanoseconds
Total uint64 `json:"total"`
// Per CPU/core usage of the container.
// Unit: nanoseconds.
PerCpu []uint64 `json:"per_cpu_usage,omitempty"`
// Time spent in user space.
// Unit: nanoseconds
User uint64 `json:"user"`
// Time spent in kernel space.
// Unit: nanoseconds
System uint64 `json:"system"`
} `json:"usage"`
Usage CpuUsage `json:"usage"`
// Smoothed average of number of runnable threads x 1000.
// We multiply by thousand to avoid using floats, but preserving precision.
// Load is smoothed over the last 10 seconds. Instantaneous value can be read
......
......@@ -128,6 +128,9 @@ type MachineInfo struct {
// The system uuid
SystemUUID string `json:"system_uuid"`
// The boot id
BootID string `json:"boot_id"`
// Filesystems on this machine.
Filesystems []FsInfo `json:"filesystems"`
......
......@@ -22,6 +22,11 @@ import (
"github.com/google/cadvisor/info/v1"
)
const (
TypeName = "name"
TypeDocker = "docker"
)
type CpuSpec struct {
// Requested cpu shares. Default is 1024.
Limit uint64 `json:"limit"`
......@@ -51,6 +56,14 @@ type ContainerSpec struct {
// Time at which the container was created.
CreationTime time.Time `json:"creation_time,omitempty"`
// Other names by which the container is known within a certain namespace.
// This is unique within that namespace.
Aliases []string `json:"aliases,omitempty"`
// Namespace under which the aliases of a container are unique.
// An example of a namespace is "docker" for Docker containers.
Namespace string `json:"namespace,omitempty"`
HasCpu bool `json:"has_cpu"`
Cpu CpuSpec `json:"cpu,omitempty"`
......@@ -142,7 +155,7 @@ type FsInfo struct {
Labels []string `json:"labels"`
}
type StatsRequest struct {
type RequestOptions struct {
// Type of container identifier specified - "name", "dockerid", dockeralias"
IdType string `json:"type"`
// Number of stats to return
......
// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package v2
import (
// TODO(rjnagal): Move structs from v1.
"github.com/google/cadvisor/info/v1"
)
type Attributes struct {
// Kernel version.
KernelVersion string `json:"kernel_version"`
// OS image being used for cadvisor container, or host image if running on host directly.
ContainerOsVersion string `json:"container_os_version"`
// Docker version.
DockerVersion string `json:"docker_version"`
// cAdvisor version.
CadvisorVersion string `json:"cadvisor_version"`
// The number of cores in this machine.
NumCores int `json:"num_cores"`
// Maximum clock speed for the cores, in KHz.
CpuFrequency uint64 `json:"cpu_frequency_khz"`
// The amount of memory (in bytes) in this machine
MemoryCapacity int64 `json:"memory_capacity"`
// The machine id
MachineID string `json:"machine_id"`
// The system uuid
SystemUUID string `json:"system_uuid"`
// Filesystems on this machine.
Filesystems []v1.FsInfo `json:"filesystems"`
// Disk map
DiskMap map[string]v1.DiskInfo `json:"disk_map"`
// Network devices
NetworkDevices []v1.NetInfo `json:"network_devices"`
// Machine Topology
// Describes cpu/memory layout and hierarchy.
Topology []v1.Node `json:"topology"`
}
func GetAttributes(mi *v1.MachineInfo, vi *v1.VersionInfo) Attributes {
return Attributes{
KernelVersion: vi.KernelVersion,
ContainerOsVersion: vi.ContainerOsVersion,
DockerVersion: vi.DockerVersion,
CadvisorVersion: vi.CadvisorVersion,
NumCores: mi.NumCores,
CpuFrequency: mi.CpuFrequency,
MemoryCapacity: mi.MemoryCapacity,
MachineID: mi.MachineID,
SystemUUID: mi.SystemUUID,
Filesystems: mi.Filesystems,
DiskMap: mi.DiskMap,
NetworkDevices: mi.NetworkDevices,
Topology: mi.Topology,
}
}
......@@ -182,7 +182,7 @@ func (c *containerData) housekeeping() {
}
// Housekeep every second.
glog.Infof("Start housekeeping for container %q\n", c.info.Name)
glog.V(3).Infof("Start housekeeping for container %q\n", c.info.Name)
lastHousekeeping := time.Now()
for {
select {
......
......@@ -42,6 +42,7 @@ var CpuClockSpeedMHz = regexp.MustCompile("cpu MHz\\t*: +([0-9]+.[0-9]+)")
var memoryCapacityRegexp = regexp.MustCompile("MemTotal: *([0-9]+) kB")
var machineIdFilePath = flag.String("machine_id_file", "/etc/machine-id,/var/lib/dbus/machine-id", "Comma-separated list of files to check for machine-id. Use the first one that exists.")
var bootIdFilePath = flag.String("boot_id_file", "/proc/sys/kernel/random/boot_id", "Comma-separated list of files to check for boot-id. Use the first one that exists.")
func getClockSpeed(procInfo []byte) (uint64, error) {
// First look through sys to find a max supported cpu frequency.
......@@ -209,17 +210,17 @@ func getTopology(sysFs sysfs.SysFs, cpuinfo string) ([]info.Node, int, error) {
return nodes, numCores, nil
}
func getMachineID() string {
if len(*machineIdFilePath) == 0 {
func getInfoFromFiles(filePaths string) string {
if len(filePaths) == 0 {
return ""
}
for _, file := range strings.Split(*machineIdFilePath, ",") {
for _, file := range strings.Split(filePaths, ",") {
id, err := ioutil.ReadFile(file)
if err == nil {
return strings.TrimSpace(string(id))
}
}
glog.Infof("Couldn't collect machine-id from any of the files in %q", *machineIdFilePath)
glog.Infof("Couldn't collect info from any of the files in %q", filePaths)
return ""
}
......@@ -273,8 +274,9 @@ func getMachineInfo(sysFs sysfs.SysFs, fsInfo fs.FsInfo) (*info.MachineInfo, err
DiskMap: diskMap,
NetworkDevices: netDevices,
Topology: topology,
MachineID: getMachineID(),
MachineID: getInfoFromFiles(*machineIdFilePath),
SystemUUID: systemUUID,
BootID: getInfoFromFiles(*bootIdFilePath),
}
for _, fs := range filesystems {
......
......@@ -55,14 +55,19 @@ func (c *ManagerMock) DockerContainer(name string, query *info.ContainerInfoRequ
return args.Get(0).(info.ContainerInfo), args.Error(1)
}
func (c *ManagerMock) GetContainerSpec(containerName string) (info.ContainerSpec, error) {
args := c.Called(containerName)
return args.Get(0).(info.ContainerSpec), args.Error(1)
func (c *ManagerMock) GetContainerSpec(containerName string, options v2.RequestOptions) (map[string]v2.ContainerSpec, error) {
args := c.Called(containerName, options)
return args.Get(0).(map[string]v2.ContainerSpec), args.Error(1)
}
func (c *ManagerMock) GetContainerDerivedStats(containerName string) (v2.DerivedStats, error) {
args := c.Called(containerName)
return args.Get(0).(v2.DerivedStats), args.Error(1)
func (c *ManagerMock) GetDerivedStats(containerName string, options v2.RequestOptions) (map[string]v2.DerivedStats, error) {
args := c.Called(containerName, options)
return args.Get(0).(map[string]v2.DerivedStats), args.Error(1)
}
func (c *ManagerMock) GetRequestedContainersInfo(containerName string, options v2.RequestOptions) (map[string]*info.ContainerInfo, error) {
args := c.Called(containerName, options)
return args.Get(0).(map[string]*info.ContainerInfo), args.Error(1)
}
func (c *ManagerMock) WatchForEvents(queryuest *events.Request, passedChannel chan *events.Event) error {
......
// Copyright 2014 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package metrics
import (
"io/ioutil"
"net/http"
"net/http/httptest"
"regexp"
"strings"
"testing"
info "github.com/google/cadvisor/info/v1"
"github.com/prometheus/client_golang/prometheus"
)
type testSubcontainersInfoProvider struct{}
func (p testSubcontainersInfoProvider) SubcontainersInfo(string, *info.ContainerInfoRequest) ([]*info.ContainerInfo, error) {
return []*info.ContainerInfo{
{
ContainerReference: info.ContainerReference{
Name: "testcontainer",
},
Stats: []*info.ContainerStats{
{
Cpu: info.CpuStats{
Usage: info.CpuUsage{
Total: 1,
PerCpu: []uint64{2, 3, 4, 5},
User: 6,
System: 7,
},
},
Memory: info.MemoryStats{
Usage: 8,
WorkingSet: 9,
ContainerData: info.MemoryStatsMemoryData{
Pgfault: 10,
Pgmajfault: 11,
},
HierarchicalData: info.MemoryStatsMemoryData{
Pgfault: 12,
Pgmajfault: 13,
},
},
Network: info.NetworkStats{
RxBytes: 14,
RxPackets: 15,
RxErrors: 16,
RxDropped: 17,
TxBytes: 18,
TxPackets: 19,
TxErrors: 20,
TxDropped: 21,
},
Filesystem: []info.FsStats{
{
Device: "sda1",
Limit: 22,
Usage: 23,
ReadsCompleted: 24,
ReadsMerged: 25,
SectorsRead: 26,
ReadTime: 27,
WritesCompleted: 28,
WritesMerged: 39,
SectorsWritten: 40,
WriteTime: 41,
IoInProgress: 42,
IoTime: 43,
WeightedIoTime: 44,
},
{
Device: "sda2",
Limit: 37,
Usage: 38,
ReadsCompleted: 39,
ReadsMerged: 40,
SectorsRead: 41,
ReadTime: 42,
WritesCompleted: 43,
WritesMerged: 44,
SectorsWritten: 45,
WriteTime: 46,
IoInProgress: 47,
IoTime: 48,
WeightedIoTime: 49,
},
},
TaskStats: info.LoadStats{
NrSleeping: 50,
NrRunning: 51,
NrStopped: 52,
NrUninterruptible: 53,
NrIoWait: 54,
},
},
},
},
}, nil
}
func TestPrometheusCollector(t *testing.T) {
prometheus.MustRegister(NewPrometheusCollector(testSubcontainersInfoProvider{}))
rw := httptest.NewRecorder()
prometheus.Handler().ServeHTTP(rw, &http.Request{})
metricsFile := "testdata/prometheus_metrics"
wantMetrics, err := ioutil.ReadFile(metricsFile)
if err != nil {
t.Fatalf("unable to read input test file %s", metricsFile)
}
wantLines := strings.Split(string(wantMetrics), "\n")
gotLines := strings.Split(string(rw.Body.String()), "\n")
// Until the Prometheus Go client library offers better testability
// (https://github.com/prometheus/client_golang/issues/58), we simply compare
// verbatim text-format metrics outputs, but ignore certain metric lines
// whose value depends on the current time or local circumstances.
includeRe := regexp.MustCompile("^(# HELP |# TYPE |)container_")
ignoreRe := regexp.MustCompile("^container_last_seen{")
for i, want := range wantLines {
if !includeRe.MatchString(want) || ignoreRe.MatchString(want) {
continue
}
if want != gotLines[i] {
t.Fatalf("want %s, got %s", want, gotLines[i])
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment