Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix mongodb multiple hosts connection issue #34624

Merged
merged 30 commits into from
May 24, 2023
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
3dbc304
Fix mongodb multiple hosts connection issue
ritalwar Feb 21, 2023
9a7e6de
Update docker image for mongodb
ritalwar Feb 22, 2023
cc34509
Update status_integration_test.go
ritalwar Feb 23, 2023
784212d
Update changelog
ritalwar Feb 23, 2023
7e26cbc
Merge branch 'main' into mongodb_multihost_32188
ritalwar Feb 23, 2023
533815a
Update doc
ritalwar Feb 23, 2023
dcf38f4
Merge branch 'mongodb_multihost_32188' of github.com:ritalwar/beats i…
ritalwar Feb 23, 2023
2d1cfbf
Update test cases and documentation
ritalwar Mar 10, 2023
7583fef
update doc
ritalwar Mar 10, 2023
95c2d95
Merge branch 'main' into mongodb_multihost_32188
ritalwar Mar 20, 2023
ff1802b
Update mongodb_test.go
ritalwar Apr 3, 2023
8446e2a
Merge branch 'main' into mongodb_multihost_32188
shmsr Apr 19, 2023
a18e20e
Merge branch 'mongodb_multihost_32188' of github.com:ritalwar/beats i…
ritalwar May 2, 2023
3848bd7
code refactoring
ritalwar May 14, 2023
13f218f
Merge branch 'elastic:main' into mongodb_multihost_32188
ritalwar May 14, 2023
6015e27
address review comments
ritalwar May 14, 2023
2d9b929
rebuild
ritalwar May 14, 2023
599f741
fixing test call
ritalwar May 14, 2023
d7bfb1c
Merge branch 'elastic:main' into mongodb_multihost_32188
ritalwar May 15, 2023
67aebdd
Merge branch 'elastic:main' into mongodb_multihost_32188
ritalwar May 16, 2023
e038e88
update docs
ritalwar May 22, 2023
e26cc4f
Merge branch 'mongodb_multihost_32188' of github.com:ritalwar/beats i…
ritalwar May 22, 2023
133b5dc
Merge branch 'elastic:main' into mongodb_multihost_32188
ritalwar May 22, 2023
8393bc2
address comments
ritalwar May 22, 2023
5779448
Merge branch 'mongodb_multihost_32188' of github.com:ritalwar/beats i…
ritalwar May 22, 2023
2ffb0a5
Merge branch 'elastic:main' into mongodb_multihost_32188
ritalwar May 22, 2023
a58e59d
Merge branch 'elastic:main' into mongodb_multihost_32188
ritalwar May 22, 2023
7e6c150
Merge branch 'elastic:main' into mongodb_multihost_32188
ritalwar May 23, 2023
beefe84
Merge branch 'elastic:main' into mongodb_multihost_32188
ritalwar May 23, 2023
82ff724
Merge branch 'elastic:main' into mongodb_multihost_32188
ritalwar May 23, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG-developer.next.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ The list below covers the major changes between 7.0.0-rc2 and main only.
- The beat.cgroup.memory.mem.usage.bytes metric is now a gauge {issue}31582[31582] {pull}32652[32652]
- Fix the integration testcase docker port mapping for sql and oracle modules {pull}34221[34221]
- Fix the ingest pipeline for mysql slowlog to parse schema name with dash {pull}34371[34372]
- Fix the multiple host support for mongodb module {pull}34624[34624]

==== Added

Expand Down
36 changes: 34 additions & 2 deletions metricbeat/docs/modules/mongodb.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ format:
[mongodb://][user:pass@]host[:port][?options]
-----------------------------------

Or

-----------------------------------------------------------------------------------------
mongodb://[username:password@]host1[:port1][,...hostN[:portN]][/[defaultauthdb][?options]]
-----------------------------------------------------------------------------------------

The URL can be as simple as:

[source,yaml]
Expand All @@ -42,6 +48,32 @@ Or more complex like:
hosts: ["mongodb://myuser:mypass@localhost:40001", "otherhost:40001"]
----------------------------------------------------------------------

Some more supported URLs are:

[source,yaml]
----------------------------------------------------------------------
- module: mongodb
hosts: ["mongodb://localhost:27017,localhost:27022,localhost:27023"]
ritalwar marked this conversation as resolved.
Show resolved Hide resolved
----------------------------------------------------------------------

[source,yaml]
----------------------------------------------------------------------
- module: mongodb
hosts: ["mongodb://localhost:27017/?directConnection=true"]
----------------------------------------------------------------------

When the parameter `directConnection=true` is included in the connection URI,
all operations are executed on the host specified in the URI.
It's important to note that `directConnection=true` must be explicitly specified in the URI,
as it won't be added automatically unless specified.

[source,yaml]
----------------------------------------------------------------------
- module: mongodb
hosts: ["mongodb://localhost:27017,localhost:27022,localhost:27023/?replicaSet=dbrs"]
shmsr marked this conversation as resolved.
Show resolved Hide resolved
----------------------------------------------------------------------


The username and password can be included in the URL or they can be set using
the respective configuration options. The credentials in the URL take precedence
over the username and password configuration options.
Expand All @@ -60,8 +92,8 @@ The default metricsets are `collstats`, `dbstats` and `status`.
[float]
=== Compatibility

The MongoDB metricsets were tested with MongoDB 3.4 and 3.0 and are expected to
work with all versions >= 2.8.
The MongoDB metricsets were tested with MongoDB 5.0 and are expected to
work with all versions >= 5.0.

[float]
=== MongoDB Privileges
Expand Down
36 changes: 34 additions & 2 deletions metricbeat/module/mongodb/_meta/docs.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ format:
[mongodb://][user:pass@]host[:port][?options]
-----------------------------------

Or

-----------------------------------------------------------------------------------------
mongodb://[username:password@]host1[:port1][,...hostN[:portN]][/[defaultauthdb][?options]]
-----------------------------------------------------------------------------------------

The URL can be as simple as:

[source,yaml]
Expand All @@ -31,6 +37,32 @@ Or more complex like:
hosts: ["mongodb://myuser:mypass@localhost:40001", "otherhost:40001"]
----------------------------------------------------------------------

Some more supported URLs are:

[source,yaml]
----------------------------------------------------------------------
- module: mongodb
hosts: ["mongodb://localhost:27017,localhost:27022,localhost:27023"]
----------------------------------------------------------------------

[source,yaml]
----------------------------------------------------------------------
- module: mongodb
hosts: ["mongodb://localhost:27017/?directConnection=true"]
----------------------------------------------------------------------

When the parameter `directConnection=true` is included in the connection URI,
all operations are executed on the host specified in the URI.
It's important to note that `directConnection=true` must be explicitly specified in the URI,
as it won't be added automatically unless specified.

[source,yaml]
----------------------------------------------------------------------
- module: mongodb
hosts: ["mongodb://localhost:27017,localhost:27022,localhost:27023/?replicaSet=dbrs"]
----------------------------------------------------------------------


The username and password can be included in the URL or they can be set using
the respective configuration options. The credentials in the URL take precedence
over the username and password configuration options.
Expand All @@ -49,8 +81,8 @@ The default metricsets are `collstats`, `dbstats` and `status`.
[float]
=== Compatibility

The MongoDB metricsets were tested with MongoDB 3.4 and 3.0 and are expected to
work with all versions >= 2.8.
The MongoDB metricsets were tested with MongoDB 5.0 and are expected to
work with all versions >= 5.0.

[float]
=== MongoDB Privileges
Expand Down
2 changes: 1 addition & 1 deletion metricbeat/module/mongodb/collstats/collstats.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func New(base mb.BaseMetricSet) (mb.MetricSet, error) {
// format. It publishes the event which is then forwarded to the output. In case
// of an error set the Error field of mb.Event or simply call report.Error().
func (m *Metricset) Fetch(reporter mb.ReporterV2) error {
client, err := mongodb.NewClient(m.Metricset.Config, m.Module().Config().Timeout, 0)
client, err := mongodb.NewClient(m.Metricset.Config, m.HostData().URI, m.Module().Config().Timeout, 0)
if err != nil {
return fmt.Errorf("could not create mongodb client: %w", err)
}
Expand Down
2 changes: 1 addition & 1 deletion metricbeat/module/mongodb/dbstats/dbstats.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ func New(base mb.BaseMetricSet) (mb.MetricSet, error) {
// format. It publishes the event which is then forwarded to the output. In case
// of an error set the Error field of mb.Event or simply call report.Error().
func (m *MetricSet) Fetch(reporter mb.ReporterV2) error {
client, err := mongodb.NewClient(m.Metricset.Config, m.Module().Config().Timeout, 0)
client, err := mongodb.NewClient(m.Metricset.Config, m.HostData().URI, m.Module().Config().Timeout, 0)
if err != nil {
return fmt.Errorf("could not create mongodb client: %w", err)
}
Expand Down
14 changes: 8 additions & 6 deletions metricbeat/module/mongodb/dbstats/dbstats_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,22 +50,24 @@ func TestFetch(t *testing.T) {
assert.True(t, collections > 0)

objects := metricsetFields["objects"].(int32)
assert.True(t, objects > 0)
assert.True(t, objects >= 0)
shmsr marked this conversation as resolved.
Show resolved Hide resolved

avgObjSize, err := metricsetFields.GetValue("avg_obj_size.bytes")
assert.NoError(t, err)
assert.True(t, avgObjSize.(float64) > 0)
assert.True(t, avgObjSize.(float64) >= 0)

dataSize, err := metricsetFields.GetValue("data_size.bytes")
assert.NoError(t, err)
assert.True(t, dataSize.(float64) > 0)
assert.True(t, dataSize.(float64) >= 0)

storageSize, err := metricsetFields.GetValue("storage_size.bytes")
assert.NoError(t, err)
assert.True(t, storageSize.(float64) > 0)
assert.True(t, storageSize.(float64) >= 0)

numExtents := metricsetFields["num_extents"].(int32)
assert.True(t, numExtents >= 0)
if metricsetFields["num_extents"] != nil {
numExtents := metricsetFields["num_extents"].(int32)
assert.True(t, numExtents >= 0)
}

indexes := metricsetFields["indexes"].(int32)
assert.True(t, indexes >= 0)
Expand Down
9 changes: 4 additions & 5 deletions metricbeat/module/mongodb/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
version: "2.3"
version: '2.3'

services:
mongodb:
image: docker.elastic.co/integrations-ci/beats-mongodb:${MONGODB_VERSION:-3.4}-1
image: docker.elastic.co/integrations-ci/beats-mongodb:${MONGODB_VERSION:-5.0}-1
build:
context: ./_meta
args:
MONGODB_VERSION: "${MONGODB_VERSION:-3.4}"
command: mongod --replSet beats
MONGODB_VERSION: ${MONGODB_VERSION:-5.0}
ports:
- 27017
- 27017:27017
leehinman marked this conversation as resolved.
Show resolved Hide resolved
2 changes: 1 addition & 1 deletion metricbeat/module/mongodb/metrics/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func New(base mb.BaseMetricSet) (mb.MetricSet, error) {
// format. It publishes the event which is then forwarded to the output. In case
// of an error set the Error field of mb.Event or simply call report.Error().
func (m *MetricSet) Fetch(reporter mb.ReporterV2) error {
client, err := mongodb.NewClient(m.Metricset.Config, m.Module().Config().Timeout, 0)
client, err := mongodb.NewClient(m.Metricset.Config, m.HostData().URI, m.Module().Config().Timeout, 0)
if err != nil {
return fmt.Errorf("could not create mongodb client: %w", err)
}
Expand Down
25 changes: 4 additions & 21 deletions metricbeat/module/mongodb/mongodb.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,28 +114,11 @@ func ParseURL(module mb.Module, host string) (mb.HostData, error) {

parse.SetURLUser(u, c.Username, c.Password)

clientOptions := options.Client()
clientOptions.Auth = &options.Credential{
AuthMechanism: c.Credentials.AuthMechanism,
AuthMechanismProperties: c.Credentials.AuthMechanismProperties,
AuthSource: c.Credentials.AuthSource,
PasswordSet: c.Credentials.PasswordSet,
Username: c.Username,
Password: c.Password,
}
clientOptions.SetDirect(true)
shmsr marked this conversation as resolved.
Show resolved Hide resolved
clientOptions.ApplyURI(host)

// https://docs.mongodb.com/manual/reference/connection-string/
_, err = url.Parse(clientOptions.GetURI())
if err != nil {
return mb.HostData{}, fmt.Errorf("error parsing URL: %w", err)
}

return parse.NewHostDataFromURL(u), nil
}

func NewClient(config ModuleConfig, timeout time.Duration, mode readpref.Mode) (*mongo.Client, error) {
func NewClient(config ModuleConfig, uri string, timeout time.Duration, mode readpref.Mode) (*mongo.Client, error) {

clientOptions := options.Client()

// options.Credentials must be nil for the driver to work properly if no auth is provided. Zero values breaks
Expand All @@ -154,7 +137,8 @@ func NewClient(config ModuleConfig, timeout time.Duration, mode readpref.Mode) (
clientOptions.Auth.AuthMechanismProperties = config.Credentials.AuthMechanismProperties
}
}
clientOptions.SetHosts(config.Hosts)

clientOptions.ApplyURI(uri)

if mode == 0 {
mode = readpref.NearestMode
Expand All @@ -165,7 +149,6 @@ func NewClient(config ModuleConfig, timeout time.Duration, mode readpref.Mode) (
return nil, err
}
clientOptions.SetReadPreference(readPreference)
clientOptions.SetDirect(true)
clientOptions.SetConnectTimeout(timeout)

if config.TLS.IsEnabled() {
Expand Down
12 changes: 11 additions & 1 deletion metricbeat/module/mongodb/mongodb_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ func TestParseMongoURL(t *testing.T) {
},
{
Name: "with options",
URL: "mongodb://localhost:40001?connect=direct&authSource=me",
shmsr marked this conversation as resolved.
Show resolved Hide resolved
URL: "mongodb://localhost:40001/directConnection=true&authSource=me",
Username: "anotheruser",
Password: "anotherpass",

Expand All @@ -95,6 +95,16 @@ func TestParseMongoURL(t *testing.T) {
ExpectedUsername: "",
ExpectedPassword: "",
},
{
Name: "with replicaSet option",
URL: "mongodb://localhost:40001,localhost:40002/?replicaSet=dbrs",
Username: "anotheruser",
Password: "anotherpass",

ExpectedAddr: "localhost:40001,localhost:40002",
ExpectedUsername: "anotheruser",
ExpectedPassword: "anotherpass",
},
}
ritalwar marked this conversation as resolved.
Show resolved Hide resolved

for _, test := range tests {
Expand Down
2 changes: 1 addition & 1 deletion metricbeat/module/mongodb/replstatus/replstatus.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ func New(base mb.BaseMetricSet) (mb.MetricSet, error) {
// format. It publishes the event which is then forwarded to the output. In case
// of an error set the Error field of mb.Event or simply call report.Error().
func (m *MetricSet) Fetch(reporter mb.ReporterV2) error {
client, err := mongodb.NewClient(m.Metricset.Config, m.Module().Config().Timeout, readpref.PrimaryMode)
client, err := mongodb.NewClient(m.Metricset.Config, m.HostData().URI, m.Module().Config().Timeout, readpref.PrimaryMode)
if err != nil {
return fmt.Errorf("could not create mongodb client: %w", err)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,10 @@ func getConfig(host string) map[string]interface{} {
}

func initiateReplicaSet(t *testing.T, host string) error {
uri := "mongodb://" + host
client, err := mongodb.NewClient(mongodb.ModuleConfig{
Hosts: []string{host},
}, time.Second*5, readpref.PrimaryMode)
}, uri, time.Second*5, readpref.PrimaryMode)
if err != nil {
return fmt.Errorf("could not create mongodb client: %w", err)
}
Expand Down
2 changes: 1 addition & 1 deletion metricbeat/module/mongodb/status/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func New(base mb.BaseMetricSet) (mb.MetricSet, error) {
// It returns the event which is then forward to the output. In case of an error, a
// descriptive error must be returned.
func (m *MetricSet) Fetch(r mb.ReporterV2) error {
client, err := mongodb.NewClient(m.Metricset.Config, m.Module().Config().Timeout, readpref.PrimaryMode)
client, err := mongodb.NewClient(m.Metricset.Config, m.HostData().URI, m.Module().Config().Timeout, readpref.PrimaryMode)
if err != nil {
return fmt.Errorf("could not create mongodb client: %w", err)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ import (

func TestFetch(t *testing.T) {
service := compose.EnsureUp(t, "mongodb")

f := mbtest.NewReportingMetricSetV2Error(t, getConfig(service.Host()))
events, errs := mbtest.ReportingFetchV2Error(f)

Expand All @@ -52,7 +51,7 @@ func TestFetch(t *testing.T) {
assert.True(t, available.(int32) > 0)

pageFaults, _ := event.GetValue("mongodb.status.extra_info.page_faults")
assert.True(t, pageFaults.(int32) >= 0)
assert.True(t, pageFaults.(int64) >= 0)
}

func TestData(t *testing.T) {
Expand Down