mirror of
https://github.com/mongodb/mongo.git
synced 2024-12-01 09:32:32 +01:00
SERVER-56241 Don't allow setting getLastErrorDefaults on startup/reconfig
This commit is contained in:
parent
0de67b8e46
commit
f6b96a603d
@ -0,0 +1,139 @@
|
||||
/**
|
||||
* Tests that upgrading a set that has a non-default getLastErrorDefaults field to 'latest'
|
||||
* will trigger an fassert on startup.
|
||||
* TODO SERVER-56576: Remove upgrade_with_non_default_get_last_error_defaults_fails_on_startup.js
|
||||
* once we branch 5.0
|
||||
*/
|
||||
(function() {
|
||||
"use strict";
|
||||
load("jstests/multiVersion/libs/multi_rs.js");
|
||||
load('jstests/multiVersion/libs/multi_cluster.js');
|
||||
|
||||
// Checking UUID/index consistency and orphans involves talking to shards, but this test shuts down
|
||||
// one shard.
|
||||
TestData.skipCheckingUUIDsConsistentAcrossCluster = true;
|
||||
TestData.skipCheckingIndexesConsistentAcrossCluster = true;
|
||||
TestData.skipCheckOrphans = true;
|
||||
|
||||
function testReplSet(gleDefaults) {
|
||||
const replTest = new ReplSetTest({
|
||||
nodes: {
|
||||
0: {binVersion: "last-lts"},
|
||||
1: {binVersion: "last-lts"},
|
||||
},
|
||||
settings: gleDefaults
|
||||
});
|
||||
replTest.startSet();
|
||||
replTest.initiate();
|
||||
const primary = replTest.getPrimary();
|
||||
|
||||
// Test that the current config has the expected fields.
|
||||
let config = primary.adminCommand({replSetGetConfig: 1}).config;
|
||||
|
||||
assert.eq(
|
||||
config.settings.getLastErrorDefaults.w, gleDefaults.getLastErrorDefaults.w, tojson(config));
|
||||
assert.eq(config.settings.getLastErrorDefaults.wTimeout,
|
||||
gleDefaults.getLastErrorDefaults.wTimeout,
|
||||
tojson(config));
|
||||
assert.eq(
|
||||
config.settings.getLastErrorDefaults.j, gleDefaults.getLastErrorDefaults.j, tojson(config));
|
||||
assert.eq(config.settings.getLastErrorDefaults.fsync,
|
||||
gleDefaults.getLastErrorDefaults.fsync,
|
||||
tojson(config));
|
||||
|
||||
clearRawMongoProgramOutput();
|
||||
jsTestLog("Attempting to upgrade set");
|
||||
assert.soon(
|
||||
function() {
|
||||
try {
|
||||
replTest.upgradeSet({binVersion: "latest"});
|
||||
return false;
|
||||
} catch (ex) {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
"Node should fail when starting up with a non-default getLastErrorDefaults field",
|
||||
ReplSetTest.kDefaultTimeoutMS);
|
||||
|
||||
assert(rawMongoProgramOutput().match('Fatal assertion.*5624100'),
|
||||
'Node should fassert when starting up with a non-default getLastErrorDefaults field');
|
||||
|
||||
replTest.stopSet();
|
||||
}
|
||||
|
||||
function testSharding(gleDefaults) {
|
||||
const st = new ShardingTest({
|
||||
shards: {
|
||||
rs0: {
|
||||
nodes: {
|
||||
0: {binVersion: "last-lts"},
|
||||
1: {binVersion: "last-lts"},
|
||||
},
|
||||
settings: gleDefaults
|
||||
},
|
||||
rs1: {
|
||||
nodes: {
|
||||
0: {binVersion: "last-lts"},
|
||||
1: {binVersion: "last-lts"},
|
||||
},
|
||||
settings: gleDefaults
|
||||
}
|
||||
},
|
||||
other: {mongosOptions: {binVersion: "last-lts"}, configOptions: {binVersion: "last-lts"}}
|
||||
});
|
||||
|
||||
// Test that the current config has the expected fields.
|
||||
const primary = st.rs0.getPrimary();
|
||||
const config = primary.adminCommand({replSetGetConfig: 1}).config;
|
||||
assert.eq(
|
||||
config.settings.getLastErrorDefaults.w, gleDefaults.getLastErrorDefaults.w, tojson(config));
|
||||
assert.eq(config.settings.getLastErrorDefaults.wTimeout,
|
||||
gleDefaults.getLastErrorDefaults.wTimeout,
|
||||
tojson(config));
|
||||
assert.eq(
|
||||
config.settings.getLastErrorDefaults.j, gleDefaults.getLastErrorDefaults.j, tojson(config));
|
||||
assert.eq(config.settings.getLastErrorDefaults.fsync,
|
||||
gleDefaults.getLastErrorDefaults.fsync,
|
||||
tojson(config));
|
||||
|
||||
clearRawMongoProgramOutput();
|
||||
jsTestLog("Attempting to upgrade set");
|
||||
assert.soon(
|
||||
function() {
|
||||
try {
|
||||
st.upgradeCluster(
|
||||
'latest', {upgradeShards: true, upgradeConfigs: false, upgradeMongos: false});
|
||||
return false;
|
||||
} catch (ex) {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
"Node should fail when starting up with a non-default getLastErrorDefaults field",
|
||||
ReplSetTest.kDefaultTimeoutMS);
|
||||
|
||||
assert(rawMongoProgramOutput().match('Fatal assertion.*5624100'),
|
||||
'Node should fassert when starting up with a non-default getLastErrorDefaults field');
|
||||
|
||||
st.stop();
|
||||
}
|
||||
|
||||
function runTest(gleDefaults) {
|
||||
testReplSet(gleDefaults);
|
||||
testSharding(gleDefaults);
|
||||
}
|
||||
|
||||
jsTestLog("Testing getLastErrorDefaults with {w: 'majority'}");
|
||||
runTest({getLastErrorDefaults: {w: 'majority', wtimeout: 0}});
|
||||
|
||||
jsTestLog("Testing getLastErrorDefaults with {w:1, wtimeout: 1}");
|
||||
runTest({getLastErrorDefaults: {w: 1, wtimeout: 1}});
|
||||
|
||||
jsTestLog("Testing getLastErrorDefaults with {w:1, wtimeout: 0, j: true}");
|
||||
runTest({getLastErrorDefaults: {w: 1, wtimeout: 0, j: true}});
|
||||
|
||||
jsTestLog("Testing getLastErrorDefaults with {w:1, wtimeout: 0, fsync: true}");
|
||||
runTest({getLastErrorDefaults: {w: 1, wtimeout: 0, fsync: true}});
|
||||
|
||||
jsTestLog("Testing getLastErrorDefaults with {w:1, wtimeout: 0, j: false}");
|
||||
runTest({getLastErrorDefaults: {w: 1, wtimeout: 0, j: false}});
|
||||
}());
|
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Test that initiating and reconfiguring when settings.getLastErrorDefaults is set
|
||||
* and not {w:1, wtimeout: 0} will fail.
|
||||
* @tags: [requires_fcv_50]
|
||||
*/
|
||||
(function() {
|
||||
"use strict";
|
||||
|
||||
function testInitiate(gleDefaults) {
|
||||
const replTest = new ReplSetTest({name: jsTestName(), nodes: 1});
|
||||
clearRawMongoProgramOutput();
|
||||
const conns = replTest.startSet();
|
||||
const admin = conns[0].getDB("admin");
|
||||
|
||||
const conf = replTest.getReplSetConfig();
|
||||
conf.settings = gleDefaults;
|
||||
assert.soon(
|
||||
function() {
|
||||
try {
|
||||
admin.runCommand({replSetInitiate: conf});
|
||||
return false;
|
||||
} catch (ex) {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
"Node should fail when initiating with a non-default getLastErrorDefaults field",
|
||||
ReplSetTest.kDefaultTimeoutMS);
|
||||
|
||||
assert(
|
||||
rawMongoProgramOutput().match('Fatal assertion.*5624101'),
|
||||
"Node should have fasserted when initiating with a non-default getLastErrorDefaults field");
|
||||
|
||||
replTest.stop(conns[0], undefined, {allowedExitCode: MongoRunner.EXIT_ABRUPT});
|
||||
replTest.stopSet(undefined, undefined, {skipValidation: true});
|
||||
}
|
||||
|
||||
function testReconfig(gleDefaults) {
|
||||
const replTest = new ReplSetTest({name: jsTestName(), nodes: 1});
|
||||
const conns = replTest.startSet();
|
||||
const admin = conns[0].getDB("admin");
|
||||
|
||||
replTest.initiate();
|
||||
const conf = admin.runCommand({replSetGetConfig: 1}).config;
|
||||
conf.settings = gleDefaults;
|
||||
conf.version++;
|
||||
|
||||
jsTestLog("Node should fail to reconfig with a non-default getLastErrorDefaults field.");
|
||||
assert.commandFailedWithCode(admin.runCommand({replSetReconfig: conf}), 5624102);
|
||||
assert.commandFailedWithCode(admin.runCommand({replSetReconfig: conf, force: true}), 5624102);
|
||||
|
||||
replTest.stopSet();
|
||||
}
|
||||
|
||||
function runTest(gleDefaults) {
|
||||
testInitiate(gleDefaults);
|
||||
testReconfig(gleDefaults);
|
||||
}
|
||||
|
||||
jsTestLog("Testing getLastErrorDefaults with {w: 'majority'}");
|
||||
runTest({getLastErrorDefaults: {w: 'majority', wtimeout: 0}});
|
||||
|
||||
jsTestLog("Testing getLastErrorDefaults with {w:1, wtimeout: 1}");
|
||||
runTest({getLastErrorDefaults: {w: 1, wtimeout: 1}});
|
||||
|
||||
jsTestLog("Testing getLastErrorDefaults with {w:1, wtimeout: 0, j: true}");
|
||||
runTest({getLastErrorDefaults: {w: 1, wtimeout: 0, j: true}});
|
||||
|
||||
jsTestLog("Testing getLastErrorDefaults with {w:1, wtimeout: 0, fsync: true}");
|
||||
runTest({getLastErrorDefaults: {w: 1, wtimeout: 0, fsync: true}});
|
||||
|
||||
jsTestLog("Testing getLastErrorDefaults with {w:1, wtimeout: 0, j: false}");
|
||||
runTest({getLastErrorDefaults: {w: 1, wtimeout: 0, j: false}});
|
||||
}());
|
@ -382,17 +382,6 @@ Status ReplSetConfig::_validate(bool allowSplitHorizonIP) const {
|
||||
"one non-arbiter member with priority > 0");
|
||||
}
|
||||
|
||||
// This validation must be done outside the IDL because we need to parse the settings object
|
||||
// completely to get the custom write modes.
|
||||
const auto& defaultWriteConcern = getSettings()->getDefaultWriteConcern();
|
||||
if (!defaultWriteConcern.wMode.empty() &&
|
||||
WriteConcernOptions::kMajority != defaultWriteConcern.wMode &&
|
||||
!findCustomWriteMode(defaultWriteConcern.wMode).isOK()) {
|
||||
return Status(ErrorCodes::BadValue,
|
||||
str::stream() << "Default write concern requires undefined write mode "
|
||||
<< defaultWriteConcern.wMode);
|
||||
}
|
||||
|
||||
if (getConfigServer()) {
|
||||
if (arbiterCount > 0) {
|
||||
return Status(ErrorCodes::BadValue,
|
||||
@ -728,6 +717,14 @@ bool ReplSetConfig::isImplicitDefaultWriteConcernMajority() const {
|
||||
return arbiters == 0 || _writableVotingMembersCount > _majorityVoteCount;
|
||||
}
|
||||
|
||||
bool ReplSetConfig::containsCustomizedGetLastErrorDefaults() const {
|
||||
// Since the ReplSetConfig always has a WriteConcernOptions, the only way to know if it has been
|
||||
// customized through getLastErrorDefaults is if it's different from { w: 1, wtimeout: 0 }.
|
||||
const auto& getLastErrorDefaults = getDefaultWriteConcern();
|
||||
return !(getLastErrorDefaults.wNumNodes == 1 && getLastErrorDefaults.wTimeout == 0 &&
|
||||
getLastErrorDefaults.syncMode == WriteConcernOptions::SyncMode::UNSET);
|
||||
}
|
||||
|
||||
MemberConfig* MutableReplSetConfig::_findMemberByID(MemberId id) {
|
||||
for (auto it = getMembers().begin(); it != getMembers().end(); ++it) {
|
||||
if (it->getId() == id) {
|
||||
|
@ -536,6 +536,11 @@ public:
|
||||
return getNumMembers() == 3 && getNumDataBearingMembers() == 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the getLastErrorDefaults has been customized.
|
||||
*/
|
||||
bool containsCustomizedGetLastErrorDefaults() const;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Sets replica set ID to 'defaultReplicaSetId' if 'cfg' does not contain an ID.
|
||||
|
@ -431,6 +431,15 @@ StatusWith<int> validateConfigForStartUp(ReplicationCoordinatorExternalState* ex
|
||||
if (!status.isOK()) {
|
||||
return StatusWith<int>(status);
|
||||
}
|
||||
if (newConfig.containsCustomizedGetLastErrorDefaults()) {
|
||||
fassertFailedWithStatusNoTrace(
|
||||
5624100,
|
||||
{ErrorCodes::IllegalOperation,
|
||||
str::stream() << "Failed to start up: Replica set config contains customized "
|
||||
"getLastErrorDefaults, which "
|
||||
"has been deprecated and is now ignored. Use setDefaultRWConcern "
|
||||
"instead to set a cluster-wide default writeConcern."});
|
||||
}
|
||||
return findSelfInConfig(externalState, newConfig, ctx);
|
||||
}
|
||||
|
||||
@ -447,10 +456,14 @@ StatusWith<int> validateConfigForInitiate(ReplicationCoordinatorExternalState* e
|
||||
return StatusWith<int>(status);
|
||||
}
|
||||
|
||||
status = newConfig.checkIfWriteConcernCanBeSatisfied(newConfig.getDefaultWriteConcern());
|
||||
if (!status.isOK()) {
|
||||
return status.withContext(
|
||||
"Found invalid default write concern in 'getLastErrorDefaults' field");
|
||||
if (newConfig.containsCustomizedGetLastErrorDefaults()) {
|
||||
fassertFailedWithStatusNoTrace(
|
||||
5624101,
|
||||
{ErrorCodes::IllegalOperation,
|
||||
str::stream() << "Failed to initiate: Replica set config contains customized "
|
||||
"getLastErrorDefaults, which "
|
||||
"has been deprecated and is now ignored. Use setDefaultRWConcern "
|
||||
"instead to set a cluster-wide default writeConcern."});
|
||||
}
|
||||
|
||||
status = validateArbiterPriorities(newConfig);
|
||||
@ -496,11 +509,12 @@ Status validateConfigForReconfig(const ReplSetConfig& oldConfig,
|
||||
}
|
||||
}
|
||||
|
||||
status = newConfig.checkIfWriteConcernCanBeSatisfied(newConfig.getDefaultWriteConcern());
|
||||
if (!status.isOK()) {
|
||||
return status.withContext(
|
||||
"Found invalid default write concern in 'getLastErrorDefaults' field");
|
||||
}
|
||||
uassert(5624102,
|
||||
"Failed to reconfig: Replica set config contains customized "
|
||||
"getLastErrorDefaults, which has "
|
||||
"been deprecated and is now ignored. Use setDefaultRWConcern instead to "
|
||||
"set a cluster-wide default writeConcern.",
|
||||
!newConfig.containsCustomizedGetLastErrorDefaults());
|
||||
|
||||
status = validateOldAndNewConfigsCompatible(oldConfig, newConfig);
|
||||
if (!status.isOK()) {
|
||||
@ -534,6 +548,13 @@ StatusWith<int> validateConfigForHeartbeatReconfig(
|
||||
return StatusWith<int>(status);
|
||||
}
|
||||
|
||||
tassert(5624103,
|
||||
"Replica set config during heartbeat reconfig contains "
|
||||
"customized getLastErrorDefaults, which has "
|
||||
"been deprecated and is now ignored. Use setDefaultRWConcern instead to "
|
||||
"set a cluster-wide default writeConcern.",
|
||||
!newConfig.containsCustomizedGetLastErrorDefaults());
|
||||
|
||||
return findSelfInConfig(externalState, newConfig, ctx);
|
||||
}
|
||||
|
||||
|
@ -40,6 +40,7 @@
|
||||
#include "mongo/db/server_options.h"
|
||||
#include "mongo/db/service_context.h"
|
||||
#include "mongo/db/service_context_test_fixture.h"
|
||||
#include "mongo/unittest/death_test.h"
|
||||
#include "mongo/unittest/ensure_fcv.h"
|
||||
#include "mongo/unittest/unittest.h"
|
||||
|
||||
@ -155,7 +156,9 @@ TEST_F(ServiceContextTest, ValidateConfigForInitiate_SelfMustBeElectable) {
|
||||
.getStatus());
|
||||
}
|
||||
|
||||
TEST_F(ServiceContextTest, ValidateConfigForInitiate_WriteConcernMustBeSatisfiable) {
|
||||
DEATH_TEST_REGEX_F(ServiceContextTest,
|
||||
ValidateConfigForInitiate_NonDefaultGetLastErrorDefaults,
|
||||
"Fatal assertion.*5624101") {
|
||||
ReplSetConfig config;
|
||||
OID newReplSetId = OID::gen();
|
||||
config =
|
||||
@ -170,10 +173,7 @@ TEST_F(ServiceContextTest, ValidateConfigForInitiate_WriteConcernMustBeSatisfiab
|
||||
newReplSetId);
|
||||
ReplicationCoordinatorExternalStateMock presentOnceExternalState;
|
||||
presentOnceExternalState.addSelf(HostAndPort("h2"));
|
||||
|
||||
ASSERT_EQUALS(ErrorCodes::UnsatisfiableWriteConcern,
|
||||
validateConfigForInitiate(&presentOnceExternalState, config, getServiceContext())
|
||||
.getStatus());
|
||||
validateConfigForInitiate(&presentOnceExternalState, config, getServiceContext()).getStatus();
|
||||
}
|
||||
|
||||
TEST_F(ServiceContextTest, ValidateConfigForInitiate_ArbiterPriorityMustBeZeroOrOne) {
|
||||
@ -771,7 +771,7 @@ TEST_F(ServiceContextTest, ValidateConfigForReconfig_NewConfigInvalid) {
|
||||
validateConfigForReconfig(oldConfig, newConfig, true, false, false));
|
||||
}
|
||||
|
||||
TEST_F(ServiceContextTest, ValidateConfigForReconfig_NewConfigWriteConcernNotSatisifiable) {
|
||||
TEST_F(ServiceContextTest, ValidateConfigForReconfig_NonDefaultGetLastErrorDefaults) {
|
||||
// The new config is not valid due to an unsatisfiable write concern. This tests that if the
|
||||
// new config is invalid, validateConfigForReconfig will return a status indicating what is
|
||||
// wrong with the new config.
|
||||
@ -793,11 +793,13 @@ TEST_F(ServiceContextTest, ValidateConfigForReconfig_NewConfigWriteConcernNotSat
|
||||
|
||||
ReplicationCoordinatorExternalStateMock presentOnceExternalState;
|
||||
presentOnceExternalState.addSelf(HostAndPort("h2"));
|
||||
ASSERT_EQUALS(ErrorCodes::UnsatisfiableWriteConcern,
|
||||
validateConfigForReconfig(oldConfig, newConfig, false, false, false));
|
||||
ASSERT_THROWS_CODE(validateConfigForReconfig(oldConfig, newConfig, false, false, false),
|
||||
AssertionException,
|
||||
5624102);
|
||||
// Forced reconfigs also do not allow this.
|
||||
ASSERT_EQUALS(ErrorCodes::UnsatisfiableWriteConcern,
|
||||
validateConfigForReconfig(oldConfig, newConfig, true, false, false));
|
||||
ASSERT_THROWS_CODE(validateConfigForReconfig(oldConfig, newConfig, true, false, false),
|
||||
AssertionException,
|
||||
5624102);
|
||||
}
|
||||
|
||||
TEST_F(ServiceContextTest, ValidateConfigForStartUp_NewConfigInvalid) {
|
||||
@ -840,7 +842,9 @@ TEST_F(ServiceContextTest, ValidateConfigForStartUp_NewConfigValid) {
|
||||
.getStatus());
|
||||
}
|
||||
|
||||
TEST_F(ServiceContextTest, ValidateConfigForStartUp_NewConfigWriteConcernNotSatisfiable) {
|
||||
DEATH_TEST_REGEX_F(ServiceContextTest,
|
||||
ValidateConfigForStartUp_NewConfigNonDefaultGetLastErrorDefaults,
|
||||
"Fatal assertion.*5624100") {
|
||||
// The new config contains an unsatisfiable write concern. We don't allow these configs to be
|
||||
// created anymore, but we allow any which exist to pass and the database to start up to
|
||||
// maintain backwards compatibility.
|
||||
@ -855,8 +859,7 @@ TEST_F(ServiceContextTest, ValidateConfigForStartUp_NewConfigWriteConcernNotSati
|
||||
|
||||
ReplicationCoordinatorExternalStateMock presentOnceExternalState;
|
||||
presentOnceExternalState.addSelf(HostAndPort("h2"));
|
||||
ASSERT_OK(validateConfigForStartUp(&presentOnceExternalState, newConfig, getServiceContext())
|
||||
.getStatus());
|
||||
validateConfigForStartUp(&presentOnceExternalState, newConfig, getServiceContext()).getStatus();
|
||||
}
|
||||
|
||||
TEST_F(ServiceContextTest, ValidateConfigForHeartbeatReconfig_NewConfigInvalid) {
|
||||
@ -899,7 +902,9 @@ TEST_F(ServiceContextTest, ValidateConfigForHeartbeatReconfig_NewConfigValid) {
|
||||
.getStatus());
|
||||
}
|
||||
|
||||
TEST_F(ServiceContextTest, ValidateConfigForHeartbeatReconfig_NewConfigWriteConcernNotSatisfiable) {
|
||||
DEATH_TEST_REGEX_F(ServiceContextTest,
|
||||
ValidateConfigForHeartbeatReconfig_NonDefaultGetLastErrorDefaults,
|
||||
"Tripwire assertion.*5624103") {
|
||||
// The new config contains an unsatisfiable write concern. We don't allow these configs to be
|
||||
// created anymore, but we allow any which exist to be received in a heartbeat.
|
||||
ReplSetConfig newConfig;
|
||||
@ -915,9 +920,11 @@ TEST_F(ServiceContextTest, ValidateConfigForHeartbeatReconfig_NewConfigWriteConc
|
||||
|
||||
ReplicationCoordinatorExternalStateMock presentOnceExternalState;
|
||||
presentOnceExternalState.addSelf(HostAndPort("h2"));
|
||||
ASSERT_OK(validateConfigForHeartbeatReconfig(
|
||||
&presentOnceExternalState, newConfig, getServiceContext())
|
||||
.getStatus());
|
||||
ASSERT_THROWS_CODE(validateConfigForHeartbeatReconfig(
|
||||
&presentOnceExternalState, newConfig, getServiceContext())
|
||||
.getStatus(),
|
||||
AssertionException,
|
||||
5624103);
|
||||
}
|
||||
|
||||
TEST_F(ServiceContextTest, ValidateForReconfig_ForceStillNeedsValidConfig) {
|
||||
|
@ -118,10 +118,7 @@ TEST(ReplSetConfig, ParseLargeConfigAndCheckAccessors) {
|
||||
<< BSON("NYC"
|
||||
<< "NY")))
|
||||
<< "protocolVersion" << 1 << "settings"
|
||||
<< BSON("getLastErrorDefaults"
|
||||
<< BSON("w"
|
||||
<< "majority")
|
||||
<< "getLastErrorModes"
|
||||
<< BSON("getLastErrorModes"
|
||||
<< BSON("eastCoast" << BSON("NYC" << 1))
|
||||
<< "chainingAllowed" << false << "heartbeatIntervalMillis"
|
||||
<< 5000 << "heartbeatTimeoutSecs" << 120
|
||||
@ -132,8 +129,6 @@ TEST(ReplSetConfig, ParseLargeConfigAndCheckAccessors) {
|
||||
ASSERT_EQUALS(1, config.getConfigTerm());
|
||||
ASSERT_EQUALS(1, config.getNumMembers());
|
||||
ASSERT_EQUALS(MemberId(234), config.membersBegin()->getId());
|
||||
ASSERT_EQUALS(0, config.getDefaultWriteConcern().wNumNodes);
|
||||
ASSERT_EQUALS("majority", config.getDefaultWriteConcern().wMode);
|
||||
ASSERT_FALSE(config.isChainingAllowed());
|
||||
ASSERT_TRUE(config.getWriteConcernMajorityShouldJournal());
|
||||
ASSERT_FALSE(config.getConfigServer());
|
||||
@ -1230,59 +1225,6 @@ TEST(ReplSetConfig, HeartbeatTimeoutField) {
|
||||
DBException);
|
||||
}
|
||||
|
||||
TEST(ReplSetConfig, GleDefaultField) {
|
||||
ReplSetConfig config(
|
||||
ReplSetConfig::parse(BSON("_id"
|
||||
<< "rs0"
|
||||
<< "version" << 1 << "protocolVersion" << 1 << "members"
|
||||
<< BSON_ARRAY(BSON("_id" << 0 << "host"
|
||||
<< "localhost:12345"))
|
||||
<< "settings"
|
||||
<< BSON("getLastErrorDefaults" << BSON("w"
|
||||
<< "majority")))));
|
||||
ASSERT_OK(config.validate());
|
||||
ASSERT_EQUALS("majority", config.getDefaultWriteConcern().wMode);
|
||||
|
||||
config = ReplSetConfig::parse(BSON("_id"
|
||||
<< "rs0"
|
||||
<< "version" << 1 << "protocolVersion" << 1 << "members"
|
||||
<< BSON_ARRAY(BSON("_id" << 0 << "host"
|
||||
<< "localhost:12345"))
|
||||
<< "settings"
|
||||
<< BSON("getLastErrorDefaults" << BSON("w"
|
||||
<< "frim"))));
|
||||
ASSERT_EQUALS(ErrorCodes::BadValue, config.validate());
|
||||
|
||||
// Test that default write concern must have at least one member.
|
||||
ASSERT_THROWS(
|
||||
ReplSetConfig::parse(BSON("_id"
|
||||
<< "rs0"
|
||||
<< "version" << 1 << "protocolVersion" << 1 << "members"
|
||||
<< BSON_ARRAY(BSON("_id" << 0 << "host"
|
||||
<< "localhost:12345"))
|
||||
<< "settings" << BSON("getLastErrorDefaults" << BSON("w" << 0)))),
|
||||
DBException);
|
||||
|
||||
|
||||
config = ReplSetConfig::parse(BSON("_id"
|
||||
<< "rs0"
|
||||
<< "version" << 1 << "protocolVersion" << 1 << "members"
|
||||
<< BSON_ARRAY(BSON("_id" << 0 << "host"
|
||||
<< "localhost:12345"
|
||||
<< "tags"
|
||||
<< BSON("a"
|
||||
<< "v")))
|
||||
<< "settings"
|
||||
<< BSON("getLastErrorDefaults"
|
||||
<< BSON("w"
|
||||
<< "frim")
|
||||
<< "getLastErrorModes"
|
||||
<< BSON("frim" << BSON("a" << 1)))));
|
||||
ASSERT_OK(config.validate());
|
||||
ASSERT_EQUALS("frim", config.getDefaultWriteConcern().wMode);
|
||||
ASSERT_OK(config.findCustomWriteMode("frim").getStatus());
|
||||
}
|
||||
|
||||
bool operator==(const MemberConfig& a, const MemberConfig& b) {
|
||||
// do tag comparisons
|
||||
for (MemberConfig::TagIterator itrA = a.tagsBegin(); itrA != a.tagsEnd(); ++itrA) {
|
||||
@ -1416,14 +1358,11 @@ TEST(ReplSetConfig, toBSONRoundTripAbilityLarge) {
|
||||
<< "true")))
|
||||
<< "protocolVersion" << 1 << "settings"
|
||||
|
||||
<< BSON("heartbeatIntervalMillis" << 5000 << "heartbeatTimeoutSecs" << 20
|
||||
<< "electionTimeoutMillis" << 4 << "chainingAllowed"
|
||||
<< true << "getLastErrorDefaults"
|
||||
<< BSON("w"
|
||||
<< "majority")
|
||||
<< "getLastErrorModes"
|
||||
<< BSON("disks" << BSON("ssd" << 1 << "hdd" << 1)
|
||||
<< "coasts" << BSON("coast" << 2)))));
|
||||
<< BSON("heartbeatIntervalMillis"
|
||||
<< 5000 << "heartbeatTimeoutSecs" << 20 << "electionTimeoutMillis" << 4
|
||||
<< "chainingAllowed" << true << "getLastErrorModes"
|
||||
<< BSON("disks" << BSON("ssd" << 1 << "hdd" << 1) << "coasts"
|
||||
<< BSON("coast" << 2)))));
|
||||
BSONObj configObjA = configA.toBSON();
|
||||
configB = ReplSetConfig::parse(configObjA);
|
||||
ASSERT_TRUE(configA == configB);
|
||||
|
@ -4563,17 +4563,17 @@ ReplicationCoordinatorImpl::_setCurrentRSConfig(WithLock lk,
|
||||
}
|
||||
}
|
||||
|
||||
// Since the ReplSetConfig always has a WriteConcernOptions, the only way to know if it has been
|
||||
// customized is if it's different to the implicit defaults of { w: 1, wtimeout: 0 }.
|
||||
if (const auto& wc = newConfig.getDefaultWriteConcern();
|
||||
!(wc.wNumNodes == 1 && wc.wTimeout == 0)) {
|
||||
// Check that getLastErrorDefaults has not been changed from the default settings of
|
||||
// { w: 1, wtimeout: 0 }.
|
||||
if (newConfig.containsCustomizedGetLastErrorDefaults()) {
|
||||
LOGV2_OPTIONS(21387, {logv2::LogTag::kStartupWarnings}, "");
|
||||
LOGV2_OPTIONS(21388,
|
||||
{logv2::LogTag::kStartupWarnings},
|
||||
"** WARNING: Replica set config contains customized getLastErrorDefaults,");
|
||||
LOGV2_OPTIONS(21389,
|
||||
{logv2::LogTag::kStartupWarnings},
|
||||
"** which are deprecated. Use setDefaultRWConcern instead to set a");
|
||||
"** which have been deprecated and are now ignored. Use "
|
||||
"setDefaultRWConcern instead to set a");
|
||||
LOGV2_OPTIONS(21390,
|
||||
{logv2::LogTag::kStartupWarnings},
|
||||
"** cluster-wide default writeConcern.");
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include "mongo/db/auth/privilege.h"
|
||||
#include "mongo/db/commands.h"
|
||||
#include "mongo/db/dbdirectclient.h"
|
||||
#include "mongo/db/repl/replication_coordinator.h"
|
||||
#include "mongo/db/s/add_shard_cmd_gen.h"
|
||||
#include "mongo/db/s/add_shard_util.h"
|
||||
#include "mongo/rpc/get_status_from_command_result.h"
|
||||
@ -60,6 +61,13 @@ public:
|
||||
uassert(50876,
|
||||
"Cannot run addShard on a node started without --shardsvr",
|
||||
serverGlobalParams.clusterRole == ClusterRole::ShardServer);
|
||||
tassert(5624104,
|
||||
"Cannot run addShard on a node that contains customized getLastErrorDefaults, "
|
||||
"which has been deprecated and is now ignored. Use setDefaultRWConcern instead "
|
||||
"to set a cluster-wide default writeConcern.",
|
||||
!repl::ReplicationCoordinator::get(opCtx)
|
||||
->getConfig()
|
||||
.containsCustomizedGetLastErrorDefaults());
|
||||
|
||||
auto addShardCmd = request();
|
||||
auto shardIdUpsertCmd =
|
||||
|
Loading…
Reference in New Issue
Block a user