diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-05 12:08:03 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-05 12:08:18 +0000 |
commit | 5da14042f70711ea5cf66e034699730335462f66 (patch) | |
tree | 0f6354ccac934ed87a2d555f45be4c831cf92f4a /src/go/collectors/go.d.plugin/modules/docker/collect.go | |
parent | Releasing debian version 1.44.3-2. (diff) | |
download | netdata-5da14042f70711ea5cf66e034699730335462f66.tar.xz netdata-5da14042f70711ea5cf66e034699730335462f66.zip |
Merging upstream version 1.45.3+dfsg.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | src/go/collectors/go.d.plugin/modules/docker/collect.go | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/src/go/collectors/go.d.plugin/modules/docker/collect.go b/src/go/collectors/go.d.plugin/modules/docker/collect.go new file mode 100644 index 000000000..7b5af7cab --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/docker/collect.go @@ -0,0 +1,199 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package docker + +import ( + "context" + "fmt" + "strings" + + "github.com/docker/docker/api/types" + typesContainer "github.com/docker/docker/api/types/container" + "github.com/docker/docker/api/types/filters" +) + +func (d *Docker) collect() (map[string]int64, error) { + if d.client == nil { + client, err := d.newClient(d.Config) + if err != nil { + return nil, err + } + d.client = client + } + + if !d.verNegotiated { + d.verNegotiated = true + d.negotiateAPIVersion() + } + + defer func() { _ = d.client.Close() }() + + mx := make(map[string]int64) + + if err := d.collectInfo(mx); err != nil { + return nil, err + } + if err := d.collectImages(mx); err != nil { + return nil, err + } + if err := d.collectContainers(mx); err != nil { + return nil, err + } + + return mx, nil +} + +func (d *Docker) collectInfo(mx map[string]int64) error { + ctx, cancel := context.WithTimeout(context.Background(), d.Timeout.Duration()) + defer cancel() + + info, err := d.client.Info(ctx) + if err != nil { + return err + } + + mx["containers_state_running"] = int64(info.ContainersRunning) + mx["containers_state_paused"] = int64(info.ContainersPaused) + mx["containers_state_exited"] = int64(info.ContainersStopped) + + return nil +} + +func (d *Docker) collectImages(mx map[string]int64) error { + ctx, cancel := context.WithTimeout(context.Background(), d.Timeout.Duration()) + defer cancel() + + images, err := d.client.ImageList(ctx, types.ImageListOptions{}) + if err != nil { + return err + } + + mx["images_size"] = 0 + mx["images_dangling"] = 0 + mx["images_active"] = 0 + + for _, v := range images { + mx["images_size"] += v.Size + if v.Containers == 0 { + mx["images_dangling"]++ + } else { + mx["images_active"]++ + } + } + + return nil +} + +var ( + containerHealthStatuses = []string{ + types.Healthy, + types.Unhealthy, + types.Starting, + types.NoHealthcheck, + } + containerStates = []string{ + "created", + "running", + "paused", + "restarting", + "removing", + "exited", + "dead", + } +) + +func (d *Docker) collectContainers(mx map[string]int64) error { + containerSet := make(map[string][]types.Container) + + for _, status := range containerHealthStatuses { + if err := func() error { + ctx, cancel := context.WithTimeout(context.Background(), d.Timeout.Duration()) + defer cancel() + + v, err := d.client.ContainerList(ctx, typesContainer.ListOptions{ + All: true, + Filters: filters.NewArgs(filters.KeyValuePair{Key: "health", Value: status}), + Size: d.CollectContainerSize, + }) + if err != nil { + return err + } + containerSet[status] = v + return nil + + }(); err != nil { + return err + } + } + + seen := make(map[string]bool) + + for _, s := range containerHealthStatuses { + mx["containers_health_status_"+s] = 0 + } + mx["containers_health_status_not_running_unhealthy"] = 0 + + for status, containers := range containerSet { + if status != types.Unhealthy { + mx["containers_health_status_"+status] = int64(len(containers)) + } + + for _, cntr := range containers { + if status == types.Unhealthy { + if cntr.State == "running" { + mx["containers_health_status_"+status] += 1 + } else { + mx["containers_health_status_not_running_unhealthy"] += 1 + } + } + + if len(cntr.Names) == 0 { + continue + } + + name := strings.TrimPrefix(cntr.Names[0], "/") + + seen[name] = true + + if !d.containers[name] { + d.containers[name] = true + d.addContainerCharts(name, cntr.Image) + } + + px := fmt.Sprintf("container_%s_", name) + + for _, s := range containerHealthStatuses { + mx[px+"health_status_"+s] = 0 + } + mx[px+"health_status_not_running_unhealthy"] = 0 + for _, s := range containerStates { + mx[px+"state_"+s] = 0 + } + + if status == types.Unhealthy && cntr.State != "running" { + mx[px+"health_status_not_running_unhealthy"] += 1 + } else { + mx[px+"health_status_"+status] = 1 + } + mx[px+"state_"+cntr.State] = 1 + mx[px+"size_rw"] = cntr.SizeRw + mx[px+"size_root_fs"] = cntr.SizeRootFs + } + } + + for name := range d.containers { + if !seen[name] { + delete(d.containers, name) + d.removeContainerCharts(name) + } + } + + return nil +} + +func (d *Docker) negotiateAPIVersion() { + ctx, cancel := context.WithTimeout(context.Background(), d.Timeout.Duration()) + defer cancel() + + d.client.NegotiateAPIVersion(ctx) +} |