From f6ece6ad51d39cf62764012f55d333ce162ae8f3 Mon Sep 17 00:00:00 2001 From: shalper2 <99686388+shalper2@users.noreply.github.com> Date: Mon, 16 Oct 2023 12:26:18 -0500 Subject: [PATCH] Splunkent client refactor (#27205) Refactored parts of the Splunk Enterprise receiver to better leverage the pre-existing otel SDK. This PR also updates the README to be a more informative document. [27026](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/27026) Unit testing is included and updated to accommodate the new refactor. --- .../splunkent-client-refactor-with-sdk.yaml | 28 +++++ receiver/splunkenterprisereceiver/README.md | 39 ++++++- receiver/splunkenterprisereceiver/client.go | 46 ++------ .../splunkenterprisereceiver/client_test.go | 94 ++++++++++----- receiver/splunkenterprisereceiver/config.go | 22 +--- .../splunkenterprisereceiver/config_test.go | 110 +----------------- receiver/splunkenterprisereceiver/factory.go | 12 +- .../splunkenterprisereceiver/factory_test.go | 10 +- receiver/splunkenterprisereceiver/go.mod | 6 +- receiver/splunkenterprisereceiver/scraper.go | 14 ++- .../splunkenterprisereceiver/scraper_test.go | 23 +++- .../testdata/config.yaml | 12 +- 12 files changed, 203 insertions(+), 213 deletions(-) create mode 100644 .chloggen/splunkent-client-refactor-with-sdk.yaml diff --git a/.chloggen/splunkent-client-refactor-with-sdk.yaml b/.chloggen/splunkent-client-refactor-with-sdk.yaml new file mode 100644 index 000000000000..05df9fb04d5d --- /dev/null +++ b/.chloggen/splunkent-client-refactor-with-sdk.yaml @@ -0,0 +1,28 @@ +# Use this changelog template to create an entry for release notes. + +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: 'enhancement' + +# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver) +component: splunkentreceiver + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: "Users can now use auth settings and basicauth extension to connect to their Splunk enterprise deployments" + +# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. +issues: [27026] + +# (Optional) One or more lines of additional information to render under the primary note. +# These lines will be padded with 2 spaces and then inserted directly into the document. +# Use pipe (|) for multiline entries. +subtext: + +# If your change doesn't affect end users or the exported elements of any package, +# you should instead start your pull request title with [chore] or use the "Skip Changelog" label. +# Optional: The change log or logs in which this entry should be included. +# e.g. '[user]' or '[user, api]' +# Include 'user' if the change is relevant to end users. +# Include 'api' if there is a change to a library API. +# Default: '[user]' +change_logs: [user] + diff --git a/receiver/splunkenterprisereceiver/README.md b/receiver/splunkenterprisereceiver/README.md index 15ab877aef4e..e45319366868 100644 --- a/receiver/splunkenterprisereceiver/README.md +++ b/receiver/splunkenterprisereceiver/README.md @@ -1,5 +1,38 @@ # Splunk Enterprise Receiver ---- -The Splunk Enterprise Receiver is a pull based tool which enables the ingestion of key performance metrics (KPI's) describing the operational status of a user's Splunk Enterprise deployment to be -added to their OpenTelemetry Pipeline. +The Splunk Enterprise Receiver is a pull based tool which enables the ingestion of performance metrics describing the operational status of a user's Splunk Enterprise deployment to an appropriate observability tool. +It is designed to leverage several different data sources to gather these metrics including the [introspection api endpoint](https://docs.splunk.com/Documentation/Splunk/9.1.1/RESTREF/RESTintrospect) and serializing +results from ad-hoc searches. Because of this, care must be taken by users when enabling metrics as running searches can effect your Splunk Enterprise Deployment and introspection may fail to report for Splunk +Cloud deployments. The primary purpose of this receiver is to empower those tasked with the maintenance and care of a Splunk Enterprise deployment to leverage opentelemetry and their observability toolset in their +jobs. + +## Configuration + +The following settings are required, omitting them will either cause your receiver to fail to compile or result in 4/5xx return codes during scraping. + +* `basicauth` (from [basicauthextension](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/extension/basicauthextension)): A configured stanza for the basicauthextension. +* `auth` (no default): String name referencing your auth extension. +* `endpoint` (no default): your Splunk Enterprise host's endpoint. + +The following settings are optional: + +* `collection_interval` (default: 10m): The time between scrape attempts. +* `timeout` (default: 60s): The time the scrape function will wait for a response before returning empty. + +Example: + +```yaml +extensions: + basicauth/client: + client_auth: + username: admin + password: securityFirst + +receivers: + splunkenterprise: + auth: basicauth/client + endpoint: "https://localhost:8089" + timeout: 45s +``` + +For a full list of settings exposed by this receiver please look [here](./config.go) with a detailed configuration [here](./testdata/config.yaml). diff --git a/receiver/splunkenterprisereceiver/client.go b/receiver/splunkenterprisereceiver/client.go index 46e4713a14f3..10381be94eea 100644 --- a/receiver/splunkenterprisereceiver/client.go +++ b/receiver/splunkenterprisereceiver/client.go @@ -5,41 +5,31 @@ package splunkenterprisereceiver // import "github.com/open-telemetry/openteleme import ( "context" - "crypto/tls" - "encoding/base64" "fmt" "net/http" "net/url" "strings" + + "go.opentelemetry.io/collector/component" ) type splunkEntClient struct { - endpoint *url.URL - client *http.Client - basicAuth string + client *http.Client + endpoint *url.URL } -func newSplunkEntClient(cfg *Config) splunkEntClient { - // tls party - tr := &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, +func newSplunkEntClient(cfg *Config, h component.Host, s component.TelemetrySettings) (*splunkEntClient, error) { + client, err := cfg.HTTPClientSettings.ToClient(h, s) + if err != nil { + return nil, err } - client := &http.Client{Transport: tr} - endpoint, _ := url.Parse(cfg.Endpoint) - // build and encode our auth string. Do this work once to avoid rebuilding the - // auth header every time we make a new request - authString := fmt.Sprintf("%s:%s", cfg.Username, cfg.Password) - auth64 := base64.StdEncoding.EncodeToString([]byte(authString)) - basicAuth := fmt.Sprintf("Basic %s", auth64) - - return splunkEntClient{ - client: client, - endpoint: endpoint, - basicAuth: basicAuth, - } + return &splunkEntClient{ + client: client, + endpoint: endpoint, + }, nil } // For running ad hoc searches only @@ -59,10 +49,6 @@ func (c *splunkEntClient) createRequest(ctx context.Context, sr *searchResponse) return nil, err } - // Required headers - req.Header.Add("Authorization", c.basicAuth) - req.Header.Add("Content-Type", "application/x-www-form-urlencoded") - return req, nil } path := fmt.Sprintf("/services/search/jobs/%s/results", *sr.Jobid) @@ -73,10 +59,6 @@ func (c *splunkEntClient) createRequest(ctx context.Context, sr *searchResponse) return nil, err } - // Required headers - req.Header.Add("Authorization", c.basicAuth) - req.Header.Add("Content-Type", "application/x-www-form-urlencoded") - return req, nil } @@ -88,10 +70,6 @@ func (c *splunkEntClient) createAPIRequest(ctx context.Context, apiEndpoint stri return nil, err } - // Required headers - req.Header.Add("Authorization", c.basicAuth) - req.Header.Add("Content-Type", "application/x-www-form-urlencoded") - return req, nil } diff --git a/receiver/splunkenterprisereceiver/client_test.go b/receiver/splunkenterprisereceiver/client_test.go index be60bc608c8d..51fca704c346 100644 --- a/receiver/splunkenterprisereceiver/client_test.go +++ b/receiver/splunkenterprisereceiver/client_test.go @@ -5,7 +5,6 @@ package splunkenterprisereceiver // import "github.com/open-telemetry/openteleme import ( "context" - "encoding/base64" "fmt" "net/http" "net/url" @@ -14,58 +13,87 @@ import ( "time" "github.com/stretchr/testify/require" + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/component/componenttest" + "go.opentelemetry.io/collector/config/configauth" "go.opentelemetry.io/collector/config/confighttp" + "go.opentelemetry.io/collector/extension/auth" "go.opentelemetry.io/collector/receiver/scraperhelper" ) +// mockHost allows us to create a test host with a no op extension that can be used to satisfy the SDK without having to parse from an +// actual config.yaml. +type mockHost struct { + component.Host + extensions map[component.ID]component.Component +} + +func (m *mockHost) GetExtensions() map[component.ID]component.Component { + return m.extensions +} + func TestClientCreation(t *testing.T) { - // create a client from an example config - client := newSplunkEntClient(&Config{ - Username: "admin", - Password: "securityFirst", - MaxSearchWaitTime: 11 * time.Second, + cfg := &Config{ HTTPClientSettings: confighttp.HTTPClientSettings{ Endpoint: "https://localhost:8089", + Auth: &configauth.Authentication{ + AuthenticatorID: component.NewID("basicauth/client"), + }, }, ScraperControllerSettings: scraperhelper.ScraperControllerSettings{ CollectionInterval: 10 * time.Second, InitialDelay: 1 * time.Second, + Timeout: 11 * time.Second, }, - }) + } - testEndpoint, _ := url.Parse("https://localhost:8089") + host := &mockHost{ + extensions: map[component.ID]component.Component{ + component.NewID("basicauth/client"): auth.NewClient(), + }, + } + // create a client from an example config + client, err := newSplunkEntClient(cfg, host, componenttest.NewNopTelemetrySettings()) + require.NoError(t, err) - authString := fmt.Sprintf("%s:%s", "admin", "securityFirst") - auth64 := base64.StdEncoding.EncodeToString([]byte(authString)) - testBasicAuth := fmt.Sprintf("Basic %s", auth64) + testEndpoint, _ := url.Parse("https://localhost:8089") require.Equal(t, client.endpoint, testEndpoint) - require.Equal(t, client.basicAuth, testBasicAuth) } // test functionality of createRequest which is used for building metrics out of // ad-hoc searches func TestClientCreateRequest(t *testing.T) { - // create a client from an example config - client := newSplunkEntClient(&Config{ - Username: "admin", - Password: "securityFirst", - MaxSearchWaitTime: 11 * time.Second, + cfg := &Config{ HTTPClientSettings: confighttp.HTTPClientSettings{ Endpoint: "https://localhost:8089", + Auth: &configauth.Authentication{ + AuthenticatorID: component.NewID("basicauth/client"), + }, }, ScraperControllerSettings: scraperhelper.ScraperControllerSettings{ CollectionInterval: 10 * time.Second, InitialDelay: 1 * time.Second, + Timeout: 11 * time.Second, }, - }) + } + + host := &mockHost{ + extensions: map[component.ID]component.Component{ + component.NewID("basicauth/client"): auth.NewClient(), + }, + } + // create a client from an example config + client, err := newSplunkEntClient(cfg, host, componenttest.NewNopTelemetrySettings()) + + require.NoError(t, err) testJobID := "123" tests := []struct { desc string sr *searchResponse - client splunkEntClient + client *splunkEntClient expected *http.Request }{ { @@ -81,8 +109,6 @@ func TestClientCreateRequest(t *testing.T) { url, _ := url.JoinPath(testEndpoint.String(), path) data := strings.NewReader("example search") req, _ := http.NewRequest(method, url, data) - req.Header.Add("Authorization", client.basicAuth) - req.Header.Add("Content-Type", "application/x-www-form-urlencoded") return req }(), }, @@ -99,8 +125,6 @@ func TestClientCreateRequest(t *testing.T) { testEndpoint, _ := url.Parse("https://localhost:8089") url, _ := url.JoinPath(testEndpoint.String(), path) req, _ := http.NewRequest(method, url, nil) - req.Header.Add("Authorization", client.basicAuth) - req.Header.Add("Content-Type", "application/x-www-form-urlencoded") return req }(), }, @@ -122,27 +146,37 @@ func TestClientCreateRequest(t *testing.T) { // createAPIRequest creates a request for api calls i.e. to introspection endpoint func TestAPIRequestCreate(t *testing.T) { - client := newSplunkEntClient(&Config{ - Username: "admin", - Password: "securityFirst", - MaxSearchWaitTime: 11 * time.Second, + cfg := &Config{ HTTPClientSettings: confighttp.HTTPClientSettings{ Endpoint: "https://localhost:8089", + Auth: &configauth.Authentication{ + AuthenticatorID: component.NewID("basicauth/client"), + }, }, ScraperControllerSettings: scraperhelper.ScraperControllerSettings{ CollectionInterval: 10 * time.Second, InitialDelay: 1 * time.Second, + Timeout: 11 * time.Second, }, - }) + } + + host := &mockHost{ + extensions: map[component.ID]component.Component{ + component.NewID("basicauth/client"): auth.NewClient(), + }, + } + // create a client from an example config + client, err := newSplunkEntClient(cfg, host, componenttest.NewNopTelemetrySettings()) + + require.NoError(t, err) ctx := context.Background() req, err := client.createAPIRequest(ctx, "/test/endpoint") require.NoError(t, err) + // build the expected request expectedURL := client.endpoint.String() + "/test/endpoint" expected, _ := http.NewRequest(http.MethodGet, expectedURL, nil) - expected.Header.Add("Authorization", client.basicAuth) - expected.Header.Add("Content-Type", "application/x-www-form-urlencoded") require.Equal(t, expected.URL, req.URL) require.Equal(t, expected.Method, req.Method) diff --git a/receiver/splunkenterprisereceiver/config.go b/receiver/splunkenterprisereceiver/config.go index 48546777b71d..62c87d01c5ce 100644 --- a/receiver/splunkenterprisereceiver/config.go +++ b/receiver/splunkenterprisereceiver/config.go @@ -7,7 +7,6 @@ import ( "errors" "net/url" "strings" - "time" "go.opentelemetry.io/collector/config/confighttp" "go.opentelemetry.io/collector/receiver/scraperhelper" @@ -17,22 +16,15 @@ import ( ) var ( - errBadOrMissingEndpoint = errors.New("Missing a valid endpoint") - errMissingUsername = errors.New("Missing valid username") - errMissingPassword = errors.New("Missing valid password") - errBadScheme = errors.New("Endpoint scheme must be either http or https") + errBadOrMissingEndpoint = errors.New("missing a valid endpoint") + errBadScheme = errors.New("endpoint scheme must be either http or https") + errMissingAuthExtension = errors.New("auth extension missing from config") ) type Config struct { confighttp.HTTPClientSettings `mapstructure:",squash"` scraperhelper.ScraperControllerSettings `mapstructure:",squash"` metadata.MetricsBuilderConfig `mapstructure:",squash"` - // Username and password with associated with an account with - // permission to access the Splunk deployments REST api - Username string `mapstructure:"username"` - Password string `mapstructure:"password"` - // default is 60s - MaxSearchWaitTime time.Duration `mapstructure:"max_search_wait_time"` } func (cfg *Config) Validate() (errors error) { @@ -54,12 +46,8 @@ func (cfg *Config) Validate() (errors error) { } } - if cfg.Username == "" { - errors = multierr.Append(errors, errMissingUsername) - } - - if cfg.Password == "" { - errors = multierr.Append(errors, errMissingPassword) + if cfg.HTTPClientSettings.Auth.AuthenticatorID.Name() == "" { + errors = multierr.Append(errors, errMissingAuthExtension) } return errors diff --git a/receiver/splunkenterprisereceiver/config_test.go b/receiver/splunkenterprisereceiver/config_test.go index 264f9b745f32..8079fc04a3e0 100644 --- a/receiver/splunkenterprisereceiver/config_test.go +++ b/receiver/splunkenterprisereceiver/config_test.go @@ -6,126 +6,22 @@ package splunkenterprisereceiver // import "github.com/open-telemetry/openteleme import ( "path/filepath" "testing" - "time" - "github.com/google/go-cmp/cmp" - "github.com/google/go-cmp/cmp/cmpopts" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" - "go.opentelemetry.io/collector/config/confighttp" "go.opentelemetry.io/collector/confmap/confmaptest" - "go.opentelemetry.io/collector/receiver/scraperhelper" - "go.uber.org/multierr" "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/splunkenterprisereceiver/internal/metadata" ) -func TestValidateConfig(t *testing.T) { - t.Parallel() - - var multipleErrors error - - multipleErrors = multierr.Combine(multipleErrors, errBadOrMissingEndpoint, errMissingUsername, errMissingPassword) - - tests := []struct { - desc string - expect error - conf Config - }{ - { - desc: "Missing password", - expect: errMissingPassword, - conf: Config{ - Username: "admin", - HTTPClientSettings: confighttp.HTTPClientSettings{ - Endpoint: "https://localhost:8089", - }, - }, - }, - { - desc: "Missing username", - expect: errMissingUsername, - conf: Config{ - Password: "securityFirst", - HTTPClientSettings: confighttp.HTTPClientSettings{ - Endpoint: "https://localhost:8089", - }, - }, - }, - { - desc: "Bad scheme (none http/s)", - expect: errBadScheme, - conf: Config{ - Password: "securityFirst", - Username: "admin", - HTTPClientSettings: confighttp.HTTPClientSettings{ - Endpoint: "localhost:8089", - }, - }, - }, - { - desc: "Missing endpoint", - expect: errBadOrMissingEndpoint, - conf: Config{ - Username: "admin", - Password: "securityFirst", - }, - }, - { - desc: "Missing multiple", - expect: multipleErrors, - conf: Config{}, - }, - } - - for i := range tests { - test := tests[i] - - t.Run(test.desc, func(t *testing.T) { - t.Parallel() - - err := test.conf.Validate() - require.Error(t, err) - require.Contains(t, err.Error(), test.expect.Error()) - }) - } -} - +// Since there are no custom fields in config the existing tests for the components should +// cover the testing requirement. func TestLoadConfig(t *testing.T) { t.Parallel() cm, err := confmaptest.LoadConf(filepath.Join("testdata", "config.yaml")) require.NoError(t, err) id := component.NewID(metadata.Type) - cmSub, err := cm.Sub(id.String()) + _, err = cm.Sub(id.String()) require.NoError(t, err) - - testmetrics := metadata.DefaultMetricsBuilderConfig() - testmetrics.Metrics.SplunkLicenseIndexUsage.Enabled = true - testmetrics.Metrics.SplunkIndexerThroughput.Enabled = false - - expected := &Config{ - Username: "admin", - Password: "securityFirst", - MaxSearchWaitTime: 11 * time.Second, - HTTPClientSettings: confighttp.HTTPClientSettings{ - Endpoint: "https://localhost:8089", - }, - ScraperControllerSettings: scraperhelper.ScraperControllerSettings{ - CollectionInterval: 10 * time.Second, - InitialDelay: 1 * time.Second, - }, - MetricsBuilderConfig: testmetrics, - } - - factory := NewFactory() - cfg := factory.CreateDefaultConfig() - - require.NoError(t, component.UnmarshalConfig(cmSub, cfg)) - require.NoError(t, component.ValidateConfig(cfg)) - - diff := cmp.Diff(expected, cfg, cmpopts.IgnoreUnexported(metadata.MetricConfig{})) - if diff != "" { - t.Errorf("config mismatch (-expected / +actual)\n%s", diff) - } } diff --git a/receiver/splunkenterprisereceiver/factory.go b/receiver/splunkenterprisereceiver/factory.go index c956e99b9508..51882aff0cd8 100644 --- a/receiver/splunkenterprisereceiver/factory.go +++ b/receiver/splunkenterprisereceiver/factory.go @@ -8,6 +8,8 @@ import ( "time" "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/config/confighttp" + "go.opentelemetry.io/collector/config/configopaque" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/receiver" "go.opentelemetry.io/collector/receiver/scraperhelper" @@ -21,13 +23,21 @@ const ( ) func createDefaultConfig() component.Config { + // Default HttpClient settings + httpCfg := confighttp.NewDefaultHTTPClientSettings() + httpCfg.Headers = map[string]configopaque.String{ + "Content-Type": "application/x-www-form-urlencoded", + } + + // Default ScraperController settings scfg := scraperhelper.NewDefaultScraperControllerSettings(metadata.Type) scfg.CollectionInterval = defaultInterval + scfg.Timeout = defaultMaxSearchWaitTime return &Config{ + HTTPClientSettings: httpCfg, ScraperControllerSettings: scfg, MetricsBuilderConfig: metadata.DefaultMetricsBuilderConfig(), - MaxSearchWaitTime: defaultMaxSearchWaitTime, } } diff --git a/receiver/splunkenterprisereceiver/factory_test.go b/receiver/splunkenterprisereceiver/factory_test.go index 4df2a00d471b..866b512fce63 100644 --- a/receiver/splunkenterprisereceiver/factory_test.go +++ b/receiver/splunkenterprisereceiver/factory_test.go @@ -9,6 +9,8 @@ import ( "time" "github.com/stretchr/testify/require" + "go.opentelemetry.io/collector/config/confighttp" + "go.opentelemetry.io/collector/config/configopaque" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/receiver/receivertest" "go.opentelemetry.io/collector/receiver/scraperhelper" @@ -22,11 +24,17 @@ func TestFactoryCreate(t *testing.T) { } func TestDefaultConfig(t *testing.T) { + cfg := confighttp.NewDefaultHTTPClientSettings() + cfg.Headers = map[string]configopaque.String{ + "Content-Type": "application/x-www-form-urlencoded", + } + expectedConf := &Config{ - MaxSearchWaitTime: 60 * time.Second, + HTTPClientSettings: cfg, ScraperControllerSettings: scraperhelper.ScraperControllerSettings{ CollectionInterval: 10 * time.Minute, InitialDelay: 1 * time.Second, + Timeout: 60 * time.Second, }, MetricsBuilderConfig: metadata.DefaultMetricsBuilderConfig(), } diff --git a/receiver/splunkenterprisereceiver/go.mod b/receiver/splunkenterprisereceiver/go.mod index 33d10175065f..a7bb769d3554 100644 --- a/receiver/splunkenterprisereceiver/go.mod +++ b/receiver/splunkenterprisereceiver/go.mod @@ -8,9 +8,12 @@ require ( github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest v0.87.0 github.com/stretchr/testify v1.8.4 go.opentelemetry.io/collector/component v0.87.0 + go.opentelemetry.io/collector/config/configauth v0.87.0 go.opentelemetry.io/collector/config/confighttp v0.87.0 + go.opentelemetry.io/collector/config/configopaque v0.87.0 go.opentelemetry.io/collector/confmap v0.87.0 go.opentelemetry.io/collector/consumer v0.87.0 + go.opentelemetry.io/collector/extension/auth v0.87.0 go.opentelemetry.io/collector/pdata v1.0.0-rcv0016 go.opentelemetry.io/collector/receiver v0.87.0 go.uber.org/multierr v1.11.0 @@ -42,14 +45,11 @@ require ( github.com/rs/cors v1.10.1 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/collector v0.87.0 // indirect - go.opentelemetry.io/collector/config/configauth v0.87.0 // indirect go.opentelemetry.io/collector/config/configcompression v0.87.0 // indirect - go.opentelemetry.io/collector/config/configopaque v0.87.0 // indirect go.opentelemetry.io/collector/config/configtelemetry v0.87.0 // indirect go.opentelemetry.io/collector/config/configtls v0.87.0 // indirect go.opentelemetry.io/collector/config/internal v0.87.0 // indirect go.opentelemetry.io/collector/extension v0.87.0 // indirect - go.opentelemetry.io/collector/extension/auth v0.87.0 // indirect go.opentelemetry.io/collector/featuregate v1.0.0-rcv0016 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 // indirect go.opentelemetry.io/otel v1.19.0 // indirect diff --git a/receiver/splunkenterprisereceiver/scraper.go b/receiver/splunkenterprisereceiver/scraper.go index 9fe3dd6b21a8..8cbe50cbb7ec 100644 --- a/receiver/splunkenterprisereceiver/scraper.go +++ b/receiver/splunkenterprisereceiver/scraper.go @@ -24,7 +24,7 @@ import ( ) var ( - errMaxSearchWaitTimeExceeded = errors.New("Maximum search wait time exceeded for metric") + errMaxSearchWaitTimeExceeded = errors.New("maximum search wait time exceeded for metric") ) type splunkScraper struct { @@ -43,9 +43,12 @@ func newSplunkMetricsScraper(params receiver.CreateSettings, cfg *Config) splunk } // Create a client instance and add to the splunkScraper -func (s *splunkScraper) start(_ context.Context, _ component.Host) (err error) { - c := newSplunkEntClient(s.conf) - s.splunkClient = &c +func (s *splunkScraper) start(_ context.Context, h component.Host) (err error) { + client, err := newSplunkEntClient(s.conf, h, s.settings) + if err != nil { + return err + } + s.splunkClient = client return nil } @@ -105,7 +108,6 @@ func (s *splunkScraper) scrapeLicenseUsageByIndex(ctx context.Context, now pcomm err = unmarshallSearchReq(res, &sr) if err != nil { errs.Add(err) - return } res.Body.Close() @@ -119,7 +121,7 @@ func (s *splunkScraper) scrapeLicenseUsageByIndex(ctx context.Context, now pcomm time.Sleep(2 * time.Second) } - if time.Since(start) > s.conf.MaxSearchWaitTime { + if time.Since(start) > s.conf.ScraperControllerSettings.Timeout { errs.Add(errMaxSearchWaitTimeExceeded) return } diff --git a/receiver/splunkenterprisereceiver/scraper_test.go b/receiver/splunkenterprisereceiver/scraper_test.go index f39e59494416..201aba5a20af 100644 --- a/receiver/splunkenterprisereceiver/scraper_test.go +++ b/receiver/splunkenterprisereceiver/scraper_test.go @@ -13,7 +13,11 @@ import ( "time" "github.com/stretchr/testify/require" + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/component/componenttest" + "go.opentelemetry.io/collector/config/configauth" "go.opentelemetry.io/collector/config/confighttp" + "go.opentelemetry.io/collector/extension/auth" "go.opentelemetry.io/collector/receiver/receivertest" "go.opentelemetry.io/collector/receiver/scraperhelper" @@ -80,24 +84,31 @@ func TestScraper(t *testing.T) { metricsettings.Metrics.SplunkServerIntrospectionQueuesCurrentBytes.Enabled = true cfg := &Config{ - Username: "admin", - Password: "securityFirst", - MaxSearchWaitTime: 11 * time.Second, HTTPClientSettings: confighttp.HTTPClientSettings{ Endpoint: ts.URL, + Auth: &configauth.Authentication{ + AuthenticatorID: component.NewID("basicauth/client"), + }, }, ScraperControllerSettings: scraperhelper.ScraperControllerSettings{ CollectionInterval: 10 * time.Second, InitialDelay: 1 * time.Second, + Timeout: 11 * time.Second, }, MetricsBuilderConfig: metricsettings, } - require.NoError(t, cfg.Validate()) + host := &mockHost{ + extensions: map[component.ID]component.Component{ + component.NewID("basicauth/client"): auth.NewClient(), + }, + } scraper := newSplunkMetricsScraper(receivertest.NewNopCreateSettings(), cfg) - client := newSplunkEntClient(cfg) - scraper.splunkClient = &client + client, err := newSplunkEntClient(cfg, host, componenttest.NewNopTelemetrySettings()) + require.NoError(t, err) + + scraper.splunkClient = client actualMetrics, err := scraper.scrape(context.Background()) require.NoError(t, err) diff --git a/receiver/splunkenterprisereceiver/testdata/config.yaml b/receiver/splunkenterprisereceiver/testdata/config.yaml index ba27c230bf44..48bf9742b416 100644 --- a/receiver/splunkenterprisereceiver/testdata/config.yaml +++ b/receiver/splunkenterprisereceiver/testdata/config.yaml @@ -1,13 +1,15 @@ # Example config for the Splunk Enterprise Receiver. +basicauth/client: + client_auth: + username: admin + password: securityFirst splunkenterprise: # required settings - username: "admin" - password: "securityFirst" - endpoint: "https://localhost:8089" - # Optional settings + auth: basicauth/client # must use basicauthextension + endpoint: "https://localhost:8089" # Optional settings collection_interval: 10s - max_search_wait_time: 11s + timeout: 11s # Also optional: metric settings metrics: splunk.license.index.usage: