From ec9dfc1d404920af1301fa0c78729ed208b07533 Mon Sep 17 00:00:00 2001 From: mattdurham Date: Wed, 4 Oct 2023 09:37:27 -0700 Subject: [PATCH] Remove singleton and allow unix exporter to be used multiple times (#5361) * Initial checkin for the removing of singleton and modifying unix exporter to allow multiple configs to be defined. * Change documentation. * Remove unused configuration. * Cleanup code. * PR feedback. * Add check back in for labels that I removed. * Update with breaking changes. * Update with newest node_exporter changes. * Fix tests for integrations. * Update docs/sources/flow/release-notes.md Co-authored-by: Robert Fratto * Change name to default from u * Merge and update node_exporter reference * merge code changes for node_exporter --------- Co-authored-by: Robert Fratto --- CHANGELOG.md | 3 + component/prometheus/exporter/unix/unix.go | 1 - .../prometheus/exporter/windows/windows.go | 1 - component/registry.go | 23 -- .../internal/build/node_exporter.go | 4 +- .../staticconvert/testdata/integrations.river | 4 +- .../components/prometheus.exporter.unix.md | 7 +- docs/sources/flow/release-notes.md | 17 + go.mod | 22 +- go.sum | 40 +- pkg/flow/internal/controller/loader.go | 22 +- pkg/flow/internal/controller/loader_test.go | 13 - pkg/flow/internal/testcomponents/singleton.go | 59 --- pkg/integrations/node_exporter/config.go | 345 ++++++++++-------- .../node_exporter/node_exporter.go | 21 +- .../node_exporter/node_exporter_test.go | 64 ---- 16 files changed, 252 insertions(+), 394 deletions(-) delete mode 100644 pkg/flow/internal/testcomponents/singleton.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 38863a71f77f..3d79f910d90a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,9 @@ Main (unreleased) got replaced by the pair of `__meta_component_name` and `__meta_component_id` labels. (@tpaschalis) +- Flow: Allow `prometheus.exporter.unix` to be specified multiple times and used in modules. This now means all + `prometheus.exporter.unix` references will need a label `prometheus.exporter.unix "example"`. (@mattdurham) + ### Features - New Grafana Agent Flow components: diff --git a/component/prometheus/exporter/unix/unix.go b/component/prometheus/exporter/unix/unix.go index 24dd546c8eee..e33fa9a63136 100644 --- a/component/prometheus/exporter/unix/unix.go +++ b/component/prometheus/exporter/unix/unix.go @@ -11,7 +11,6 @@ func init() { Name: "prometheus.exporter.unix", Args: Arguments{}, Exports: exporter.Exports{}, - Singleton: true, NeedsServices: exporter.RequiredServices(), Build: exporter.New(createExporter, "unix"), }) diff --git a/component/prometheus/exporter/windows/windows.go b/component/prometheus/exporter/windows/windows.go index ee4b8333d61a..214302748aee 100644 --- a/component/prometheus/exporter/windows/windows.go +++ b/component/prometheus/exporter/windows/windows.go @@ -11,7 +11,6 @@ func init() { Name: "prometheus.exporter.windows", Args: Arguments{}, Exports: exporter.Exports{}, - Singleton: false, NeedsServices: exporter.RequiredServices(), Build: exporter.New(createExporter, "windows"), }) diff --git a/component/registry.go b/component/registry.go index 4425b11b096b..f544bf8287f7 100644 --- a/component/registry.go +++ b/component/registry.go @@ -118,29 +118,6 @@ type Registration struct { // any number of underscores or alphanumeric ASCII characters. Name string - // A singleton component only supports one instance of itself across the - // whole process. Normally, multiple components of the same type may be - // created. - // - // The fully-qualified name of a component is the combination of River block - // name and all of its labels. Fully-qualified names must be unique across - // the process. Components which are *NOT* singletons automatically support - // user-supplied identifiers: - // - // // Fully-qualified names: remote.s3.object-a, remote.s3.object-b - // remote.s3 "object-a" { ... } - // remote.s3 "object-b" { ... } - // - // This allows for multiple instances of the same component to be defined. - // However, components registered as a singleton do not support user-supplied - // identifiers: - // - // node_exporter { ... } - // - // This prevents the user from defining multiple instances of node_exporter - // with different fully-qualified names. - Singleton bool - // An example Arguments value that the registered component expects to // receive as input. Components should provide the zero value of their // Arguments type here. diff --git a/converter/internal/staticconvert/internal/build/node_exporter.go b/converter/internal/staticconvert/internal/build/node_exporter.go index 30ee3bdfc32e..f0b76e0a273e 100644 --- a/converter/internal/staticconvert/internal/build/node_exporter.go +++ b/converter/internal/staticconvert/internal/build/node_exporter.go @@ -12,11 +12,11 @@ func (b *IntegrationsV1ConfigBuilder) appendNodeExporter(config *node_exporter.C args := toNodeExporter(config) b.f.Body().AppendBlock(common.NewBlockWithOverride( []string{"prometheus", "exporter", "unix"}, - "", + "default", args, )) - return prometheusconvert.NewDiscoveryExports("prometheus.exporter.unix.targets") + return prometheusconvert.NewDiscoveryExports("prometheus.exporter.unix.default.targets") } func toNodeExporter(config *node_exporter.Config) *unix.Arguments { diff --git a/converter/internal/staticconvert/testdata/integrations.river b/converter/internal/staticconvert/testdata/integrations.river index 355bb309c182..5ccc6ecf6240 100644 --- a/converter/internal/staticconvert/testdata/integrations.river +++ b/converter/internal/staticconvert/testdata/integrations.river @@ -371,10 +371,10 @@ prometheus.scrape "integrations_mysqld_exporter" { } } -prometheus.exporter.unix { } +prometheus.exporter.unix "default" { } discovery.relabel "integrations_node_exporter" { - targets = prometheus.exporter.unix.targets + targets = prometheus.exporter.unix.default.targets rule { source_labels = ["__address__"] diff --git a/docs/sources/flow/reference/components/prometheus.exporter.unix.md b/docs/sources/flow/reference/components/prometheus.exporter.unix.md index 4eb5aad000f6..74bea7db7459 100644 --- a/docs/sources/flow/reference/components/prometheus.exporter.unix.md +++ b/docs/sources/flow/reference/components/prometheus.exporter.unix.md @@ -18,9 +18,6 @@ The `node_exporter` itself is comprised of various _collectors_, which can be enabled and disabled at will. For more information on collectors, refer to the [`collectors-list`](#collectors-list) section. -The `prometheus.exporter.unix` component can only appear once per -configuration file, and a block label must not be passed to it. - ## Usage ```river @@ -381,11 +378,11 @@ This example uses a [`prometheus.scrape` component][scrape] to collect metrics from `prometheus.exporter.unix`: ```river -prometheus.exporter.unix { } +prometheus.exporter.unix "demo" { } // Configure a prometheus.scrape component to collect unix metrics. prometheus.scrape "demo" { - targets = prometheus.exporter.unix.targets + targets = prometheus.exporter.unix.demo.targets forward_to = [prometheus.remote_write.demo.receiver] } diff --git a/docs/sources/flow/release-notes.md b/docs/sources/flow/release-notes.md index fb0ab1f221bb..8d4ba736dce3 100644 --- a/docs/sources/flow/release-notes.md +++ b/docs/sources/flow/release-notes.md @@ -62,6 +62,23 @@ to `true` and controlled via the `include_scope_labels` argument. `name` to `otel_scope_name` and `version` to `otel_scope_version`. This is now correct with the OTLP Instrumentation Scope specification. +### Breaking change: `prometheus.exporter.unix` now requires a label. + +Previously the exporter was a singleton and did not require a label. The exporter now can be used multiple times and +needs a label. + +Old configuration example: + +```river +prometheus.exporter.unix { /* ... */ } +``` + +New configuration example: + +```river +prometheus.exporter.unix "example" { /* ... */ } +``` + ## v0.36 ### Breaking change: The default value of `retry_on_http_429` is changed to `true` for the `queue_config` in `prometheus.remote_write` diff --git a/go.mod b/go.mod index ad2d4fed4559..990d92cfc9b7 100644 --- a/go.mod +++ b/go.mod @@ -302,7 +302,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.5 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.21.5 // indirect github.com/aws/smithy-go v1.14.2 // indirect - github.com/beevik/ntp v0.3.0 // indirect + github.com/beevik/ntp v1.3.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/blang/semver v3.5.2-0.20180723201105-3c1074078d32+incompatible // indirect github.com/blang/semver/v4 v4.0.0 // indirect @@ -344,7 +344,7 @@ require ( github.com/efficientgo/tools/core v0.0.0-20220817170617-6c25e3b627dd // indirect github.com/elastic/go-sysinfo v1.8.1 // indirect github.com/elastic/go-windows v1.0.1 // indirect - github.com/ema/qdisc v0.0.0-20230120214811-5b708f463de3 // indirect + github.com/ema/qdisc v1.0.0 // indirect github.com/emicklei/go-restful/v3 v3.10.2 // indirect github.com/emirpasic/gods v1.12.0 // indirect github.com/envoyproxy/go-control-plane v0.11.1 // indirect @@ -456,7 +456,7 @@ require ( github.com/josharian/native v1.1.0 // indirect github.com/joyent/triton-go v0.0.0-20180628001255-830d2b111e62 // indirect github.com/jpillora/backoff v1.0.0 // indirect - github.com/jsimonetti/rtnetlink v1.3.2 // indirect + github.com/jsimonetti/rtnetlink v1.3.5 // indirect github.com/karrick/godirwalk v1.17.0 // indirect github.com/kevinburke/ssh_config v1.1.0 // indirect github.com/klauspost/asmfmt v1.3.2 // indirect @@ -476,11 +476,11 @@ require ( github.com/mattn/go-runewidth v0.0.14 // indirect github.com/mattn/go-xmlrpc v0.0.3 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect - github.com/mdlayher/ethtool v0.0.0-20221212131811-ba3b4bc2e02c // indirect - github.com/mdlayher/genetlink v1.3.1 // indirect + github.com/mdlayher/ethtool v0.1.0 // indirect + github.com/mdlayher/genetlink v1.3.2 // indirect github.com/mdlayher/netlink v1.7.2 // indirect github.com/mdlayher/socket v0.4.1 // indirect - github.com/mdlayher/wifi v0.0.0-20220330172155-a44c70b6d3c8 // indirect + github.com/mdlayher/wifi v0.1.0 // indirect github.com/microsoft/go-mssqldb v0.19.0 // indirect github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8 // indirect github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3 // indirect @@ -621,10 +621,9 @@ require ( sigs.k8s.io/structured-merge-diff/v4 v4.3.0 // indirect ) -require ( - github.com/githubexporter/github-exporter v0.0.0-20230925090839-9e31cd0e7721 - github.com/ianlancetaylor/demangle v0.0.0-20230524184225-eabc099b10ab -) +require github.com/ianlancetaylor/demangle v0.0.0-20230524184225-eabc099b10ab + +require github.com/githubexporter/github-exporter v0.0.0-20230925090839-9e31cd0e7721 require ( dario.cat/mergo v1.0.0 // indirect @@ -711,6 +710,9 @@ replace ( // TODO(mattdurham): this is to allow defaults to propogate properly. github.com/prometheus-community/windows_exporter => github.com/grafana/windows_exporter v0.15.1-0.20230612134738-fdb3ba7accd8 github.com/prometheus/mysqld_exporter => github.com/grafana/mysqld_exporter v0.12.2-0.20201015182516-5ac885b2d38a + + // Replace node_export with custom fork for multi usage. https://github.com/prometheus/node_exporter/pull/2812 + github.com/prometheus/node_exporter => github.com/grafana/node_exporter v0.18.1-grafana-r01.0.20231004161416-702318429731 ) // Excluding fixes a conflict in test packages and allows "go mod tidy" to run. diff --git a/go.sum b/go.sum index 7789548ff0f0..1b8d4e50fac5 100644 --- a/go.sum +++ b/go.sum @@ -402,8 +402,8 @@ github.com/aws/smithy-go v1.14.2 h1:MJU9hqBGbvWZdApzpvoF2WAIJDbtjK2NDJSiJP7HblQ= github.com/aws/smithy-go v1.14.2/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= github.com/aybabtme/iocontrol v0.0.0-20150809002002-ad15bcfc95a0 h1:0NmehRCgyk5rljDQLKUO+cRJCnduDyn11+zGZIc9Z48= github.com/aybabtme/iocontrol v0.0.0-20150809002002-ad15bcfc95a0/go.mod h1:6L7zgvqo0idzI7IO8de6ZC051AfXb5ipkIJ7bIA2tGA= -github.com/beevik/ntp v0.3.0 h1:xzVrPrE4ziasFXgBVBZJDP0Wg/KpMwk2KHJ4Ba8GrDw= -github.com/beevik/ntp v0.3.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg= +github.com/beevik/ntp v1.3.0 h1:/w5VhpW5BGKS37vFm1p9oVk/t4HnnkKZAZIubHM6F7Q= +github.com/beevik/ntp v1.3.0/go.mod h1:vD6h1um4kzXpqmLTuu0cCLcC+NfvC0IC+ltmEDA8E78= github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= @@ -630,8 +630,8 @@ github.com/elastic/go-windows v1.0.1/go.mod h1:FoVvqWSun28vaDQPbj2Elfc0JahhPB7WQ github.com/elazarl/go-bindata-assetfs v0.0.0-20160803192304-e1a2a7ec64b0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4= github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= -github.com/ema/qdisc v0.0.0-20230120214811-5b708f463de3 h1:Jrl8sD8wO34+EE1dV2vhOXrqFAZa/FILDnZRaV28+cw= -github.com/ema/qdisc v0.0.0-20230120214811-5b708f463de3/go.mod h1:FhIc0fLYi7f+lK5maMsesDqwYojIOh3VfRs8EVd5YJQ= +github.com/ema/qdisc v1.0.0 h1:EHLG08FVRbWLg8uRICa3xzC9Zm0m7HyMHfXobWFnXYg= +github.com/ema/qdisc v1.0.0/go.mod h1:FhIc0fLYi7f+lK5maMsesDqwYojIOh3VfRs8EVd5YJQ= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful/v3 v3.10.2 h1:hIovbnmBTLjHXkqEBUz3HGpXZdM7ZrE9fJIZIqlJLqE= @@ -1063,6 +1063,8 @@ github.com/grafana/loki/pkg/push v0.0.0-20230904153656-e4cc2a4f5ec8 h1:yQK/dX7WB github.com/grafana/loki/pkg/push v0.0.0-20230904153656-e4cc2a4f5ec8/go.mod h1:5ll3An1wAxYejo6aM04+3/lc6N4joYVYLY5U+Z4O6vI= github.com/grafana/mysqld_exporter v0.12.2-0.20201015182516-5ac885b2d38a h1:D5NSR64/6xMXnSFD9y1m1DPYIcBcHvtfeuI9/M/0qtI= github.com/grafana/mysqld_exporter v0.12.2-0.20201015182516-5ac885b2d38a/go.mod h1:rjb/swXiCWLlC3gWlyugy/xEOZioF5PclbB8sf/9p/Q= +github.com/grafana/node_exporter v0.18.1-grafana-r01.0.20231004161416-702318429731 h1:vyyIYY2sLpmgFIckJ1vSO/oYkvB0thDF6UiFYp5PThM= +github.com/grafana/node_exporter v0.18.1-grafana-r01.0.20231004161416-702318429731/go.mod h1:vOZxEzxm0nZmuNqjtIfvtmvdRtJik9POmcN5mQVLf5E= github.com/grafana/opentelemetry-collector v0.4.1-0.20230925123210-ef4435f79a8a h1:co7JnXySBilXDBu0hhw3furJZLJg9SFojos1PMO+lW4= github.com/grafana/opentelemetry-collector v0.4.1-0.20230925123210-ef4435f79a8a/go.mod h1:jcETa0UJmwkDSyhkOTwQi8rgie1M3TjsIO98KeGM2vk= github.com/grafana/perflib_exporter v0.1.1-0.20230511173423-6166026bd090 h1:Ko80Xcl7xo1eYqkqLUb9AVVCLGVmuQp2jOV69hEEeZw= @@ -1412,8 +1414,8 @@ github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2E github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw= github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ= -github.com/jsimonetti/rtnetlink v1.3.2 h1:dcn0uWkfxycEEyNy0IGfx3GrhQ38LH7odjxAghimsVI= -github.com/jsimonetti/rtnetlink v1.3.2/go.mod h1:BBu4jZCpTjP6Gk0/wfrO8qcqymnN3g0hoFqObRmUo6U= +github.com/jsimonetti/rtnetlink v1.3.5 h1:hVlNQNRlLDGZz31gBPicsG7Q53rnlsz1l1Ix/9XlpVA= +github.com/jsimonetti/rtnetlink v1.3.5/go.mod h1:0LFedyiTkebnd43tE4YAkWGIq9jQphow4CcwxaT2Y00= github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= @@ -1563,11 +1565,11 @@ github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfr github.com/maxatome/go-testdeep v1.12.0 h1:Ql7Go8Tg0C1D/uMMX59LAoYK7LffeJQ6X2T04nTH68g= github.com/maxatome/go-testdeep v1.12.0/go.mod h1:lPZc/HAcJMP92l7yI6TRz1aZN5URwUBUAfUNvrclaNM= github.com/mdlayher/apcupsd v0.0.0-20200608131503-2bf01da7bf1b/go.mod h1:WYK/Z/aXq9cbMFIL5ihcA4sX/r/3/WCas/Qvs/2fXcA= -github.com/mdlayher/ethtool v0.0.0-20221212131811-ba3b4bc2e02c h1:Y7LoKqIgD7vmqJ7+6ZVnADuwUO+m3tGXbf2lK0OvjIw= -github.com/mdlayher/ethtool v0.0.0-20221212131811-ba3b4bc2e02c/go.mod h1:i0nPbE+sL2G3OtdIb9SXxW/T4UiAwh6rxPW7zcuX+KQ= +github.com/mdlayher/ethtool v0.1.0 h1:XAWHsmKhyPOo42qq/yTPb0eFBGUKKTR1rE0dVrWVQ0Y= +github.com/mdlayher/ethtool v0.1.0/go.mod h1:fBMLn2UhfRGtcH5ZFjr+6GUiHEjZsItFD7fSn7jbZVQ= github.com/mdlayher/genetlink v1.0.0/go.mod h1:0rJ0h4itni50A86M2kHcgS85ttZazNt7a8H2a2cw0Gc= -github.com/mdlayher/genetlink v1.3.1 h1:roBiPnual+eqtRkKX2Jb8UQN5ZPWnhDCGj/wR6Jlz2w= -github.com/mdlayher/genetlink v1.3.1/go.mod h1:uaIPxkWmGk753VVIzDtROxQ8+T+dkHqOI0vB1NA9S/Q= +github.com/mdlayher/genetlink v1.3.2 h1:KdrNKe+CTu+IbZnm/GVUMXSqBBLqcGpRDa0xkQy56gw= +github.com/mdlayher/genetlink v1.3.2/go.mod h1:tcC3pkCrPUGIKKsCsp0B3AdaaKuHtaxoJRz3cc+528o= github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA= github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M= github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY= @@ -1575,8 +1577,8 @@ github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/ github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw= github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U= github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA= -github.com/mdlayher/wifi v0.0.0-20220330172155-a44c70b6d3c8 h1:/HCRFfpoICSWHvNrJ356VO4opd9dg/LaU7m8Tzdf39c= -github.com/mdlayher/wifi v0.0.0-20220330172155-a44c70b6d3c8/go.mod h1:IqdtNfemiXr50M8tnxLWSFdZKZ9vcI1Mgt0oTrCIS7A= +github.com/mdlayher/wifi v0.1.0 h1:y8wYRUXwok5CtUZOXT3egghYesX0O79E3ALl+SIDm9Q= +github.com/mdlayher/wifi v0.1.0/go.mod h1:+gBYnZAMcUKHSFzMJXwlz7tLsEHgwDJ9DJCefhJM+gI= github.com/metalmatze/signal v0.0.0-20210307161603-1c9aa721a97a h1:0usWxe5SGXKQovz3p+BiQ81Jy845xSMu2CWKuXsXuUM= github.com/metalmatze/signal v0.0.0-20210307161603-1c9aa721a97a/go.mod h1:3OETvrxfELvGsU2RoGGWercfeZ4bCL3+SOwzIWtJH/Q= github.com/microsoft/go-mssqldb v0.19.0 h1:LMRSgLcNMF8paPX14xlyQBmBH+jnFylPsYpVZf86eHM= @@ -1986,8 +1988,6 @@ github.com/prometheus/exporter-toolkit v0.10.1-0.20230714054209-2f4150c63f97 h1: github.com/prometheus/exporter-toolkit v0.10.1-0.20230714054209-2f4150c63f97/go.mod h1:LoBCZeRh+5hX+fSULNyFnagYlQG/gBsyA/deNzROkq8= github.com/prometheus/memcached_exporter v0.13.0 h1:d246RYODFCXy39XA8S2PBrqp5jLCSvl9b4KsYspDCHk= github.com/prometheus/memcached_exporter v0.13.0/go.mod h1:fp7Wk6v0RFijeP3Syvd1TShBSJoCG5iFfvPdi5dCMEU= -github.com/prometheus/node_exporter v1.6.0 h1:TKPvENRy8/yhKQWf862ssecaT9kQ1jnW9mQDtTzTIAU= -github.com/prometheus/node_exporter v1.6.0/go.mod h1:+zK+m9vwxu19JHl/kVVmixdCT6fWWHlmcOUHDFpkt0Y= github.com/prometheus/procfs v0.0.0-20180408092902-8b1c2da0d56d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= @@ -2495,6 +2495,7 @@ golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0 golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -2541,6 +2542,7 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -2616,6 +2618,8 @@ golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/oauth2 v0.0.0-20170807180024-9a379c6b3e95/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -2651,6 +2655,7 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -2778,6 +2783,8 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -2788,6 +2795,8 @@ golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuX golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo= golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -2804,6 +2813,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -2893,6 +2904,7 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.12.0 h1:YW6HUoUmYBpwSgyaGaZq1fHjrBjX1rlpZ54T6mu2kss= golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/pkg/flow/internal/controller/loader.go b/pkg/flow/internal/controller/loader.go index 357d7d0f86d1..02408907f35e 100644 --- a/pkg/flow/internal/controller/loader.go +++ b/pkg/flow/internal/controller/loader.go @@ -445,17 +445,7 @@ func (l *Loader) populateComponentNodes(g *dag.Graph, componentBlocks []*ast.Blo continue } - if registration.Singleton && block.Label != "" { - diags.Add(diag.Diagnostic{ - Severity: diag.SeverityLevelError, - Message: fmt.Sprintf("Component %q does not support labels", componentName), - StartPos: block.LabelPos.Position(), - EndPos: block.LabelPos.Add(len(block.Label) + 1).Position(), - }) - continue - } - - if !registration.Singleton && block.Label == "" { + if block.Label == "" { diags.Add(diag.Diagnostic{ Severity: diag.SeverityLevelError, Message: fmt.Sprintf("Component %q must have a label", componentName), @@ -465,16 +455,6 @@ func (l *Loader) populateComponentNodes(g *dag.Graph, componentBlocks []*ast.Blo continue } - if registration.Singleton && l.isModule() { - diags.Add(diag.Diagnostic{ - Severity: diag.SeverityLevelError, - Message: fmt.Sprintf("Component %q is a singleton and unsupported inside a module", componentName), - StartPos: block.NamePos.Position(), - EndPos: block.NamePos.Add(len(componentName) - 1).Position(), - }) - continue - } - // Create a new component c = NewComponentNode(l.globals, registration, block) } diff --git a/pkg/flow/internal/controller/loader_test.go b/pkg/flow/internal/controller/loader_test.go index c6f9fff971fd..2351218d642b 100644 --- a/pkg/flow/internal/controller/loader_test.go +++ b/pkg/flow/internal/controller/loader_test.go @@ -177,19 +177,6 @@ func TestLoader(t *testing.T) { diags := applyFromContent(t, l, []byte(invalidFile), nil) require.Error(t, diags.ErrorOrNil()) }) - - t.Run("Handling of singleton component labels", func(t *testing.T) { - invalidFile := ` - testcomponents.tick { - } - testcomponents.singleton "first" { - } - ` - l := controller.NewLoader(newLoaderOptions()) - diags := applyFromContent(t, l, []byte(invalidFile), nil) - require.ErrorContains(t, diags[0], `Component "testcomponents.tick" must have a label`) - require.ErrorContains(t, diags[1], `Component "testcomponents.singleton" does not support labels`) - }) } // TestScopeWithFailingComponent is used to ensure that the scope is filled out, even if the component diff --git a/pkg/flow/internal/testcomponents/singleton.go b/pkg/flow/internal/testcomponents/singleton.go deleted file mode 100644 index 3dcf8a1d0e94..000000000000 --- a/pkg/flow/internal/testcomponents/singleton.go +++ /dev/null @@ -1,59 +0,0 @@ -package testcomponents - -import ( - "context" - - "github.com/go-kit/log" - "github.com/grafana/agent/component" -) - -func init() { - component.Register(component.Registration{ - Name: "testcomponents.singleton", - Args: SingletonArguments{}, - Exports: SingletonExports{}, - Singleton: true, - - Build: func(opts component.Options, args component.Arguments) (component.Component, error) { - return NewSingleton(opts, args.(SingletonArguments)) - }, - }) -} - -// SingletonArguments configures the testcomponents.singleton component. -type SingletonArguments struct{} - -// SingletonExports describes exported fields for the -// testcomponents.singleton component. -type SingletonExports struct{} - -// Singleton implements the testcomponents.singleton component, which is a -// no-op component. -type Singleton struct { - opts component.Options - log log.Logger -} - -// NewSingleton creates a new singleton component. -func NewSingleton(o component.Options, cfg SingletonArguments) (*Singleton, error) { - t := &Singleton{opts: o, log: o.Logger} - if err := t.Update(cfg); err != nil { - return nil, err - } - return t, nil -} - -var ( - _ component.Component = (*Passthrough)(nil) -) - -// Run implements Component. -func (t *Singleton) Run(ctx context.Context) error { - <-ctx.Done() - return nil -} - -// Update implements Component. -func (t *Singleton) Update(args component.Arguments) error { - return nil -} diff --git a/pkg/integrations/node_exporter/config.go b/pkg/integrations/node_exporter/config.go index 6bb1f8281f01..ff16bf966b3b 100644 --- a/pkg/integrations/node_exporter/config.go +++ b/pkg/integrations/node_exporter/config.go @@ -7,12 +7,12 @@ import ( "strings" "time" - "github.com/alecthomas/kingpin/v2" "github.com/go-kit/log" "github.com/grafana/agent/pkg/integrations" integrations_v2 "github.com/grafana/agent/pkg/integrations/v2" "github.com/grafana/agent/pkg/integrations/v2/metricsutils" "github.com/grafana/dskit/flagext" + "github.com/prometheus/node_exporter/collector" "github.com/prometheus/procfs" ) @@ -265,10 +265,8 @@ func init() { integrations_v2.RegisterLegacy(&Config{}, integrations_v2.TypeSingleton, metricsutils.Shim) } -// MapConfigToNodeExporterFlags takes in a node_exporter Config and converts -// it to the set of flags that node_exporter usually expects when running as a -// separate binary. -func MapConfigToNodeExporterFlags(c *Config) (accepted []string, ignored []string) { +func (c *Config) mapConfigToNodeConfig() *collector.NodeCollectorConfig { + validCollectors := make(map[string]bool) collectors := make(map[string]CollectorState, len(Collectors)) for k, v := range Collectors { collectors[k] = v @@ -290,8 +288,12 @@ func MapConfigToNodeExporterFlags(c *Config) (accepted []string, ignored []strin collectors[k] = CollectorStateDisabled } } + } else { + // This gets the default enabled passed in via register. + for k, v := range collector.GetDefaults() { + collectors[k] = CollectorState(v) + } } - // Explicitly disable/enable specific collectors for _, c := range c.DisableCollectors { collectors[c] = CollectorStateDisabled @@ -300,209 +302,232 @@ func MapConfigToNodeExporterFlags(c *Config) (accepted []string, ignored []strin collectors[c] = CollectorStateEnabled } - DisableUnavailableCollectors(collectors) + for k, v := range collectors { + validCollectors[k] = bool(v) + } + + // This removes any collectors not available on the platform. + availableCollectors := collector.GetAvailableCollectors() + for name := range validCollectors { + var found bool + for _, availableName := range availableCollectors { + if name != availableName { + continue + } + found = true + break + } + if !found { + delete(validCollectors, name) + } + } + + // blankString is a hack to emulate the behavior of kingpin, where node_exporter checks for blank string against a pointer + // without first checking the validity of the pointer. + // TODO change node_exporter to check for nil first. + blankString := "" + blankBool := false + blankInt := 0 - var flags flags - flags.accepted = append(flags.accepted, MapCollectorsToFlags(collectors)...) + cfg := &collector.NodeCollectorConfig{} - flags.add( - "--path.procfs", c.ProcFSPath, - "--path.sysfs", c.SysFSPath, - "--path.rootfs", c.RootFSPath, - "--path.udev.data", c.UdevDataPath, - ) + // It is safe to set all these configs these since only collectors that are enabled are used. - if collectors[CollectorBCache] { - flags.addBools(map[*bool]string{ - &c.BcachePriorityStats: "collector.bcache.priorityStats", - }) + cfg.Path = collector.PathConfig{ + ProcPath: &c.ProcFSPath, + SysPath: &c.SysFSPath, + RootfsPath: &c.RootFSPath, + UdevDataPath: &c.UdevDataPath, } - if collectors[CollectorCPU] { - flags.addBools(map[*bool]string{ - &c.CPUEnableCPUGuest: "collector.cpu.guest", - &c.CPUEnableCPUInfo: "collector.cpu.info", - }) - flags.add("--collector.cpu.info.flags-include", c.CPUFlagsInclude) - flags.add("--collector.cpu.info.bugs-include", c.CPUBugsInclude) + cfg.Bcache = collector.BcacheConfig{ + PriorityStats: &c.BcachePriorityStats, } - - if collectors[CollectorDiskstats] { - if c.DiskStatsDeviceInclude != "" { - flags.add("--collector.diskstats.device-include", c.DiskStatsDeviceInclude) - } else { - flags.add("--collector.diskstats.device-exclude", c.DiskStatsDeviceExclude) + cfg.CPU = collector.CPUConfig{ + EnableCPUGuest: &c.CPUEnableCPUGuest, + EnableCPUInfo: &c.CPUEnableCPUInfo, + BugsInclude: &c.CPUBugsInclude, + FlagsInclude: &c.CPUFlagsInclude, + } + if c.DiskStatsDeviceInclude != "" { + cfg.DiskstatsDeviceFilter = collector.DiskstatsDeviceFilterConfig{ + DeviceInclude: &c.DiskStatsDeviceInclude, + OldDeviceExclude: &blankString, + DeviceExclude: &blankString, + DeviceExcludeSet: false, + } + } else { + cfg.DiskstatsDeviceFilter = collector.DiskstatsDeviceFilterConfig{ + DeviceExclude: &c.DiskStatsDeviceExclude, + DeviceExcludeSet: true, + OldDeviceExclude: &blankString, + DeviceInclude: &blankString, } } - if collectors[CollectorEthtool] { - flags.add("--collector.ethtool.device-include", c.EthtoolDeviceInclude) - flags.add("--collector.ethtool.device-exclude", c.EthtoolDeviceExclude) - flags.add("--collector.ethtool.metrics-include", c.EthtoolMetricsInclude) + cfg.Ethtool = collector.EthtoolConfig{ + DeviceInclude: &c.EthtoolDeviceInclude, + DeviceExclude: &c.EthtoolDeviceExclude, + IncludedMetrics: &c.EthtoolMetricsInclude, } - if collectors[CollectorFilesystem] { - flags.add( - "--collector.filesystem.mount-timeout", c.FilesystemMountTimeout.String(), - "--collector.filesystem.mount-points-exclude", c.FilesystemMountPointsExclude, - "--collector.filesystem.fs-types-exclude", c.FilesystemFSTypesExclude, - ) + cfg.Filesystem = collector.FilesystemConfig{ + MountPointsExclude: &c.FilesystemMountPointsExclude, + MountPointsExcludeSet: true, + MountTimeout: &c.FilesystemMountTimeout, + FSTypesExclude: &c.FilesystemFSTypesExclude, + FSTypesExcludeSet: true, + OldFSTypesExcluded: &blankString, + OldMountPointsExcluded: &blankString, + StatWorkerCount: &blankInt, } - if collectors[CollectorIPVS] { - flags.add("--collector.ipvs.backend-labels", strings.Join(c.IPVSBackendLabels, ",")) + var joinedLabels string + if len(c.IPVSBackendLabels) > 0 { + joinedLabels = strings.Join(c.IPVSBackendLabels, ",") + cfg.IPVS = collector.IPVSConfig{ + Labels: &joinedLabels, + LabelsSet: true, + } + } else { + cfg.IPVS = collector.IPVSConfig{ + Labels: &joinedLabels, + LabelsSet: false, + } } - if collectors[CollectorNetclass] { - flags.addBools(map[*bool]string{ - &c.NetclassIgnoreInvalidSpeedDevice: "collector.netclass.ignore-invalid-speed", - }) - - flags.add("--collector.netclass.ignored-devices", c.NetclassIgnoredDevices) + cfg.NetClass = collector.NetClassConfig{ + IgnoredDevices: &c.NetclassIgnoredDevices, + InvalidSpeed: &c.NetclassIgnoreInvalidSpeedDevice, + Netlink: &blankBool, + RTNLWithStats: &blankBool, } - if collectors[CollectorNetdev] { - flags.addBools(map[*bool]string{ - &c.NetdevAddressInfo: "collector.netdev.address-info", - }) - - flags.add( - "--collector.netdev.device-include", c.NetdevDeviceInclude, - "--collector.netdev.device-exclude", c.NetdevDeviceExclude, - ) + cfg.NetDev = collector.NetDevConfig{ + DeviceInclude: &c.NetdevDeviceInclude, + DeviceExclude: &c.NetdevDeviceExclude, + AddressInfo: &c.NetdevAddressInfo, + OldDeviceInclude: &blankString, + OldDeviceExclude: &blankString, + Netlink: &blankBool, + DetailedMetrics: &blankBool, } - if collectors[CollectorNetstat] { - flags.add("--collector.netstat.fields", c.NetstatFields) + cfg.NetStat = collector.NetStatConfig{ + Fields: &c.NetstatFields, } - if collectors[CollectorNTP] { - flags.add( - "--collector.ntp.server", c.NTPServer, - "--collector.ntp.protocol-version", fmt.Sprintf("%d", c.NTPProtocolVersion), - "--collector.ntp.ip-ttl", fmt.Sprintf("%d", c.NTPIPTTL), - "--collector.ntp.max-distance", c.NTPMaxDistance.String(), - "--collector.ntp.local-offset-tolerance", c.NTPLocalOffsetTolerance.String(), - ) - - flags.addBools(map[*bool]string{ - &c.NTPServerIsLocal: "collector.ntp.server-is-local", - }) + defaultPort := 123 + cfg.NTP = collector.NTPConfig{ + Server: &c.NTPServer, + ServerPort: &defaultPort, + ProtocolVersion: &c.NTPProtocolVersion, + IPTTL: &c.NTPIPTTL, + MaxDistance: &c.NTPMaxDistance, + OffsetTolerance: &c.NTPLocalOffsetTolerance, + ServerIsLocal: &c.NTPServerIsLocal, } - if collectors[CollectorPerf] { - flags.add("--collector.perf.cpus", c.PerfCPUS) - - for _, tp := range c.PerfTracepoint { - flags.add("--collector.perf.tracepoint", tp) - } - - flags.addBools(map[*bool]string{ - &c.PerfDisableHardwareProfilers: "collector.perf.disable-hardware-profilers", - &c.PerfDisableSoftwareProfilers: "collector.perf.disable-software-profilers", - &c.PerfDisableCacheProfilers: "collector.perf.disable-cache-profilers", - }) - - for _, hwp := range c.PerfHardwareProfilers { - flags.add("--collector.perf.hardware-profilers", hwp) - } - for _, swp := range c.PerfSoftwareProfilers { - flags.add("--collector.perf.software-profilers", swp) - } - for _, cp := range c.PerfCacheProfilers { - flags.add("--collector.perf.cache-profilers", cp) - } + cfg.Perf = collector.PerfConfig{ + CPUs: &c.PerfCPUS, + Tracepoint: flagSliceToStringSlice(c.PerfTracepoint), + NoHwProfiler: &c.PerfDisableHardwareProfilers, + HwProfiler: flagSliceToStringSlice(c.PerfHardwareProfilers), + NoSwProfiler: &c.PerfDisableSoftwareProfilers, + SwProfiler: flagSliceToStringSlice(c.PerfSoftwareProfilers), + NoCaProfiler: &c.PerfDisableCacheProfilers, + CaProfilerFlag: flagSliceToStringSlice(c.PerfCacheProfilers), } - if collectors[CollectorPowersuppply] { - flags.add("--collector.powersupply.ignored-supplies", c.PowersupplyIgnoredSupplies) + cfg.PowerSupplyClass = collector.PowerSupplyClassConfig{ + IgnoredPowerSupplies: &c.PowersupplyIgnoredSupplies, } - if collectors[CollectorRunit] { - flags.add("--collector.runit.servicedir", c.RunitServiceDir) + cfg.Runit = collector.RunitConfig{ + ServiceDir: &c.RunitServiceDir, } - if collectors[CollectorSupervisord] { - flags.add("--collector.supervisord.url", c.SupervisordURL) + cfg.Supervisord = collector.SupervisordConfig{ + URL: &c.SupervisordURL, } - if collectors[CollectorSysctl] { - for _, numValue := range c.SysctlInclude { - flags.add("--collector.sysctl.include", numValue) - } + cfg.Sysctl = collector.SysctlConfig{ + Include: flagSliceToStringSlice(c.SysctlInclude), + IncludeInfo: flagSliceToStringSlice(c.SysctlIncludeInfo), + } - for _, stringValue := range c.SysctlIncludeInfo { - flags.add("--collector.sysctl.include-info", stringValue) - } + cfg.Systemd = collector.SystemdConfig{ + UnitInclude: &c.SystemdUnitInclude, + UnitIncludeSet: true, + UnitExclude: &c.SystemdUnitExclude, + UnitExcludeSet: true, + EnableTaskMetrics: &c.SystemdEnableTaskMetrics, + EnableRestartsMetrics: &c.SystemdEnableRestartsMetrics, + EnableStartTimeMetrics: &c.SystemdEnableStartTimeMetrics, + OldUnitExclude: &blankString, + OldUnitInclude: &blankString, + Private: &blankBool, } - if collectors[CollectorSystemd] { - flags.add( - "--collector.systemd.unit-include", c.SystemdUnitInclude, - "--collector.systemd.unit-exclude", c.SystemdUnitExclude, - ) + cfg.Tapestats = collector.TapestatsConfig{ + IgnoredDevices: &c.TapestatsIgnoredDevices, + } - flags.addBools(map[*bool]string{ - &c.SystemdEnableTaskMetrics: "collector.systemd.enable-task-metrics", - &c.SystemdEnableRestartsMetrics: "collector.systemd.enable-restarts-metrics", - &c.SystemdEnableStartTimeMetrics: "collector.systemd.enable-start-time-metrics", - }) + cfg.TextFile = collector.TextFileConfig{ + Directory: &c.TextfileDirectory, } - if collectors[CollectorTapestats] { - flags.add("--collector.tapestats.ignored-devices", c.TapestatsIgnoredDevices) + cfg.VmStat = collector.VmStatConfig{ + Fields: &c.VMStatFields, } - if collectors[CollectorTextfile] { - flags.add("--collector.textfile.directory", c.TextfileDirectory) + cfg.Arp = collector.ArpConfig{ + DeviceInclude: &blankString, + DeviceExclude: &blankString, + Netlink: &blankBool, } - if collectors[CollectorVMStat] { - flags.add("--collector.vmstat.fields", c.VMStatFields) + cfg.Stat = collector.StatConfig{ + Softirq: &blankBool, } - return flags.accepted, flags.ignored -} + cfg.HwMon = collector.HwMonConfig{ + ChipInclude: &blankString, + ChipExclude: &blankString, + } -type flags struct { - accepted []string - ignored []string -} + cfg.Qdisc = collector.QdiscConfig{ + Fixtures: &blankString, + DeviceInclude: &blankString, + OldDeviceInclude: &blankString, + DeviceExclude: &blankString, + OldDeviceExclude: &blankString, + } -// add pushes new flags as key value pairs. If the flag isn't registered with kingpin, -// it will be ignored. -func (f *flags) add(kvp ...string) { - if (len(kvp) % 2) != 0 { - panic("missing value for added flag") + cfg.Systemd = collector.SystemdConfig{ + UnitInclude: &c.SystemdUnitInclude, + UnitIncludeSet: true, + UnitExclude: &c.SystemdUnitExclude, + UnitExcludeSet: true, + OldUnitInclude: &blankString, + OldUnitExclude: &blankString, + Private: &blankBool, + EnableTaskMetrics: &c.SystemdEnableTaskMetrics, + EnableRestartsMetrics: &c.SystemdEnableRestartsMetrics, + EnableStartTimeMetrics: &c.SystemdEnableStartTimeMetrics, } - for i := 0; i < len(kvp); i += 2 { - key := kvp[i+0] - value := kvp[i+1] + cfg.Wifi = collector.WifiConfig{ + Fixtures: &blankString, + } - rawFlag := strings.TrimPrefix(key, "--") - if kingpin.CommandLine.GetFlag(rawFlag) == nil { - f.ignored = append(f.ignored, rawFlag) - continue - } + cfg.Collectors = validCollectors - f.accepted = append(f.accepted, key, value) - } + return cfg } -func (f *flags) addBools(m map[*bool]string) { - for setting, key := range m { - // The flag might not exist on this platform, so skip it if it's not - // defined. - if kingpin.CommandLine.GetFlag(key) == nil { - f.ignored = append(f.ignored, key) - continue - } - - if *setting { - f.accepted = append(f.accepted, "--"+key) - } else { - f.accepted = append(f.accepted, "--no-"+key) - } - } +func flagSliceToStringSlice(fl flagext.StringSlice) *[]string { + sl := make([]string, len(fl)) + copy(sl, fl) + return &sl } diff --git a/pkg/integrations/node_exporter/node_exporter.go b/pkg/integrations/node_exporter/node_exporter.go index d4f261b780eb..6e9e8dd3ce2f 100644 --- a/pkg/integrations/node_exporter/node_exporter.go +++ b/pkg/integrations/node_exporter/node_exporter.go @@ -7,9 +7,7 @@ import ( "fmt" "net/http" "sort" - "strings" - "github.com/alecthomas/kingpin/v2" "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/grafana/agent/pkg/build" @@ -31,23 +29,8 @@ type Integration struct { // New creates a new node_exporter integration. func New(log log.Logger, c *Config) (*Integration, error) { - // NOTE(rfratto): this works as long as node_exporter is the only thing using - // kingpin across the codebase. node_exporter may need a PR eventually to pass - // in a custom kingpin application or expose methods to explicitly enable/disable - // collectors that we can use instead of this command line hack. - flags, _ := MapConfigToNodeExporterFlags(c) - level.Debug(log).Log("msg", "initializing node_exporter with flags converted from agent config", "flags", strings.Join(flags, " ")) - - for _, warn := range c.UnmarshalWarnings { - level.Warn(log).Log("msg", warn) - } - - _, err := kingpin.CommandLine.Parse(flags) - if err != nil { - return nil, fmt.Errorf("failed to parse flags for generating node_exporter configuration: %w", err) - } - - nc, err := collector.NewNodeCollector(log) + cfg := c.mapConfigToNodeConfig() + nc, err := collector.NewNodeCollector(cfg, log) if err != nil { return nil, fmt.Errorf("failed to create node_exporter: %w", err) } diff --git a/pkg/integrations/node_exporter/node_exporter_test.go b/pkg/integrations/node_exporter/node_exporter_test.go index b6b1bdb056bb..3fe58233cf8d 100644 --- a/pkg/integrations/node_exporter/node_exporter_test.go +++ b/pkg/integrations/node_exporter/node_exporter_test.go @@ -6,16 +6,11 @@ import ( "io" "net/http" "net/http/httptest" - "runtime" "testing" - "github.com/alecthomas/kingpin/v2" "github.com/go-kit/log" - "github.com/go-kit/log/level" "github.com/gorilla/mux" - "github.com/grafana/agent/pkg/util" "github.com/prometheus/prometheus/model/textparse" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -69,62 +64,3 @@ func TestNodeExporter(t *testing.T) { require.NoError(t, err) } } - -// TestFTestNodeExporter_IgnoredFlags ensures that flags don't get ignored for -// misspellings. -func TestNodeExporter_IgnoredFlags(t *testing.T) { - l := util.TestLogger(t) - cfg := DefaultConfig - - // Enable all collectors except perf - cfg.SetCollectors = make([]string, 0, len(Collectors)) - for c := range Collectors { - cfg.SetCollectors = append(cfg.SetCollectors, c) - } - cfg.DisableCollectors = []string{CollectorPerf} - - _, ignored := MapConfigToNodeExporterFlags(&cfg) - var expect []string - - switch runtime.GOOS { - case "darwin": - expect = []string{ - "collector.cpu.info", - "collector.cpu.guest", - "collector.cpu.info.flags-include", - "collector.cpu.info.bugs-include", - "collector.filesystem.mount-timeout", - } - } - - if !assert.ElementsMatch(t, expect, ignored) { - level.Debug(l).Log("msg", "printing available flags") - for _, flag := range kingpin.CommandLine.Model().Flags { - level.Debug(l).Log("flag", flag.Name, "hidden", flag.Hidden) - } - } -} - -// TestFlags makes sure that boolean flags and some known non-boolean flags -// work as expected -func TestFlags(t *testing.T) { - var f flags - f.add("--path.rootfs", "/") - require.Equal(t, []string{"--path.rootfs", "/"}, f.accepted) - - // Set up booleans to use as pointers - var ( - truth = true - - // You know, the opposite of truth? - falth = false - ) - - f = flags{} - f.addBools(map[*bool]string{&truth: "collector.textfile"}) - require.Equal(t, []string{"--collector.textfile"}, f.accepted) - - f = flags{} - f.addBools(map[*bool]string{&falth: "collector.textfile"}) - require.Equal(t, []string{"--no-collector.textfile"}, f.accepted) -}