2017-02-17 19:36:44 +00:00
|
|
|
package docker
|
2016-01-20 23:21:19 +00:00
|
|
|
|
|
|
|
import (
|
2017-07-27 22:12:29 +00:00
|
|
|
"context"
|
2017-07-28 00:18:44 +00:00
|
|
|
"crypto/tls"
|
2018-10-12 21:36:55 +00:00
|
|
|
"io/ioutil"
|
2018-03-30 20:17:48 +00:00
|
|
|
"sort"
|
2018-10-12 21:36:55 +00:00
|
|
|
"strings"
|
2016-01-20 23:21:19 +00:00
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/influxdata/telegraf/testutil"
|
|
|
|
|
2017-02-17 19:36:44 +00:00
|
|
|
"github.com/docker/docker/api/types"
|
2017-10-03 21:36:26 +00:00
|
|
|
"github.com/docker/docker/api/types/swarm"
|
2016-02-24 04:58:14 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
2016-01-20 23:21:19 +00:00
|
|
|
)
|
|
|
|
|
2017-07-27 22:12:29 +00:00
|
|
|
type MockClient struct {
|
|
|
|
InfoF func(ctx context.Context) (types.Info, error)
|
|
|
|
ContainerListF func(ctx context.Context, options types.ContainerListOptions) ([]types.Container, error)
|
|
|
|
ContainerStatsF func(ctx context.Context, containerID string, stream bool) (types.ContainerStats, error)
|
|
|
|
ContainerInspectF func(ctx context.Context, containerID string) (types.ContainerJSON, error)
|
2017-10-03 21:36:26 +00:00
|
|
|
ServiceListF func(ctx context.Context, options types.ServiceListOptions) ([]swarm.Service, error)
|
|
|
|
TaskListF func(ctx context.Context, options types.TaskListOptions) ([]swarm.Task, error)
|
|
|
|
NodeListF func(ctx context.Context, options types.NodeListOptions) ([]swarm.Node, error)
|
2017-07-27 22:12:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *MockClient) Info(ctx context.Context) (types.Info, error) {
|
|
|
|
return c.InfoF(ctx)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *MockClient) ContainerList(
|
|
|
|
ctx context.Context,
|
|
|
|
options types.ContainerListOptions,
|
|
|
|
) ([]types.Container, error) {
|
|
|
|
return c.ContainerListF(ctx, options)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *MockClient) ContainerStats(
|
|
|
|
ctx context.Context,
|
|
|
|
containerID string,
|
|
|
|
stream bool,
|
|
|
|
) (types.ContainerStats, error) {
|
|
|
|
return c.ContainerStatsF(ctx, containerID, stream)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *MockClient) ContainerInspect(
|
|
|
|
ctx context.Context,
|
|
|
|
containerID string,
|
|
|
|
) (types.ContainerJSON, error) {
|
|
|
|
return c.ContainerInspectF(ctx, containerID)
|
|
|
|
}
|
|
|
|
|
2017-10-03 21:36:26 +00:00
|
|
|
func (c *MockClient) ServiceList(
|
|
|
|
ctx context.Context,
|
|
|
|
options types.ServiceListOptions,
|
|
|
|
) ([]swarm.Service, error) {
|
|
|
|
return c.ServiceListF(ctx, options)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *MockClient) TaskList(
|
|
|
|
ctx context.Context,
|
|
|
|
options types.TaskListOptions,
|
|
|
|
) ([]swarm.Task, error) {
|
|
|
|
return c.TaskListF(ctx, options)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *MockClient) NodeList(
|
|
|
|
ctx context.Context,
|
|
|
|
options types.NodeListOptions,
|
|
|
|
) ([]swarm.Node, error) {
|
|
|
|
return c.NodeListF(ctx, options)
|
|
|
|
}
|
|
|
|
|
2017-10-12 22:50:09 +00:00
|
|
|
var baseClient = MockClient{
|
|
|
|
InfoF: func(context.Context) (types.Info, error) {
|
|
|
|
return info, nil
|
|
|
|
},
|
|
|
|
ContainerListF: func(context.Context, types.ContainerListOptions) ([]types.Container, error) {
|
|
|
|
return containerList, nil
|
|
|
|
},
|
2018-07-13 01:41:49 +00:00
|
|
|
ContainerStatsF: func(c context.Context, s string, b bool) (types.ContainerStats, error) {
|
|
|
|
return containerStats(s), nil
|
2017-10-12 22:50:09 +00:00
|
|
|
},
|
|
|
|
ContainerInspectF: func(context.Context, string) (types.ContainerJSON, error) {
|
|
|
|
return containerInspect, nil
|
|
|
|
},
|
|
|
|
ServiceListF: func(context.Context, types.ServiceListOptions) ([]swarm.Service, error) {
|
|
|
|
return ServiceList, nil
|
|
|
|
},
|
|
|
|
TaskListF: func(context.Context, types.TaskListOptions) ([]swarm.Task, error) {
|
|
|
|
return TaskList, nil
|
|
|
|
},
|
|
|
|
NodeListF: func(context.Context, types.NodeListOptions) ([]swarm.Node, error) {
|
|
|
|
return NodeList, nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2017-07-28 00:18:44 +00:00
|
|
|
func newClient(host string, tlsConfig *tls.Config) (Client, error) {
|
2017-10-12 22:50:09 +00:00
|
|
|
return &baseClient, nil
|
2017-07-27 22:12:29 +00:00
|
|
|
}
|
|
|
|
|
2016-01-20 23:21:19 +00:00
|
|
|
func TestDockerGatherContainerStats(t *testing.T) {
|
|
|
|
var acc testutil.Accumulator
|
|
|
|
stats := testStats()
|
|
|
|
|
|
|
|
tags := map[string]string{
|
2016-04-12 20:59:19 +00:00
|
|
|
"container_name": "redis",
|
|
|
|
"container_image": "redis/image",
|
2016-01-20 23:21:19 +00:00
|
|
|
}
|
2017-06-08 20:17:31 +00:00
|
|
|
|
2018-07-13 01:41:49 +00:00
|
|
|
parseContainerStats(stats, &acc, tags, "123456789", true, true, "linux")
|
2016-01-20 23:21:19 +00:00
|
|
|
|
2016-04-12 20:59:19 +00:00
|
|
|
// test docker_container_net measurement
|
2016-01-20 23:21:19 +00:00
|
|
|
netfields := map[string]interface{}{
|
2016-04-12 20:59:19 +00:00
|
|
|
"rx_dropped": uint64(1),
|
|
|
|
"rx_bytes": uint64(2),
|
|
|
|
"rx_errors": uint64(3),
|
|
|
|
"tx_packets": uint64(4),
|
|
|
|
"tx_dropped": uint64(1),
|
|
|
|
"rx_packets": uint64(2),
|
|
|
|
"tx_errors": uint64(3),
|
|
|
|
"tx_bytes": uint64(4),
|
|
|
|
"container_id": "123456789",
|
2016-01-20 23:21:19 +00:00
|
|
|
}
|
|
|
|
nettags := copyTags(tags)
|
|
|
|
nettags["network"] = "eth0"
|
2016-04-12 20:59:19 +00:00
|
|
|
acc.AssertContainsTaggedFields(t, "docker_container_net", netfields, nettags)
|
2016-01-20 23:21:19 +00:00
|
|
|
|
2016-07-21 15:50:12 +00:00
|
|
|
netfields = map[string]interface{}{
|
|
|
|
"rx_dropped": uint64(6),
|
|
|
|
"rx_bytes": uint64(8),
|
|
|
|
"rx_errors": uint64(10),
|
|
|
|
"tx_packets": uint64(12),
|
|
|
|
"tx_dropped": uint64(6),
|
|
|
|
"rx_packets": uint64(8),
|
|
|
|
"tx_errors": uint64(10),
|
|
|
|
"tx_bytes": uint64(12),
|
|
|
|
"container_id": "123456789",
|
|
|
|
}
|
|
|
|
nettags = copyTags(tags)
|
|
|
|
nettags["network"] = "total"
|
|
|
|
acc.AssertContainsTaggedFields(t, "docker_container_net", netfields, nettags)
|
|
|
|
|
2016-01-20 23:21:19 +00:00
|
|
|
// test docker_blkio measurement
|
|
|
|
blkiotags := copyTags(tags)
|
|
|
|
blkiotags["device"] = "6:0"
|
|
|
|
blkiofields := map[string]interface{}{
|
|
|
|
"io_service_bytes_recursive_read": uint64(100),
|
|
|
|
"io_serviced_recursive_write": uint64(101),
|
2016-05-04 12:17:23 +00:00
|
|
|
"container_id": "123456789",
|
2016-01-20 23:21:19 +00:00
|
|
|
}
|
2016-04-18 22:20:46 +00:00
|
|
|
acc.AssertContainsTaggedFields(t, "docker_container_blkio", blkiofields, blkiotags)
|
2016-01-20 23:21:19 +00:00
|
|
|
|
2016-07-21 15:50:12 +00:00
|
|
|
blkiotags = copyTags(tags)
|
|
|
|
blkiotags["device"] = "total"
|
|
|
|
blkiofields = map[string]interface{}{
|
|
|
|
"io_service_bytes_recursive_read": uint64(100),
|
|
|
|
"io_serviced_recursive_write": uint64(302),
|
|
|
|
"container_id": "123456789",
|
|
|
|
}
|
|
|
|
acc.AssertContainsTaggedFields(t, "docker_container_blkio", blkiofields, blkiotags)
|
|
|
|
|
2016-04-12 20:59:19 +00:00
|
|
|
// test docker_container_mem measurement
|
2016-02-11 10:49:48 +00:00
|
|
|
memfields := map[string]interface{}{
|
2017-07-27 22:12:29 +00:00
|
|
|
"active_anon": uint64(0),
|
|
|
|
"active_file": uint64(1),
|
|
|
|
"cache": uint64(0),
|
|
|
|
"container_id": "123456789",
|
2016-02-11 10:49:48 +00:00
|
|
|
"fail_count": uint64(1),
|
2017-07-27 22:12:29 +00:00
|
|
|
"hierarchical_memory_limit": uint64(0),
|
|
|
|
"inactive_anon": uint64(0),
|
|
|
|
"inactive_file": uint64(3),
|
2016-02-11 10:49:48 +00:00
|
|
|
"limit": uint64(2000),
|
|
|
|
"mapped_file": uint64(0),
|
2017-07-27 22:12:29 +00:00
|
|
|
"max_usage": uint64(1001),
|
|
|
|
"pgfault": uint64(2),
|
2016-02-11 10:49:48 +00:00
|
|
|
"pgmajfault": uint64(0),
|
2017-07-27 22:12:29 +00:00
|
|
|
"pgpgin": uint64(0),
|
|
|
|
"pgpgout": uint64(0),
|
2016-02-11 10:49:48 +00:00
|
|
|
"rss_huge": uint64(0),
|
2017-07-27 22:12:29 +00:00
|
|
|
"rss": uint64(0),
|
2016-02-11 10:49:48 +00:00
|
|
|
"total_active_anon": uint64(0),
|
2017-07-27 22:12:29 +00:00
|
|
|
"total_active_file": uint64(0),
|
2016-02-11 10:49:48 +00:00
|
|
|
"total_cache": uint64(0),
|
2017-07-27 22:12:29 +00:00
|
|
|
"total_inactive_anon": uint64(0),
|
|
|
|
"total_inactive_file": uint64(0),
|
|
|
|
"total_mapped_file": uint64(0),
|
|
|
|
"total_pgfault": uint64(0),
|
|
|
|
"total_pgmajfault": uint64(0),
|
2016-02-11 10:49:48 +00:00
|
|
|
"total_pgpgin": uint64(4),
|
2017-07-27 22:12:29 +00:00
|
|
|
"total_pgpgout": uint64(0),
|
|
|
|
"total_rss_huge": uint64(444),
|
|
|
|
"total_rss": uint64(44),
|
|
|
|
"total_unevictable": uint64(0),
|
|
|
|
"total_writeback": uint64(55),
|
|
|
|
"unevictable": uint64(0),
|
2016-02-11 10:49:48 +00:00
|
|
|
"usage_percent": float64(55.55),
|
2017-07-27 22:12:29 +00:00
|
|
|
"usage": uint64(1111),
|
|
|
|
"writeback": uint64(0),
|
2016-02-11 10:49:48 +00:00
|
|
|
}
|
|
|
|
|
2016-04-12 20:59:19 +00:00
|
|
|
acc.AssertContainsTaggedFields(t, "docker_container_mem", memfields, tags)
|
2016-01-20 23:21:19 +00:00
|
|
|
|
2016-04-12 20:59:19 +00:00
|
|
|
// test docker_container_cpu measurement
|
2016-01-20 23:21:19 +00:00
|
|
|
cputags := copyTags(tags)
|
|
|
|
cputags["cpu"] = "cpu-total"
|
2016-02-11 10:49:48 +00:00
|
|
|
cpufields := map[string]interface{}{
|
|
|
|
"usage_total": uint64(500),
|
|
|
|
"usage_in_usermode": uint64(100),
|
|
|
|
"usage_in_kernelmode": uint64(200),
|
|
|
|
"usage_system": uint64(100),
|
|
|
|
"throttling_periods": uint64(1),
|
|
|
|
"throttling_throttled_periods": uint64(0),
|
|
|
|
"throttling_throttled_time": uint64(0),
|
|
|
|
"usage_percent": float64(400.0),
|
2016-04-12 20:59:19 +00:00
|
|
|
"container_id": "123456789",
|
2016-02-11 10:49:48 +00:00
|
|
|
}
|
2016-04-12 20:59:19 +00:00
|
|
|
acc.AssertContainsTaggedFields(t, "docker_container_cpu", cpufields, cputags)
|
2016-01-20 23:21:19 +00:00
|
|
|
|
|
|
|
cputags["cpu"] = "cpu0"
|
|
|
|
cpu0fields := map[string]interface{}{
|
2016-05-09 08:22:53 +00:00
|
|
|
"usage_total": uint64(1),
|
|
|
|
"container_id": "123456789",
|
2016-01-20 23:21:19 +00:00
|
|
|
}
|
2016-04-12 20:59:19 +00:00
|
|
|
acc.AssertContainsTaggedFields(t, "docker_container_cpu", cpu0fields, cputags)
|
2016-01-20 23:21:19 +00:00
|
|
|
|
|
|
|
cputags["cpu"] = "cpu1"
|
|
|
|
cpu1fields := map[string]interface{}{
|
2016-05-09 08:22:53 +00:00
|
|
|
"usage_total": uint64(1002),
|
|
|
|
"container_id": "123456789",
|
2016-01-20 23:21:19 +00:00
|
|
|
}
|
2016-04-12 20:59:19 +00:00
|
|
|
acc.AssertContainsTaggedFields(t, "docker_container_cpu", cpu1fields, cputags)
|
2017-07-21 21:25:17 +00:00
|
|
|
|
|
|
|
// Those tagged filed should not be present because of offline CPUs
|
|
|
|
cputags["cpu"] = "cpu2"
|
|
|
|
cpu2fields := map[string]interface{}{
|
|
|
|
"usage_total": uint64(0),
|
|
|
|
"container_id": "123456789",
|
|
|
|
}
|
|
|
|
acc.AssertDoesNotContainsTaggedFields(t, "docker_container_cpu", cpu2fields, cputags)
|
|
|
|
|
|
|
|
cputags["cpu"] = "cpu3"
|
|
|
|
cpu3fields := map[string]interface{}{
|
|
|
|
"usage_total": uint64(0),
|
|
|
|
"container_id": "123456789",
|
|
|
|
}
|
|
|
|
acc.AssertDoesNotContainsTaggedFields(t, "docker_container_cpu", cpu3fields, cputags)
|
2016-01-20 23:21:19 +00:00
|
|
|
}
|
|
|
|
|
2017-07-27 22:12:29 +00:00
|
|
|
func TestDocker_WindowsMemoryContainerStats(t *testing.T) {
|
|
|
|
var acc testutil.Accumulator
|
2016-01-20 23:21:19 +00:00
|
|
|
|
2017-07-27 22:12:29 +00:00
|
|
|
d := Docker{
|
2017-07-28 00:18:44 +00:00
|
|
|
newClient: func(string, *tls.Config) (Client, error) {
|
2017-07-27 22:12:29 +00:00
|
|
|
return &MockClient{
|
|
|
|
InfoF: func(ctx context.Context) (types.Info, error) {
|
|
|
|
return info, nil
|
|
|
|
},
|
|
|
|
ContainerListF: func(ctx context.Context, options types.ContainerListOptions) ([]types.Container, error) {
|
|
|
|
return containerList, nil
|
|
|
|
},
|
|
|
|
ContainerStatsF: func(ctx context.Context, containerID string, stream bool) (types.ContainerStats, error) {
|
|
|
|
return containerStatsWindows(), nil
|
|
|
|
},
|
|
|
|
ContainerInspectF: func(ctx context.Context, containerID string) (types.ContainerJSON, error) {
|
|
|
|
return containerInspect, nil
|
|
|
|
},
|
2017-10-03 21:36:26 +00:00
|
|
|
ServiceListF: func(context.Context, types.ServiceListOptions) ([]swarm.Service, error) {
|
|
|
|
return ServiceList, nil
|
|
|
|
},
|
|
|
|
TaskListF: func(context.Context, types.TaskListOptions) ([]swarm.Task, error) {
|
|
|
|
return TaskList, nil
|
|
|
|
},
|
|
|
|
NodeListF: func(context.Context, types.NodeListOptions) ([]swarm.Node, error) {
|
|
|
|
return NodeList, nil
|
|
|
|
},
|
2017-07-27 22:12:29 +00:00
|
|
|
}, nil
|
|
|
|
},
|
2016-07-21 15:50:12 +00:00
|
|
|
}
|
2017-07-27 22:12:29 +00:00
|
|
|
err := d.Gather(&acc)
|
|
|
|
require.NoError(t, err)
|
|
|
|
}
|
2016-07-21 15:50:12 +00:00
|
|
|
|
2017-10-12 22:50:09 +00:00
|
|
|
func TestContainerLabels(t *testing.T) {
|
|
|
|
var tests = []struct {
|
|
|
|
name string
|
|
|
|
container types.Container
|
|
|
|
include []string
|
|
|
|
exclude []string
|
|
|
|
expected map[string]string
|
2017-07-27 22:12:29 +00:00
|
|
|
}{
|
2017-10-12 22:50:09 +00:00
|
|
|
{
|
|
|
|
name: "Nil filters matches all",
|
2018-07-13 01:41:49 +00:00
|
|
|
container: genContainerLabeled(map[string]string{
|
|
|
|
"a": "x",
|
|
|
|
}),
|
2017-10-12 22:50:09 +00:00
|
|
|
include: nil,
|
|
|
|
exclude: nil,
|
|
|
|
expected: map[string]string{
|
|
|
|
"a": "x",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Empty filters matches all",
|
2018-07-13 01:41:49 +00:00
|
|
|
container: genContainerLabeled(map[string]string{
|
|
|
|
"a": "x",
|
|
|
|
}),
|
2017-10-12 22:50:09 +00:00
|
|
|
include: []string{},
|
|
|
|
exclude: []string{},
|
|
|
|
expected: map[string]string{
|
|
|
|
"a": "x",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Must match include",
|
2018-07-13 01:41:49 +00:00
|
|
|
container: genContainerLabeled(map[string]string{
|
|
|
|
"a": "x",
|
|
|
|
"b": "y",
|
|
|
|
}),
|
2017-10-12 22:50:09 +00:00
|
|
|
include: []string{"a"},
|
|
|
|
exclude: []string{},
|
|
|
|
expected: map[string]string{
|
|
|
|
"a": "x",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Must not match exclude",
|
2018-07-13 01:41:49 +00:00
|
|
|
container: genContainerLabeled(map[string]string{
|
|
|
|
"a": "x",
|
|
|
|
"b": "y",
|
|
|
|
}),
|
2017-10-12 22:50:09 +00:00
|
|
|
include: []string{},
|
|
|
|
exclude: []string{"b"},
|
|
|
|
expected: map[string]string{
|
|
|
|
"a": "x",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Include Glob",
|
2018-07-13 01:41:49 +00:00
|
|
|
container: genContainerLabeled(map[string]string{
|
|
|
|
"aa": "x",
|
|
|
|
"ab": "y",
|
|
|
|
"bb": "z",
|
|
|
|
}),
|
2017-10-12 22:50:09 +00:00
|
|
|
include: []string{"a*"},
|
|
|
|
exclude: []string{},
|
|
|
|
expected: map[string]string{
|
|
|
|
"aa": "x",
|
|
|
|
"ab": "y",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Exclude Glob",
|
2018-07-13 01:41:49 +00:00
|
|
|
container: genContainerLabeled(map[string]string{
|
|
|
|
"aa": "x",
|
|
|
|
"ab": "y",
|
|
|
|
"bb": "z",
|
|
|
|
}),
|
2017-10-12 22:50:09 +00:00
|
|
|
include: []string{},
|
|
|
|
exclude: []string{"a*"},
|
|
|
|
expected: map[string]string{
|
|
|
|
"bb": "z",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Excluded Includes",
|
2018-07-13 01:41:49 +00:00
|
|
|
container: genContainerLabeled(map[string]string{
|
|
|
|
"aa": "x",
|
|
|
|
"ab": "y",
|
|
|
|
"bb": "z",
|
|
|
|
}),
|
2017-10-12 22:50:09 +00:00
|
|
|
include: []string{"a*"},
|
|
|
|
exclude: []string{"*b"},
|
|
|
|
expected: map[string]string{
|
|
|
|
"aa": "x",
|
|
|
|
},
|
|
|
|
},
|
2016-07-21 15:50:12 +00:00
|
|
|
}
|
2017-10-12 22:50:09 +00:00
|
|
|
for _, tt := range tests {
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
2017-07-27 22:12:29 +00:00
|
|
|
var acc testutil.Accumulator
|
2016-01-20 23:21:19 +00:00
|
|
|
|
2017-10-12 22:50:09 +00:00
|
|
|
newClientFunc := func(host string, tlsConfig *tls.Config) (Client, error) {
|
|
|
|
client := baseClient
|
|
|
|
client.ContainerListF = func(context.Context, types.ContainerListOptions) ([]types.Container, error) {
|
|
|
|
return []types.Container{tt.container}, nil
|
|
|
|
}
|
|
|
|
return &client, nil
|
2017-07-27 22:12:29 +00:00
|
|
|
}
|
2017-10-12 22:50:09 +00:00
|
|
|
|
|
|
|
d := Docker{
|
|
|
|
newClient: newClientFunc,
|
|
|
|
LabelInclude: tt.include,
|
|
|
|
LabelExclude: tt.exclude,
|
2017-07-27 22:12:29 +00:00
|
|
|
}
|
2016-02-24 04:58:14 +00:00
|
|
|
|
2017-07-27 22:12:29 +00:00
|
|
|
err := d.Gather(&acc)
|
|
|
|
require.NoError(t, err)
|
2017-04-03 20:43:15 +00:00
|
|
|
|
2017-10-12 22:50:09 +00:00
|
|
|
// Grab tags from a container metric
|
|
|
|
var actual map[string]string
|
|
|
|
for _, metric := range acc.Metrics {
|
|
|
|
if metric.Measurement == "docker_container_cpu" {
|
|
|
|
actual = metric.Tags
|
2017-07-27 22:12:29 +00:00
|
|
|
}
|
2017-04-03 20:43:15 +00:00
|
|
|
}
|
|
|
|
|
2017-10-12 22:50:09 +00:00
|
|
|
for k, v := range tt.expected {
|
|
|
|
require.Equal(t, v, actual[k])
|
2017-04-03 20:43:15 +00:00
|
|
|
}
|
2017-07-27 22:12:29 +00:00
|
|
|
})
|
2017-04-03 20:43:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-13 01:41:49 +00:00
|
|
|
func genContainerLabeled(labels map[string]string) types.Container {
|
|
|
|
c := containerList[0]
|
|
|
|
c.Labels = labels
|
|
|
|
return c
|
|
|
|
}
|
|
|
|
|
2017-06-08 20:17:31 +00:00
|
|
|
func TestContainerNames(t *testing.T) {
|
2017-10-12 22:50:09 +00:00
|
|
|
var tests = []struct {
|
|
|
|
name string
|
|
|
|
containers [][]string
|
|
|
|
include []string
|
|
|
|
exclude []string
|
|
|
|
expected []string
|
2017-07-27 22:12:29 +00:00
|
|
|
}{
|
2017-10-12 22:50:09 +00:00
|
|
|
{
|
2018-07-13 01:41:49 +00:00
|
|
|
name: "Nil filters matches all",
|
2017-10-12 22:50:09 +00:00
|
|
|
include: nil,
|
|
|
|
exclude: nil,
|
2018-07-13 01:41:49 +00:00
|
|
|
expected: []string{"etcd", "etcd2", "acme", "acme-test", "foo"},
|
2017-10-12 22:50:09 +00:00
|
|
|
},
|
|
|
|
{
|
2018-07-13 01:41:49 +00:00
|
|
|
name: "Empty filters matches all",
|
2017-10-12 22:50:09 +00:00
|
|
|
include: []string{},
|
|
|
|
exclude: []string{},
|
2018-07-13 01:41:49 +00:00
|
|
|
expected: []string{"etcd", "etcd2", "acme", "acme-test", "foo"},
|
2017-10-12 22:50:09 +00:00
|
|
|
},
|
|
|
|
{
|
2018-07-13 01:41:49 +00:00
|
|
|
name: "Match all containers",
|
2017-10-12 22:50:09 +00:00
|
|
|
include: []string{"*"},
|
|
|
|
exclude: []string{},
|
2018-07-13 01:41:49 +00:00
|
|
|
expected: []string{"etcd", "etcd2", "acme", "acme-test", "foo"},
|
2017-10-12 22:50:09 +00:00
|
|
|
},
|
|
|
|
{
|
2018-07-13 01:41:49 +00:00
|
|
|
name: "Include prefix match",
|
2017-10-12 22:50:09 +00:00
|
|
|
include: []string{"etc*"},
|
|
|
|
exclude: []string{},
|
|
|
|
expected: []string{"etcd", "etcd2"},
|
|
|
|
},
|
|
|
|
{
|
2018-07-13 01:41:49 +00:00
|
|
|
name: "Exact match",
|
2017-10-12 22:50:09 +00:00
|
|
|
include: []string{"etcd"},
|
|
|
|
exclude: []string{},
|
|
|
|
expected: []string{"etcd"},
|
|
|
|
},
|
|
|
|
{
|
2018-07-13 01:41:49 +00:00
|
|
|
name: "Star matches zero length",
|
2017-10-12 22:50:09 +00:00
|
|
|
include: []string{"etcd2*"},
|
|
|
|
exclude: []string{},
|
|
|
|
expected: []string{"etcd2"},
|
|
|
|
},
|
|
|
|
{
|
2018-07-13 01:41:49 +00:00
|
|
|
name: "Exclude matches all",
|
2017-10-12 22:50:09 +00:00
|
|
|
include: []string{},
|
|
|
|
exclude: []string{"etc*"},
|
2018-07-13 01:41:49 +00:00
|
|
|
expected: []string{"acme", "acme-test", "foo"},
|
2017-10-12 22:50:09 +00:00
|
|
|
},
|
|
|
|
{
|
2018-07-13 01:41:49 +00:00
|
|
|
name: "Exclude single",
|
2017-10-12 22:50:09 +00:00
|
|
|
include: []string{},
|
|
|
|
exclude: []string{"etcd"},
|
2018-07-13 01:41:49 +00:00
|
|
|
expected: []string{"etcd2", "acme", "acme-test", "foo"},
|
2017-10-12 22:50:09 +00:00
|
|
|
},
|
|
|
|
{
|
2018-07-13 01:41:49 +00:00
|
|
|
name: "Exclude all",
|
2017-10-12 22:50:09 +00:00
|
|
|
include: []string{"*"},
|
|
|
|
exclude: []string{"*"},
|
|
|
|
expected: []string{},
|
|
|
|
},
|
|
|
|
{
|
2018-07-13 01:41:49 +00:00
|
|
|
name: "Exclude item matching include",
|
2017-10-12 22:50:09 +00:00
|
|
|
include: []string{"acme*"},
|
|
|
|
exclude: []string{"*test*"},
|
|
|
|
expected: []string{"acme"},
|
|
|
|
},
|
|
|
|
{
|
2018-07-13 01:41:49 +00:00
|
|
|
name: "Exclude item no wildcards",
|
2017-10-12 22:50:09 +00:00
|
|
|
include: []string{"acme*"},
|
|
|
|
exclude: []string{"test"},
|
|
|
|
expected: []string{"acme", "acme-test"},
|
|
|
|
},
|
2017-07-27 22:12:29 +00:00
|
|
|
}
|
2017-10-12 22:50:09 +00:00
|
|
|
for _, tt := range tests {
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
2017-07-27 22:12:29 +00:00
|
|
|
var acc testutil.Accumulator
|
|
|
|
|
2017-10-12 22:50:09 +00:00
|
|
|
newClientFunc := func(host string, tlsConfig *tls.Config) (Client, error) {
|
|
|
|
client := baseClient
|
|
|
|
client.ContainerListF = func(context.Context, types.ContainerListOptions) ([]types.Container, error) {
|
2018-07-13 01:41:49 +00:00
|
|
|
return containerList, nil
|
|
|
|
}
|
|
|
|
client.ContainerStatsF = func(c context.Context, s string, b bool) (types.ContainerStats, error) {
|
|
|
|
return containerStats(s), nil
|
2017-10-12 22:50:09 +00:00
|
|
|
}
|
2018-07-13 01:41:49 +00:00
|
|
|
|
2017-10-12 22:50:09 +00:00
|
|
|
return &client, nil
|
|
|
|
}
|
|
|
|
|
2017-07-27 22:12:29 +00:00
|
|
|
d := Docker{
|
2017-10-12 22:50:09 +00:00
|
|
|
newClient: newClientFunc,
|
2017-07-27 22:12:29 +00:00
|
|
|
ContainerInclude: tt.include,
|
|
|
|
ContainerExclude: tt.exclude,
|
|
|
|
}
|
|
|
|
|
|
|
|
err := d.Gather(&acc)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
2017-10-12 22:50:09 +00:00
|
|
|
// Set of expected names
|
|
|
|
var expected = make(map[string]bool)
|
|
|
|
for _, v := range tt.expected {
|
|
|
|
expected[v] = true
|
2017-06-08 20:17:31 +00:00
|
|
|
}
|
2017-07-27 22:12:29 +00:00
|
|
|
|
2017-10-12 22:50:09 +00:00
|
|
|
// Set of actual names
|
|
|
|
var actual = make(map[string]bool)
|
2017-07-27 22:12:29 +00:00
|
|
|
for _, metric := range acc.Metrics {
|
2017-10-12 22:50:09 +00:00
|
|
|
if name, ok := metric.Tags["container_name"]; ok {
|
|
|
|
actual[name] = true
|
2017-06-08 20:17:31 +00:00
|
|
|
}
|
|
|
|
}
|
2017-10-12 22:50:09 +00:00
|
|
|
|
|
|
|
require.Equal(t, expected, actual)
|
2017-07-27 22:12:29 +00:00
|
|
|
})
|
2017-06-08 20:17:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-24 04:58:14 +00:00
|
|
|
func TestDockerGatherInfo(t *testing.T) {
|
|
|
|
var acc testutil.Accumulator
|
2017-02-17 19:36:44 +00:00
|
|
|
d := Docker{
|
2017-07-27 22:12:29 +00:00
|
|
|
newClient: newClient,
|
2017-05-18 23:58:34 +00:00
|
|
|
TagEnvironment: []string{"ENVVAR1", "ENVVAR2", "ENVVAR3", "ENVVAR5",
|
|
|
|
"ENVVAR6", "ENVVAR7", "ENVVAR8", "ENVVAR9"},
|
2017-02-17 19:36:44 +00:00
|
|
|
}
|
2016-02-24 04:58:14 +00:00
|
|
|
|
2017-04-24 18:13:26 +00:00
|
|
|
err := acc.GatherError(d.Gather)
|
2016-02-24 04:58:14 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
acc.AssertContainsTaggedFields(t,
|
|
|
|
"docker",
|
|
|
|
map[string]interface{}{
|
2016-04-03 17:37:41 +00:00
|
|
|
"n_listener_events": int(0),
|
|
|
|
"n_cpus": int(4),
|
|
|
|
"n_used_file_descriptors": int(19),
|
|
|
|
"n_containers": int(108),
|
2016-09-21 09:37:49 +00:00
|
|
|
"n_containers_running": int(98),
|
|
|
|
"n_containers_stopped": int(6),
|
|
|
|
"n_containers_paused": int(3),
|
2016-04-03 17:37:41 +00:00
|
|
|
"n_images": int(199),
|
|
|
|
"n_goroutines": int(39),
|
2016-02-24 04:58:14 +00:00
|
|
|
},
|
2018-04-23 22:09:04 +00:00
|
|
|
map[string]string{
|
|
|
|
"engine_host": "absol",
|
|
|
|
"server_version": "17.09.0-ce",
|
|
|
|
},
|
2016-02-24 04:58:14 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
acc.AssertContainsTaggedFields(t,
|
|
|
|
"docker_data",
|
|
|
|
map[string]interface{}{
|
|
|
|
"used": int64(17300000000),
|
|
|
|
"total": int64(107400000000),
|
|
|
|
"available": int64(36530000000),
|
|
|
|
},
|
|
|
|
map[string]string{
|
2018-04-23 22:09:04 +00:00
|
|
|
"unit": "bytes",
|
|
|
|
"engine_host": "absol",
|
|
|
|
"server_version": "17.09.0-ce",
|
2016-02-24 04:58:14 +00:00
|
|
|
},
|
|
|
|
)
|
|
|
|
acc.AssertContainsTaggedFields(t,
|
2016-04-12 20:59:19 +00:00
|
|
|
"docker_container_cpu",
|
2016-02-24 04:58:14 +00:00
|
|
|
map[string]interface{}{
|
2016-05-09 08:22:53 +00:00
|
|
|
"usage_total": uint64(1231652),
|
|
|
|
"container_id": "b7dfbb9478a6ae55e237d4d74f8bbb753f0817192b5081334dc78476296e2173",
|
2016-02-24 04:58:14 +00:00
|
|
|
},
|
|
|
|
map[string]string{
|
2016-07-19 16:31:01 +00:00
|
|
|
"container_name": "etcd2",
|
2016-12-16 13:53:16 +00:00
|
|
|
"container_image": "quay.io:4443/coreos/etcd",
|
2016-07-19 16:31:01 +00:00
|
|
|
"cpu": "cpu3",
|
|
|
|
"container_version": "v2.2.2",
|
2016-09-06 07:37:46 +00:00
|
|
|
"engine_host": "absol",
|
2017-05-18 23:58:34 +00:00
|
|
|
"ENVVAR1": "loremipsum",
|
|
|
|
"ENVVAR2": "dolorsitamet",
|
|
|
|
"ENVVAR3": "=ubuntu:10.04",
|
|
|
|
"ENVVAR7": "ENVVAR8=ENVVAR9",
|
2017-04-03 20:43:15 +00:00
|
|
|
"label1": "test_value_1",
|
|
|
|
"label2": "test_value_2",
|
2018-04-23 22:09:04 +00:00
|
|
|
"server_version": "17.09.0-ce",
|
2018-06-18 22:33:14 +00:00
|
|
|
"container_status": "running",
|
2016-02-24 04:58:14 +00:00
|
|
|
},
|
|
|
|
)
|
|
|
|
acc.AssertContainsTaggedFields(t,
|
2016-04-12 20:59:19 +00:00
|
|
|
"docker_container_mem",
|
2016-02-24 04:58:14 +00:00
|
|
|
map[string]interface{}{
|
2017-07-27 22:12:29 +00:00
|
|
|
"container_id": "b7dfbb9478a6ae55e237d4d74f8bbb753f0817192b5081334dc78476296e2173",
|
|
|
|
"limit": uint64(18935443456),
|
|
|
|
"max_usage": uint64(0),
|
|
|
|
"usage": uint64(0),
|
|
|
|
"usage_percent": float64(0),
|
2016-02-24 04:58:14 +00:00
|
|
|
},
|
|
|
|
map[string]string{
|
2016-09-06 07:37:46 +00:00
|
|
|
"engine_host": "absol",
|
2016-07-19 16:31:01 +00:00
|
|
|
"container_name": "etcd2",
|
2016-12-16 13:53:16 +00:00
|
|
|
"container_image": "quay.io:4443/coreos/etcd",
|
2016-07-19 16:31:01 +00:00
|
|
|
"container_version": "v2.2.2",
|
2017-05-18 23:58:34 +00:00
|
|
|
"ENVVAR1": "loremipsum",
|
|
|
|
"ENVVAR2": "dolorsitamet",
|
|
|
|
"ENVVAR3": "=ubuntu:10.04",
|
|
|
|
"ENVVAR7": "ENVVAR8=ENVVAR9",
|
2017-04-03 20:43:15 +00:00
|
|
|
"label1": "test_value_1",
|
|
|
|
"label2": "test_value_2",
|
2018-04-23 22:09:04 +00:00
|
|
|
"server_version": "17.09.0-ce",
|
2018-06-18 22:33:14 +00:00
|
|
|
"container_status": "running",
|
2016-02-24 04:58:14 +00:00
|
|
|
},
|
|
|
|
)
|
|
|
|
}
|
2017-10-03 21:36:26 +00:00
|
|
|
|
|
|
|
func TestDockerGatherSwarmInfo(t *testing.T) {
|
|
|
|
var acc testutil.Accumulator
|
|
|
|
d := Docker{
|
|
|
|
newClient: newClient,
|
|
|
|
}
|
|
|
|
|
|
|
|
err := acc.GatherError(d.Gather)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
d.gatherSwarmInfo(&acc)
|
|
|
|
|
|
|
|
// test docker_container_net measurement
|
|
|
|
acc.AssertContainsTaggedFields(t,
|
|
|
|
"docker_swarm",
|
|
|
|
map[string]interface{}{
|
|
|
|
"tasks_running": int(2),
|
|
|
|
"tasks_desired": uint64(2),
|
|
|
|
},
|
|
|
|
map[string]string{
|
|
|
|
"service_id": "qolkls9g5iasdiuihcyz9rnx2",
|
|
|
|
"service_name": "test1",
|
|
|
|
"service_mode": "replicated",
|
|
|
|
},
|
|
|
|
)
|
|
|
|
|
|
|
|
acc.AssertContainsTaggedFields(t,
|
|
|
|
"docker_swarm",
|
|
|
|
map[string]interface{}{
|
|
|
|
"tasks_running": int(1),
|
|
|
|
"tasks_desired": int(1),
|
|
|
|
},
|
|
|
|
map[string]string{
|
|
|
|
"service_id": "qolkls9g5iasdiuihcyz9rn3",
|
|
|
|
"service_name": "test2",
|
|
|
|
"service_mode": "global",
|
|
|
|
},
|
|
|
|
)
|
|
|
|
}
|
2018-03-30 20:17:48 +00:00
|
|
|
|
|
|
|
func TestContainerStateFilter(t *testing.T) {
|
|
|
|
var tests = []struct {
|
|
|
|
name string
|
|
|
|
include []string
|
|
|
|
exclude []string
|
|
|
|
expected map[string][]string
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "default",
|
|
|
|
expected: map[string][]string{
|
|
|
|
"status": []string{"running"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "include running",
|
|
|
|
include: []string{"running"},
|
|
|
|
expected: map[string][]string{
|
|
|
|
"status": []string{"running"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "include glob",
|
|
|
|
include: []string{"r*"},
|
|
|
|
expected: map[string][]string{
|
|
|
|
"status": []string{"restarting", "running", "removing"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "include all",
|
|
|
|
include: []string{"*"},
|
|
|
|
expected: map[string][]string{
|
|
|
|
"status": []string{"created", "restarting", "running", "removing", "paused", "exited", "dead"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "exclude all",
|
|
|
|
exclude: []string{"*"},
|
|
|
|
expected: map[string][]string{
|
|
|
|
"status": []string{},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "exclude all",
|
|
|
|
include: []string{"*"},
|
|
|
|
exclude: []string{"exited"},
|
|
|
|
expected: map[string][]string{
|
|
|
|
"status": []string{"created", "restarting", "running", "removing", "paused", "dead"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, tt := range tests {
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
var acc testutil.Accumulator
|
|
|
|
|
|
|
|
newClientFunc := func(host string, tlsConfig *tls.Config) (Client, error) {
|
|
|
|
client := baseClient
|
|
|
|
client.ContainerListF = func(ctx context.Context, options types.ContainerListOptions) ([]types.Container, error) {
|
|
|
|
for k, v := range tt.expected {
|
|
|
|
actual := options.Filters.Get(k)
|
|
|
|
sort.Strings(actual)
|
|
|
|
sort.Strings(v)
|
|
|
|
require.Equal(t, v, actual)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
return &client, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
d := Docker{
|
|
|
|
newClient: newClientFunc,
|
|
|
|
ContainerStateInclude: tt.include,
|
|
|
|
ContainerStateExclude: tt.exclude,
|
|
|
|
}
|
|
|
|
|
|
|
|
err := d.Gather(&acc)
|
|
|
|
require.NoError(t, err)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2018-10-12 21:36:55 +00:00
|
|
|
|
|
|
|
func TestContainerName(t *testing.T) {
|
|
|
|
tests := []struct {
|
|
|
|
name string
|
|
|
|
clientFunc func(host string, tlsConfig *tls.Config) (Client, error)
|
|
|
|
expected string
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "container stats name is preferred",
|
|
|
|
clientFunc: func(host string, tlsConfig *tls.Config) (Client, error) {
|
|
|
|
client := baseClient
|
|
|
|
client.ContainerListF = func(context.Context, types.ContainerListOptions) ([]types.Container, error) {
|
|
|
|
var containers []types.Container
|
|
|
|
containers = append(containers, types.Container{
|
|
|
|
Names: []string{"/logspout/foo"},
|
|
|
|
})
|
|
|
|
return containers, nil
|
|
|
|
}
|
|
|
|
client.ContainerStatsF = func(ctx context.Context, containerID string, stream bool) (types.ContainerStats, error) {
|
|
|
|
return types.ContainerStats{
|
|
|
|
Body: ioutil.NopCloser(strings.NewReader(`{"name": "logspout"}`)),
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
return &client, nil
|
|
|
|
},
|
|
|
|
expected: "logspout",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "container stats without name uses container list name",
|
|
|
|
clientFunc: func(host string, tlsConfig *tls.Config) (Client, error) {
|
|
|
|
client := baseClient
|
|
|
|
client.ContainerListF = func(context.Context, types.ContainerListOptions) ([]types.Container, error) {
|
|
|
|
var containers []types.Container
|
|
|
|
containers = append(containers, types.Container{
|
|
|
|
Names: []string{"/logspout"},
|
|
|
|
})
|
|
|
|
return containers, nil
|
|
|
|
}
|
|
|
|
client.ContainerStatsF = func(ctx context.Context, containerID string, stream bool) (types.ContainerStats, error) {
|
|
|
|
return types.ContainerStats{
|
|
|
|
Body: ioutil.NopCloser(strings.NewReader(`{}`)),
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
return &client, nil
|
|
|
|
},
|
|
|
|
expected: "logspout",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
d := Docker{
|
|
|
|
newClient: tt.clientFunc,
|
|
|
|
}
|
|
|
|
var acc testutil.Accumulator
|
|
|
|
err := d.Gather(&acc)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
for _, metric := range acc.Metrics {
|
|
|
|
// This tag is set on all container measurements
|
|
|
|
if metric.Measurement == "docker_container_mem" {
|
|
|
|
require.Equal(t, tt.expected, metric.Tags["container_name"])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|