From 59241f62c59ebb3f08ecf2013c5706d9240391d7 Mon Sep 17 00:00:00 2001 From: Dudi Dolev Date: Sun, 19 Jan 2025 18:20:10 +0200 Subject: [PATCH] Fix: Exporter not initiating connection to mongo when Unauthorized --- exporter/currentop_collector.go | 8 +++++++ exporter/dbstats_collector.go | 7 +++++++ exporter/diagnostic_data_collector.go | 14 ++++++++++++- ...feature_compatibility_version_collector.go | 7 +++++++ exporter/replset_status_collector.go | 6 ++++++ exporter/top_collector.go | 7 +++++++ exporter/topology_info.go | 13 ++++++++++++ exporter/v1_compatibility.go | 19 +++++++++++++++++ internal/util/util.go | 21 +++++++++++++++++++ 9 files changed, 101 insertions(+), 1 deletion(-) diff --git a/exporter/currentop_collector.go b/exporter/currentop_collector.go index b93316e96..79f4b246c 100644 --- a/exporter/currentop_collector.go +++ b/exporter/currentop_collector.go @@ -19,6 +19,7 @@ import ( "context" "strconv" "time" + "os" "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" @@ -90,6 +91,13 @@ func (d *currentopCollector) collect(ch chan<- prometheus.Metric) { var r primitive.M if err := res.Decode(&r); err != nil { + if e, ok := err.(mongo.CommandError); ok { + if e.Code == Unauthorized { + logger.Errorf("unauthorized to run currtop: %s", err) + os.Exit(1) + } + } + logger.Errorf("Failed to decode currentOp response: %s", err) ch <- prometheus.NewInvalidMetric(prometheus.NewInvalidDesc(err), err) return diff --git a/exporter/dbstats_collector.go b/exporter/dbstats_collector.go index b43141456..846e5616e 100644 --- a/exporter/dbstats_collector.go +++ b/exporter/dbstats_collector.go @@ -17,6 +17,7 @@ package exporter import ( "context" + "os" "github.com/prometheus/client_golang/prometheus" "github.com/sirupsen/logrus" @@ -84,6 +85,12 @@ func (d *dbstatsCollector) collect(ch chan<- prometheus.Metric) { r := client.Database(db).RunCommand(d.ctx, cmd) err := r.Decode(&dbStats) if err != nil { + if e, ok := err.(mongo.CommandError); ok { + if e.Code == Unauthorized { + logger.Errorf("unauthorized to run replSetGetStatus: %s", err) + os.Exit(1) + } + } logger.Errorf("Failed to get $dbstats for database %s: %s", db, err) continue diff --git a/exporter/diagnostic_data_collector.go b/exporter/diagnostic_data_collector.go index 3fb322bdc..c6c5a9f00 100644 --- a/exporter/diagnostic_data_collector.go +++ b/exporter/diagnostic_data_collector.go @@ -17,7 +17,7 @@ package exporter import ( "context" - + "os" "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "github.com/sirupsen/logrus" @@ -94,6 +94,12 @@ func (d *diagnosticDataCollector) collect(ch chan<- prometheus.Metric) { } } else { if err := res.Decode(&m); err != nil { + if e, ok := err.(mongo.CommandError); ok { + if e.Code == Unauthorized { + logger.Errorf("unauthorized to run getDiagnosticData: %s", err) + os.Exit(1) + } + } logger.Errorf("cannot run getDiagnosticData: %s", err) return } @@ -163,6 +169,12 @@ func (d *diagnosticDataCollector) getSecurityMetricFromLineOptions(client *mongo return nil, errors.Wrap(resCmdLineOptions.Err(), "cannot execute getCmdLineOpts command") } if err := resCmdLineOptions.Decode(&cmdLineOpionsBson); err != nil { + if e, ok := err.(mongo.CommandError); ok { + if e.Code == Unauthorized { + errors.New("unauthorized to run getCmdLineOpts") + os.Exit(1) + } + } return nil, errors.Wrap(err, "cannot parse response of the getCmdLineOpts command") } diff --git a/exporter/feature_compatibility_version_collector.go b/exporter/feature_compatibility_version_collector.go index 871544c6c..1b4104cb6 100644 --- a/exporter/feature_compatibility_version_collector.go +++ b/exporter/feature_compatibility_version_collector.go @@ -19,6 +19,7 @@ import ( "context" "fmt" "strconv" + "os" "github.com/prometheus/client_golang/prometheus" "github.com/sirupsen/logrus" @@ -61,6 +62,12 @@ func (d *featureCompatibilityCollector) collect(ch chan<- prometheus.Metric) { if err := res.Decode(&m); err != nil { d.base.logger.Errorf("Failed to decode featureCompatibilityVersion: %v", err) ch <- prometheus.NewInvalidMetric(prometheus.NewInvalidDesc(err), err) + if e, ok := err.(mongo.CommandError); ok { + if e.Code == Unauthorized { + d.base.logger.Errorf("Failed to decode featureCompatibilityVersion: %v", err) + os.Exit(1) + } + } return } diff --git a/exporter/replset_status_collector.go b/exporter/replset_status_collector.go index afbbd6d39..be305007d 100644 --- a/exporter/replset_status_collector.go +++ b/exporter/replset_status_collector.go @@ -17,6 +17,7 @@ package exporter import ( "context" + "os" "github.com/prometheus/client_golang/prometheus" "github.com/sirupsen/logrus" @@ -27,6 +28,7 @@ import ( const ( replicationNotEnabled = 76 replicationNotYetInitialized = 94 + Unauthorized = 13 ) type replSetGetStatusCollector struct { @@ -72,6 +74,10 @@ func (d *replSetGetStatusCollector) collect(ch chan<- prometheus.Metric) { if e.Code == replicationNotYetInitialized || e.Code == replicationNotEnabled { return } + if e.Code == Unauthorized { + logger.Errorf("unauthorized to run replSetGetStatus: %s", err) + os.Exit(1) + } } logger.Errorf("cannot get replSetGetStatus: %s", err) diff --git a/exporter/top_collector.go b/exporter/top_collector.go index 562a28ec6..0b6b7ae99 100644 --- a/exporter/top_collector.go +++ b/exporter/top_collector.go @@ -18,6 +18,7 @@ package exporter import ( "context" "fmt" + "os" "github.com/prometheus/client_golang/prometheus" "github.com/sirupsen/logrus" @@ -66,6 +67,12 @@ func (d *topCollector) collect(ch chan<- prometheus.Metric) { var m primitive.M if err := res.Decode(&m); err != nil { + if e, ok := err.(mongo.CommandError); ok { + if e.Code == Unauthorized { + logger.Errorf("unauthorized to run top command") + os.Exit(1) + } + } ch <- prometheus.NewInvalidMetric(prometheus.NewInvalidDesc(err), err) return } diff --git a/exporter/topology_info.go b/exporter/topology_info.go index 08d05d841..a76864772 100644 --- a/exporter/topology_info.go +++ b/exporter/topology_info.go @@ -19,6 +19,7 @@ import ( "context" "fmt" "sync" + "os" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -143,6 +144,12 @@ func getNodeType(ctx context.Context, client *mongo.Client) (mongoDBNodeType, er } md := proto.MasterDoc{} if err := client.Database("admin").RunCommand(ctx, primitive.M{"isMaster": 1}).Decode(&md); err != nil { + if e, ok := err.(mongo.CommandError); ok { + if e.Code == Unauthorized { + errors.New("unauthorized to getisMaster") + os.Exit(1) + } + } return "", err } @@ -171,6 +178,12 @@ func getClusterRole(ctx context.Context, client *mongo.Client) (string, error) { } if err := res.Decode(&cmdOpts); err != nil { + if e, ok := err.(mongo.CommandError); ok { + if e.Code == Unauthorized { + errors.New("unauthorized to getCmdLineOpts") + os.Exit(1) + } + } return "", errors.Wrap(err, "cannot decode getCmdLineOpts response") } diff --git a/exporter/v1_compatibility.go b/exporter/v1_compatibility.go index 3a3d49895..27a53c2e8 100644 --- a/exporter/v1_compatibility.go +++ b/exporter/v1_compatibility.go @@ -21,6 +21,7 @@ import ( "math" "strings" "time" + "os" "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" @@ -835,6 +836,12 @@ func retrieveMongoDBBuildInfo(ctx context.Context, client *mongo.Client, l *logr var buildInfoDoc bson.M err := res.Decode(&buildInfoDoc) if err != nil { + if e, ok := err.(mongo.CommandError); ok { + if e.Code == Unauthorized { + errors.Wrap(err,"unauthorized to run command buildInfo") + os.Exit(1) + } + } return buildInfo{}, errors.Wrap(err, "Failed to run buildInfo command") } @@ -1176,6 +1183,12 @@ func chunksBalancerRunning(ctx context.Context, client *mongo.Client) (prometheu res := client.Database("admin").RunCommand(ctx, cmd) if err := res.Decode(&m); err != nil { + if e, ok := err.(mongo.CommandError); ok { + if e.Code == Unauthorized { + errors.Wrap(err,"unauthorized to run command balancerStatus") + os.Exit(1) + } + } return nil, err } @@ -1201,6 +1214,12 @@ func balancerEnabled(ctx context.Context, client *mongo.Client) (prometheus.Metr cmd := bson.D{{Key: "balancerStatus", Value: "1"}} err := client.Database("admin").RunCommand(ctx, cmd).Decode(&bs) if err != nil { + if e, ok := err.(mongo.CommandError); ok { + if e.Code == Unauthorized { + errors.Wrap(err,"unauthorized to run command balancerStatus") + os.Exit(1) + } + } return nil, err } if bs.Mode == "full" { diff --git a/internal/util/util.go b/internal/util/util.go index bebf5ee18..7284b924b 100644 --- a/internal/util/util.go +++ b/internal/util/util.go @@ -17,6 +17,8 @@ package util import ( "context" + "fmt" + "os" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" @@ -29,6 +31,7 @@ const ( ErrNotYetInitialized = int32(94) ErrNoReplicationEnabled = int32(76) ErrNotPrimaryOrSecondary = int32(13436) + ErrNotUnauthorized = int32(13) ) // MyState returns the replica set and the instance's state if available. @@ -37,6 +40,12 @@ func MyState(ctx context.Context, client *mongo.Client) (string, int, error) { err := client.Database("admin").RunCommand(ctx, bson.M{"replSetGetStatus": 1}).Decode(&status) if err != nil { + if e, ok := err.(mongo.CommandError); ok { + if e.Code == ErrNotUnauthorized { + fmt.Fprintf(os.Stderr, "unauthorized to run command replSetGetStatus: %v\n", err) + os.Exit(1) + } + } return "", 0, err } @@ -48,6 +57,12 @@ func MyRole(ctx context.Context, client *mongo.Client) (*proto.HelloResponse, er var role proto.HelloResponse err := client.Database("admin").RunCommand(ctx, bson.M{"isMaster": 1}).Decode(&role) if err != nil { + if e, ok := err.(mongo.CommandError); ok { + if e.Code == ErrNotUnauthorized { + fmt.Fprintf(os.Stderr, "unauthorized to run command isMaster: %v\n", err) + os.Exit(1) + } + } return nil, err } @@ -57,6 +72,12 @@ func MyRole(ctx context.Context, client *mongo.Client) (*proto.HelloResponse, er func ReplicasetConfig(ctx context.Context, client *mongo.Client) (*proto.ReplicasetConfig, error) { var rs proto.ReplicasetConfig if err := client.Database("admin").RunCommand(ctx, bson.M{"replSetGetConfig": 1}).Decode(&rs); err != nil { + if e, ok := err.(mongo.CommandError); ok { + if e.Code == ErrNotUnauthorized { + fmt.Fprintf(os.Stderr, "unauthorized to run command replSetGetConfig: %v\n", err) + os.Exit(1) + } + } return nil, err }