SERVER-109560 Allow FCV downgrade to the previous minor release (#43673)

GitOrigin-RevId: 6cb3e3bd6660ee5d3b3324e9659546867c501d64
This commit is contained in:
Joan Bruguera Micó (at MongoDB) 2025-11-12 08:40:08 +00:00 committed by MongoDB Bot
parent 2307001b3d
commit cae3b64685
19 changed files with 34 additions and 196 deletions

1
.github/CODEOWNERS vendored
View File

@ -1107,7 +1107,6 @@ WORKSPACE.bazel @10gen/devprod-build @svc-auto-approve-bot
/jstests/multiVersion/genericSetFCVUsage/**/1_test_launching_replset.js @10gen/server-replication-reviewers @svc-auto-approve-bot
/jstests/multiVersion/genericSetFCVUsage/**/3_upgrade_replset.js @10gen/server-fcv @svc-auto-approve-bot
/jstests/multiVersion/genericSetFCVUsage/**/arbiter_always_has_latest_fcv.js @10gen/server-fcv @svc-auto-approve-bot
/jstests/multiVersion/genericSetFCVUsage/**/cannot_downgrade_from_latest_to_last_continuous.js @10gen/server-fcv @svc-auto-approve-bot
/jstests/multiVersion/genericSetFCVUsage/**/create_coll_validator_new_feature_no_applyops_check.js @10gen/query-optimization @svc-auto-approve-bot
/jstests/multiVersion/genericSetFCVUsage/**/default_startup_FCV_parameter.js @10gen/server-fcv @svc-auto-approve-bot
/jstests/multiVersion/genericSetFCVUsage/**/do_upgrade_downgrade.js @10gen/server-fcv @svc-auto-approve-bot

View File

@ -130,5 +130,4 @@ executor:
mongod_options:
set_parameters:
enableTestCommands: 1
disableTransitionFromLatestToLastContinuous: False
num_nodes: 2

View File

@ -276,9 +276,7 @@ executor:
mongos_options:
set_parameters:
enableTestCommands: 1
disableTransitionFromLatestToLastContinuous: False
mongod_options:
set_parameters:
enableTestCommands: 1
disableTransitionFromLatestToLastContinuous: False
num_rs_nodes_per_shard: 2

View File

@ -151,9 +151,7 @@ executor:
mongos_options:
set_parameters:
enableTestCommands: 1
disableTransitionFromLatestToLastContinuous: False
mongod_options:
set_parameters:
enableTestCommands: 1
disableTransitionFromLatestToLastContinuous: False
num_rs_nodes_per_shard: 2

View File

@ -1038,4 +1038,3 @@ def _add_testing_set_parameters(suite_set_parameters):
"""
suite_set_parameters.setdefault("testingDiagnosticsEnabled", True)
suite_set_parameters.setdefault("enableTestCommands", True)
suite_set_parameters.setdefault("disableTransitionFromLatestToLastContinuous", False)

View File

@ -607,5 +607,4 @@ def _add_testing_set_parameters(suite_set_parameters):
# Set it to true for now as a placeholder that will error if no further processing is done.
# The placeholder is needed so older versions don't have this option won't have this value set.
suite_set_parameters.setdefault("backtraceLogFile", True)
suite_set_parameters.setdefault("disableTransitionFromLatestToLastContinuous", False)
suite_set_parameters.setdefault("oplogApplicationEnforcesSteadyStateConstraints", True)

View File

@ -2933,8 +2933,6 @@ export class ReplSetTest {
// spinning up. We will re-enable this check after the replica set has finished initiating.
if (jsTestOptions().enableTestCommands) {
options.setParameter.enableReconfigRollbackCommittedWritesCheck = false;
options.setParameter.disableTransitionFromLatestToLastContinuous =
options.setParameter.disableTransitionFromLatestToLastContinuous || false;
}
if (jsTestOptions().performTimeseriesCompressionIntermediateDataIntegrityCheckOnInsert) {

View File

@ -24,9 +24,6 @@ filters:
- "arbiter_always_has_latest_fcv.js":
approvers:
- 10gen/server-fcv
- "cannot_downgrade_from_latest_to_last_continuous.js":
approvers:
- 10gen/server-fcv
- "create_coll_validator_new_feature_no_applyops_check.js":
approvers:
- 10gen/query-optimization

View File

@ -1,6 +1,7 @@
/**
* Tests for the following fcv paths where an upgrade or downgrade fails an can be rolled back:
* Tests for the following fcv paths where an upgrade or downgrade fails and can be rolled back:
* - Failed downgrading from latestFCV to lastLTSFCV, then upgrading back to latestFCV
* - Failed downgrading from latestFCV to lastContinuousFCV, then upgrading back to latestFCV
* - Failed upgrading from lastLTSFCV to latestFCV, then downgrading back to lastLTSFCV
* - Failed upgrading from lastContinuousFCV to latestFCV, then downgrading back to
* lastContinuousFCV
@ -50,6 +51,7 @@ function revertUpgradeOrDowngradeToOriginalFCV(conn, adminDB, originalFCV, targe
}
function runTests(conn, adminDB) {
revertUpgradeOrDowngradeToOriginalFCV(conn, adminDB, latestFCV, lastLTSFCV);
revertUpgradeOrDowngradeToOriginalFCV(conn, adminDB, latestFCV, lastContinuousFCV);
revertUpgradeOrDowngradeToOriginalFCV(conn, adminDB, lastLTSFCV, latestFCV);
revertUpgradeOrDowngradeToOriginalFCV(conn, adminDB, lastContinuousFCV, latestFCV);
}
@ -231,7 +233,10 @@ function runShardingTests() {
shard1: st.rs1.getPrimary().getDB("admin"),
};
const testCases = [{originalFCV: latestFCV, targetFCV: lastLTSFCV}];
const testCases = [
{originalFCV: latestFCV, targetFCV: lastLTSFCV},
{originalFCV: latestFCV, targetFCV: lastContinuousFCV},
];
if (FeatureFlagUtil.isPresentAndEnabled(adminDBs.mongos, "UpgradingToDowngrading")) {
testCases.push(
{originalFCV: lastLTSFCV, targetFCV: latestFCV},

View File

@ -1,77 +0,0 @@
/**
* Tests that we cannot downgrade from latest to last continuous.
*/
import {ReplSetTest} from "jstests/libs/replsettest.js";
import {ShardingTest} from "jstests/libs/shardingtest.js";
TestData.setParameters = TestData.setParameters || {};
TestData.setParameters.disableTransitionFromLatestToLastContinuous = true;
let dbpath = MongoRunner.dataPath + "cannot_downgrade_from_latest_to_last_continuous";
resetDbpath(dbpath);
function runTest(conn, configSvrPrimary = null) {
const checkFCVConn = configSvrPrimary !== null ? configSvrPrimary : conn;
checkFCV(checkFCVConn, latestFCV);
// Fail when attempting to transition from latest to last continuous.
assert.commandFailedWithCode(
conn.runCommand({setFeatureCompatibilityVersion: lastContinuousFCV, confirm: true}),
5147403,
);
checkFCV(checkFCVConn, latestFCV);
// Successfully downgrade to last LTS FCV.
assert.commandWorked(conn.runCommand({setFeatureCompatibilityVersion: lastLTSFCV, confirm: true}));
checkFCV(checkFCVConn, lastLTSFCV);
}
function runStandaloneTest() {
jsTestLog("Running standalone downgrade test");
// Spin up a standalone with latest FCV.
const conn = MongoRunner.runMongod({dbpath: dbpath, binVersion: "latest"});
assert.neq(null, conn, "mongod was unable to start up");
const adminDB = conn.getDB("admin");
runTest(adminDB);
MongoRunner.stopMongod(conn);
}
function runReplicaSetTest() {
jsTestLog("Running replica set downgrade test");
// Spin up a replica set with latest FCV.
const rst = new ReplSetTest({nodes: 3, nodeOptions: {binVersion: "latest"}});
rst.startSet();
rst.initiate();
const primary = rst.getPrimary();
const adminDB = primary.getDB("admin");
runTest(adminDB);
rst.stopSet();
}
function runShardingTest() {
jsTestLog("Running sharded cluster downgrade test");
// Spin up a sharded cluster with latest FCV.
const st = new ShardingTest({shards: 2});
const conn = st.s;
const adminDB = conn.getDB("admin");
const configSvrPrimaryConn = st.configRS.getPrimary().getDB("admin");
runTest(adminDB, configSvrPrimaryConn);
st.stop();
}
if (lastContinuousFCV != lastLTSFCV) {
runStandaloneTest();
runReplicaSetTest();
runShardingTest();
}
TestData.setParameters.disableTransitionFromLatestToLastContinuous = false;

View File

@ -5,9 +5,6 @@
import {ReplSetTest} from "jstests/libs/replsettest.js";
import {ShardingTest} from "jstests/libs/shardingtest.js";
TestData.setParameters = TestData.setParameters || {};
TestData.setParameters.disableTransitionFromLatestToLastContinuous = true;
const latest = "latest";
const testName = "default_startup_FCV_parameter";
const dbpath = MongoRunner.dataPath + testName;

View File

@ -120,8 +120,6 @@ function runAbortUnpreparedTransactionsTest(initialFCV, targetFCV, runSetFCVFn)
assert.commandFailedWithCode(session.commitTransaction_forTesting(), ErrorCodes.NoSuchTransaction);
jsTestLog("Restore the featureCompatibilityVersion to latest.");
// Complete the transition because we can't e.g. upgrade from "downgrading to lastContinuous" -> latest.
assert.commandWorked(testDB.adminCommand({setFeatureCompatibilityVersion: targetFCV, confirm: true}));
assert.commandWorked(testDB.adminCommand({setFeatureCompatibilityVersion: latestFCV, confirm: true}));
session.endSession();
@ -166,8 +164,6 @@ function runAwaitPreparedTransactionsTest(initialFCV, targetFCV, runSetFCVFn) {
assert.commandWorked(PrepareHelpers.commitTransaction(session, prepareTimestamp));
jsTestLog("Restore the featureCompatibilityVersion to latest.");
// Complete the transition because we can't e.g. upgrade from "downgrading to lastContinuous" -> latest.
assert.commandWorked(testDB.adminCommand({setFeatureCompatibilityVersion: targetFCV, confirm: true}));
assert.commandWorked(testDB.adminCommand({setFeatureCompatibilityVersion: latestFCV, confirm: true}));
session.endSession();

View File

@ -10,22 +10,14 @@ import {requireSSLProvider} from "jstests/ssl/libs/ssl_helpers.js";
requireSSLProvider(["openssl", "windows"], function () {
let testUnrevoked = new TLSTest(
// Server option overrides
{
tlsMode: "requireTLS",
tlsCRLFile: "jstests/libs/crl.pem",
setParameter: {enableTestCommands: 1},
},
{tlsMode: "requireTLS", tlsCRLFile: "jstests/libs/crl.pem"},
);
assert(testUnrevoked.connectWorked());
let testRevoked = new TLSTest(
// Server option overrides
{
tlsMode: "requireTLS",
tlsCRLFile: "jstests/libs/crl_expired.pem",
setParameter: {enableTestCommands: 1},
},
{tlsMode: "requireTLS", tlsCRLFile: "jstests/libs/crl_expired.pem"},
);
assert(!testRevoked.connectWorked());

View File

@ -11,7 +11,7 @@ function testCombination(tlsMode, sslShell, shouldSucceed) {
(sslShell ? "true" : "false" + " (should " + (shouldSucceed ? "" : "not ") + "succeed)"),
);
let serverOptionOverrides = {tlsMode: tlsMode, setParameter: {enableTestCommands: 1}};
let serverOptionOverrides = {tlsMode: tlsMode};
let clientOptions = sslShell ? TLSTest.prototype.defaultTLSClientOptions : TLSTest.prototype.noTLSClientOptions;

View File

@ -152,23 +152,26 @@ public:
GenericFCV::kLastLTS /* effective */, GenericFCV::kLastContinuous /* target */);
}
for (auto&& isFromConfigServer : {false, true}) {
_transitions[{GenericFCV::kLatest, GenericFCV::kLastLTS, isFromConfigServer}] =
GenericFCV::kDowngradingFromLatestToLastLTS;
_transitions[{GenericFCV::kDowngradingFromLatestToLastLTS,
GenericFCV::kLastLTS,
isFromConfigServer}] = GenericFCV::kLastLTS;
for (auto [downgrading, upgrading, to] :
std::vector{std::make_tuple(GenericFCV::kDowngradingFromLatestToLastContinuous,
GenericFCV::kUpgradingFromLastContinuousToLatest,
GenericFCV::kLastContinuous),
std::make_tuple(GenericFCV::kDowngradingFromLatestToLastLTS,
GenericFCV::kUpgradingFromLastLTSToLatest,
GenericFCV::kLastLTS)}) {
for (auto&& isFromConfigServer : {false, true}) {
// Start or complete downgrade from latest. If this release's lastContinuous ==
// lastLTS then the second loop iteration just overwrites the first.
_transitions[{GenericFCV::kLatest, to, isFromConfigServer}] = downgrading;
_transitions[{downgrading, to, isFromConfigServer}] = to;
// Add transition from downgrading -> upgrading.
_transitions[{GenericFCV::kDowngradingFromLatestToLastLTS,
GenericFCV::kLatest,
isFromConfigServer}] = GenericFCV::kUpgradingFromLastLTSToLatest;
// Add transition from downgrading -> upgrading.
_transitions[{downgrading, GenericFCV::kLatest, isFromConfigServer}] = upgrading;
}
_fcvDocuments[downgrading] =
makeFCVDoc(to /* effective */, to /* target */, GenericFCV::kLatest /* previous */
);
}
_fcvDocuments[GenericFCV::kDowngradingFromLatestToLastLTS] =
makeFCVDoc(GenericFCV::kLastLTS /* effective */,
GenericFCV::kLastLTS /* target */,
GenericFCV::kLatest /* previous */
);
}
void addTransitionsUpgradingToDowngrading() {
@ -185,23 +188,6 @@ public:
}
}
void addTransitionFromLatestToLastContinuous() {
for (auto&& isFromConfigServer : {false, true}) {
_transitions[{GenericFCV::kLatest, GenericFCV::kLastContinuous, isFromConfigServer}] =
GenericFCV::kDowngradingFromLatestToLastContinuous;
_transitions[{GenericFCV::kDowngradingFromLatestToLastContinuous,
GenericFCV::kLastContinuous,
isFromConfigServer}] = GenericFCV::kLastContinuous;
}
FeatureCompatibilityVersionDocument fcvDoc;
fcvDoc.setVersion(GenericFCV::kLastContinuous);
fcvDoc.setTargetVersion(GenericFCV::kLastContinuous);
fcvDoc.setPreviousVersion(GenericFCV::kLatest);
_fcvDocuments[GenericFCV::kDowngradingFromLatestToLastContinuous] = fcvDoc;
}
/**
* True if a server in multiversion::FeatureCompatibilityVersion "fromVersion" can
* transition to "newVersion". Different rules apply if the request is from a config server.
@ -423,22 +409,14 @@ void FeatureCompatibilityVersion::updateFeatureCompatibilityVersionDocument(
// We may have just stepped down, in which case we should not proceed.
opCtx->checkForInterrupt();
bool isUpgradingOrDowngrading =
serverGlobalParams.featureCompatibility.acquireFCVSnapshot().isUpgradingOrDowngrading(
fromVersion);
bool isUpgradingToDowngradingPath = (fromVersion == GenericFCV::kUpgradingFromLastLTSToLatest &&
newVersion == GenericFCV::kLastLTS) ||
(fromVersion == GenericFCV::kUpgradingFromLastContinuousToLatest &&
newVersion == GenericFCV::kLastContinuous);
bool isDowngradingToUpgradingPath =
fromVersion == GenericFCV::kDowngradingFromLatestToLastLTS &&
newVersion == GenericFCV::kLatest;
// Only transition to fully upgraded or downgraded states when we have completed all required
// upgrade/downgrade behavior, unless it is the downgrading to upgrading path or the upgrading
// to downgrading path.
auto transitioningVersion = setTargetVersion && isUpgradingOrDowngrading &&
!isDowngradingToUpgradingPath && !isUpgradingToDowngradingPath
bool isContinuingSameUpgradeOrDowngrade =
ServerGlobalParams::FCVSnapshot::isUpgradingOrDowngrading(fromVersion) &&
getTransitionFCVInfo(fromVersion).to == newVersion;
auto transitioningVersion = setTargetVersion && isContinuingSameUpgradeOrDowngrade
? fromVersion
: fcvTransitions.getTransitionalVersion(fromVersion, newVersion, isFromConfigServer);
@ -720,19 +698,12 @@ void FeatureCompatibilityVersion::fassertInitializedAfterStartup(OperationContex
}
}
void FeatureCompatibilityVersion::addTransitionFromLatestToLastContinuous() {
fcvTransitions.addTransitionFromLatestToLastContinuous();
}
void FeatureCompatibilityVersion::addTransitionsUpgradingToDowngrading() {
fcvTransitions.addTransitionsUpgradingToDowngrading();
}
void FeatureCompatibilityVersion::afterStartupActions(OperationContext* opCtx) {
fassertInitializedAfterStartup(opCtx);
if (!mongo::repl::disableTransitionFromLatestToLastContinuous) {
addTransitionFromLatestToLastContinuous();
}
addTransitionsUpgradingToDowngrading();
}

View File

@ -62,13 +62,6 @@ public:
*/
static void fassertInitializedAfterStartup(OperationContext* opCtx);
/**
* Adds a transition that allows users to downgrade from latest FCV to last continuous FCV.
* This function should only be called if the 'disableTransitionFromLatestToLastContinuous'
* server parameter is set to 'false'. That parameter is test-only and defaulted to 'true'.
*/
static void addTransitionFromLatestToLastContinuous();
/**
* Adds transitions that allow users to downgrade back to the originalFCV after a failed
* upgrade.

View File

@ -115,8 +115,7 @@ The FCV can be set using the `setFeatureCompatibilityVersion` admin command to o
Each `mongod` release will support the following upgrade/downgrade paths:
- Last-Continuous → Latest
- Note that we do not support downgrading to or from Last-Continuous.
- Last-Continuous ←→ Latest
- Last-LTS ←→ Latest
- Last-LTS → Last-Continuous
- This upgrade-only transition is only possible when requested by the [config server](https://docs.mongodb.com/manual/core/sharded-cluster-config-servers/).

View File

@ -644,17 +644,6 @@ server_parameters:
gte: 0
redact: false
disableTransitionFromLatestToLastContinuous:
description: >-
Prohibits downgrading from latest FCV to last continuous FCV. Disabled by default.
Test-only.
test_only: true
set_at: startup
cpp_vartype: bool
cpp_varname: disableTransitionFromLatestToLastContinuous
default: true
redact: false
unsupportedSyncSource:
description: >-
**Not a supported feature**. Specifies the host/port for a node to use as a sync source.

View File

@ -693,19 +693,6 @@ MongoRunner.mongodOptions = function (opts = {}) {
opts.pathOpts = Object.merge(opts.pathOpts, {dbpath: opts.dbpath});
opts.setParameter ||= {};
if (jsTestOptions().enableTestCommands && typeof opts.setParameter !== "string") {
if (
jsTestOptions().setParameters &&
jsTestOptions().setParameters.disableTransitionFromLatestToLastContinuous
) {
opts.setParameter["disableTransitionFromLatestToLastContinuous"] =
jsTestOptions().setParameters.disableTransitionFromLatestToLastContinuous;
} else {
opts.setParameter["disableTransitionFromLatestToLastContinuous"] = false;
}
}
if (jsTestOptions().mongodTlsCertificateKeyFile && !opts.tlsCertificateKeyFile) {
opts.tlsCertificateKeyFile = jsTestOptions().mongodTlsCertificateKeyFile;
}
@ -720,7 +707,6 @@ MongoRunner.mongodOptions = function (opts = {}) {
_removeSetParameterIfBeforeVersion(opts, "enableReconfigRollbackCommittedWritesCheck", "5.0.0");
_removeSetParameterIfBeforeVersion(opts, "allowMultipleArbiters", "5.3.0");
_removeSetParameterIfBeforeVersion(opts, "internalQueryDisableExclusionProjectionFastPath", "6.2.0");
_removeSetParameterIfBeforeVersion(opts, "disableTransitionFromLatestToLastContinuous", "7.0.0");
_removeSetParameterIfBeforeVersion(opts, "defaultConfigCommandTimeoutMS", "7.3.0");
_removeSetParameterIfBeforeVersion(opts, "enableAutoCompaction", "7.3.0");
_removeSetParameterIfBeforeVersion(opts, "opentelemetryTraceDirectory", "8.3.0");