From df6c665503effbf8c8c1ca8e05688f9f165a3ab9 Mon Sep 17 00:00:00 2001 From: efbar <17676301+efbar@users.noreply.github.com> Date: Mon, 29 Nov 2021 17:01:21 +0100 Subject: [PATCH 01/10] add vault input plugin --- plugins/inputs/all/all.go | 1 + plugins/inputs/vault/vault.go | 200 ++++++++++++++++++++++++++ plugins/inputs/vault/vault_metrics.go | 40 ++++++ 3 files changed, 241 insertions(+) create mode 100644 plugins/inputs/vault/vault.go create mode 100644 plugins/inputs/vault/vault_metrics.go diff --git a/plugins/inputs/all/all.go b/plugins/inputs/all/all.go index 1320e7b025ca8..e08ddd60d3633 100644 --- a/plugins/inputs/all/all.go +++ b/plugins/inputs/all/all.go @@ -196,6 +196,7 @@ import ( _ "github.com/influxdata/telegraf/plugins/inputs/unbound" _ "github.com/influxdata/telegraf/plugins/inputs/uwsgi" _ "github.com/influxdata/telegraf/plugins/inputs/varnish" + _ "github.com/influxdata/telegraf/plugins/inputs/vault" _ "github.com/influxdata/telegraf/plugins/inputs/vsphere" _ "github.com/influxdata/telegraf/plugins/inputs/webhooks" _ "github.com/influxdata/telegraf/plugins/inputs/win_eventlog" diff --git a/plugins/inputs/vault/vault.go b/plugins/inputs/vault/vault.go new file mode 100644 index 0000000000000..5a9a6d5403b17 --- /dev/null +++ b/plugins/inputs/vault/vault.go @@ -0,0 +1,200 @@ +package vault + +import ( + "encoding/json" + "fmt" + "net/http" + "os" + "strings" + "time" + + "github.com/influxdata/telegraf" + "github.com/influxdata/telegraf/config" + "github.com/influxdata/telegraf/plugins/common/tls" + "github.com/influxdata/telegraf/plugins/inputs" +) + +// Nomad configuration object +type Vault struct { + URL string `toml:"url"` + + VaultToken string `toml:"vault_token"` + VaultTokenString string `toml:"vault_token_string"` + + ResponseTimeout config.Duration `toml:"response_timeout"` + + tls.ClientConfig + + roundTripper http.RoundTripper +} + +const timeLayout = "2006-01-02 15:04:05 -0700 MST" + +var sampleConfig = ` + ## URL for the Vault agent + # url = "http://127.0.0.1:8200" + + ## Use vault token for authorization. + ## Only one of the options can be set. Leave empty to not use any token. + # vault_token = "/path/to/auth/token" + ## OR + # vault_token_string = "a1234567-40c7-9048-7bae-378687048181" + + ## Set response_timeout (default 5 seconds) + # response_timeout = "5s" + + ## Optional TLS Config + # tls_ca = /path/to/cafile + # tls_cert = /path/to/certfile + # tls_key = /path/to/keyfile +` + +func init() { + inputs.Add("vault", func() telegraf.Input { + return &Vault{ + ResponseTimeout: config.Duration(5 * time.Second), + } + }) +} + +// SampleConfig returns a sample config +func (n *Vault) SampleConfig() string { + return sampleConfig +} + +// Description returns a description of the plugin +func (n *Vault) Description() string { + return "Read metrics from the Vault API" +} + +func (n *Vault) Init() error { + if n.URL == "" { + n.URL = "http://127.0.0.1:8200" + } + + if n.VaultToken != "" && n.VaultTokenString != "" { + return fmt.Errorf("config error: both auth_token and auth_token_string are set") + } + + if n.VaultToken != "" { + token, err := os.ReadFile(n.VaultToken) + if err != nil { + return fmt.Errorf("reading file failed: %v", err) + } + n.VaultTokenString = strings.TrimSpace(string(token)) + } + + tlsCfg, err := n.ClientConfig.TLSConfig() + if err != nil { + return fmt.Errorf("setting up TLS configuration failed: %v", err) + } + + n.roundTripper = &http.Transport{ + TLSHandshakeTimeout: 5 * time.Second, + TLSClientConfig: tlsCfg, + ResponseHeaderTimeout: time.Duration(n.ResponseTimeout), + } + + return nil +} + +// Gather, collects metrics from Vault endpoint +func (n *Vault) Gather(acc telegraf.Accumulator) error { + sysMetrics := &SysMetrics{} + err := n.loadJSON(n.URL+"/v1/sys/metrics", sysMetrics) + if err != nil { + return err + } + + err = buildVaultMetrics(acc, sysMetrics) + if err != nil { + return err + } + + return nil +} + +func (n *Vault) loadJSON(url string, v interface{}) error { + req, err := http.NewRequest("GET", url, nil) + if err != nil { + return err + } + + req.Header.Set("Authorization", "X-Vault-Token "+n.VaultTokenString) + req.Header.Add("Accept", "application/json") + + resp, err := n.roundTripper.RoundTrip(req) + if err != nil { + return fmt.Errorf("error making HTTP request to %s: %s", url, err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("%s returned HTTP status %s", url, resp.Status) + } + + err = json.NewDecoder(resp.Body).Decode(v) + if err != nil { + return fmt.Errorf("error parsing json response: %s", err) + } + + return nil +} + +// buildVaultMetrics, it builds all the metrics and adds them to the accumulator) +func buildVaultMetrics(acc telegraf.Accumulator, sysMetrics *SysMetrics) error { + t, err := time.Parse(timeLayout, sysMetrics.Timestamp) + if err != nil { + return fmt.Errorf("error parsing time: %s", err) + } + + for _, counters := range sysMetrics.Counters { + tags := make(map[string]string) + for key, val := range counters.baseInfo.Labels { + tags[key] = val.(string) + } + + fields := map[string]interface{}{ + "count": counters.Count, + "rate": counters.Rate, + "sum": counters.Sum, + "min": counters.Min, + "max": counters.Max, + "mean": counters.Mean, + } + acc.AddCounter(counters.baseInfo.Name, fields, tags, t) + } + + for _, gauges := range sysMetrics.Gauges { + tags := make(map[string]string) + for key, val := range gauges.baseInfo.Labels { + tags[key] = val.(string) + } + + fields := map[string]interface{}{ + "value": gauges.Value, + } + + acc.AddGauge(gauges.Name, fields, tags, t) + } + + for _, summaries := range sysMetrics.Summaries { + tags := make(map[string]string) + for key, val := range summaries.baseInfo.Labels { + tags[key] = val.(string) + } + + fields := map[string]interface{}{ + "count": summaries.Count, + "rate": summaries.Rate, + "sum": summaries.Sum, + "stddev": summaries.Stddev, + "min": summaries.Min, + "max": summaries.Max, + "mean": summaries.Mean, + } + acc.AddCounter(summaries.Name, fields, tags, t) + } + + return nil +} diff --git a/plugins/inputs/vault/vault_metrics.go b/plugins/inputs/vault/vault_metrics.go new file mode 100644 index 0000000000000..8100f98915d22 --- /dev/null +++ b/plugins/inputs/vault/vault_metrics.go @@ -0,0 +1,40 @@ +package vault + +type SysMetrics struct { + Timestamp string `json:"timestamp"` + Gauges []gauge `json:"Gauges"` + Counters []counter `json:"Counters"` + Summaries []summary `json:"Samples"` +} + +type baseInfo struct { + Name string `json:"Name"` + Labels map[string]interface{} `json:"Labels"` +} + +type gauge struct { + baseInfo + Value int `json:"Value"` +} + +type counter struct { + baseInfo + Count int `json:"Count"` + Rate float64 `json:"Rate"` + Sum int `json:"Sum"` + Min int `json:"Min"` + Max int `json:"Max"` + Mean float64 `json:"Mean"` + Stddev float64 `json:"Stddev"` +} + +type summary struct { + baseInfo + Count int `json:"Count"` + Rate float64 `json:"Rate"` + Sum float64 `json:"Sum"` + Min float64 `json:"Min"` + Max float64 `json:"Max"` + Mean float64 `json:"Mean"` + Stddev float64 `json:"Stddev"` +} From f39336277a2723900261062f71371cefa445fe6d Mon Sep 17 00:00:00 2001 From: efbar <17676301+efbar@users.noreply.github.com> Date: Tue, 30 Nov 2021 11:59:45 +0100 Subject: [PATCH 02/10] mandatory token --- plugins/inputs/vault/vault.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/plugins/inputs/vault/vault.go b/plugins/inputs/vault/vault.go index 5a9a6d5403b17..5e4e9a5313fd7 100644 --- a/plugins/inputs/vault/vault.go +++ b/plugins/inputs/vault/vault.go @@ -38,7 +38,7 @@ var sampleConfig = ` ## Only one of the options can be set. Leave empty to not use any token. # vault_token = "/path/to/auth/token" ## OR - # vault_token_string = "a1234567-40c7-9048-7bae-378687048181" + vault_token_string = "a1234567-40c7-9048-7bae-378687048181" ## Set response_timeout (default 5 seconds) # response_timeout = "5s" @@ -72,8 +72,12 @@ func (n *Vault) Init() error { n.URL = "http://127.0.0.1:8200" } + if n.VaultToken == "" && n.VaultTokenString == "" { + return fmt.Errorf("Vault token missing") + } + if n.VaultToken != "" && n.VaultTokenString != "" { - return fmt.Errorf("config error: both auth_token and auth_token_string are set") + return fmt.Errorf("config error: both vault_token and vault_token_string are set") } if n.VaultToken != "" { From ae5668785496f1782cea9c6acb03db1a684caee0 Mon Sep 17 00:00:00 2001 From: efbar <17676301+efbar@users.noreply.github.com> Date: Tue, 30 Nov 2021 15:02:39 +0100 Subject: [PATCH 03/10] fix token --- plugins/inputs/vault/vault.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/inputs/vault/vault.go b/plugins/inputs/vault/vault.go index 5e4e9a5313fd7..bafc4ec731a18 100644 --- a/plugins/inputs/vault/vault.go +++ b/plugins/inputs/vault/vault.go @@ -124,7 +124,7 @@ func (n *Vault) loadJSON(url string, v interface{}) error { return err } - req.Header.Set("Authorization", "X-Vault-Token "+n.VaultTokenString) + req.Header.Set("X-Vault-Token", n.VaultTokenString) req.Header.Add("Accept", "application/json") resp, err := n.roundTripper.RoundTrip(req) From b59c6c927440affefb0dacf0e0961aebf30eb593 Mon Sep 17 00:00:00 2001 From: efbar <17676301+efbar@users.noreply.github.com> Date: Wed, 1 Dec 2021 09:53:51 +0100 Subject: [PATCH 04/10] add Readme file --- plugins/inputs/vault/README.md | 35 ++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 plugins/inputs/vault/README.md diff --git a/plugins/inputs/vault/README.md b/plugins/inputs/vault/README.md new file mode 100644 index 0000000000000..8c65752789bd7 --- /dev/null +++ b/plugins/inputs/vault/README.md @@ -0,0 +1,35 @@ +# Hashicorp Vault Input Plugin + +The Vault plugin could grab metrics from every Vault agent of the cluster. Telegraf may be present in every node and connect to the agent locally. In this case should be something like `http://127.0.0.1:8200`. + +> Tested on vault 1.8.5 + +## Configuration + +```toml +[[inputs.vault]] + ## URL for the vault agent + # url = "http://127.0.0.1:8200" + + ## Use auth token for authorization. + ## Vault token configuration is mandatory. + ## If both are empty or both are set, an error is thrown. + # vault_token = "/path/to/auth/token" + ## OR + vault_token_string = "s.CDDrgg5zPv5ssI0Z2P4qxJj2" + + ## Set response_timeout (default 5 seconds) + # response_timeout = "5s" + + ## Optional TLS Config + # tls_ca = /path/to/cafile + # tls_cert = /path/to/certfile + # tls_key = /path/to/keyfile +``` + +## Metrics + +For a more deep understanding of Vault monitoring, please have a look at the following Vault documentation: + +- [https://www.vaultproject.io/docs/internals/telemetry](https://www.vaultproject.io/docs/internals/telemetry) +- [https://learn.hashicorp.com/tutorials/vault/monitor-telemetry-audit-splunk?in=vault/monitoring](https://learn.hashicorp.com/tutorials/vault/monitor-telemetry-audit-splunk?in=vault/monitoring) From 0489b20f1ec5f7130bd4396db3b6e91d02e60797 Mon Sep 17 00:00:00 2001 From: efbar <17676301+efbar@users.noreply.github.com> Date: Wed, 1 Dec 2021 09:55:19 +0100 Subject: [PATCH 05/10] add vault tests and fix fields --- .../vault/testdata/response_key_metrics.json | 40 ++++++++ plugins/inputs/vault/vault.go | 46 ++++----- plugins/inputs/vault/vault_test.go | 97 +++++++++++++++++++ 3 files changed, 161 insertions(+), 22 deletions(-) create mode 100644 plugins/inputs/vault/testdata/response_key_metrics.json create mode 100644 plugins/inputs/vault/vault_test.go diff --git a/plugins/inputs/vault/testdata/response_key_metrics.json b/plugins/inputs/vault/testdata/response_key_metrics.json new file mode 100644 index 0000000000000..845acb3690d6b --- /dev/null +++ b/plugins/inputs/vault/testdata/response_key_metrics.json @@ -0,0 +1,40 @@ +{ + "Gauges": [ + { + "Name": "vault.core.unsealed", + "Value": 1, + "Labels": { + "cluster": "vault-cluster-23b671c7" + } + } + ], + "Counters": [ + { + "Name": "vault.raft.replication.appendEntries.logs", + "Count": 130, + "Rate": 0.2, + "Sum": 2, + "Min": 0, + "Max": 1, + "Mean": 0.015384615384615385, + "Stddev": 0.12355304447984486, + "Labels": { + "peer_id": "clustnode-02" + } + } + ], + "Samples": [ + { + "Name": "vault.token.lookup", + "Count": 5135, + "Rate": 87.21228296905755, + "Sum": 872.1228296905756, + "Min": 0.06690400093793869, + "Max": 16.22449493408203, + "Mean": 0.1698389152269865, + "Stddev": 0.24637634000854705, + "Labels": {} + } + ], + "Timestamp": "2021-11-30 15:49:00 +0000 UTC" +} diff --git a/plugins/inputs/vault/vault.go b/plugins/inputs/vault/vault.go index bafc4ec731a18..137c51684f427 100644 --- a/plugins/inputs/vault/vault.go +++ b/plugins/inputs/vault/vault.go @@ -14,7 +14,7 @@ import ( "github.com/influxdata/telegraf/plugins/inputs" ) -// Nomad configuration object +// Vault configuration object type Vault struct { URL string `toml:"url"` @@ -34,11 +34,12 @@ var sampleConfig = ` ## URL for the Vault agent # url = "http://127.0.0.1:8200" - ## Use vault token for authorization. - ## Only one of the options can be set. Leave empty to not use any token. + ## Use Vault token for authorization. + ## Vault token configuration is mandatory. + ## If both are empty or both are set, an error is thrown. # vault_token = "/path/to/auth/token" ## OR - vault_token_string = "a1234567-40c7-9048-7bae-378687048181" + vault_token_string = "s.CDDrgg5zPv5ssI0Z2P4qxJj2" ## Set response_timeout (default 5 seconds) # response_timeout = "5s" @@ -73,7 +74,7 @@ func (n *Vault) Init() error { } if n.VaultToken == "" && n.VaultTokenString == "" { - return fmt.Errorf("Vault token missing") + return fmt.Errorf("vault token missing") } if n.VaultToken != "" && n.VaultTokenString != "" { @@ -145,7 +146,7 @@ func (n *Vault) loadJSON(url string, v interface{}) error { return nil } -// buildVaultMetrics, it builds all the metrics and adds them to the accumulator) +// buildVaultMetrics, it builds all the metrics and adds them to the accumulator func buildVaultMetrics(acc telegraf.Accumulator, sysMetrics *SysMetrics) error { t, err := time.Parse(timeLayout, sysMetrics.Timestamp) if err != nil { @@ -159,12 +160,13 @@ func buildVaultMetrics(acc telegraf.Accumulator, sysMetrics *SysMetrics) error { } fields := map[string]interface{}{ - "count": counters.Count, - "rate": counters.Rate, - "sum": counters.Sum, - "min": counters.Min, - "max": counters.Max, - "mean": counters.Mean, + "count": counters.Count, + "rate": counters.Rate, + "sum": counters.Sum, + "min": counters.Min, + "max": counters.Max, + "mean": counters.Mean, + "stddev": counters.Stddev, } acc.AddCounter(counters.baseInfo.Name, fields, tags, t) } @@ -182,22 +184,22 @@ func buildVaultMetrics(acc telegraf.Accumulator, sysMetrics *SysMetrics) error { acc.AddGauge(gauges.Name, fields, tags, t) } - for _, summaries := range sysMetrics.Summaries { + for _, summary := range sysMetrics.Summaries { tags := make(map[string]string) - for key, val := range summaries.baseInfo.Labels { + for key, val := range summary.baseInfo.Labels { tags[key] = val.(string) } fields := map[string]interface{}{ - "count": summaries.Count, - "rate": summaries.Rate, - "sum": summaries.Sum, - "stddev": summaries.Stddev, - "min": summaries.Min, - "max": summaries.Max, - "mean": summaries.Mean, + "count": summary.Count, + "rate": summary.Rate, + "sum": summary.Sum, + "stddev": summary.Stddev, + "min": summary.Min, + "max": summary.Max, + "mean": summary.Mean, } - acc.AddCounter(summaries.Name, fields, tags, t) + acc.AddCounter(summary.Name, fields, tags, t) } return nil diff --git a/plugins/inputs/vault/vault_test.go b/plugins/inputs/vault/vault_test.go new file mode 100644 index 0000000000000..bad5a0c85ebcb --- /dev/null +++ b/plugins/inputs/vault/vault_test.go @@ -0,0 +1,97 @@ +package vault + +import ( + "fmt" + "io/ioutil" + "net/http" + "net/http/httptest" + "testing" + "time" + + "github.com/influxdata/telegraf" + "github.com/influxdata/telegraf/testutil" + "github.com/stretchr/testify/require" +) + +func TestVaultStats(t *testing.T) { + var applyTests = []struct { + name string + expected []telegraf.Metric + }{ + { + name: "Metrics", + expected: []telegraf.Metric{ + testutil.MustMetric( + "vault.raft.replication.appendEntries.logs", + map[string]string{ + "peer_id": "clustnode-02", + }, + map[string]interface{}{ + "count": int(130), + "rate": float64(0.2), + "sum": int(2), + "min": int(0), + "max": int(1), + "mean": float64(0.015384615384615385), + "stddev": float64(0.12355304447984486), + }, + time.Unix(1638287340, 0), + 1, + ), + testutil.MustMetric( + "vault.core.unsealed", + map[string]string{ + "cluster": "vault-cluster-23b671c7", + }, + map[string]interface{}{ + "value": int(1), + }, + time.Unix(1638287340, 0), + 2, + ), + testutil.MustMetric( + "vault.token.lookup", + map[string]string{}, + map[string]interface{}{ + "count": int(5135), + "max": float64(16.22449493408203), + "mean": float64(0.1698389152269865), + "min": float64(0.06690400093793869), + "rate": float64(87.21228296905755), + "stddev": float64(0.24637634000854705), + "sum": float64(872.1228296905756), + }, + time.Unix(1638287340, 0), + 1, + ), + }, + }, + } + + for _, tt := range applyTests { + t.Run(tt.name, func(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.RequestURI == "/v1/sys/metrics" { + w.WriteHeader(http.StatusOK) + responseKeyMetrics, _ := ioutil.ReadFile("testdata/response_key_metrics.json") + _, err := fmt.Fprintln(w, string(responseKeyMetrics)) + require.NoError(t, err) + } + })) + defer ts.Close() + + plugin := &Vault{ + URL: ts.URL, + VaultTokenString: "s.CDDrgg5zPv5ssI0Z2P4qxJj2", + } + err := plugin.Init() + require.NoError(t, err) + + acc := testutil.Accumulator{} + err = plugin.Gather(&acc) + require.NoError(t, err) + + testutil.RequireMetricsEqual(t, tt.expected, acc.GetTelegrafMetrics()) + }) + } +} From d0b3ea7e06d48183b62a65d8fc7c6b94b58b702b Mon Sep 17 00:00:00 2001 From: efbar <17676301+efbar@users.noreply.github.com> Date: Wed, 1 Dec 2021 12:53:48 +0100 Subject: [PATCH 06/10] fixes and better values converting --- plugins/inputs/vault/README.md | 4 +-- plugins/inputs/vault/vault.go | 43 +++++++++++++++++++----------- plugins/inputs/vault/vault_test.go | 4 +-- 3 files changed, 32 insertions(+), 19 deletions(-) diff --git a/plugins/inputs/vault/README.md b/plugins/inputs/vault/README.md index 8c65752789bd7..2f4e77e05c8f5 100644 --- a/plugins/inputs/vault/README.md +++ b/plugins/inputs/vault/README.md @@ -14,9 +14,9 @@ The Vault plugin could grab metrics from every Vault agent of the cluster. Teleg ## Use auth token for authorization. ## Vault token configuration is mandatory. ## If both are empty or both are set, an error is thrown. - # vault_token = "/path/to/auth/token" + # token = "/path/to/auth/token" ## OR - vault_token_string = "s.CDDrgg5zPv5ssI0Z2P4qxJj2" + token_string = "s.CDDrgg5zPv5ssI0Z2P4qxJj2" ## Set response_timeout (default 5 seconds) # response_timeout = "5s" diff --git a/plugins/inputs/vault/vault.go b/plugins/inputs/vault/vault.go index 137c51684f427..11833e93dd702 100644 --- a/plugins/inputs/vault/vault.go +++ b/plugins/inputs/vault/vault.go @@ -10,6 +10,7 @@ import ( "github.com/influxdata/telegraf" "github.com/influxdata/telegraf/config" + "github.com/influxdata/telegraf/internal" "github.com/influxdata/telegraf/plugins/common/tls" "github.com/influxdata/telegraf/plugins/inputs" ) @@ -18,8 +19,8 @@ import ( type Vault struct { URL string `toml:"url"` - VaultToken string `toml:"vault_token"` - VaultTokenString string `toml:"vault_token_string"` + Token string `toml:"token"` + TokenString string `toml:"token_string"` ResponseTimeout config.Duration `toml:"response_timeout"` @@ -37,9 +38,9 @@ var sampleConfig = ` ## Use Vault token for authorization. ## Vault token configuration is mandatory. ## If both are empty or both are set, an error is thrown. - # vault_token = "/path/to/auth/token" + # token = "/path/to/auth/token" ## OR - vault_token_string = "s.CDDrgg5zPv5ssI0Z2P4qxJj2" + token_string = "s.CDDrgg5zPv5ssI0Z2P4qxJj2" ## Set response_timeout (default 5 seconds) # response_timeout = "5s" @@ -73,20 +74,20 @@ func (n *Vault) Init() error { n.URL = "http://127.0.0.1:8200" } - if n.VaultToken == "" && n.VaultTokenString == "" { - return fmt.Errorf("vault token missing") + if n.Token == "" && n.TokenString == "" { + return fmt.Errorf("token missing") } - if n.VaultToken != "" && n.VaultTokenString != "" { - return fmt.Errorf("config error: both vault_token and vault_token_string are set") + if n.Token != "" && n.TokenString != "" { + return fmt.Errorf("both token and token_string are set") } - if n.VaultToken != "" { - token, err := os.ReadFile(n.VaultToken) + if n.Token != "" { + token, err := os.ReadFile(n.Token) if err != nil { return fmt.Errorf("reading file failed: %v", err) } - n.VaultTokenString = strings.TrimSpace(string(token)) + n.TokenString = strings.TrimSpace(string(token)) } tlsCfg, err := n.ClientConfig.TLSConfig() @@ -125,7 +126,7 @@ func (n *Vault) loadJSON(url string, v interface{}) error { return err } - req.Header.Set("X-Vault-Token", n.VaultTokenString) + req.Header.Set("X-Vault-Token", n.TokenString) req.Header.Add("Accept", "application/json") resp, err := n.roundTripper.RoundTrip(req) @@ -156,7 +157,11 @@ func buildVaultMetrics(acc telegraf.Accumulator, sysMetrics *SysMetrics) error { for _, counters := range sysMetrics.Counters { tags := make(map[string]string) for key, val := range counters.baseInfo.Labels { - tags[key] = val.(string) + convertedVal, err := internal.ToString(val) + if err != nil { + return fmt.Errorf("error converting value: %s", err) + } + tags[key] = convertedVal } fields := map[string]interface{}{ @@ -174,7 +179,11 @@ func buildVaultMetrics(acc telegraf.Accumulator, sysMetrics *SysMetrics) error { for _, gauges := range sysMetrics.Gauges { tags := make(map[string]string) for key, val := range gauges.baseInfo.Labels { - tags[key] = val.(string) + convertedVal, err := internal.ToString(val) + if err != nil { + return fmt.Errorf("error converting value: %s", err) + } + tags[key] = convertedVal } fields := map[string]interface{}{ @@ -187,7 +196,11 @@ func buildVaultMetrics(acc telegraf.Accumulator, sysMetrics *SysMetrics) error { for _, summary := range sysMetrics.Summaries { tags := make(map[string]string) for key, val := range summary.baseInfo.Labels { - tags[key] = val.(string) + convertedVal, err := internal.ToString(val) + if err != nil { + return fmt.Errorf("error converting value: %s", err) + } + tags[key] = convertedVal } fields := map[string]interface{}{ diff --git a/plugins/inputs/vault/vault_test.go b/plugins/inputs/vault/vault_test.go index bad5a0c85ebcb..d6088b22c83de 100644 --- a/plugins/inputs/vault/vault_test.go +++ b/plugins/inputs/vault/vault_test.go @@ -81,8 +81,8 @@ func TestVaultStats(t *testing.T) { defer ts.Close() plugin := &Vault{ - URL: ts.URL, - VaultTokenString: "s.CDDrgg5zPv5ssI0Z2P4qxJj2", + URL: ts.URL, + TokenString: "s.CDDrgg5zPv5ssI0Z2P4qxJj2", } err := plugin.Init() require.NoError(t, err) From 3fa1599651860faa5e4fa77a9af0ae2f0e653846 Mon Sep 17 00:00:00 2001 From: efbar <17676301+efbar@users.noreply.github.com> Date: Wed, 1 Dec 2021 15:59:07 +0100 Subject: [PATCH 07/10] fix error and metric handling --- plugins/inputs/vault/vault.go | 46 +++++++++++++++++------------------ 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/plugins/inputs/vault/vault.go b/plugins/inputs/vault/vault.go index 11833e93dd702..0254b132cbe4c 100644 --- a/plugins/inputs/vault/vault.go +++ b/plugins/inputs/vault/vault.go @@ -19,8 +19,8 @@ import ( type Vault struct { URL string `toml:"url"` - Token string `toml:"token"` - TokenString string `toml:"token_string"` + TokenFile string `toml:"token_file"` + Token string `toml:"token"` ResponseTimeout config.Duration `toml:"response_timeout"` @@ -38,9 +38,9 @@ var sampleConfig = ` ## Use Vault token for authorization. ## Vault token configuration is mandatory. ## If both are empty or both are set, an error is thrown. - # token = "/path/to/auth/token" + # token_file = "/path/to/auth/token" ## OR - token_string = "s.CDDrgg5zPv5ssI0Z2P4qxJj2" + token = "s.CDDrgg5zPv5ssI0Z2P4qxJj2" ## Set response_timeout (default 5 seconds) # response_timeout = "5s" @@ -74,20 +74,20 @@ func (n *Vault) Init() error { n.URL = "http://127.0.0.1:8200" } - if n.Token == "" && n.TokenString == "" { + if n.TokenFile == "" && n.Token == "" { return fmt.Errorf("token missing") } - if n.Token != "" && n.TokenString != "" { - return fmt.Errorf("both token and token_string are set") + if n.TokenFile != "" && n.Token != "" { + return fmt.Errorf("both token_file and token are set") } - if n.Token != "" { - token, err := os.ReadFile(n.Token) + if n.TokenFile != "" { + token, err := os.ReadFile(n.TokenFile) if err != nil { return fmt.Errorf("reading file failed: %v", err) } - n.TokenString = strings.TrimSpace(string(token)) + n.Token = strings.TrimSpace(string(token)) } tlsCfg, err := n.ClientConfig.TLSConfig() @@ -106,8 +106,7 @@ func (n *Vault) Init() error { // Gather, collects metrics from Vault endpoint func (n *Vault) Gather(acc telegraf.Accumulator) error { - sysMetrics := &SysMetrics{} - err := n.loadJSON(n.URL+"/v1/sys/metrics", sysMetrics) + sysMetrics, err := n.loadJSON(n.URL + "/v1/sys/metrics") if err != nil { return err } @@ -120,31 +119,32 @@ func (n *Vault) Gather(acc telegraf.Accumulator) error { return nil } -func (n *Vault) loadJSON(url string, v interface{}) error { +func (n *Vault) loadJSON(url string) (*SysMetrics, error) { req, err := http.NewRequest("GET", url, nil) if err != nil { - return err + return &SysMetrics{}, err } - req.Header.Set("X-Vault-Token", n.TokenString) + req.Header.Set("X-Vault-Token", n.Token) req.Header.Add("Accept", "application/json") resp, err := n.roundTripper.RoundTrip(req) if err != nil { - return fmt.Errorf("error making HTTP request to %s: %s", url, err) + return &SysMetrics{}, fmt.Errorf("error making HTTP request to %s: %s", url, err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { - return fmt.Errorf("%s returned HTTP status %s", url, resp.Status) + return &SysMetrics{}, fmt.Errorf("%s returned HTTP status %s", url, resp.Status) } - err = json.NewDecoder(resp.Body).Decode(v) + var metrics SysMetrics + err = json.NewDecoder(resp.Body).Decode(&metrics) if err != nil { - return fmt.Errorf("error parsing json response: %s", err) + return &SysMetrics{}, fmt.Errorf("error parsing json response: %s", err) } - return nil + return &metrics, nil } // buildVaultMetrics, it builds all the metrics and adds them to the accumulator @@ -159,7 +159,7 @@ func buildVaultMetrics(acc telegraf.Accumulator, sysMetrics *SysMetrics) error { for key, val := range counters.baseInfo.Labels { convertedVal, err := internal.ToString(val) if err != nil { - return fmt.Errorf("error converting value: %s", err) + return fmt.Errorf("converting counter %s=%v failed: %v", key, val, err) } tags[key] = convertedVal } @@ -181,7 +181,7 @@ func buildVaultMetrics(acc telegraf.Accumulator, sysMetrics *SysMetrics) error { for key, val := range gauges.baseInfo.Labels { convertedVal, err := internal.ToString(val) if err != nil { - return fmt.Errorf("error converting value: %s", err) + return fmt.Errorf("converting gauges %s=%v failed: %v", key, val, err) } tags[key] = convertedVal } @@ -198,7 +198,7 @@ func buildVaultMetrics(acc telegraf.Accumulator, sysMetrics *SysMetrics) error { for key, val := range summary.baseInfo.Labels { convertedVal, err := internal.ToString(val) if err != nil { - return fmt.Errorf("error converting value: %s", err) + return fmt.Errorf("converting summary %s=%v failed: %v", key, val, err) } tags[key] = convertedVal } From 0f7b55c581e1f61e0eba866925a08b96a81c39c4 Mon Sep 17 00:00:00 2001 From: efbar <17676301+efbar@users.noreply.github.com> Date: Wed, 1 Dec 2021 15:59:15 +0100 Subject: [PATCH 08/10] some renaming --- plugins/inputs/vault/README.md | 6 +++--- plugins/inputs/vault/vault_test.go | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/inputs/vault/README.md b/plugins/inputs/vault/README.md index 2f4e77e05c8f5..0261efe6c1c34 100644 --- a/plugins/inputs/vault/README.md +++ b/plugins/inputs/vault/README.md @@ -11,12 +11,12 @@ The Vault plugin could grab metrics from every Vault agent of the cluster. Teleg ## URL for the vault agent # url = "http://127.0.0.1:8200" - ## Use auth token for authorization. + ## Use Vault token for authorization. ## Vault token configuration is mandatory. ## If both are empty or both are set, an error is thrown. - # token = "/path/to/auth/token" + # token_file = "/path/to/auth/token" ## OR - token_string = "s.CDDrgg5zPv5ssI0Z2P4qxJj2" + token = "s.CDDrgg5zPv5ssI0Z2P4qxJj2" ## Set response_timeout (default 5 seconds) # response_timeout = "5s" diff --git a/plugins/inputs/vault/vault_test.go b/plugins/inputs/vault/vault_test.go index d6088b22c83de..1cf72584d1cb4 100644 --- a/plugins/inputs/vault/vault_test.go +++ b/plugins/inputs/vault/vault_test.go @@ -81,8 +81,8 @@ func TestVaultStats(t *testing.T) { defer ts.Close() plugin := &Vault{ - URL: ts.URL, - TokenString: "s.CDDrgg5zPv5ssI0Z2P4qxJj2", + URL: ts.URL, + Token: "s.CDDrgg5zPv5ssI0Z2P4qxJj2", } err := plugin.Init() require.NoError(t, err) From 61780988b0beaac2ff1ddc9c5d3f157cd1ba6cf9 Mon Sep 17 00:00:00 2001 From: efbar <17676301+efbar@users.noreply.github.com> Date: Thu, 2 Dec 2021 15:02:35 +0100 Subject: [PATCH 09/10] some refinements --- plugins/inputs/vault/vault.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/inputs/vault/vault.go b/plugins/inputs/vault/vault.go index 0254b132cbe4c..70f5bf7a890af 100644 --- a/plugins/inputs/vault/vault.go +++ b/plugins/inputs/vault/vault.go @@ -31,7 +31,7 @@ type Vault struct { const timeLayout = "2006-01-02 15:04:05 -0700 MST" -var sampleConfig = ` +const sampleConfig = ` ## URL for the Vault agent # url = "http://127.0.0.1:8200" @@ -122,7 +122,7 @@ func (n *Vault) Gather(acc telegraf.Accumulator) error { func (n *Vault) loadJSON(url string) (*SysMetrics, error) { req, err := http.NewRequest("GET", url, nil) if err != nil { - return &SysMetrics{}, err + return nil, err } req.Header.Set("X-Vault-Token", n.Token) @@ -130,18 +130,18 @@ func (n *Vault) loadJSON(url string) (*SysMetrics, error) { resp, err := n.roundTripper.RoundTrip(req) if err != nil { - return &SysMetrics{}, fmt.Errorf("error making HTTP request to %s: %s", url, err) + return nil, fmt.Errorf("error making HTTP request to %s: %s", url, err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { - return &SysMetrics{}, fmt.Errorf("%s returned HTTP status %s", url, resp.Status) + return nil, fmt.Errorf("%s returned HTTP status %s", url, resp.Status) } var metrics SysMetrics err = json.NewDecoder(resp.Body).Decode(&metrics) if err != nil { - return &SysMetrics{}, fmt.Errorf("error parsing json response: %s", err) + return nil, fmt.Errorf("error parsing json response: %s", err) } return &metrics, nil From f217ae11abfde1fe97ba001eb7050732db3f681d Mon Sep 17 00:00:00 2001 From: efbar <17676301+efbar@users.noreply.github.com> Date: Fri, 3 Dec 2021 09:53:33 +0100 Subject: [PATCH 10/10] harmonizing --- plugins/inputs/vault/vault.go | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/plugins/inputs/vault/vault.go b/plugins/inputs/vault/vault.go index 70f5bf7a890af..04524c78ab28d 100644 --- a/plugins/inputs/vault/vault.go +++ b/plugins/inputs/vault/vault.go @@ -111,12 +111,7 @@ func (n *Vault) Gather(acc telegraf.Accumulator) error { return err } - err = buildVaultMetrics(acc, sysMetrics) - if err != nil { - return err - } - - return nil + return buildVaultMetrics(acc, sysMetrics) } func (n *Vault) loadJSON(url string) (*SysMetrics, error) {