diff --git a/CHANGELOG.next.asciidoc b/CHANGELOG.next.asciidoc index ee4c8a0c136..43dde97ea1b 100644 --- a/CHANGELOG.next.asciidoc +++ b/CHANGELOG.next.asciidoc @@ -236,6 +236,7 @@ https://github.com/elastic/beats/compare/v7.0.0-alpha2...master[Check the HEAD d - Remove io.time from windows {pull}22237[22237] - Fix `logstash` module when `xpack.enabled: true` is set from emitting redundant events. {pull}22808[22808] - Change vsphere.datastore.capacity.used.pct value to betweeen 0 and 1. {pull}23148[23148] +- `beat` module respects `basepath` config option. {pull}28162[28162] *Packetbeat* diff --git a/metricbeat/module/beat/beat.go b/metricbeat/module/beat/beat.go index eb4d9b8f724..828e819443e 100644 --- a/metricbeat/module/beat/beat.go +++ b/metricbeat/module/beat/beat.go @@ -21,6 +21,8 @@ import ( "encoding/json" "fmt" "net/url" + "path" + "strings" "github.com/elastic/beats/v7/libbeat/logp" "github.com/elastic/beats/v7/metricbeat/helper" @@ -35,9 +37,11 @@ func init() { } } +var metricSets = []string{"state", "stats"} + // NewModule creates a new module func NewModule(base mb.BaseModule) (mb.Module, error) { - return elastic.NewModule(&base, []string{"state", "stats"}, logp.NewLogger(ModuleName)) + return elastic.NewModule(&base, metricSets, logp.NewLogger(ModuleName)) } // ModuleName is the name of this module. @@ -76,7 +80,7 @@ type State struct { // GetInfo returns the data for the Beat's / endpoint. func GetInfo(m *MetricSet) (*Info, error) { - content, err := fetchPath(m.HTTP, "/", "") + content, err := fetchPath(m.HTTP, "/") if err != nil { return nil, err } @@ -92,7 +96,7 @@ func GetInfo(m *MetricSet) (*Info, error) { // GetState returns the data for the Beat's /state endpoint. func GetState(m *MetricSet) (*State, error) { - content, err := fetchPath(m.HTTP, "/state", "") + content, err := fetchPath(m.HTTP, "/state") if err != nil { return nil, err } @@ -106,16 +110,28 @@ func GetState(m *MetricSet) (*State, error) { return info, nil } -func fetchPath(httpHelper *helper.HTTP, path string, query string) ([]byte, error) { +func fetchPath(httpHelper *helper.HTTP, path string) ([]byte, error) { currentURI := httpHelper.GetURI() defer httpHelper.SetURI(currentURI) // Parses the uri to replace the path - u, _ := url.Parse(currentURI) - u.Path = path - u.RawQuery = query + u, err := url.Parse(currentURI) + if err != nil { + return nil, err + } - // Http helper includes the HostData with username and password - httpHelper.SetURI(u.String()) + // HTTP helper includes the HostData with username and password + httpHelper.SetURI(fetchURI(u, path)) return httpHelper.FetchContent() } + +func fetchURI(u *url.URL, uriPath string) string { + for _, s := range metricSets { + if strings.HasSuffix(u.Path, s) { + u.Path = u.Path[:len(u.Path)-len(s)] + break + } + } + u.Path = path.Join(u.Path, uriPath) + return u.String() +} diff --git a/metricbeat/module/beat/beat_external_test.go b/metricbeat/module/beat/beat_external_test.go new file mode 100644 index 00000000000..d47441b0668 --- /dev/null +++ b/metricbeat/module/beat/beat_external_test.go @@ -0,0 +1,50 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you under +// the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package beat_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + mbtest "github.com/elastic/beats/v7/metricbeat/mb/testing" + "github.com/elastic/beats/v7/metricbeat/module/beat" + + // Make sure metricsets are registered in mb.Registry + _ "github.com/elastic/beats/v7/metricbeat/module/beat/state" + _ "github.com/elastic/beats/v7/metricbeat/module/beat/stats" +) + +func TestXPackEnabledMetricsets(t *testing.T) { + config := map[string]interface{}{ + "module": beat.ModuleName, + "hosts": []string{"foobar:5066"}, + "xpack.enabled": true, + } + + metricSets := mbtest.NewReportingMetricSetV2Errors(t, config) + require.Len(t, metricSets, 2) + for _, ms := range metricSets { + name := ms.Name() + switch name { + case "state", "stats": + default: + t.Errorf("unexpected metricset name = %v", name) + } + } +} diff --git a/metricbeat/module/beat/beat_test.go b/metricbeat/module/beat/beat_test.go index d47441b0668..99a8be6edb0 100644 --- a/metricbeat/module/beat/beat_test.go +++ b/metricbeat/module/beat/beat_test.go @@ -15,36 +15,59 @@ // specific language governing permissions and limitations // under the License. -package beat_test +package beat import ( + "net/url" "testing" "github.com/stretchr/testify/require" - - mbtest "github.com/elastic/beats/v7/metricbeat/mb/testing" - "github.com/elastic/beats/v7/metricbeat/module/beat" - - // Make sure metricsets are registered in mb.Registry - _ "github.com/elastic/beats/v7/metricbeat/module/beat/state" - _ "github.com/elastic/beats/v7/metricbeat/module/beat/stats" + "gotest.tools/assert" ) -func TestXPackEnabledMetricsets(t *testing.T) { - config := map[string]interface{}{ - "module": beat.ModuleName, - "hosts": []string{"foobar:5066"}, - "xpack.enabled": true, +func TestFetchURI(t *testing.T) { + tcs := []struct { + orig, path, want string + }{ + { + orig: "https://localhost:5000/some/proxy/path", + path: "/state", + want: "https://localhost:5000/some/proxy/path/state", + }, { + orig: "https://localhost:5000/some/proxy/path/state", + path: "/state", + want: "https://localhost:5000/some/proxy/path/state", + }, { + orig: "https://localhost:5000/some/proxy/path/state", + path: "/", + want: "https://localhost:5000/some/proxy/path", + }, { + orig: "http://localhost:5000", + path: "/state", + want: "http://localhost:5000/state", + }, { + orig: "http://localhost:5000/state", + path: "/state", + want: "http://localhost:5000/state", + }, { + orig: "http://localhost:5000/stats", + path: "/state", + want: "http://localhost:5000/state", + }, { + orig: "http://localhost:5000/stats", + path: "/", + want: "http://localhost:5000/", + }, { + orig: "http://localhost:5000/state", + path: "/", + want: "http://localhost:5000/", + }, } - metricSets := mbtest.NewReportingMetricSetV2Errors(t, config) - require.Len(t, metricSets, 2) - for _, ms := range metricSets { - name := ms.Name() - switch name { - case "state", "stats": - default: - t.Errorf("unexpected metricset name = %v", name) - } + for _, tc := range tcs { + u, err := url.Parse(tc.orig) + require.NoError(t, err) + got := fetchURI(u, tc.path) + assert.Equal(t, tc.want, got) } }