master
go 161 lines 4.21 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package docker
4
5 import (
6 "context"
7 _ "embed"
8 "errors"
9 "time"
10
11 "github.com/netdata/netdata/go/plugins/pkg/confopt"
12 "github.com/netdata/netdata/go/plugins/pkg/funcapi"
13 "github.com/netdata/netdata/go/plugins/pkg/matcher"
14 "github.com/netdata/netdata/go/plugins/plugin/framework/collectorapi"
15 "github.com/netdata/netdata/go/plugins/plugin/go.d/collector/docker/dockerfunc"
16 "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/dockerhost"
17
18 "github.com/docker/docker/api/types"
19 typesContainer "github.com/docker/docker/api/types/container"
20 typesImage "github.com/docker/docker/api/types/image"
21 typesSystem "github.com/docker/docker/api/types/system"
22 docker "github.com/docker/docker/client"
23 )
24
25 //go:embed "config_schema.json"
26 var configSchema string
27
28 func init() {
29 collectorapi.Register("docker", collectorapi.Creator{
30 JobConfigSchema: configSchema,
31 Create: func() collectorapi.CollectorV1 { return New() },
32 Config: func() any { return &Config{} },
33 Methods: dockerfunc.Methods,
34 MethodHandler: func(job collectorapi.RuntimeJob) funcapi.MethodHandler {
35 c, ok := job.Collector().(*Collector)
36 if !ok {
37 return nil
38 }
39 return c.funcRouter
40 },
41 })
42 }
43
44 func New() *Collector {
45 c := &Collector{
46 Config: Config{
47 Address: docker.DefaultDockerHost,
48 Timeout: confopt.Duration(time.Second * 2),
49 ContainerSelector: "*",
50 CollectContainerSize: false,
51 },
52
53 charts: summaryCharts.Copy(),
54 newClient: func(cfg Config) (dockerClient, error) {
55 return docker.NewClientWithOpts(docker.WithHost(cfg.Address))
56 },
57 cntrSr: matcher.TRUE(),
58 containers: make(map[string]bool),
59 }
60 c.funcRouter = dockerfunc.NewRouter(funcDepsAdapter{collector: c})
61 return c
62 }
63
64 type Config struct {
65 Vnode string `yaml:"vnode,omitempty" json:"vnode"`
66 UpdateEvery int `yaml:"update_every,omitempty" json:"update_every"`
67 AutoDetectionRetry int `yaml:"autodetection_retry,omitempty" json:"autodetection_retry"`
68 Address string `yaml:"address" json:"address"`
69 Timeout confopt.Duration `yaml:"timeout,omitempty" json:"timeout"`
70 ContainerSelector string `yaml:"container_selector,omitempty" json:"container_selector"`
71 CollectContainerSize bool `yaml:"collect_container_size" json:"collect_container_size"`
72 }
73
74 type (
75 Collector struct {
76 collectorapi.Base
77 Config `yaml:",inline" json:""`
78
79 charts *collectorapi.Charts
80
81 client dockerClient
82 newClient func(Config) (dockerClient, error)
83
84 funcRouter funcapi.MethodHandler
85
86 verNegotiated bool
87 containers map[string]bool
88 cntrSr matcher.Matcher
89 }
90 dockerClient interface {
91 NegotiateAPIVersion(context.Context)
92 Info(context.Context) (typesSystem.Info, error)
93 ImageList(context.Context, typesImage.ListOptions) ([]typesImage.Summary, error)
94 ContainerList(context.Context, typesContainer.ListOptions) ([]types.Container, error)
95 Close() error
96 }
97 )
98
99 func (c *Collector) Configuration() any {
100 return c.Config
101 }
102
103 func (c *Collector) Init(context.Context) error {
104 if addr := dockerhost.FromEnv(); addr != "" && c.Address == docker.DefaultDockerHost {
105 c.Infof("using docker host from environment: %s ", addr)
106 c.Address = addr
107 }
108 if c.ContainerSelector != "" {
109 sr, err := matcher.NewSimplePatternsMatcher(c.ContainerSelector)
110 if err != nil {
111 return err
112 }
113 c.cntrSr = sr
114 }
115 if c.funcRouter == nil {
116 c.funcRouter = dockerfunc.NewRouter(funcDepsAdapter{collector: c})
117 }
118
119 return nil
120 }
121
122 func (c *Collector) Check(context.Context) error {
123 mx, err := c.collect()
124 if err != nil {
125 return err
126 }
127 if len(mx) == 0 {
128 return errors.New("no metrics collected")
129
130 }
131 return nil
132 }
133
134 func (c *Collector) Charts() *collectorapi.Charts {
135 return c.charts
136 }
137
138 func (c *Collector) Collect(context.Context) map[string]int64 {
139 mx, err := c.collect()
140 if err != nil {
141 c.Error(err)
142 }
143
144 if len(mx) == 0 {
145 return nil
146 }
147 return mx
148 }
149
150 func (c *Collector) Cleanup(ctx context.Context) {
151 if c.funcRouter != nil {
152 c.funcRouter.Cleanup(ctx)
153 }
154 if c.client == nil {
155 return
156 }
157 if err := c.client.Close(); err != nil {
158 c.Warningf("error on closing docker client: %v", err)
159 }
160 c.client = nil
161 }