Skip to content

Commit 23502f1

Browse files
cfsalgueroJiriCtvrtkaBupycHuk
authored
PMM-13141 Added feature compatibility version collector (#863)
* PMM-13141 Added feature compatibility version collector * PMM-13141 Fixed testing mongo version * PMM-13141 Ran format * PMM-13141 Fix for linters * PMM-13141 Fixed tests for different mdb versions * PMM-13141 Fix for linters * PMM-13141 Trigger build * PMM-13141 Fix for linters * PMM-13141 Trigger build * PMM-13141 Removed scrape interval. * PMM-13141 Removed last_scrape label. * PMM-13141 Fix linters. * PMM-13141 fix test. * PMM-13141 fix test. * PMM-13141 fix test. * PMM-13141 fix test. * PMM-13141 fix test. * PMM-13141 fix test. * PMM-13141 fix test. --------- Co-authored-by: Jiří Čtvrtka <[email protected]> Co-authored-by: Nurlan Moldomurov <[email protected]>
1 parent 88ce83d commit 23502f1

9 files changed

+228
-64
lines changed

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ REPO ?= percona/$(NAME)
1717
GORELEASER_FLAGS ?=
1818
UID ?= $(shell id -u)
1919

20-
export TEST_MONGODB_IMAGE?=mongo:4.2
20+
export TEST_MONGODB_IMAGE?=mongo:4.4
2121
export TEST_MONGODB_ADMIN_USERNAME?=
2222
export TEST_MONGODB_ADMIN_PASSWORD?=
2323
export TEST_MONGODB_USERNAME?=

docker-compose.yml

+13-13
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
services:
22
mongo-1-1:
33
container_name: "mongo-1-1"
4-
image: ${TEST_MONGODB_IMAGE:-mongo:4.2}
4+
image: ${TEST_MONGODB_IMAGE:-mongo:4.4}
55
ports:
66
- "${TEST_MONGODB_S1_PRIMARY_PORT:-17001}:27017"
77
command: mongod --replSet rs1 --shardsvr --port 27017 --oplogSize 16 --bind_ip 0.0.0.0
@@ -14,7 +14,7 @@ services:
1414

1515
mongo-1-2:
1616
container_name: "mongo-1-2"
17-
image: ${TEST_MONGODB_IMAGE:-mongo:4.2}
17+
image: ${TEST_MONGODB_IMAGE:-mongo:4.4}
1818
ports:
1919
- "${TEST_MONGODB_S1_SECONDARY1_PORT:-17002}:27017"
2020
command: mongod --replSet rs1 --shardsvr --port 27017 --oplogSize 16 --bind_ip 0.0.0.0
@@ -23,7 +23,7 @@ services:
2323

2424
mongo-1-3:
2525
container_name: "mongo-1-3"
26-
image: ${TEST_MONGODB_IMAGE:-mongo:4.2}
26+
image: ${TEST_MONGODB_IMAGE:-mongo:4.4}
2727
ports:
2828
- "${TEST_MONGODB_S1_SECONDARY2_PORT:-17003}:27017"
2929
command: mongod --replSet rs1 --shardsvr --port 27017 --oplogSize 16 --bind_ip 0.0.0.0
@@ -32,7 +32,7 @@ services:
3232

3333
mongo-1-arbiter:
3434
container_name: "mongo-1-arbiter"
35-
image: ${TEST_MONGODB_IMAGE:-mongo:4.2}
35+
image: ${TEST_MONGODB_IMAGE:-mongo:4.4}
3636
ports:
3737
- "${TEST_MONGODB_S1_ARBITER:-17011}:27017"
3838
command: mongod --replSet rs1 --shardsvr --port 27017 --oplogSize 16
@@ -41,7 +41,7 @@ services:
4141

4242
mongo-rs1-setup:
4343
container_name: "mongo-rs1-setup"
44-
image: ${TEST_MONGODB_IMAGE:-mongo:4.2}
44+
image: ${TEST_MONGODB_IMAGE:-mongo:4.4}
4545
depends_on:
4646
- "mongo-1-1"
4747
- "mongo-1-2"
@@ -150,7 +150,7 @@ services:
150150

151151
mongo-rs2-setup:
152152
container_name: "mongo-rs2-setup"
153-
image: ${TEST_MONGODB_IMAGE:-mongo:4.2}
153+
image: ${TEST_MONGODB_IMAGE:-mongo:4.4}
154154
depends_on:
155155
- "mongo-2-1"
156156
- "mongo-2-2"
@@ -174,7 +174,7 @@ services:
174174
# Config servers
175175
mongo-cnf-2:
176176
container_name: "mongo-cnf-2"
177-
image: ${TEST_MONGODB_IMAGE:-mongo:4.2}
177+
image: ${TEST_MONGODB_IMAGE:-mongo:4.4}
178178
ports:
179179
- "${TEST_MONGODB_CONFIGSVR1_PORT:-17007}:27017"
180180
command: mongod --dbpath /data/db --replSet cnf-serv --configsvr --port 27017 --oplogSize 16
@@ -183,7 +183,7 @@ services:
183183

184184
mongo-cnf-3:
185185
container_name: "mongo-cnf-3"
186-
image: ${TEST_MONGODB_IMAGE:-mongo:4.2}
186+
image: ${TEST_MONGODB_IMAGE:-mongo:4.4}
187187
ports:
188188
- "${TEST_MONGODB_CONFIGSVR2_PORT:-17008}:27017"
189189
command: mongod --dbpath /data/db --replSet cnf-serv --configsvr --port 27017 --oplogSize 16
@@ -192,7 +192,7 @@ services:
192192

193193
mongo-cnf-1:
194194
container_name: "mongo-cnf-1"
195-
image: ${TEST_MONGODB_IMAGE:-mongo:4.2}
195+
image: ${TEST_MONGODB_IMAGE:-mongo:4.4}
196196
ports:
197197
- "${TEST_MONGODB_CONFIGSVR3_PORT:-17009}:27017"
198198
command: mongod --dbpath /data/db --replSet cnf-serv --configsvr --port 27017 --oplogSize 16
@@ -204,7 +204,7 @@ services:
204204

205205
mongo-cnf-setup:
206206
container_name: "mongo-cnf-setup"
207-
image: ${TEST_MONGODB_IMAGE:-mongo:4.2}
207+
image: ${TEST_MONGODB_IMAGE:-mongo:4.4}
208208
depends_on:
209209
- "mongo-cnf-1"
210210
- "mongo-cnf-2"
@@ -224,7 +224,7 @@ services:
224224

225225
mongos:
226226
container_name: "mongos"
227-
image: ${TEST_MONGODB_IMAGE:-mongo:4.2}
227+
image: ${TEST_MONGODB_IMAGE:-mongo:4.4}
228228
ports:
229229
- "${TEST_MONGODB_MONGOS_PORT:-17000}:27017"
230230
networks:
@@ -240,7 +240,7 @@ services:
240240

241241
mongo-shard-setup:
242242
container_name: "mongo-shard-setup"
243-
image: ${TEST_MONGODB_IMAGE:-mongo:4.2}
243+
image: ${TEST_MONGODB_IMAGE:-mongo:4.4}
244244
depends_on:
245245
- "mongos"
246246
networks:
@@ -270,7 +270,7 @@ services:
270270

271271
standalone:
272272
container_name: "standalone"
273-
image: ${TEST_MONGODB_IMAGE:-mongo:4.2}
273+
image: ${TEST_MONGODB_IMAGE:-mongo:4.4}
274274
ports:
275275
- "${TEST_MONGODB_STANDALONE_PORT:-27017}:27017"
276276
command: mongod --port 27017 --oplogSize 16

exporter/exporter.go

+10
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ type Opts struct {
7070
EnableCollStats bool
7171
EnableProfile bool
7272
EnableShards bool
73+
EnableFCV bool // Feature Compatibility Version.
7374

7475
EnableOverrideDescendingIndex bool
7576

@@ -164,6 +165,7 @@ func (e *Exporter) makeRegistry(ctx context.Context, client *mongo.Client, topol
164165
e.opts.EnableCurrentopMetrics = true
165166
e.opts.EnableProfile = true
166167
e.opts.EnableShards = true
168+
e.opts.EnableFCV = true
167169
e.opts.EnablePBMMetrics = true
168170
}
169171

@@ -178,6 +180,7 @@ func (e *Exporter) makeRegistry(ctx context.Context, client *mongo.Client, topol
178180
e.opts.EnableCurrentopMetrics = false
179181
e.opts.EnableProfile = false
180182
e.opts.EnableShards = false
183+
e.opts.EnableFCV = false
181184
e.opts.EnablePBMMetrics = false
182185
}
183186

@@ -239,6 +242,11 @@ func (e *Exporter) makeRegistry(ctx context.Context, client *mongo.Client, topol
239242
registry.MustRegister(sc)
240243
}
241244

245+
if e.opts.EnableFCV && nodeType != typeMongos {
246+
fcvc := newFeatureCompatibilityCollector(ctx, client, e.opts.Logger)
247+
registry.MustRegister(fcvc)
248+
}
249+
242250
if e.opts.EnablePBMMetrics && requestOpts.EnablePBMMetrics {
243251
pbmc := newPbmCollector(ctx, client, e.opts.URI, e.opts.Logger)
244252
registry.MustRegister(pbmc)
@@ -320,6 +328,8 @@ func (e *Exporter) Handler() http.Handler {
320328
requestOpts.EnableProfile = true
321329
case "shards":
322330
requestOpts.EnableShards = true
331+
case "fcv":
332+
requestOpts.EnableFCV = true
323333
case "pbm":
324334
requestOpts.EnablePBMMetrics = true
325335
}

exporter/exporter_test.go

+29-50
Original file line numberDiff line numberDiff line change
@@ -199,34 +199,11 @@ func TestMongoS(t *testing.T) {
199199
}
200200
}
201201

202-
func TestMongoUp(t *testing.T) {
203-
ctx := context.Background()
204-
205-
exporterOpts := &Opts{
206-
Logger: logrus.New(),
207-
URI: "mongodb://127.0.0.1:123456/admin",
208-
DirectConnect: true,
209-
GlobalConnPool: false,
210-
CollectAll: true,
211-
}
212-
213-
client, err := connect(ctx, exporterOpts)
214-
assert.Error(t, err)
215-
216-
e := New(exporterOpts)
217-
nodeType, _ := getNodeType(ctx, client)
218-
gc := newGeneralCollector(ctx, client, nodeType, e.opts.Logger)
219-
220-
r := e.makeRegistry(ctx, client, new(labelsGetterMock), *e.opts)
221-
222-
res := r.Unregister(gc)
223-
assert.Equal(t, true, res)
224-
}
225-
226202
func TestMongoUpMetric(t *testing.T) {
227203
ctx := context.Background()
228204

229205
type testcase struct {
206+
name string
230207
URI string
231208
clusterRole string
232209
Want int
@@ -242,39 +219,41 @@ func TestMongoUpMetric(t *testing.T) {
242219
}
243220

244221
for _, tc := range testCases {
245-
exporterOpts := &Opts{
246-
Logger: logrus.New(),
247-
URI: tc.URI,
248-
ConnectTimeoutMS: 200,
249-
DirectConnect: true,
250-
GlobalConnPool: false,
251-
CollectAll: true,
252-
}
222+
t.Run(tc.clusterRole+"/"+tc.URI, func(t *testing.T) {
223+
exporterOpts := &Opts{
224+
Logger: logrus.New(),
225+
URI: tc.URI,
226+
ConnectTimeoutMS: 200,
227+
DirectConnect: true,
228+
GlobalConnPool: false,
229+
CollectAll: true,
230+
}
253231

254-
client, err := connect(ctx, exporterOpts)
255-
if tc.Want == 1 {
256-
assert.NoError(t, err, "Must be able to connect to %s", tc.URI)
257-
} else {
258-
assert.Error(t, err, "Must be unable to connect to %s", tc.URI)
259-
}
232+
client, err := connect(ctx, exporterOpts)
233+
if tc.Want == 1 {
234+
assert.NoError(t, err, "Must be able to connect to %s", tc.URI)
235+
} else {
236+
assert.Error(t, err, "Must be unable to connect to %s", tc.URI)
237+
}
260238

261-
e := New(exporterOpts)
262-
nodeType, _ := getNodeType(ctx, client)
263-
gc := newGeneralCollector(ctx, client, nodeType, e.opts.Logger)
264-
r := e.makeRegistry(ctx, client, new(labelsGetterMock), *e.opts)
239+
e := New(exporterOpts)
240+
nodeType, _ := getNodeType(ctx, client)
241+
gc := newGeneralCollector(ctx, client, nodeType, e.opts.Logger)
242+
r := e.makeRegistry(ctx, client, new(labelsGetterMock), *e.opts)
265243

266-
expected := strings.NewReader(fmt.Sprintf(`
244+
expected := strings.NewReader(fmt.Sprintf(`
267245
# HELP mongodb_up Whether MongoDB is up.
268246
# TYPE mongodb_up gauge
269247
mongodb_up {cluster_role="%s"} %s`, tc.clusterRole, strconv.Itoa(tc.Want)) + "\n")
270248

271-
filter := []string{
272-
"mongodb_up",
273-
}
274-
err = testutil.CollectAndCompare(gc, expected, filter...)
275-
assert.NoError(t, err, "mongodb_up metric should be %d", tc.Want)
249+
filter := []string{
250+
"mongodb_up",
251+
}
252+
err = testutil.CollectAndCompare(gc, expected, filter...)
253+
assert.NoError(t, err, "mongodb_up metric should be %d", tc.Want)
276254

277-
res := r.Unregister(gc)
278-
assert.Equal(t, true, res)
255+
res := r.Unregister(gc)
256+
assert.Equal(t, true, res)
257+
})
279258
}
280259
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// mongodb_exporter
2+
// Copyright (C) 2017 Percona LLC
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
16+
package exporter
17+
18+
import (
19+
"context"
20+
"fmt"
21+
"strconv"
22+
23+
"github.com/prometheus/client_golang/prometheus"
24+
"github.com/sirupsen/logrus"
25+
"go.mongodb.org/mongo-driver/bson"
26+
"go.mongodb.org/mongo-driver/mongo"
27+
)
28+
29+
type featureCompatibilityCollector struct {
30+
ctx context.Context
31+
base *baseCollector
32+
}
33+
34+
// newProfileCollector creates a collector for being processed queries.
35+
func newFeatureCompatibilityCollector(ctx context.Context, client *mongo.Client, logger *logrus.Logger) *featureCompatibilityCollector {
36+
return &featureCompatibilityCollector{
37+
ctx: ctx,
38+
base: newBaseCollector(client, logger.WithFields(logrus.Fields{"collector": "featureCompatibility"})),
39+
}
40+
}
41+
42+
func (d *featureCompatibilityCollector) Describe(ch chan<- *prometheus.Desc) {
43+
d.base.Describe(d.ctx, ch, d.collect)
44+
}
45+
46+
func (d *featureCompatibilityCollector) Collect(ch chan<- prometheus.Metric) {
47+
d.base.Collect(ch)
48+
}
49+
50+
func (d *featureCompatibilityCollector) collect(ch chan<- prometheus.Metric) {
51+
defer measureCollectTime(ch, "mongodb", "profile")()
52+
53+
cmd := bson.D{{Key: "getParameter", Value: 1}, {Key: "featureCompatibilityVersion", Value: 1}}
54+
client := d.base.client
55+
if client == nil {
56+
return
57+
}
58+
res := client.Database("admin").RunCommand(d.ctx, cmd)
59+
60+
m := make(map[string]interface{})
61+
if err := res.Decode(&m); err != nil {
62+
d.base.logger.Errorf("Failed to decode featureCompatibilityVersion: %v", err)
63+
ch <- prometheus.NewInvalidMetric(prometheus.NewInvalidDesc(err), err)
64+
return
65+
}
66+
67+
rawValue := walkTo(m, []string{"featureCompatibilityVersion", "version"})
68+
if rawValue != nil {
69+
versionString := fmt.Sprintf("%v", rawValue)
70+
version, err := strconv.ParseFloat(versionString, 64)
71+
if err != nil {
72+
d.base.logger.Errorf("Failed to parse featureCompatibilityVersion: %v", err)
73+
ch <- prometheus.NewInvalidMetric(prometheus.NewInvalidDesc(err), err)
74+
return
75+
}
76+
77+
d := prometheus.NewDesc("mongodb_fcv_feature_compatibility_version", "Feature compatibility version", []string{"version"}, map[string]string{})
78+
ch <- prometheus.MustNewConstMetric(d, prometheus.GaugeValue, version, versionString)
79+
}
80+
}

0 commit comments

Comments
 (0)