From d807dd3c0514f99cc96b6cd411407f5f5d87e5c6 Mon Sep 17 00:00:00 2001 From: Luke Winikates <521457+LukeWinikates@users.noreply.github.com> Date: Fri, 8 Sep 2023 11:46:08 -0700 Subject: [PATCH] feat(outputs.wavefront): Add more auth options and update SDK (#13857) --- go.mod | 3 +- go.sum | 6 +- plugins/outputs/wavefront/README.md | 62 ++++--- plugins/outputs/wavefront/sample.conf | 62 ++++--- plugins/outputs/wavefront/wavefront.go | 171 ++++++++++++++------ plugins/outputs/wavefront/wavefront_test.go | 73 +++++++-- 6 files changed, 272 insertions(+), 105 deletions(-) diff --git a/go.mod b/go.mod index a49030995..4d08eea07 100644 --- a/go.mod +++ b/go.mod @@ -178,7 +178,7 @@ require ( github.com/vapourismo/knx-go v0.0.0-20220829185957-fb5458a5389d github.com/vjeantet/grok v1.0.1 github.com/vmware/govmomi v0.28.1-0.20220921224932-b4b508abf208 - github.com/wavefronthq/wavefront-sdk-go v0.13.0 + github.com/wavefronthq/wavefront-sdk-go v0.14.0 github.com/wvanbergen/kafka v0.0.0-20171203153745-e2edea948ddf github.com/x448/float16 v0.8.4 github.com/xdg/scram v1.0.5 @@ -272,6 +272,7 @@ require ( github.com/bitly/go-hostpool v0.1.0 // indirect github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect github.com/bufbuild/protocompile v0.4.0 // indirect + github.com/caio/go-tdigest/v4 v4.0.1 // indirect github.com/cenkalti/backoff v2.2.1+incompatible // indirect github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect diff --git a/go.sum b/go.sum index 31d4e2151..bc7af6595 100644 --- a/go.sum +++ b/go.sum @@ -355,6 +355,8 @@ github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZ github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8= github.com/caio/go-tdigest v3.1.0+incompatible h1:uoVMJ3Q5lXmVLCCqaMGHLBWnbGoN6Lpu7OAUPR60cds= github.com/caio/go-tdigest v3.1.0+incompatible/go.mod h1:sHQM/ubZStBUmF1WbB8FAm8q9GjDajLC5T7ydxE3JHI= +github.com/caio/go-tdigest/v4 v4.0.1 h1:sx4ZxjmIEcLROUPs2j1BGe2WhOtHD6VSe6NNbBdKYh4= +github.com/caio/go-tdigest/v4 v4.0.1/go.mod h1:Wsa+f0EZnV2gShdj1adgl0tQSoXRxtM0QioTgukFw8U= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff/v4 v4.0.0/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg= @@ -1500,8 +1502,8 @@ github.com/vjeantet/grok v1.0.1 h1:2rhIR7J4gThTgcZ1m2JY4TrJZNgjn985U28kT2wQrJ4= github.com/vjeantet/grok v1.0.1/go.mod h1:ax1aAchzC6/QMXMcyzHQGZWaW1l195+uMYIkCWPCNIo= github.com/vmware/govmomi v0.28.1-0.20220921224932-b4b508abf208 h1:IDVzGQ2aczmTEfTos4hzmFw20tGQ4zZsVnel9C6VEpA= github.com/vmware/govmomi v0.28.1-0.20220921224932-b4b508abf208/go.mod h1:F7adsVewLNHsW/IIm7ziFURaXDaHEwcc+ym4r3INMdY= -github.com/wavefronthq/wavefront-sdk-go v0.13.0 h1:3s9maJmzI4orW+hiVBfCNp/SIu8ISXi6rtewmDGzheE= -github.com/wavefronthq/wavefront-sdk-go v0.13.0/go.mod h1:KA69ERADh+ePHNET6AqBCnna3W6lkHXwss/fTTZEFLg= +github.com/wavefronthq/wavefront-sdk-go v0.14.0 h1:Nq+yobFZrVw3bfXh+EsWmWDtwMHYRKLRVXgnB1S0j34= +github.com/wavefronthq/wavefront-sdk-go v0.14.0/go.mod h1:V72c8e+bXuLK8HpA6ioW0ll5mK9IPD+4IHNNDY75ksA= github.com/wvanbergen/kafka v0.0.0-20171203153745-e2edea948ddf h1:TOV5PC6fIWwFOFra9xJfRXZcL2pLhMI8oNuDugNxg9Q= github.com/wvanbergen/kafka v0.0.0-20171203153745-e2edea948ddf/go.mod h1:nxx7XRXbR9ykhnC8lXqQyJS0rfvJGxKyKw/sT1YOttg= github.com/wvanbergen/kazoo-go v0.0.0-20180202103751-f72d8611297a h1:ILoU84rj4AQ3q6cjQvtb9jBjx4xzR/Riq/zYhmDQiOk= diff --git a/plugins/outputs/wavefront/README.md b/plugins/outputs/wavefront/README.md index 22d454af1..43369b4ad 100644 --- a/plugins/outputs/wavefront/README.md +++ b/plugins/outputs/wavefront/README.md @@ -24,57 +24,52 @@ to use them. ```toml @sample.conf [[outputs.wavefront]] - ## Url for Wavefront API or Wavefront Proxy instance. + ## Url for Wavefront API or Wavefront proxy instance. + ## Direct Ingestion via Wavefront API requires authentication. See below. url = "https://metrics.wavefront.com" - ## Authentication Token for Wavefront. Required if using Direct Ingestion. Not required if using a Wavefront Proxy. - #token = "DUMMY_TOKEN" - ## Maximum number of metrics to send per HTTP request. This value should be higher than the `metric_batch_size`. Default is 10,000. Values higher than 40,000 are not recommended. # http_maximum_batch_size = 10000 - ## Deprecated. DNS name of the Wavefront server or Wavefront Proxy. Use the `url` field instead. - #host = "wavefront.example.com" - - ## Deprecated. Wavefront proxy port. Use the `url` field instead. - #port = 2878 - ## prefix for metrics keys - #prefix = "my.specific.prefix." + # prefix = "my.specific.prefix." ## whether to use "value" for name of simple fields. default is false - #simple_fields = false + # simple_fields = false ## character to use between metric and field name. default is . (dot) - #metric_separator = "." + # metric_separator = "." ## Convert metric name paths to use metricSeparator character ## When true will convert all _ (underscore) characters in final metric name. default is true - #convert_paths = true + # convert_paths = true ## Use Strict rules to sanitize metric and tag names from invalid characters ## When enabled forward slash (/) and comma (,) will be accepted - #use_strict = false + # use_strict = false ## Use Regex to sanitize metric and tag names from invalid characters ## Regex is more thorough, but significantly slower. default is false - #use_regex = false + # use_regex = false ## point tags to use as the source name for Wavefront (if none found, host will be used) - #source_override = ["hostname", "address", "agent_host", "node_host"] + # source_override = ["hostname", "address", "agent_host", "node_host"] ## whether to convert boolean values to numeric values, with false -> 0.0 and true -> 1.0. default is true - #convert_bool = true + # convert_bool = true ## Truncate metric tags to a total of 254 characters for the tag name value. Wavefront will reject any ## data point exceeding this limit if not truncated. Defaults to 'false' to provide backwards compatibility. - #truncate_tags = false + # truncate_tags = false ## Flush the internal buffers after each batch. This effectively bypasses the background sending of metrics ## normally done by the Wavefront SDK. This can be used if you are experiencing buffer overruns. The sending ## of metrics will block for a longer time, but this will be handled gracefully by the internal buffering in ## Telegraf. - #immediate_flush = true + # immediate_flush = true + + ## Send internal metrics (starting with `~sdk.go`) for valid, invalid, and dropped metrics. default is true. + # send_internal_metrics = true ## Optional TLS Config ## Set to true/false to enforce TLS being enabled/disabled. If not set, @@ -92,7 +87,32 @@ to use them. # insecure_skip_verify = false ## HTTP Timeout - #timeout="10s" + # timeout="10s" + + ## Authentication for Direct Ingestion. + ## Direct Ingestion requires one of: `token`,`auth_csp_api_token`, or `auth_csp_client_credentials` + ## See https://docs.wavefront.com/csp_getting_started.html to learn more about using CSP credentials with Wavefront. + ## Not required if using a Wavefront proxy. + + ## Wavefront API Token Authentication. Ignored if using a Wavefront proxy. + ## 1. Click the gear icon at the top right in the Wavefront UI. + ## 2. Click your account name (usually your email) + ## 3. Click *API access*. + # token = "YOUR_TOKEN" + + ## Optional. defaults to "https://console.cloud.vmware.com/" + ## Ignored if using a Wavefront proxy or a Wavefront API token. + # auth_csp_base_url=https://console.cloud.vmware.com + + ## CSP API Token Authentication for Wavefront. Ignored if using a Wavefront proxy. + # auth_csp_api_token=CSP_API_TOKEN_HERE + + ## CSP Client Credentials Authentication Information for Wavefront. Ignored if using a Wavefront proxy. + ## See also: https://docs.wavefront.com/csp_getting_started.html#whats-a-server-to-server-app + # [outputs.wavefront.auth_csp_client_credentials] + # app_id=CSP_APP_ID_HERE + # app_secret=CSP_APP_SECRET_HERE + # org_id=CSP_ORG_ID_HERE ``` ### Convert Path & Metric Separator diff --git a/plugins/outputs/wavefront/sample.conf b/plugins/outputs/wavefront/sample.conf index e396592e0..3433644e6 100644 --- a/plugins/outputs/wavefront/sample.conf +++ b/plugins/outputs/wavefront/sample.conf @@ -1,55 +1,50 @@ [[outputs.wavefront]] - ## Url for Wavefront API or Wavefront Proxy instance. + ## Url for Wavefront API or Wavefront proxy instance. + ## Direct Ingestion via Wavefront API requires authentication. See below. url = "https://metrics.wavefront.com" - ## Authentication Token for Wavefront. Required if using Direct Ingestion. Not required if using a Wavefront Proxy. - #token = "DUMMY_TOKEN" - ## Maximum number of metrics to send per HTTP request. This value should be higher than the `metric_batch_size`. Default is 10,000. Values higher than 40,000 are not recommended. # http_maximum_batch_size = 10000 - ## Deprecated. DNS name of the Wavefront server or Wavefront Proxy. Use the `url` field instead. - #host = "wavefront.example.com" - - ## Deprecated. Wavefront proxy port. Use the `url` field instead. - #port = 2878 - ## prefix for metrics keys - #prefix = "my.specific.prefix." + # prefix = "my.specific.prefix." ## whether to use "value" for name of simple fields. default is false - #simple_fields = false + # simple_fields = false ## character to use between metric and field name. default is . (dot) - #metric_separator = "." + # metric_separator = "." ## Convert metric name paths to use metricSeparator character ## When true will convert all _ (underscore) characters in final metric name. default is true - #convert_paths = true + # convert_paths = true ## Use Strict rules to sanitize metric and tag names from invalid characters ## When enabled forward slash (/) and comma (,) will be accepted - #use_strict = false + # use_strict = false ## Use Regex to sanitize metric and tag names from invalid characters ## Regex is more thorough, but significantly slower. default is false - #use_regex = false + # use_regex = false ## point tags to use as the source name for Wavefront (if none found, host will be used) - #source_override = ["hostname", "address", "agent_host", "node_host"] + # source_override = ["hostname", "address", "agent_host", "node_host"] ## whether to convert boolean values to numeric values, with false -> 0.0 and true -> 1.0. default is true - #convert_bool = true + # convert_bool = true ## Truncate metric tags to a total of 254 characters for the tag name value. Wavefront will reject any ## data point exceeding this limit if not truncated. Defaults to 'false' to provide backwards compatibility. - #truncate_tags = false + # truncate_tags = false ## Flush the internal buffers after each batch. This effectively bypasses the background sending of metrics ## normally done by the Wavefront SDK. This can be used if you are experiencing buffer overruns. The sending ## of metrics will block for a longer time, but this will be handled gracefully by the internal buffering in ## Telegraf. - #immediate_flush = true + # immediate_flush = true + + ## Send internal metrics (starting with `~sdk.go`) for valid, invalid, and dropped metrics. default is true. + # send_internal_metrics = true ## Optional TLS Config ## Set to true/false to enforce TLS being enabled/disabled. If not set, @@ -67,4 +62,29 @@ # insecure_skip_verify = false ## HTTP Timeout - #timeout="10s" \ No newline at end of file + # timeout="10s" + + ## Authentication for Direct Ingestion. + ## Direct Ingestion requires one of: `token`,`auth_csp_api_token`, or `auth_csp_client_credentials` + ## See https://docs.wavefront.com/csp_getting_started.html to learn more about using CSP credentials with Wavefront. + ## Not required if using a Wavefront proxy. + + ## Wavefront API Token Authentication. Ignored if using a Wavefront proxy. + ## 1. Click the gear icon at the top right in the Wavefront UI. + ## 2. Click your account name (usually your email) + ## 3. Click *API access*. + # token = "YOUR_TOKEN" + + ## Optional. defaults to "https://console.cloud.vmware.com/" + ## Ignored if using a Wavefront proxy or a Wavefront API token. + # auth_csp_base_url=https://console.cloud.vmware.com + + ## CSP API Token Authentication for Wavefront. Ignored if using a Wavefront proxy. + # auth_csp_api_token=CSP_API_TOKEN_HERE + + ## CSP Client Credentials Authentication Information for Wavefront. Ignored if using a Wavefront proxy. + ## See also: https://docs.wavefront.com/csp_getting_started.html#whats-a-server-to-server-app + # [outputs.wavefront.auth_csp_client_credentials] + # app_id=CSP_APP_ID_HERE + # app_secret=CSP_APP_SECRET_HERE + # org_id=CSP_ORG_ID_HERE diff --git a/plugins/outputs/wavefront/wavefront.go b/plugins/outputs/wavefront/wavefront.go index 5ef8991b4..f1497dd57 100644 --- a/plugins/outputs/wavefront/wavefront.go +++ b/plugins/outputs/wavefront/wavefront.go @@ -2,7 +2,9 @@ package wavefront import ( + cryptoTls "crypto/tls" _ "embed" + "errors" "fmt" "net/url" "regexp" @@ -23,24 +25,34 @@ var sampleConfig string const maxTagLength = 254 +type authCSPClientCredentials struct { + AppID config.Secret `toml:"app_id"` + AppSecret config.Secret `toml:"app_secret"` + OrgID *string `toml:"org_id"` +} + type Wavefront struct { - URL string `toml:"url"` - Token config.Secret `toml:"token"` - Host string `toml:"host" deprecated:"2.4.0;use url instead"` - Port int `toml:"port" deprecated:"2.4.0;use url instead"` - Prefix string `toml:"prefix"` - SimpleFields bool `toml:"simple_fields"` - MetricSeparator string `toml:"metric_separator"` - ConvertPaths bool `toml:"convert_paths"` - ConvertBool bool `toml:"convert_bool"` - HTTPMaximumBatchSize int `toml:"http_maximum_batch_size"` - Timeout config.Duration `toml:"timeout"` - UseRegex bool `toml:"use_regex"` - UseStrict bool `toml:"use_strict"` - TruncateTags bool `toml:"truncate_tags"` - ImmediateFlush bool `toml:"immediate_flush"` - SourceOverride []string `toml:"source_override"` - StringToNumber map[string][]map[string]float64 `toml:"string_to_number" deprecated:"1.9.0;use the enum processor instead"` + URL string `toml:"url"` + Token config.Secret `toml:"token"` + CSPBaseURL string `toml:"auth_csp_base_url"` + AuthCSPAPIToken config.Secret `toml:"auth_csp_api_token"` + AuthCSPClientCredentials *authCSPClientCredentials `toml:"auth_csp_client_credentials"` + Host string `toml:"host" deprecated:"2.4.0;use url instead"` + Port int `toml:"port" deprecated:"2.4.0;use url instead"` + Prefix string `toml:"prefix"` + SimpleFields bool `toml:"simple_fields"` + MetricSeparator string `toml:"metric_separator"` + ConvertPaths bool `toml:"convert_paths"` + ConvertBool bool `toml:"convert_bool"` + HTTPMaximumBatchSize int `toml:"http_maximum_batch_size"` + Timeout config.Duration `toml:"timeout"` + UseRegex bool `toml:"use_regex"` + UseStrict bool `toml:"use_strict"` + TruncateTags bool `toml:"truncate_tags"` + ImmediateFlush bool `toml:"immediate_flush"` + SendInternalMetrics bool `toml:"send_internal_metrics"` + SourceOverride []string `toml:"source_override"` + StringToNumber map[string][]map[string]float64 `toml:"string_to_number" deprecated:"1.9.0;use the enum processor instead"` tls.ClientConfig sender wavefront.Sender Log telegraf.Logger `toml:"-"` @@ -57,28 +69,41 @@ func (*Wavefront) SampleConfig() string { return sampleConfig } -func (w *Wavefront) senderURLFromURLAndToken() (string, error) { - newURL, err := url.Parse(w.URL) +func (w *Wavefront) parseConnectionURL() (string, error) { + if w.URL == "" { + if w.Host == "" || w.Port <= 0 { + return "", errors.New("no URL specified") + } + generatedURL := fmt.Sprintf("http://%s:%d", w.Host, w.Port) + w.Log.Warnf("translating host/port into url: %s\n", generatedURL) + return generatedURL, nil + } + + u, err := url.ParseRequestURI(w.URL) if err != nil { return "", fmt.Errorf("could not parse the provided URL: %s", w.URL) } - token := "DUMMY_TOKEN" - if !w.Token.Empty() { - b, err := w.Token.Get() - if err != nil { - return "", fmt.Errorf("getting token failed: %w", err) - } - token = string(b) - config.ReleaseSecret(b) - } - newURL.User = url.User(token) - - return newURL.String(), nil + return u.String(), nil } -func senderURLFromHostAndPort(host string, port int) string { - return fmt.Sprintf("http://%s:%d", host, port) +func (w *Wavefront) createSender(connectionURL string, flushSeconds int, tlsConfig *cryptoTls.Config) (wavefront.Sender, error) { + timeout := time.Duration(w.Timeout) + options := []wavefront.Option{ + wavefront.BatchSize(w.HTTPMaximumBatchSize), + wavefront.FlushIntervalSeconds(flushSeconds), + wavefront.TLSConfigOptions(tlsConfig), + wavefront.Timeout(timeout), + wavefront.SendInternalMetrics(w.SendInternalMetrics), + } + + authOptions, err := w.makeAuthOptions() + if err != nil { + return nil, err + } + options = append(options, authOptions...) + + return wavefront.NewSender(connectionURL, options...) } func (w *Wavefront) Connect() error { @@ -86,18 +111,9 @@ func (w *Wavefront) Connect() error { if w.ImmediateFlush { flushSeconds = 86400 // Set a very long flush interval if we're flushing directly } - var connectionURL string - if w.URL != "" { - w.Log.Debugf("Connecting over http/https using url: %s", w.URL) - connectionURLWithToken, err := w.senderURLFromURLAndToken() - if err != nil { - return err - } - connectionURL = connectionURLWithToken - } else { - w.Log.Warn("Configuration with host/port is deprecated. Please use url.") - w.Log.Debugf("Connecting over http using Host: %q and Port: %d", w.Host, w.Port) - connectionURL = senderURLFromHostAndPort(w.Host, w.Port) + connectionURL, err := w.parseConnectionURL() + if err != nil { + return err } tlsConfig, err := w.TLSConfig() @@ -105,12 +121,7 @@ func (w *Wavefront) Connect() error { return err } - sender, err := wavefront.NewSender(connectionURL, - wavefront.BatchSize(w.HTTPMaximumBatchSize), - wavefront.FlushIntervalSeconds(flushSeconds), - wavefront.TLSConfigOptions(tlsConfig), - wavefront.Timeout(time.Duration(w.Timeout)), - ) + sender, err := w.createSender(connectionURL, flushSeconds, tlsConfig) if err != nil { return fmt.Errorf("could not create Wavefront Sender for the provided url") @@ -307,6 +318,62 @@ func (w *Wavefront) Close() error { return nil } +func (w *Wavefront) makeAuthOptions() ([]wavefront.Option, error) { + if !w.Token.Empty() { + b, err := w.Token.Get() + if err != nil { + return nil, fmt.Errorf("failed to parse token value: %w", err) + } + token := string(b) + config.ReleaseSecret(b) + + return []wavefront.Option{ + wavefront.APIToken(token), + }, nil + } + + if !w.AuthCSPAPIToken.Empty() { + b, err := w.AuthCSPAPIToken.Get() + if err != nil { + return nil, fmt.Errorf("failed to CSP API token value: %w", err) + } + apiToken := string(b) + config.ReleaseSecret(b) + return []wavefront.Option{ + wavefront.CSPAPIToken(apiToken, wavefront.CSPBaseURL(w.CSPBaseURL)), + }, nil + } + + if w.AuthCSPClientCredentials != nil { + appIDBytes, err := w.AuthCSPClientCredentials.AppID.Get() + if err != nil { + return nil, fmt.Errorf("failed to parse Client Credentials App ID value: %w", err) + } + appID := string(appIDBytes) + config.ReleaseSecret(appIDBytes) + + appSecretBytes, err := w.AuthCSPClientCredentials.AppSecret.Get() + if err != nil { + return nil, fmt.Errorf("failed to parse Client Credentials App Secret value: %w", err) + } + cspAppSecret := string(appSecretBytes) + config.ReleaseSecret(appSecretBytes) + + options := []wavefront.CSPOption{ + wavefront.CSPBaseURL(w.CSPBaseURL), + } + + if w.AuthCSPClientCredentials.OrgID != nil { + options = append(options, wavefront.CSPOrgID(*w.AuthCSPClientCredentials.OrgID)) + } + return []wavefront.Option{ + wavefront.CSPClientCredentials(appID, cspAppSecret, options...), + }, nil + } + + return nil, nil +} + func init() { outputs.Add("wavefront", func() telegraf.Output { return &Wavefront{ @@ -315,8 +382,10 @@ func init() { ConvertBool: true, TruncateTags: false, ImmediateFlush: true, + SendInternalMetrics: true, HTTPMaximumBatchSize: 10000, Timeout: config.Duration(10 * time.Second), + CSPBaseURL: "https://console.cloud.vmware.com", } }) } diff --git a/plugins/outputs/wavefront/wavefront_test.go b/plugins/outputs/wavefront/wavefront_test.go index 54dd1d253..afa1c8a3a 100644 --- a/plugins/outputs/wavefront/wavefront_test.go +++ b/plugins/outputs/wavefront/wavefront_test.go @@ -365,19 +365,35 @@ func TestTagLimits(t *testing.T) { require.Equal(t, longKey, tags[longKey]) } -func TestSenderURLFromHostAndPort(t *testing.T) { - require.Equal(t, "http://localhost:2878", senderURLFromHostAndPort("localhost", 2878)) -} - -func TestSenderURLFromURLAndToken(t *testing.T) { +func TestParseConnectionUrlReturnsAnErrorForInvalidUrls(t *testing.T) { w := &Wavefront{ - URL: "https://surf.wavefront.com", - Token: config.NewSecret([]byte("11111111-2222-3333-4444-555555555555")), + URL: "invalid url", + Log: testutil.Logger{}, + } + _, err := w.parseConnectionURL() + require.EqualError(t, err, "could not parse the provided URL: invalid url") +} +func TestParseConnectionUrlReturnsAllowsTokensInUrl(t *testing.T) { + w := &Wavefront{ + URL: "https://11111111-2222-3333-4444-555555555555@surf.wavefront.com", + Log: testutil.Logger{}, } - url, err := w.senderURLFromURLAndToken() + url, err := w.parseConnectionURL() require.NoError(t, err) - require.Equal(t, "https://11111111-2222-3333-4444-555555555555@surf.wavefront.com", url) + require.Equalf(t, "https://11111111-2222-3333-4444-555555555555@surf.wavefront.com", url, "Token value should not overwrite the token embedded in url") +} + +func TestParseConnectionUrlUsesHostAndPortWhenUrlIsOmitted(t *testing.T) { + w := &Wavefront{ + Host: "surf.wavefront.com", + Port: 8080, + Log: testutil.Logger{}, + } + + url, err := w.parseConnectionURL() + require.NoError(t, err) + require.Equalf(t, "http://surf.wavefront.com:8080", url, "Should combine host and port into URI") } func TestDefaults(t *testing.T) { @@ -387,6 +403,45 @@ func TestDefaults(t *testing.T) { require.Equal(t, "", defaultWavefront.TLSCA) } +func TestMakeAuthOptions(t *testing.T) { + cspAPIWavefront := outputs.Outputs["wavefront"]().(*Wavefront) + cspAPIWavefront.AuthCSPAPIToken = config.NewSecret([]byte("fake-app-token")) + options, err := cspAPIWavefront.makeAuthOptions() + require.NoError(t, err) + require.Equal(t, 1, len(options)) + + cspClientCredsWavefront := outputs.Outputs["wavefront"]().(*Wavefront) + cspClientCredsWavefront.AuthCSPClientCredentials = &authCSPClientCredentials{ + AppID: config.NewSecret([]byte("fake-app-id")), + AppSecret: config.NewSecret([]byte("fake-app-secret")), + } + options, err = cspClientCredsWavefront.makeAuthOptions() + require.NoError(t, err) + require.Equal(t, 1, len(options)) + + orgID := "org-id" + cspClientCredsWithOrgIDWavefront := outputs.Outputs["wavefront"]().(*Wavefront) + cspClientCredsWithOrgIDWavefront.AuthCSPClientCredentials = &authCSPClientCredentials{ + AppID: config.NewSecret([]byte("fake-app-id")), + AppSecret: config.NewSecret([]byte("fake-app-secret")), + OrgID: &orgID, + } + options, err = cspClientCredsWithOrgIDWavefront.makeAuthOptions() + require.NoError(t, err) + require.Equal(t, 1, len(options)) + + apiTokenWavefront := outputs.Outputs["wavefront"]().(*Wavefront) + apiTokenWavefront.AuthCSPAPIToken = config.NewSecret([]byte("fake-wavefront-api-token")) + options, err = apiTokenWavefront.makeAuthOptions() + require.NoError(t, err) + require.Equal(t, 1, len(options)) + + noAuthOptionsWavefront := outputs.Outputs["wavefront"]().(*Wavefront) + options, err = noAuthOptionsWavefront.makeAuthOptions() + require.NoError(t, err) + require.Equal(t, 0, len(options)) +} + // Benchmarks to test performance of string replacement via Regex and Sanitize var testString = "this_is*my!test/string\\for=replacement"