summaryrefslogtreecommitdiffstats
path: root/src/go/plugin/go.d/agent
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-11-25 17:33:56 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-11-25 17:34:10 +0000
commit83ba6762cc43d9db581b979bb5e3445669e46cc2 (patch)
tree2e69833b43f791ed253a7a20318b767ebe56cdb8 /src/go/plugin/go.d/agent
parentReleasing debian version 1.47.5-1. (diff)
downloadnetdata-83ba6762cc43d9db581b979bb5e3445669e46cc2.tar.xz
netdata-83ba6762cc43d9db581b979bb5e3445669e46cc2.zip
Merging upstream version 2.0.3+dfsg (Closes: #923993, #1042533, #1045145).
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/go/plugin/go.d/agent')
-rw-r--r--src/go/plugin/go.d/agent/agent.go11
-rw-r--r--src/go/plugin/go.d/agent/agent_test.go2
-rw-r--r--src/go/plugin/go.d/agent/confgroup/config_test.go12
-rw-r--r--src/go/plugin/go.d/agent/config.go4
-rw-r--r--src/go/plugin/go.d/agent/discovery/file/parse.go2
-rw-r--r--src/go/plugin/go.d/agent/discovery/file/sim_test.go2
-rw-r--r--src/go/plugin/go.d/agent/discovery/sd/conffile.go2
-rw-r--r--src/go/plugin/go.d/agent/discovery/sd/discoverer/dockerd/docker.go8
-rw-r--r--src/go/plugin/go.d/agent/discovery/sd/discoverer/kubernetes/kubernetes.go2
-rw-r--r--src/go/plugin/go.d/agent/discovery/sd/discoverer/kubernetes/kubernetes_test.go2
-rw-r--r--src/go/plugin/go.d/agent/discovery/sd/discoverer/kubernetes/pod.go4
-rw-r--r--src/go/plugin/go.d/agent/discovery/sd/discoverer/kubernetes/service.go5
-rw-r--r--src/go/plugin/go.d/agent/discovery/sd/discoverer/netlisteners/ll.go62
-rw-r--r--src/go/plugin/go.d/agent/discovery/sd/discoverer/netlisteners/netlisteners.go76
-rw-r--r--src/go/plugin/go.d/agent/discovery/sd/pipeline/funcmap.go10
-rw-r--r--src/go/plugin/go.d/agent/discovery/sd/pipeline/pipeline_test.go6
-rw-r--r--src/go/plugin/go.d/agent/discovery/sd/pipeline/promport.go2
-rw-r--r--src/go/plugin/go.d/agent/discovery/sd/sd.go2
-rw-r--r--src/go/plugin/go.d/agent/discovery/sim_test.go1
-rw-r--r--src/go/plugin/go.d/agent/functions/manager.go4
-rw-r--r--src/go/plugin/go.d/agent/jobmgr/manager.go6
-rw-r--r--src/go/plugin/go.d/agent/jobmgr/sim_test.go5
-rw-r--r--src/go/plugin/go.d/agent/module/charts.go28
-rw-r--r--src/go/plugin/go.d/agent/module/job.go42
-rw-r--r--src/go/plugin/go.d/agent/module/module.go9
-rw-r--r--src/go/plugin/go.d/agent/netdataapi/api.go213
-rw-r--r--src/go/plugin/go.d/agent/netdataapi/api_test.go265
-rw-r--r--src/go/plugin/go.d/agent/safewriter/writer.go30
-rw-r--r--src/go/plugin/go.d/agent/ticker/ticker.go55
-rw-r--r--src/go/plugin/go.d/agent/ticker/ticket_test.go50
-rw-r--r--src/go/plugin/go.d/agent/vnodes/vnodes.go17
31 files changed, 183 insertions, 756 deletions
diff --git a/src/go/plugin/go.d/agent/agent.go b/src/go/plugin/go.d/agent/agent.go
index 2423e84e0..014f544b5 100644
--- a/src/go/plugin/go.d/agent/agent.go
+++ b/src/go/plugin/go.d/agent/agent.go
@@ -13,6 +13,9 @@ import (
"time"
"github.com/netdata/netdata/go/plugins/logger"
+ "github.com/netdata/netdata/go/plugins/pkg/multipath"
+ "github.com/netdata/netdata/go/plugins/pkg/netdataapi"
+ "github.com/netdata/netdata/go/plugins/pkg/safewriter"
"github.com/netdata/netdata/go/plugins/plugin/go.d/agent/confgroup"
"github.com/netdata/netdata/go/plugins/plugin/go.d/agent/discovery"
"github.com/netdata/netdata/go/plugins/plugin/go.d/agent/filelock"
@@ -20,10 +23,6 @@ import (
"github.com/netdata/netdata/go/plugins/plugin/go.d/agent/functions"
"github.com/netdata/netdata/go/plugins/plugin/go.d/agent/jobmgr"
"github.com/netdata/netdata/go/plugins/plugin/go.d/agent/module"
- "github.com/netdata/netdata/go/plugins/plugin/go.d/agent/netdataapi"
- "github.com/netdata/netdata/go/plugins/plugin/go.d/agent/safewriter"
- "github.com/netdata/netdata/go/plugins/plugin/go.d/agent/vnodes"
- "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/multipath"
"github.com/mattn/go-isatty"
)
@@ -187,9 +186,7 @@ func (a *Agent) run(ctx context.Context) {
jobMgr.ConfigDefaults = discCfg.Registry
jobMgr.FnReg = fnMgr
- if reg := a.setupVnodeRegistry(); reg == nil || reg.Len() == 0 {
- vnodes.Disabled = true
- } else {
+ if reg := a.setupVnodeRegistry(); reg != nil && reg.Len() > 0 {
jobMgr.Vnodes = reg
}
diff --git a/src/go/plugin/go.d/agent/agent_test.go b/src/go/plugin/go.d/agent/agent_test.go
index 9096b9015..39e12f751 100644
--- a/src/go/plugin/go.d/agent/agent_test.go
+++ b/src/go/plugin/go.d/agent/agent_test.go
@@ -9,8 +9,8 @@ import (
"testing"
"time"
+ "github.com/netdata/netdata/go/plugins/pkg/safewriter"
"github.com/netdata/netdata/go/plugins/plugin/go.d/agent/module"
- "github.com/netdata/netdata/go/plugins/plugin/go.d/agent/safewriter"
"github.com/stretchr/testify/assert"
)
diff --git a/src/go/plugin/go.d/agent/confgroup/config_test.go b/src/go/plugin/go.d/agent/confgroup/config_test.go
index 98c6c3e78..d8e865b44 100644
--- a/src/go/plugin/go.d/agent/confgroup/config_test.go
+++ b/src/go/plugin/go.d/agent/confgroup/config_test.go
@@ -13,7 +13,7 @@ import (
func TestConfig_Name(t *testing.T) {
tests := map[string]struct {
cfg Config
- expected interface{}
+ expected any
}{
"string": {cfg: Config{"name": "name"}, expected: "name"},
"empty string": {cfg: Config{"name": ""}, expected: ""},
@@ -32,7 +32,7 @@ func TestConfig_Name(t *testing.T) {
func TestConfig_Module(t *testing.T) {
tests := map[string]struct {
cfg Config
- expected interface{}
+ expected any
}{
"string": {cfg: Config{"module": "module"}, expected: "module"},
"empty string": {cfg: Config{"module": ""}, expected: ""},
@@ -51,7 +51,7 @@ func TestConfig_Module(t *testing.T) {
func TestConfig_FullName(t *testing.T) {
tests := map[string]struct {
cfg Config
- expected interface{}
+ expected any
}{
"name == module": {cfg: Config{"name": "name", "module": "name"}, expected: "name"},
"name != module": {cfg: Config{"name": "name", "module": "module"}, expected: "module_name"},
@@ -68,7 +68,7 @@ func TestConfig_FullName(t *testing.T) {
func TestConfig_UpdateEvery(t *testing.T) {
tests := map[string]struct {
cfg Config
- expected interface{}
+ expected any
}{
"int": {cfg: Config{"update_every": 1}, expected: 1},
"not int": {cfg: Config{"update_every": "1"}, expected: 0},
@@ -86,7 +86,7 @@ func TestConfig_UpdateEvery(t *testing.T) {
func TestConfig_AutoDetectionRetry(t *testing.T) {
tests := map[string]struct {
cfg Config
- expected interface{}
+ expected any
}{
"int": {cfg: Config{"autodetection_retry": 1}, expected: 1},
"not int": {cfg: Config{"autodetection_retry": "1"}, expected: 0},
@@ -104,7 +104,7 @@ func TestConfig_AutoDetectionRetry(t *testing.T) {
func TestConfig_Priority(t *testing.T) {
tests := map[string]struct {
cfg Config
- expected interface{}
+ expected any
}{
"int": {cfg: Config{"priority": 1}, expected: 1},
"not int": {cfg: Config{"priority": "1"}, expected: 0},
diff --git a/src/go/plugin/go.d/agent/config.go b/src/go/plugin/go.d/agent/config.go
index fef68c7e0..e0c3f4605 100644
--- a/src/go/plugin/go.d/agent/config.go
+++ b/src/go/plugin/go.d/agent/config.go
@@ -47,13 +47,13 @@ func (c *config) isEnabled(moduleName string, explicit bool) bool {
return c.DefaultRun
}
-func (c *config) UnmarshalYAML(unmarshal func(interface{}) error) error {
+func (c *config) UnmarshalYAML(unmarshal func(any) error) error {
type plain config
if err := unmarshal((*plain)(c)); err != nil {
return err
}
- var m map[string]interface{}
+ var m map[string]any
if err := unmarshal(&m); err != nil {
return err
}
diff --git a/src/go/plugin/go.d/agent/discovery/file/parse.go b/src/go/plugin/go.d/agent/discovery/file/parse.go
index 5fd31f32a..ae48fcb8f 100644
--- a/src/go/plugin/go.d/agent/discovery/file/parse.go
+++ b/src/go/plugin/go.d/agent/discovery/file/parse.go
@@ -97,7 +97,7 @@ func parseSDFormat(reg confgroup.Registry, path string, bs []byte) (*confgroup.G
}
func cfgFormat(bs []byte) format {
- var data interface{}
+ var data any
if err := yaml.Unmarshal(bs, &data); err != nil {
return unknownFormat
}
diff --git a/src/go/plugin/go.d/agent/discovery/file/sim_test.go b/src/go/plugin/go.d/agent/discovery/file/sim_test.go
index 3219c6892..a0a8c4425 100644
--- a/src/go/plugin/go.d/agent/discovery/file/sim_test.go
+++ b/src/go/plugin/go.d/agent/discovery/file/sim_test.go
@@ -110,7 +110,7 @@ func (d *tmpDir) renameFile(origFilename, newFilename string) {
require.NoError(d.t, err)
}
-func (d *tmpDir) writeYAML(filename string, in interface{}) {
+func (d *tmpDir) writeYAML(filename string, in any) {
bs, err := yaml.Marshal(in)
require.NoError(d.t, err)
err = os.WriteFile(filename, bs, 0644)
diff --git a/src/go/plugin/go.d/agent/discovery/sd/conffile.go b/src/go/plugin/go.d/agent/discovery/sd/conffile.go
index e08a4021b..60a7208d2 100644
--- a/src/go/plugin/go.d/agent/discovery/sd/conffile.go
+++ b/src/go/plugin/go.d/agent/discovery/sd/conffile.go
@@ -7,7 +7,7 @@ import (
"os"
"github.com/netdata/netdata/go/plugins/logger"
- "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/multipath"
+ "github.com/netdata/netdata/go/plugins/pkg/multipath"
)
type confFile struct {
diff --git a/src/go/plugin/go.d/agent/discovery/sd/discoverer/dockerd/docker.go b/src/go/plugin/go.d/agent/discovery/sd/discoverer/dockerd/docker.go
index 1cea014a9..e79d8b562 100644
--- a/src/go/plugin/go.d/agent/discovery/sd/discoverer/dockerd/docker.go
+++ b/src/go/plugin/go.d/agent/discovery/sd/discoverer/dockerd/docker.go
@@ -13,8 +13,8 @@ import (
"github.com/netdata/netdata/go/plugins/logger"
"github.com/netdata/netdata/go/plugins/plugin/go.d/agent/discovery/sd/model"
+ "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/confopt"
"github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/dockerhost"
- "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/web"
"github.com/docker/docker/api/types"
typesContainer "github.com/docker/docker/api/types/container"
@@ -64,9 +64,9 @@ func NewDiscoverer(cfg Config) (*Discoverer, error) {
type Config struct {
Source string
- Tags string `yaml:"tags"`
- Address string `yaml:"address"`
- Timeout web.Duration `yaml:"timeout"`
+ Tags string `yaml:"tags"`
+ Address string `yaml:"address"`
+ Timeout confopt.Duration `yaml:"timeout"`
}
type (
diff --git a/src/go/plugin/go.d/agent/discovery/sd/discoverer/kubernetes/kubernetes.go b/src/go/plugin/go.d/agent/discovery/sd/discoverer/kubernetes/kubernetes.go
index 439e2b695..26f8a1bd2 100644
--- a/src/go/plugin/go.d/agent/discovery/sd/discoverer/kubernetes/kubernetes.go
+++ b/src/go/plugin/go.d/agent/discovery/sd/discoverer/kubernetes/kubernetes.go
@@ -234,7 +234,7 @@ func (d *KubeDiscoverer) setupServiceDiscoverer(ctx context.Context, namespace s
return td
}
-func enqueue(queue *workqueue.Type, obj any) {
+func enqueue(queue *workqueue.Typed[any], obj any) {
key, err := cache.DeletionHandlingMetaNamespaceKeyFunc(obj)
if err != nil {
return
diff --git a/src/go/plugin/go.d/agent/discovery/sd/discoverer/kubernetes/kubernetes_test.go b/src/go/plugin/go.d/agent/discovery/sd/discoverer/kubernetes/kubernetes_test.go
index ba60a47b4..908a2a192 100644
--- a/src/go/plugin/go.d/agent/discovery/sd/discoverer/kubernetes/kubernetes_test.go
+++ b/src/go/plugin/go.d/agent/discovery/sd/discoverer/kubernetes/kubernetes_test.go
@@ -134,7 +134,7 @@ func TestKubeDiscoverer_Discover(t *testing.T) {
}
func prepareDiscoverer(role role, namespaces []string, objects ...runtime.Object) (*KubeDiscoverer, kubernetes.Interface) {
- client := fake.NewSimpleClientset(objects...)
+ client := fake.NewClientset(objects...)
tags, _ := model.ParseTags("k8s")
disc := &KubeDiscoverer{
tags: tags,
diff --git a/src/go/plugin/go.d/agent/discovery/sd/discoverer/kubernetes/pod.go b/src/go/plugin/go.d/agent/discovery/sd/discoverer/kubernetes/pod.go
index 617081742..f5918ca35 100644
--- a/src/go/plugin/go.d/agent/discovery/sd/discoverer/kubernetes/pod.go
+++ b/src/go/plugin/go.d/agent/discovery/sd/discoverer/kubernetes/pod.go
@@ -58,7 +58,7 @@ func newPodDiscoverer(pod, cmap, secret cache.SharedInformer) *podDiscoverer {
panic("nil pod or cmap or secret informer")
}
- queue := workqueue.NewWithConfig(workqueue.QueueConfig{Name: "pod"})
+ queue := workqueue.NewTypedWithConfig(workqueue.TypedQueueConfig[any]{Name: "pod"})
_, _ = pod.AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: func(obj any) { enqueue(queue, obj) },
@@ -82,7 +82,7 @@ type podDiscoverer struct {
podInformer cache.SharedInformer
cmapInformer cache.SharedInformer
secretInformer cache.SharedInformer
- queue *workqueue.Type
+ queue *workqueue.Typed[any]
}
func (p *podDiscoverer) String() string {
diff --git a/src/go/plugin/go.d/agent/discovery/sd/discoverer/kubernetes/service.go b/src/go/plugin/go.d/agent/discovery/sd/discoverer/kubernetes/service.go
index 1d5ae7cd5..ebcfe31cc 100644
--- a/src/go/plugin/go.d/agent/discovery/sd/discoverer/kubernetes/service.go
+++ b/src/go/plugin/go.d/agent/discovery/sd/discoverer/kubernetes/service.go
@@ -53,7 +53,7 @@ type serviceDiscoverer struct {
model.Base
informer cache.SharedInformer
- queue *workqueue.Type
+ queue *workqueue.Typed[any]
}
func newServiceDiscoverer(inf cache.SharedInformer) *serviceDiscoverer {
@@ -61,7 +61,8 @@ func newServiceDiscoverer(inf cache.SharedInformer) *serviceDiscoverer {
panic("nil service informer")
}
- queue := workqueue.NewWithConfig(workqueue.QueueConfig{Name: "service"})
+ queue := workqueue.NewTypedWithConfig(workqueue.TypedQueueConfig[any]{Name: "service"})
+
_, _ = inf.AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: func(obj any) { enqueue(queue, obj) },
UpdateFunc: func(_, obj any) { enqueue(queue, obj) },
diff --git a/src/go/plugin/go.d/agent/discovery/sd/discoverer/netlisteners/ll.go b/src/go/plugin/go.d/agent/discovery/sd/discoverer/netlisteners/ll.go
new file mode 100644
index 000000000..fdb70f5a3
--- /dev/null
+++ b/src/go/plugin/go.d/agent/discovery/sd/discoverer/netlisteners/ll.go
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package netlisteners
+
+import (
+ "context"
+ "fmt"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "time"
+
+ "github.com/netdata/netdata/go/plugins/pkg/executable"
+)
+
+type localListeners interface {
+ discover(ctx context.Context) ([]byte, error)
+}
+
+func newLocalListeners(timeout time.Duration) localListeners {
+ dir := os.Getenv("NETDATA_PLUGINS_DIR")
+ if dir == "" {
+ dir = executable.Directory
+ }
+ if dir == "" {
+ dir, _ = os.Getwd()
+ }
+
+ return &localListenersExec{
+ binPath: filepath.Join(dir, "local-listeners"),
+ timeout: timeout,
+ }
+}
+
+type localListenersExec struct {
+ binPath string
+ timeout time.Duration
+}
+
+func (e *localListenersExec) discover(ctx context.Context) ([]byte, error) {
+ execCtx, cancel := context.WithTimeout(ctx, e.timeout)
+ defer cancel()
+
+ // TCPv4/6 and UPDv4 sockets in LISTEN state
+ // https://github.com/netdata/netdata/blob/master/src/collectors/utils/local_listeners.c
+ args := []string{
+ "no-udp6",
+ "no-local",
+ "no-inbound",
+ "no-outbound",
+ "no-namespaces",
+ }
+
+ cmd := exec.CommandContext(execCtx, e.binPath, args...)
+
+ bs, err := cmd.Output()
+ if err != nil {
+ return nil, fmt.Errorf("error on executing '%s': %v", cmd, err)
+ }
+
+ return bs, nil
+}
diff --git a/src/go/plugin/go.d/agent/discovery/sd/discoverer/netlisteners/netlisteners.go b/src/go/plugin/go.d/agent/discovery/sd/discoverer/netlisteners/netlisteners.go
index 60dd92cb4..b38d0506f 100644
--- a/src/go/plugin/go.d/agent/discovery/sd/discoverer/netlisteners/netlisteners.go
+++ b/src/go/plugin/go.d/agent/discovery/sd/discoverer/netlisteners/netlisteners.go
@@ -10,8 +10,6 @@ import (
"fmt"
"log/slog"
"net"
- "os"
- "os/exec"
"path/filepath"
"sort"
"strconv"
@@ -19,8 +17,8 @@ import (
"time"
"github.com/netdata/netdata/go/plugins/logger"
- "github.com/netdata/netdata/go/plugins/pkg/executable"
"github.com/netdata/netdata/go/plugins/plugin/go.d/agent/discovery/sd/model"
+ "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/confopt"
"github.com/ilyam8/hashstructure"
)
@@ -30,18 +28,27 @@ var (
fullName = fmt.Sprintf("sd:%s", shortName)
)
+type Config struct {
+ Source string `yaml:"-"`
+ Tags string `yaml:"tags"`
+
+ Interval *confopt.Duration `yaml:"interval"`
+ Timeout confopt.Duration `yaml:"timeout"`
+}
+
func NewDiscoverer(cfg Config) (*Discoverer, error) {
tags, err := model.ParseTags(cfg.Tags)
if err != nil {
return nil, fmt.Errorf("parse tags: %v", err)
}
- dir := os.Getenv("NETDATA_PLUGINS_DIR")
- if dir == "" {
- dir = executable.Directory
+ interval := time.Minute * 2
+ if cfg.Interval != nil {
+ interval = cfg.Interval.Duration()
}
- if dir == "" {
- dir, _ = os.Getwd()
+ timeout := time.Second * 5
+ if cfg.Timeout.Duration() != 0 {
+ timeout = cfg.Timeout.Duration()
}
d := &Discoverer{
@@ -49,12 +56,10 @@ func NewDiscoverer(cfg Config) (*Discoverer, error) {
slog.String("component", "service discovery"),
slog.String("discoverer", shortName),
),
- cfgSource: cfg.Source,
- ll: &localListenersExec{
- binPath: filepath.Join(dir, "local-listeners"),
- timeout: time.Second * 5,
- },
- interval: time.Minute * 2,
+ cfgSource: cfg.Source,
+ ll: newLocalListeners(timeout),
+ interval: interval,
+ timeout: timeout,
expiryTime: time.Minute * 10,
cache: make(map[uint64]*cacheItem),
started: make(chan struct{}),
@@ -65,11 +70,6 @@ func NewDiscoverer(cfg Config) (*Discoverer, error) {
return d, nil
}
-type Config struct {
- Source string `yaml:"-"`
- Tags string `yaml:"tags"`
-}
-
type (
Discoverer struct {
*logger.Logger
@@ -78,6 +78,7 @@ type (
cfgSource string
interval time.Duration
+ timeout time.Duration
ll localListeners
expiryTime time.Duration
@@ -92,9 +93,6 @@ type (
lastSeenTime time.Time
tgt model.Target
}
- localListeners interface {
- discover(ctx context.Context) ([]byte, error)
- }
)
func (d *Discoverer) String() string {
@@ -103,6 +101,7 @@ func (d *Discoverer) String() string {
func (d *Discoverer) Discover(ctx context.Context, in chan<- []model.TargetGroup) {
d.Info("instance is started")
+ d.Debugf("used config: interval: %s, timeout: %s, cache expiration time: %s", d.interval, d.timeout, d.expiryTime)
defer func() { d.Info("instance is stopped") }()
close(d.started)
@@ -112,6 +111,10 @@ func (d *Discoverer) Discover(ctx context.Context, in chan<- []model.TargetGroup
return
}
+ if d.interval == 0 {
+ return
+ }
+
tk := time.NewTicker(d.interval)
defer tk.Stop()
@@ -295,35 +298,6 @@ func (d *Discoverer) parseLocalListeners(bs []byte) ([]model.Target, error) {
return tgts[:n], nil
}
-type localListenersExec struct {
- binPath string
- timeout time.Duration
-}
-
-func (e *localListenersExec) discover(ctx context.Context) ([]byte, error) {
- execCtx, cancel := context.WithTimeout(ctx, e.timeout)
- defer cancel()
-
- // TCPv4/6 and UPDv4 sockets in LISTEN state
- // https://github.com/netdata/netdata/blob/master/src/collectors/plugins.d/local_listeners.c
- args := []string{
- "no-udp6",
- "no-local",
- "no-inbound",
- "no-outbound",
- "no-namespaces",
- }
-
- cmd := exec.CommandContext(execCtx, e.binPath, args...)
-
- bs, err := cmd.Output()
- if err != nil {
- return nil, fmt.Errorf("error on executing '%s': %v", cmd, err)
- }
-
- return bs, nil
-}
-
func extractComm(cmdLine string) string {
if i := strings.IndexByte(cmdLine, ' '); i != -1 {
cmdLine = cmdLine[:i]
diff --git a/src/go/plugin/go.d/agent/discovery/sd/pipeline/funcmap.go b/src/go/plugin/go.d/agent/discovery/sd/pipeline/funcmap.go
index 5ed188a54..378e03c25 100644
--- a/src/go/plugin/go.d/agent/discovery/sd/pipeline/funcmap.go
+++ b/src/go/plugin/go.d/agent/discovery/sd/pipeline/funcmap.go
@@ -7,14 +7,16 @@ import (
"strconv"
"text/template"
- "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/matcher"
+ "github.com/netdata/netdata/go/plugins/pkg/matcher"
"github.com/Masterminds/sprig/v3"
"github.com/bmatcuk/doublestar/v4"
)
func newFuncMap() template.FuncMap {
- custom := map[string]interface{}{
+ fm := sprig.TxtFuncMap()
+
+ extra := map[string]any{
"match": funcMatchAny,
"glob": func(value, pattern string, patterns ...string) bool {
return funcMatchAny("glob", value, pattern, patterns...)
@@ -25,9 +27,7 @@ func newFuncMap() template.FuncMap {
},
}
- fm := sprig.HermeticTxtFuncMap()
-
- for name, fn := range custom {
+ for name, fn := range extra {
fm[name] = fn
}
diff --git a/src/go/plugin/go.d/agent/discovery/sd/pipeline/pipeline_test.go b/src/go/plugin/go.d/agent/discovery/sd/pipeline/pipeline_test.go
index e67b6d7ce..4f2e11199 100644
--- a/src/go/plugin/go.d/agent/discovery/sd/pipeline/pipeline_test.go
+++ b/src/go/plugin/go.d/agent/discovery/sd/pipeline/pipeline_test.go
@@ -35,13 +35,13 @@ func Test_defaultConfigs(t *testing.T) {
require.NoError(t, err, "abs path")
bs, err := os.ReadFile(file)
- require.NoError(t, err, "read config file")
+ require.NoErrorf(t, err, "read config file '%s'", file)
var cfg Config
- require.NoError(t, yaml.Unmarshal(bs, &cfg), "unmarshal")
+ require.NoErrorf(t, yaml.Unmarshal(bs, &cfg), "unmarshal '%s'", e.Name())
_, err = New(cfg)
- require.NoError(t, err, "create pipeline")
+ require.NoErrorf(t, err, "create pipeline '%s'", e.Name())
}
}
diff --git a/src/go/plugin/go.d/agent/discovery/sd/pipeline/promport.go b/src/go/plugin/go.d/agent/discovery/sd/pipeline/promport.go
index 646e1abb1..7edf227c7 100644
--- a/src/go/plugin/go.d/agent/discovery/sd/pipeline/promport.go
+++ b/src/go/plugin/go.d/agent/discovery/sd/pipeline/promport.go
@@ -46,7 +46,6 @@ var prometheusPortAllocations = map[int]string{
9125: "statsd_exporter",
9126: "new_relic_exporter",
9127: "pgbouncer_exporter",
- 9128: "ceph_exporter",
9129: "haproxy_log_exporter",
9130: "unifi_poller",
9131: "varnish_exporter",
@@ -193,7 +192,6 @@ var prometheusPortAllocations = map[int]string{
9280: "citrix_netscaler_exporter",
9281: "fastd_exporter",
9282: "freeswitch_exporter",
- 9283: "ceph_ceph-mgr_prometheus_plugin",
9284: "gobetween",
9285: "database_exporter",
9286: "vdo_compression_and_deduplication_exporter",
diff --git a/src/go/plugin/go.d/agent/discovery/sd/sd.go b/src/go/plugin/go.d/agent/discovery/sd/sd.go
index 687ebfba8..90207219d 100644
--- a/src/go/plugin/go.d/agent/discovery/sd/sd.go
+++ b/src/go/plugin/go.d/agent/discovery/sd/sd.go
@@ -9,9 +9,9 @@ import (
"sync"
"github.com/netdata/netdata/go/plugins/logger"
+ "github.com/netdata/netdata/go/plugins/pkg/multipath"
"github.com/netdata/netdata/go/plugins/plugin/go.d/agent/confgroup"
"github.com/netdata/netdata/go/plugins/plugin/go.d/agent/discovery/sd/pipeline"
- "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/multipath"
"gopkg.in/yaml.v2"
)
diff --git a/src/go/plugin/go.d/agent/discovery/sim_test.go b/src/go/plugin/go.d/agent/discovery/sim_test.go
index b20344c3c..134ec29f9 100644
--- a/src/go/plugin/go.d/agent/discovery/sim_test.go
+++ b/src/go/plugin/go.d/agent/discovery/sim_test.go
@@ -9,6 +9,7 @@ import (
"time"
"github.com/netdata/netdata/go/plugins/plugin/go.d/agent/confgroup"
+
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
diff --git a/src/go/plugin/go.d/agent/functions/manager.go b/src/go/plugin/go.d/agent/functions/manager.go
index b7cdecd6a..fe4228a75 100644
--- a/src/go/plugin/go.d/agent/functions/manager.go
+++ b/src/go/plugin/go.d/agent/functions/manager.go
@@ -13,8 +13,8 @@ import (
"time"
"github.com/netdata/netdata/go/plugins/logger"
- "github.com/netdata/netdata/go/plugins/plugin/go.d/agent/netdataapi"
- "github.com/netdata/netdata/go/plugins/plugin/go.d/agent/safewriter"
+ "github.com/netdata/netdata/go/plugins/pkg/netdataapi"
+ "github.com/netdata/netdata/go/plugins/pkg/safewriter"
)
func NewManager() *Manager {
diff --git a/src/go/plugin/go.d/agent/jobmgr/manager.go b/src/go/plugin/go.d/agent/jobmgr/manager.go
index 59947be77..b2ba7a2c7 100644
--- a/src/go/plugin/go.d/agent/jobmgr/manager.go
+++ b/src/go/plugin/go.d/agent/jobmgr/manager.go
@@ -12,12 +12,12 @@ import (
"time"
"github.com/netdata/netdata/go/plugins/logger"
+ "github.com/netdata/netdata/go/plugins/pkg/netdataapi"
+ "github.com/netdata/netdata/go/plugins/pkg/safewriter"
+ "github.com/netdata/netdata/go/plugins/pkg/ticker"
"github.com/netdata/netdata/go/plugins/plugin/go.d/agent/confgroup"
"github.com/netdata/netdata/go/plugins/plugin/go.d/agent/functions"
"github.com/netdata/netdata/go/plugins/plugin/go.d/agent/module"
- "github.com/netdata/netdata/go/plugins/plugin/go.d/agent/netdataapi"
- "github.com/netdata/netdata/go/plugins/plugin/go.d/agent/safewriter"
- "github.com/netdata/netdata/go/plugins/plugin/go.d/agent/ticker"
"github.com/mattn/go-isatty"
"gopkg.in/yaml.v2"
diff --git a/src/go/plugin/go.d/agent/jobmgr/sim_test.go b/src/go/plugin/go.d/agent/jobmgr/sim_test.go
index 9fe67175a..63369c33f 100644
--- a/src/go/plugin/go.d/agent/jobmgr/sim_test.go
+++ b/src/go/plugin/go.d/agent/jobmgr/sim_test.go
@@ -10,10 +10,11 @@ import (
"testing"
"time"
+ "github.com/netdata/netdata/go/plugins/pkg/netdataapi"
+ "github.com/netdata/netdata/go/plugins/pkg/safewriter"
"github.com/netdata/netdata/go/plugins/plugin/go.d/agent/confgroup"
"github.com/netdata/netdata/go/plugins/plugin/go.d/agent/module"
- "github.com/netdata/netdata/go/plugins/plugin/go.d/agent/netdataapi"
- "github.com/netdata/netdata/go/plugins/plugin/go.d/agent/safewriter"
+
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
diff --git a/src/go/plugin/go.d/agent/module/charts.go b/src/go/plugin/go.d/agent/module/charts.go
index b60b3bac1..70b024702 100644
--- a/src/go/plugin/go.d/agent/module/charts.go
+++ b/src/go/plugin/go.d/agent/module/charts.go
@@ -78,7 +78,7 @@ type (
}
// Chart represents a chart.
- // For the full description please visit https://docs.netdata.cloud/collectors/plugins.d/#chart
+ // For the full description please visit https://docs.netdata.cloud/plugins.d/#chart
Chart struct {
// typeID is the unique identification of the chart, if not specified,
// the orchestrator will use job full name + chart ID as typeID (default behaviour).
@@ -128,7 +128,7 @@ type (
}
// Dim represents a chart dimension.
- // For detailed description please visit https://docs.netdata.cloud/collectors/plugins.d/#dimension.
+ // For detailed description please visit https://docs.netdata.cloud/plugins.d/#dimension.
Dim struct {
ID string
Name string
@@ -141,7 +141,7 @@ type (
}
// Var represents a chart variable.
- // For detailed description please visit https://docs.netdata.cloud/collectors/plugins.d/#variable
+ // For detailed description please visit https://docs.netdata.cloud/plugins.d/#variable
Var struct {
ID string
Name string
@@ -465,27 +465,19 @@ func checkID(id string) int {
}
func TestMetricsHasAllChartsDims(t *testing.T, charts *Charts, mx map[string]int64) {
- for _, chart := range *charts {
- if chart.Obsolete {
- continue
- }
- for _, dim := range chart.Dims {
- _, ok := mx[dim.ID]
- assert.Truef(t, ok, "missing data for dimension '%s' in chart '%s'", dim.ID, chart.ID)
- }
- for _, v := range chart.Vars {
- _, ok := mx[v.ID]
- assert.Truef(t, ok, "missing data for variable '%s' in chart '%s'", v.ID, chart.ID)
- }
- }
+ TestMetricsHasAllChartsDimsSkip(t, charts, mx, nil)
}
-func TestMetricsHasAllChartsDimsSkip(t *testing.T, charts *Charts, mx map[string]int64, skip func(chart *Chart) bool) {
+func TestMetricsHasAllChartsDimsSkip(t *testing.T, charts *Charts, mx map[string]int64, skip func(chart *Chart, dim *Dim) bool) {
for _, chart := range *charts {
- if chart.Obsolete || (skip != nil && skip(chart)) {
+ if chart.Obsolete {
continue
}
for _, dim := range chart.Dims {
+ if skip != nil && skip(chart, dim) {
+ continue
+ }
+
_, ok := mx[dim.ID]
assert.Truef(t, ok, "missing data for dimension '%s' in chart '%s'", dim.ID, chart.ID)
}
diff --git a/src/go/plugin/go.d/agent/module/job.go b/src/go/plugin/go.d/agent/module/job.go
index 67fae8aa2..3db06ef00 100644
--- a/src/go/plugin/go.d/agent/module/job.go
+++ b/src/go/plugin/go.d/agent/module/job.go
@@ -16,8 +16,7 @@ import (
"time"
"github.com/netdata/netdata/go/plugins/logger"
- "github.com/netdata/netdata/go/plugins/plugin/go.d/agent/netdataapi"
- "github.com/netdata/netdata/go/plugins/plugin/go.d/agent/vnodes"
+ "github.com/netdata/netdata/go/plugins/pkg/netdataapi"
)
var obsoleteLock = &sync.Mutex{}
@@ -228,14 +227,14 @@ func (j *Job) AutoDetection() (err error) {
}
if err = j.init(); err != nil {
- j.Error("init failed")
+ j.Errorf("init failed: %v", err)
j.Unmute()
j.disableAutoDetection()
return err
}
if err = j.check(); err != nil {
- j.Error("check failed")
+ j.Errorf("check failed: %v", err)
j.Unmute()
return err
}
@@ -244,7 +243,7 @@ func (j *Job) AutoDetection() (err error) {
j.Info("check success")
if err = j.postCheck(); err != nil {
- j.Error("postCheck failed")
+ j.Errorf("postCheck failed: %v", err)
j.disableAutoDetection()
return err
}
@@ -299,13 +298,11 @@ func (j *Job) Cleanup() {
return
}
- if !vnodes.Disabled {
- if !j.vnodeCreated && j.vnodeGUID != "" {
- _ = j.api.HOSTINFO(j.vnodeGUID, j.vnodeHostname, j.vnodeLabels)
- j.vnodeCreated = true
- }
- _ = j.api.HOST(j.vnodeGUID)
+ if !j.vnodeCreated && j.vnodeGUID != "" {
+ _ = j.api.HOSTINFO(j.vnodeGUID, j.vnodeHostname, j.vnodeLabels)
+ j.vnodeCreated = true
}
+ _ = j.api.HOST(j.vnodeGUID)
if j.runChart.created {
j.runChart.MarkRemove()
@@ -397,15 +394,22 @@ func (j *Job) collect() (result map[string]int64) {
}
func (j *Job) processMetrics(metrics map[string]int64, startTime time.Time, sinceLastRun int) bool {
- if !vnodes.Disabled {
- if !j.vnodeCreated && j.vnodeGUID != "" {
+ if !j.vnodeCreated {
+ if j.vnodeGUID == "" {
+ if v := j.module.VirtualNode(); v != nil && v.GUID != "" && v.Hostname != "" {
+ j.vnodeGUID = v.GUID
+ j.vnodeHostname = v.Hostname
+ j.vnodeLabels = v.Labels
+ }
+ }
+ if j.vnodeGUID != "" {
_ = j.api.HOSTINFO(j.vnodeGUID, j.vnodeHostname, j.vnodeLabels)
j.vnodeCreated = true
}
-
- _ = j.api.HOST(j.vnodeGUID)
}
+ _ = j.api.HOST(j.vnodeGUID)
+
if !ndInternalMonitoringDisabled && !j.runChart.created {
j.runChart.ID = fmt.Sprintf("execution_time_of_%s", j.FullName())
j.createChart(j.runChart)
@@ -489,15 +493,15 @@ func (j *Job) createChart(chart *Chart) {
if ls == 0 {
ls = LabelSourceAuto
}
- _ = j.api.CLABEL(l.Key, l.Value, ls)
+ _ = j.api.CLABEL(l.Key, lblReplacer.Replace(l.Value), ls)
}
}
for k, v := range j.labels {
if !seen[k] {
- _ = j.api.CLABEL(k, v, LabelSourceConf)
+ _ = j.api.CLABEL(k, lblReplacer.Replace(v), LabelSourceConf)
}
}
- _ = j.api.CLABEL("_collect_job", j.Name(), LabelSourceAuto)
+ _ = j.api.CLABEL("_collect_job", lblReplacer.Replace(j.Name()), LabelSourceAuto)
_ = j.api.CLABELCOMMIT()
for _, dim := range chart.Dims {
@@ -643,3 +647,5 @@ func handleZero(v int) int {
}
return v
}
+
+var lblReplacer = strings.NewReplacer("'", "")
diff --git a/src/go/plugin/go.d/agent/module/module.go b/src/go/plugin/go.d/agent/module/module.go
index 13e20f2ae..8d28d8059 100644
--- a/src/go/plugin/go.d/agent/module/module.go
+++ b/src/go/plugin/go.d/agent/module/module.go
@@ -7,6 +7,7 @@ import (
"testing"
"github.com/netdata/netdata/go/plugins/logger"
+ "github.com/netdata/netdata/go/plugins/plugin/go.d/agent/vnodes"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -35,6 +36,8 @@ type Module interface {
GetBase() *Base
Configuration() any
+
+ VirtualNode() *vnodes.VirtualNode
}
// Base is a helper struct. All modules should embed this struct.
@@ -44,12 +47,14 @@ type Base struct {
func (b *Base) GetBase() *Base { return b }
+func (b *Base) VirtualNode() *vnodes.VirtualNode { return nil }
+
func TestConfigurationSerialize(t *testing.T, mod Module, cfgJSON, cfgYAML []byte) {
t.Helper()
tests := map[string]struct {
config []byte
- unmarshal func(in []byte, out interface{}) (err error)
- marshal func(in interface{}) (out []byte, err error)
+ unmarshal func(in []byte, out any) (err error)
+ marshal func(in any) (out []byte, err error)
}{
"json": {config: cfgJSON, marshal: json.Marshal, unmarshal: json.Unmarshal},
"yaml": {config: cfgYAML, marshal: yaml.Marshal, unmarshal: yaml.Unmarshal},
diff --git a/src/go/plugin/go.d/agent/netdataapi/api.go b/src/go/plugin/go.d/agent/netdataapi/api.go
deleted file mode 100644
index 4f2b7a9b5..000000000
--- a/src/go/plugin/go.d/agent/netdataapi/api.go
+++ /dev/null
@@ -1,213 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-package netdataapi
-
-import (
- "bytes"
- "fmt"
- "io"
- "strconv"
-)
-
-type (
- // API implements Netdata external plugins API.
- // https://learn.netdata.cloud/docs/agent/collectors/plugins.d#the-output-of-the-plugin
- API struct {
- io.Writer
- }
-)
-
-const quotes = "' '"
-
-var (
- end = []byte("END\n\n")
- clabelCommit = []byte("CLABEL_COMMIT\n")
- newLine = []byte("\n")
-)
-
-func New(w io.Writer) *API { return &API{w} }
-
-// CHART creates or update a chart.
-func (a *API) CHART(
- typeID string,
- ID string,
- name string,
- title string,
- units string,
- family string,
- context string,
- chartType string,
- priority int,
- updateEvery int,
- options string,
- plugin string,
- module string) error {
- _, err := a.Write([]byte("CHART " + "'" +
- typeID + "." + ID + quotes +
- name + quotes +
- title + quotes +
- units + quotes +
- family + quotes +
- context + quotes +
- chartType + quotes +
- strconv.Itoa(priority) + quotes +
- strconv.Itoa(updateEvery) + quotes +
- options + quotes +
- plugin + quotes +
- module + "'\n"))
- return err
-}
-
-// DIMENSION adds or update a dimension to the chart just created.
-func (a *API) DIMENSION(
- ID string,
- name string,
- algorithm string,
- multiplier int,
- divisor int,
- options string) error {
- _, err := a.Write([]byte("DIMENSION '" +
- ID + quotes +
- name + quotes +
- algorithm + quotes +
- strconv.Itoa(multiplier) + quotes +
- strconv.Itoa(divisor) + quotes +
- options + "'\n"))
- return err
-}
-
-// CLABEL adds or update a label to the chart.
-func (a *API) CLABEL(key, value string, source int) error {
- _, err := a.Write([]byte("CLABEL '" +
- key + quotes +
- value + quotes +
- strconv.Itoa(source) + "'\n"))
- return err
-}
-
-// CLABELCOMMIT adds labels to the chart. Should be called after one or more CLABEL.
-func (a *API) CLABELCOMMIT() error {
- _, err := a.Write(clabelCommit)
- return err
-}
-
-// BEGIN initializes data collection for a chart.
-func (a *API) BEGIN(typeID string, ID string, msSince int) (err error) {
- if msSince > 0 {
- _, err = a.Write([]byte("BEGIN " + "'" + typeID + "." + ID + "' " + strconv.Itoa(msSince) + "\n"))
- } else {
- _, err = a.Write([]byte("BEGIN " + "'" + typeID + "." + ID + "'\n"))
- }
- return err
-}
-
-// SET sets the value of a dimension for the initialized chart.
-func (a *API) SET(ID string, value int64) error {
- _, err := a.Write([]byte("SET '" + ID + "' = " + strconv.FormatInt(value, 10) + "\n"))
- return err
-}
-
-// SETEMPTY sets the empty value of a dimension for the initialized chart.
-func (a *API) SETEMPTY(ID string) error {
- _, err := a.Write([]byte("SET '" + ID + "' = \n"))
- return err
-}
-
-// VARIABLE sets the value of a CHART scope variable for the initialized chart.
-func (a *API) VARIABLE(ID string, value int64) error {
- _, err := a.Write([]byte("VARIABLE CHART '" + ID + "' = " + strconv.FormatInt(value, 10) + "\n"))
- return err
-}
-
-// END completes data collection for the initialized chart.
-func (a *API) END() error {
- _, err := a.Write(end)
- return err
-}
-
-// DISABLE disables this plugin. This will prevent Netdata from restarting the plugin.
-func (a *API) DISABLE() error {
- _, err := a.Write([]byte("DISABLE\n"))
- return err
-}
-
-// EMPTYLINE writes an empty line.
-func (a *API) EMPTYLINE() error {
- _, err := a.Write(newLine)
- return err
-}
-
-func (a *API) HOSTINFO(guid, hostname string, labels map[string]string) error {
- if err := a.HOSTDEFINE(guid, hostname); err != nil {
- return err
- }
- for k, v := range labels {
- if err := a.HOSTLABEL(k, v); err != nil {
- return err
- }
- }
- return a.HOSTDEFINEEND()
-}
-
-func (a *API) HOSTDEFINE(guid, hostname string) error {
- _, err := fmt.Fprintf(a, "HOST_DEFINE '%s' '%s'\n", guid, hostname)
- return err
-}
-
-func (a *API) HOSTLABEL(name, value string) error {
- _, err := fmt.Fprintf(a, "HOST_LABEL '%s' '%s'\n", name, value)
- return err
-}
-
-func (a *API) HOSTDEFINEEND() error {
- _, err := fmt.Fprintf(a, "HOST_DEFINE_END\n\n")
- return err
-}
-
-func (a *API) HOST(guid string) error {
- _, err := a.Write([]byte("HOST " + "'" +
- guid + "'\n\n"))
- return err
-}
-
-func (a *API) FUNCRESULT(uid, contentType, payload, code, expireTimestamp string) {
- var buf bytes.Buffer
-
- buf.WriteString("FUNCTION_RESULT_BEGIN " +
- uid + " " +
- code + " " +
- contentType + " " +
- expireTimestamp + "\n",
- )
-
- if payload != "" {
- buf.WriteString(payload + "\n")
- }
-
- buf.WriteString("FUNCTION_RESULT_END\n\n")
-
- _, _ = buf.WriteTo(a)
-}
-
-func (a *API) CONFIGCREATE(id, status, configType, path, sourceType, source, supportedCommands string) {
- // https://learn.netdata.cloud/docs/contributing/external-plugins/#config
-
- _, _ = a.Write([]byte("CONFIG " +
- id + " " +
- "create" + " " +
- status + " " +
- configType + " " +
- path + " " +
- sourceType + " '" +
- source + "' '" +
- supportedCommands + "' 0x0000 0x0000\n\n",
- ))
-}
-
-func (a *API) CONFIGDELETE(id string) {
- _, _ = a.Write([]byte("CONFIG " + id + " delete\n\n"))
-}
-
-func (a *API) CONFIGSTATUS(id, status string) {
- _, _ = a.Write([]byte("CONFIG " + id + " status " + status + "\n\n"))
-}
diff --git a/src/go/plugin/go.d/agent/netdataapi/api_test.go b/src/go/plugin/go.d/agent/netdataapi/api_test.go
deleted file mode 100644
index e5087839b..000000000
--- a/src/go/plugin/go.d/agent/netdataapi/api_test.go
+++ /dev/null
@@ -1,265 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-package netdataapi
-
-import (
- "bytes"
- "testing"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestAPI_CHART(t *testing.T) {
- buf := &bytes.Buffer{}
- a := API{Writer: buf}
-
- _ = a.CHART(
- "",
- "id",
- "name",
- "title",
- "units",
- "family",
- "context",
- "line",
- 1,
- 1,
- "",
- "plugin",
- "module",
- )
-
- assert.Equal(
- t,
- "CHART '.id' 'name' 'title' 'units' 'family' 'context' 'line' '1' '1' '' 'plugin' 'module'\n",
- buf.String(),
- )
-}
-
-func TestAPI_DIMENSION(t *testing.T) {
- buf := &bytes.Buffer{}
- a := API{Writer: buf}
-
- _ = a.DIMENSION(
- "id",
- "name",
- "absolute",
- 1,
- 1,
- "",
- )
-
- assert.Equal(
- t,
- "DIMENSION 'id' 'name' 'absolute' '1' '1' ''\n",
- buf.String(),
- )
-}
-
-func TestAPI_BEGIN(t *testing.T) {
- buf := &bytes.Buffer{}
- a := API{Writer: buf}
-
- _ = a.BEGIN(
- "typeID",
- "id",
- 0,
- )
-
- assert.Equal(
- t,
- "BEGIN 'typeID.id'\n",
- buf.String(),
- )
-
- buf.Reset()
-
- _ = a.BEGIN(
- "typeID",
- "id",
- 1,
- )
-
- assert.Equal(
- t,
- "BEGIN 'typeID.id' 1\n",
- buf.String(),
- )
-}
-
-func TestAPI_SET(t *testing.T) {
- buf := &bytes.Buffer{}
- a := API{Writer: buf}
-
- _ = a.SET("id", 100)
-
- assert.Equal(
- t,
- "SET 'id' = 100\n",
- buf.String(),
- )
-}
-
-func TestAPI_SETEMPTY(t *testing.T) {
- buf := &bytes.Buffer{}
- a := API{Writer: buf}
-
- _ = a.SETEMPTY("id")
-
- assert.Equal(
- t,
- "SET 'id' = \n",
- buf.String(),
- )
-}
-
-func TestAPI_VARIABLE(t *testing.T) {
- buf := &bytes.Buffer{}
- a := API{Writer: buf}
-
- _ = a.VARIABLE("id", 100)
-
- assert.Equal(
- t,
- "VARIABLE CHART 'id' = 100\n",
- buf.String(),
- )
-}
-
-func TestAPI_END(t *testing.T) {
- buf := &bytes.Buffer{}
- a := API{Writer: buf}
-
- _ = a.END()
-
- assert.Equal(
- t,
- "END\n\n",
- buf.String(),
- )
-}
-
-func TestAPI_CLABEL(t *testing.T) {
- buf := &bytes.Buffer{}
- a := API{Writer: buf}
-
- _ = a.CLABEL("key", "value", 1)
-
- assert.Equal(
- t,
- "CLABEL 'key' 'value' '1'\n",
- buf.String(),
- )
-}
-
-func TestAPI_CLABELCOMMIT(t *testing.T) {
- buf := &bytes.Buffer{}
- a := API{Writer: buf}
-
- _ = a.CLABELCOMMIT()
-
- assert.Equal(
- t,
- "CLABEL_COMMIT\n",
- buf.String(),
- )
-}
-
-func TestAPI_DISABLE(t *testing.T) {
- buf := &bytes.Buffer{}
- a := API{Writer: buf}
-
- _ = a.DISABLE()
-
- assert.Equal(
- t,
- "DISABLE\n",
- buf.String(),
- )
-}
-
-func TestAPI_EMPTYLINE(t *testing.T) {
- buf := &bytes.Buffer{}
- a := API{Writer: buf}
-
- _ = a.EMPTYLINE()
-
- assert.Equal(
- t,
- "\n",
- buf.String(),
- )
-}
-
-func TestAPI_HOST(t *testing.T) {
- buf := &bytes.Buffer{}
- a := API{Writer: buf}
-
- _ = a.HOST("guid")
-
- assert.Equal(
- t,
- "HOST 'guid'\n\n",
- buf.String(),
- )
-}
-
-func TestAPI_HOSTDEFINE(t *testing.T) {
- buf := &bytes.Buffer{}
- a := API{Writer: buf}
-
- _ = a.HOSTDEFINE("guid", "hostname")
-
- assert.Equal(
- t,
- "HOST_DEFINE 'guid' 'hostname'\n",
- buf.String(),
- )
-}
-
-func TestAPI_HOSTLABEL(t *testing.T) {
- buf := &bytes.Buffer{}
- a := API{Writer: buf}
-
- _ = a.HOSTLABEL("name", "value")
-
- assert.Equal(
- t,
- "HOST_LABEL 'name' 'value'\n",
- buf.String(),
- )
-}
-
-func TestAPI_HOSTDEFINEEND(t *testing.T) {
- buf := &bytes.Buffer{}
- a := API{Writer: buf}
-
- _ = a.HOSTDEFINEEND()
-
- assert.Equal(
- t,
- "HOST_DEFINE_END\n\n",
- buf.String(),
- )
-}
-
-func TestAPI_HOSTINFO(t *testing.T) {
- buf := &bytes.Buffer{}
- a := API{Writer: buf}
-
- _ = a.HOSTINFO("guid", "hostname", map[string]string{"label1": "value1"})
-
- assert.Equal(
- t,
- `HOST_DEFINE 'guid' 'hostname'
-HOST_LABEL 'label1' 'value1'
-HOST_DEFINE_END
-
-`,
- buf.String(),
- )
-}
-
-func TestAPI_FUNCRESULT(t *testing.T) {
-
-}
diff --git a/src/go/plugin/go.d/agent/safewriter/writer.go b/src/go/plugin/go.d/agent/safewriter/writer.go
deleted file mode 100644
index 533c1055d..000000000
--- a/src/go/plugin/go.d/agent/safewriter/writer.go
+++ /dev/null
@@ -1,30 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-package safewriter
-
-import (
- "io"
- "os"
- "sync"
-)
-
-var Stdout = New(os.Stdout)
-
-func New(w io.Writer) io.Writer {
- return &writer{
- mx: &sync.Mutex{},
- w: w,
- }
-}
-
-type writer struct {
- mx *sync.Mutex
- w io.Writer
-}
-
-func (w *writer) Write(p []byte) (n int, err error) {
- w.mx.Lock()
- n, err = w.w.Write(p)
- w.mx.Unlock()
- return n, err
-}
diff --git a/src/go/plugin/go.d/agent/ticker/ticker.go b/src/go/plugin/go.d/agent/ticker/ticker.go
deleted file mode 100644
index e4228fe4c..000000000
--- a/src/go/plugin/go.d/agent/ticker/ticker.go
+++ /dev/null
@@ -1,55 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-package ticker
-
-import "time"
-
-type (
- // Ticker holds a channel that delivers ticks of a clock at intervals.
- // The ticks are aligned to interval boundaries.
- Ticker struct {
- C <-chan int
- done chan struct{}
- loops int
- interval time.Duration
- }
-)
-
-// New returns a new Ticker containing a channel that will send the time with a period specified by the duration argument.
-// It adjusts the intervals or drops ticks to make up for slow receivers.
-// The duration must be greater than zero; if not, New will panic. Stop the Ticker to release associated resources.
-func New(interval time.Duration) *Ticker {
- ticker := &Ticker{
- interval: interval,
- done: make(chan struct{}, 1),
- }
- ticker.start()
- return ticker
-}
-
-func (t *Ticker) start() {
- ch := make(chan int)
- t.C = ch
- go func() {
- LOOP:
- for {
- now := time.Now()
- nextRun := now.Truncate(t.interval).Add(t.interval)
-
- time.Sleep(nextRun.Sub(now))
- select {
- case <-t.done:
- close(ch)
- break LOOP
- case ch <- t.loops:
- t.loops++
- }
- }
- }()
-}
-
-// Stop turns off a Ticker. After Stop, no more ticks will be sent.
-// Stop does not close the channel, to prevent a read from the channel succeeding incorrectly.
-func (t *Ticker) Stop() {
- t.done <- struct{}{}
-}
diff --git a/src/go/plugin/go.d/agent/ticker/ticket_test.go b/src/go/plugin/go.d/agent/ticker/ticket_test.go
deleted file mode 100644
index 193085365..000000000
--- a/src/go/plugin/go.d/agent/ticker/ticket_test.go
+++ /dev/null
@@ -1,50 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-package ticker
-
-import (
- "testing"
- "time"
-)
-
-// TODO: often fails Circle CI (~200-240)
-var allowedDelta = 500 * time.Millisecond
-
-func TestTickerParallel(t *testing.T) {
- for i := 0; i < 100; i++ {
- i := i
- go func() {
- time.Sleep(time.Second / 100 * time.Duration(i))
- TestTicker(t)
- }()
- }
- time.Sleep(4 * time.Second)
-}
-
-func TestTicker(t *testing.T) {
- tk := New(time.Second)
- defer tk.Stop()
- prev := time.Now()
- for i := 0; i < 3; i++ {
- <-tk.C
- now := time.Now()
- diff := abs(now.Round(time.Second).Sub(now))
- if diff >= allowedDelta {
- t.Errorf("Ticker is not aligned: expect delta < %v but was: %v (%s)", allowedDelta, diff, now.Format(time.RFC3339Nano))
- }
- if i > 0 {
- dt := now.Sub(prev)
- if abs(dt-time.Second) >= allowedDelta {
- t.Errorf("Ticker interval: expect delta < %v ns but was: %v", allowedDelta, abs(dt-time.Second))
- }
- }
- prev = now
- }
-}
-
-func abs(a time.Duration) time.Duration {
- if a < 0 {
- return -a
- }
- return a
-}
diff --git a/src/go/plugin/go.d/agent/vnodes/vnodes.go b/src/go/plugin/go.d/agent/vnodes/vnodes.go
index 3d332c261..2c0027b88 100644
--- a/src/go/plugin/go.d/agent/vnodes/vnodes.go
+++ b/src/go/plugin/go.d/agent/vnodes/vnodes.go
@@ -11,11 +11,10 @@ import (
"github.com/netdata/netdata/go/plugins/logger"
+ "github.com/google/uuid"
"gopkg.in/yaml.v2"
)
-var Disabled = false // TODO: remove after Netdata v1.39.0. Fix for "from source" stable-channel installations.
-
func New(confDir string) *Vnodes {
vn := &Vnodes{
Logger: logger.New().With(
@@ -39,9 +38,9 @@ type (
vnodes map[string]*VirtualNode
}
VirtualNode struct {
- GUID string `yaml:"guid"`
- Hostname string `yaml:"hostname"`
- Labels map[string]string `yaml:"labels"`
+ GUID string `yaml:"guid" json:"guid"`
+ Hostname string `yaml:"hostname" json:"hostname"`
+ Labels map[string]string `yaml:"labels" json:"labels"`
}
)
@@ -101,7 +100,11 @@ func (vn *Vnodes) readConfDir() {
for _, v := range cfg {
if v.Hostname == "" || v.GUID == "" {
- vn.Warningf("skipping virtual node '%+v': some required fields are missing (%s)", v, path)
+ vn.Warningf("skipping virtual node '%+v': required fields are missing (%s)", v, path)
+ continue
+ }
+ if err := uuid.Validate(v.GUID); err != nil {
+ vn.Warningf("skipping virtual node '%+v': invalid GUID: %v (%s)", v, err, path)
continue
}
if _, ok := vn.vnodes[v.Hostname]; ok {
@@ -127,7 +130,7 @@ func isConfigFile(path string) bool {
}
}
-func loadConfigFile(conf interface{}, path string) error {
+func loadConfigFile(conf any, path string) error {
f, err := os.Open(path)
if err != nil {
return err