diff --git a/cmd/pbm-agent/agent.go b/cmd/pbm-agent/agent.go index 9e2781cae..d8ce6b038 100644 --- a/cmd/pbm-agent/agent.go +++ b/cmd/pbm-agent/agent.go @@ -276,11 +276,12 @@ func (a *Agent) HbStatus(ctx context.Context) { } hb := topo.AgentStat{ - Node: a.brief.Me, - RS: a.brief.SetName, - AgentVer: version.Current().Version, - MongoVer: nodeVersion.VersionString, - PerconaVer: nodeVersion.PSMDBVersion, + Node: a.brief.Me, + RS: a.brief.SetName, + AgentVer: version.Current().Version, + MongoVer: nodeVersion.VersionString, + PerconaVer: nodeVersion.PSMDBVersion, + IsEnterprise: nodeVersion.IsEnterprise(), } updateAgentStat(ctx, a, l, true, &hb) diff --git a/pbm/backup/physical.go b/pbm/backup/physical.go index 8ed1559b7..9c3a2a4c2 100644 --- a/pbm/backup/physical.go +++ b/pbm/backup/physical.go @@ -16,6 +16,8 @@ import ( "go.mongodb.org/mongo-driver/bson/bsontype" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + "go.mongodb.org/mongo-driver/mongo/readconcern" "go.mongodb.org/mongo-driver/x/bsonx/bsoncore" "github.com/percona/percona-backup-mongodb/pbm/compress" @@ -91,7 +93,7 @@ func (bc *BackupCursor) create(ctx context.Context, retry int) (*mongo.Cursor, e } } - cur, err := bc.conn.Database("admin").Aggregate(ctx, mongo.Pipeline{ + cur, err := bc.conn.Database("admin", options.Database().SetReadConcern(readconcern.Local())).Aggregate(ctx, mongo.Pipeline{ {{"$backupCursor", opts}}, }) if err != nil { @@ -189,7 +191,7 @@ func (bc *BackupCursor) Data(ctx context.Context) (_ *BackupCursorData, err erro func (bc *BackupCursor) Journals(upto primitive.Timestamp) ([]File, error) { ctx := context.Background() - cur, err := bc.conn.Database("admin").Aggregate(ctx, + cur, err := bc.conn.Database("admin", options.Database().SetReadConcern(readconcern.Local())).Aggregate(ctx, mongo.Pipeline{ {{"$backupCursorExtend", bson.D{{"backupId", bc.id}, {"timestamp", upto}}}}, }) diff --git a/pbm/topo/agent.go b/pbm/topo/agent.go index 07a738a17..6bac870c7 100644 --- a/pbm/topo/agent.go +++ b/pbm/topo/agent.go @@ -59,6 +59,9 @@ type AgentStat struct { // Empty for non-PSMDB (e.i MongoDB CE). PerconaVer string `bson:"pv,omitempty"` + // IsEnterprise is set when the node runs MongoDB Enterprise edition. + IsEnterprise bool `bson:"ent,omitempty"` + // PBMStatus is the agent status. PBMStatus SubsysStatus `bson:"pbms"` @@ -114,6 +117,10 @@ func (s *AgentStat) MongoVersion() version.MongoVersion { VersionString: s.MongoVer, } + if s.IsEnterprise { + v.Modules = []string{"enterprise"} + } + vs := semver.Canonical("v" + s.MongoVer)[1:] vs = strings.SplitN(vs, "-", 2)[0] for _, a := range strings.Split(vs, ".")[:3] { diff --git a/pbm/version/version.go b/pbm/version/version.go index 06bd16a5d..7faf2bcf1 100644 --- a/pbm/version/version.go +++ b/pbm/version/version.go @@ -176,9 +176,20 @@ var BreakingChangesMap = map[defs.BackupType][]string{ } type MongoVersion struct { - PSMDBVersion string `bson:"psmdbVersion,omitempty"` - VersionString string `bson:"version"` - Version []int `bson:"versionArray"` + PSMDBVersion string `bson:"psmdbVersion,omitempty"` + VersionString string `bson:"version"` + Version []int `bson:"versionArray"` + Modules []string `bson:"modules,omitempty"` +} + +// IsEnterprise returns true if the MongoDB instance is running Enterprise edition. +func (v MongoVersion) IsEnterprise() bool { + for _, m := range v.Modules { + if m == "enterprise" { + return true + } + } + return false } func (v MongoVersion) String() string { @@ -274,7 +285,7 @@ func (f FeatureSupport) PBMSupport() error { func (f FeatureSupport) FullPhysicalBackup() bool { // PSMDB 4.2.15, 4.4.6 v := MongoVersion(f) - if v.PSMDBVersion == "" { + if v.PSMDBVersion == "" && !v.IsEnterprise() { return false } @@ -293,7 +304,7 @@ func (f FeatureSupport) FullPhysicalBackup() bool { func (f FeatureSupport) IncrementalPhysicalBackup() bool { // PSMDB 4.2.24, 4.4.18, 5.0.14, 6.0.3 v := MongoVersion(f) - if v.PSMDBVersion == "" { + if v.PSMDBVersion == "" && !v.IsEnterprise() { return false } @@ -318,17 +329,18 @@ func (f FeatureSupport) BackupType(t defs.BackupType) error { case defs.PhysicalBackup: if !f.FullPhysicalBackup() { return errors.New("full physical backup works since " + - "Percona Server for MongoDB 4.2.15, 4.4.6") + "Percona Server for MongoDB 4.2.15, 4.4.6 or MongoDB Enterprise 4.2.15, 4.4.6") } case defs.IncrementalBackup: if !f.IncrementalPhysicalBackup() { return errors.New("incremental physical backup works since " + - "Percona Server for MongoDB 4.2.24, 4.4.18, 5.0.14, 6.0.3") + "Percona Server for MongoDB 4.2.24, 4.4.18, 5.0.14, 6.0.3 or " + + "MongoDB Enterprise 4.2.24, 4.4.18, 5.0.14, 6.0.3") } case defs.ExternalBackup: if !f.FullPhysicalBackup() { return errors.New("external backup works since " + - "Percona Server for MongoDB 4.2.15, 4.4.6") + "Percona Server for MongoDB 4.2.15, 4.4.6 or MongoDB Enterprise 4.2.15, 4.4.6") } } diff --git a/pbm/version/version_test.go b/pbm/version/version_test.go index 2148a8a37..e2e7b88db 100644 --- a/pbm/version/version_test.go +++ b/pbm/version/version_test.go @@ -100,6 +100,178 @@ func TestCompatibility(t *testing.T) { } } +func TestFullPhysicalBackup(t *testing.T) { + cases := []struct { + name string + ver MongoVersion + want bool + }{ + // PSMDB cases + { + name: "psmdb 4.2.14 (too old)", + ver: MongoVersion{PSMDBVersion: "4.2.14-14", Version: []int{4, 2, 14}}, + want: false, + }, + { + name: "psmdb 4.2.15", + ver: MongoVersion{PSMDBVersion: "4.2.15-15", Version: []int{4, 2, 15}}, + want: true, + }, + { + name: "psmdb 4.4.5 (too old)", + ver: MongoVersion{PSMDBVersion: "4.4.5-5", Version: []int{4, 4, 5}}, + want: false, + }, + { + name: "psmdb 4.4.6", + ver: MongoVersion{PSMDBVersion: "4.4.6-6", Version: []int{4, 4, 6}}, + want: true, + }, + { + name: "psmdb 7.0.0", + ver: MongoVersion{PSMDBVersion: "7.0.0-1", Version: []int{7, 0, 0}}, + want: true, + }, + // Plain MongoDB (no enterprise) + { + name: "mongodb community 7.0.0", + ver: MongoVersion{Version: []int{7, 0, 0}}, + want: false, + }, + // MongoDB Enterprise cases + { + name: "mongodb enterprise 4.2.14 (too old)", + ver: MongoVersion{Modules: []string{"enterprise"}, Version: []int{4, 2, 14}}, + want: false, + }, + { + name: "mongodb enterprise 4.2.15", + ver: MongoVersion{Modules: []string{"enterprise"}, Version: []int{4, 2, 15}}, + want: true, + }, + { + name: "mongodb enterprise 4.4.5 (too old)", + ver: MongoVersion{Modules: []string{"enterprise"}, Version: []int{4, 4, 5}}, + want: false, + }, + { + name: "mongodb enterprise 4.4.6", + ver: MongoVersion{Modules: []string{"enterprise"}, Version: []int{4, 4, 6}}, + want: true, + }, + { + name: "mongodb enterprise 7.0.0", + ver: MongoVersion{Modules: []string{"enterprise"}, Version: []int{7, 0, 0}}, + want: true, + }, + { + name: "mongodb enterprise 8.0.0", + ver: MongoVersion{Modules: []string{"enterprise"}, Version: []int{8, 0, 0}}, + want: true, + }, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + got := FeatureSupport(tc.ver).FullPhysicalBackup() + if got != tc.want { + t.Errorf("FullPhysicalBackup() = %v, want %v", got, tc.want) + } + }) + } +} + +func TestIncrementalPhysicalBackup(t *testing.T) { + cases := []struct { + name string + ver MongoVersion + want bool + }{ + // PSMDB cases + { + name: "psmdb 4.2.23 (too old)", + ver: MongoVersion{PSMDBVersion: "4.2.23-23", Version: []int{4, 2, 23}}, + want: false, + }, + { + name: "psmdb 4.2.24", + ver: MongoVersion{PSMDBVersion: "4.2.24-24", Version: []int{4, 2, 24}}, + want: true, + }, + { + name: "psmdb 7.0.0", + ver: MongoVersion{PSMDBVersion: "7.0.0-1", Version: []int{7, 0, 0}}, + want: true, + }, + // Plain MongoDB (no enterprise) + { + name: "mongodb community 7.0.0", + ver: MongoVersion{Version: []int{7, 0, 0}}, + want: false, + }, + // MongoDB Enterprise cases + { + name: "mongodb enterprise 4.2.23 (too old)", + ver: MongoVersion{Modules: []string{"enterprise"}, Version: []int{4, 2, 23}}, + want: false, + }, + { + name: "mongodb enterprise 4.2.24", + ver: MongoVersion{Modules: []string{"enterprise"}, Version: []int{4, 2, 24}}, + want: true, + }, + { + name: "mongodb enterprise 4.4.17 (too old)", + ver: MongoVersion{Modules: []string{"enterprise"}, Version: []int{4, 4, 17}}, + want: false, + }, + { + name: "mongodb enterprise 4.4.18", + ver: MongoVersion{Modules: []string{"enterprise"}, Version: []int{4, 4, 18}}, + want: true, + }, + { + name: "mongodb enterprise 5.0.13 (too old)", + ver: MongoVersion{Modules: []string{"enterprise"}, Version: []int{5, 0, 13}}, + want: false, + }, + { + name: "mongodb enterprise 5.0.14", + ver: MongoVersion{Modules: []string{"enterprise"}, Version: []int{5, 0, 14}}, + want: true, + }, + { + name: "mongodb enterprise 6.0.2 (too old)", + ver: MongoVersion{Modules: []string{"enterprise"}, Version: []int{6, 0, 2}}, + want: false, + }, + { + name: "mongodb enterprise 6.0.3", + ver: MongoVersion{Modules: []string{"enterprise"}, Version: []int{6, 0, 3}}, + want: true, + }, + { + name: "mongodb enterprise 7.0.0", + ver: MongoVersion{Modules: []string{"enterprise"}, Version: []int{7, 0, 0}}, + want: true, + }, + { + name: "mongodb enterprise 8.0.0", + ver: MongoVersion{Modules: []string{"enterprise"}, Version: []int{8, 0, 0}}, + want: true, + }, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + got := FeatureSupport(tc.ver).IncrementalPhysicalBackup() + if got != tc.want { + t.Errorf("IncrementalPhysicalBackup() = %v, want %v", got, tc.want) + } + }) + } +} + func TestHasPhysicalFilesMetadata(t *testing.T) { cases := map[string]bool{ "": false,