summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVarun Ravichandran <varun.ravichandran@mongodb.com>2022-03-17 23:50:53 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2022-04-01 19:24:56 +0000
commitfe488bc9f33d81fbc77f179b4e77effc4f0844fc (patch)
tree8c81733111eb1d6266be62a734238462717255e8
parent9fe5c85db8a6aa1432807d8c473360a81a9a2eaf (diff)
downloadmongo-fe488bc9f33d81fbc77f179b4e77effc4f0844fc.tar.gz
SERVER-62261: Implement getClusterParameter command on mongod and mongos
-rw-r--r--jstests/auth/lib/commands_lib.js22
-rw-r--r--jstests/core/views/views_all_commands.js1
-rw-r--r--jstests/libs/cluster_server_parameter_utils.js249
-rw-r--r--jstests/replsets/cluster_server_parameter_commands_replset.js39
-rw-r--r--jstests/replsets/db_reads_while_recovering_all_commands.js1
-rw-r--r--jstests/sharding/cluster_server_parameter_commands_sharded.js43
-rw-r--r--jstests/sharding/database_versioning_all_commands.js1
-rw-r--r--jstests/sharding/libs/last_lts_mongod_commands.js1
-rw-r--r--jstests/sharding/libs/last_lts_mongos_commands.js1
-rw-r--r--jstests/sharding/read_write_concern_defaults_application.js1
-rw-r--r--jstests/sharding/safe_secondary_reads_drop_recreate.js1
-rw-r--r--jstests/sharding/safe_secondary_reads_single_migration_suspend_range_deletion.js1
-rw-r--r--jstests/sharding/safe_secondary_reads_single_migration_waitForDelete.js1
-rw-r--r--src/mongo/db/auth/action_type.idl1
-rw-r--r--src/mongo/db/auth/builtin_roles.cpp3
-rw-r--r--src/mongo/db/commands/SConscript9
-rw-r--r--src/mongo/db/commands/cluster_server_parameter_cmds.idl (renamed from src/mongo/db/commands/set_cluster_parameter.idl)21
-rw-r--r--src/mongo/db/commands/get_cluster_parameter_command.cpp142
-rw-r--r--src/mongo/db/commands/set_cluster_parameter_command.cpp6
-rw-r--r--src/mongo/db/commands/set_cluster_parameter_invocation.cpp4
-rw-r--r--src/mongo/db/commands/set_cluster_parameter_invocation.h4
-rw-r--r--src/mongo/db/namespace_string.cpp3
-rw-r--r--src/mongo/db/namespace_string.h3
-rw-r--r--src/mongo/idl/SConscript1
-rw-r--r--src/mongo/idl/cluster_server_parameter.idl38
-rw-r--r--src/mongo/s/SConscript2
-rw-r--r--src/mongo/s/commands/SConscript3
-rw-r--r--src/mongo/s/commands/cluster_get_cluster_parameter_cmd.cpp188
-rw-r--r--src/mongo/s/commands/cluster_set_cluster_parameter_cmd.cpp2
29 files changed, 774 insertions, 18 deletions
diff --git a/jstests/auth/lib/commands_lib.js b/jstests/auth/lib/commands_lib.js
index d42234eef7f..dbc73db0e47 100644
--- a/jstests/auth/lib/commands_lib.js
+++ b/jstests/auth/lib/commands_lib.js
@@ -4176,6 +4176,18 @@ var authCommandsLib = {
]
},
{
+ testname: "getClusterParameter",
+ command: {getClusterParameter: "testIntClusterParameter"},
+ skipTest: (conn) => !TestData.setParameters.featureFlagClusterWideConfig,
+ testcases: [
+ {
+ runOnDb: adminDbName,
+ roles: {clusterManager: 1, clusterAdmin: 1, root: 1, __system: 1},
+ privileges: [{resource: {cluster: true}, actions: ["getClusterParameter"]}]
+ }
+ ]
+ },
+ {
testname: "getCmdLineOpts",
command: {getCmdLineOpts: 1},
testcases: [
@@ -5652,10 +5664,14 @@ var authCommandsLib = {
}
]
},
- { // TODO: Temporarily disabled until an appropriate parameter is configured for testing (SERVER-62261)
+ {
testname: "setClusterParameter",
- command: {setClusterParameter: {param: true}},
- skipTest: (conn) => true || !TestData.setParameters.featureFlagClusterWideConfig,
+ command: {setClusterParameter: {testIntClusterParameterParam: {intData: 17}}},
+ skipTest: (conn) => {
+ const hello = assert.commandWorked(conn.getDB("admin").runCommand({hello: 1}));
+ const isStandalone = hello.msg !== "isdbgrid" && !hello.hasOwnProperty('setName');
+ return !TestData.setParameters.featureFlagClusterWideConfig || isStandalone;
+ },
testcases: [
{
runOnDb: adminDbName,
diff --git a/jstests/core/views/views_all_commands.js b/jstests/core/views/views_all_commands.js
index d18e14b19e3..ec722dffa4d 100644
--- a/jstests/core/views/views_all_commands.js
+++ b/jstests/core/views/views_all_commands.js
@@ -359,6 +359,7 @@ let viewsCommandTests = {
getAuditConfig: {skip: isUnrelated},
getDatabaseVersion: {skip: isUnrelated},
getChangeStreamOptions: {skip: isUnrelated},
+ getClusterParameter: {skip: isUnrelated},
getCmdLineOpts: {skip: isUnrelated},
getDefaultRWConcern: {skip: isUnrelated},
getDiagnosticData: {skip: isUnrelated},
diff --git a/jstests/libs/cluster_server_parameter_utils.js b/jstests/libs/cluster_server_parameter_utils.js
new file mode 100644
index 00000000000..8800ee45af7
--- /dev/null
+++ b/jstests/libs/cluster_server_parameter_utils.js
@@ -0,0 +1,249 @@
+/**
+ * Util functions used by cluster server parameter tests.
+ *
+ * When adding new cluster server parameters, do the following:
+ * 1. Add its name to clusterParameterNames.
+ * 2. Add the clusterParameter document that's expected as default to clusterParametersDefault.
+ * 3. Add the clusterParameter document that setClusterParameter is expected to insert after its
+ * first invocation to clusterParametersInsert.
+ * 4. Add the clusterParameter document that setClusterParameter is expected to update to after its
+ * second invocation to clusterParametersUpdate.
+ *
+ */
+
+const clusterParameterNames = ["testStrClusterParameter", "testIntClusterParameter"];
+const clusterParametersDefault = [
+ {
+ _id: "testStrClusterParameter",
+ clusterParameterTime: Timestamp(0, 0),
+ strData: "off",
+ },
+ {
+ _id: "testIntClusterParameter",
+ clusterParameterTime: Timestamp(0, 0),
+ intData: 16,
+ }
+];
+
+const clusterParametersInsert = [
+ {
+ _id: "testStrClusterParameter",
+ clusterParameterTime: Timestamp(10, 2),
+ strData: "on",
+ },
+ {
+ _id: "testIntClusterParameter",
+ clusterParameterTime: Timestamp(10, 2),
+ intData: 17,
+ }
+];
+
+const clusterParametersUpdate = [
+ {
+ _id: "testStrClusterParameter",
+ clusterParameterTime: Timestamp(20, 4),
+ strData: "sleep",
+ },
+ {
+ _id: "testIntClusterParameter",
+ clusterParameterTime: Timestamp(20, 4),
+ intData: 18,
+ }
+];
+
+// Set the log level for get/setClusterParameter logging to appear.
+function setupNode(conn) {
+ const adminDB = conn.getDB('admin');
+ adminDB.setLogLevel(2);
+}
+
+function setupReplicaSet(rst) {
+ setupNode(rst.getPrimary());
+
+ rst.getSecondaries().forEach(function(secondary) {
+ setupNode(secondary);
+ });
+}
+
+function setupSharded(st) {
+ setupNode(st.s0);
+
+ const shards = [st.rs0, st.rs1, st.rs2];
+ shards.forEach(function(shard) {
+ setupReplicaSet(shard);
+ });
+}
+
+// TO-DO SERVER-65128: replace this function with a call to setClusterParameter.
+// Upserts config.clusterParameters document with w:majority.
+function simulateSetClusterParameterReplicaSet(rst, query, update) {
+ const clusterParametersNS = rst.getPrimary().getDB('config').clusterParameters;
+ assert.commandWorked(
+ clusterParametersNS.update(query, update, {upsert: true, writeConcern: {w: "majority"}}));
+}
+
+// TO-DO SERVER-65128: replace this function with a call to setClusterParameter.
+// Upserts config.clusterParameters document with w:majority into configsvr and all shards.
+function simulateSetClusterParameterSharded(st, query, update) {
+ simulateSetClusterParameterReplicaSet(st.configRS, query, update);
+
+ const shards = [st.rs0, st.rs1, st.rs2];
+ shards.forEach(function(shard) {
+ simulateSetClusterParameterReplicaSet(shard, query, update);
+ });
+}
+
+// Runs getClusterParameter on a specific mongod or mongos node and returns true/false depending
+// on whether .
+function runGetClusterParameterNode(conn, getClusterParameterArgs, expectedClusterParameters) {
+ const adminDB = conn.getDB('admin');
+ const actualClusterParameters =
+ assert.commandWorked(adminDB.runCommand({getClusterParameter: getClusterParameterArgs}))
+ .clusterParameters;
+
+ // Sort the returned clusterParameters and the expected clusterParameters by _id.
+ actualClusterParameters.sort((a, b) => a._id.localeCompare(b._id));
+ expectedClusterParameters.sort((a, b) => a._id.localeCompare(b._id));
+ for (let i = 0; i < expectedClusterParameters.length; i++) {
+ const expectedClusterParameter = expectedClusterParameters[i];
+ const actualClusterParameter = actualClusterParameters[i];
+
+ // Sort both expectedClusterParameter and actualClusterParameter into alphabetical order
+ // by key.
+ const sortedExpectedClusterParameter =
+ Object.keys(expectedClusterParameter).sort().reduce(function(sorted, key) {
+ sorted[key] = expectedClusterParameter[key];
+ return sorted;
+ }, {});
+ const sortedActualClusterParameter =
+ Object.keys(actualClusterParameter).sort().reduce(function(sorted, key) {
+ sorted[key] = actualClusterParameter[key];
+ return sorted;
+ }, {});
+ if (bsonWoCompare(sortedExpectedClusterParameter, sortedActualClusterParameter) !== 0) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// Runs getClusterParameter on each replica set node and asserts that the response matches the
+// expected parameter objects on at least a majority of nodes.
+function runGetClusterParameterReplicaSet(rst, getClusterParameterArgs, expectedClusterParameters) {
+ let numMatches = 0;
+ const numTotalNodes = rst.getSecondaries().length + 1;
+ if (runGetClusterParameterNode(
+ rst.getPrimary(), getClusterParameterArgs, expectedClusterParameters)) {
+ numMatches++;
+ }
+
+ rst.getSecondaries().forEach(function(secondary) {
+ if (runGetClusterParameterNode(
+ secondary, getClusterParameterArgs, expectedClusterParameters)) {
+ numMatches++;
+ }
+ });
+
+ assert((numMatches / numTotalNodes) > 0.5);
+}
+
+// Runs getClusterParameter on mongos and each mongod in each shard replica set.
+function runGetClusterParameterSharded(st, getClusterParameterArgs, expectedClusterParameters) {
+ runGetClusterParameterNode(st.s0, getClusterParameterArgs, expectedClusterParameters);
+
+ const shards = [st.rs0, st.rs1, st.rs2];
+ shards.forEach(function(shard) {
+ runGetClusterParameterReplicaSet(shard, getClusterParameterArgs, expectedClusterParameters);
+ });
+}
+
+// Tests valid usages of getClusterParameter and verifies that the expected values are returned.
+function testValidParameters(conn) {
+ if (conn instanceof ReplSetTest) {
+ // Run getClusterParameter in list format and '*' and ensure it returns all default values
+ // on all nodes in the replica set.
+ runGetClusterParameterReplicaSet(conn, clusterParameterNames, clusterParametersDefault);
+ runGetClusterParameterReplicaSet(conn, '*', clusterParametersDefault);
+
+ // For each parameter, simulate setClusterParameter and verify that getClusterParameter
+ // returns the updated value on all nodes in the replica set.
+ for (let i = 0; i < clusterParameterNames.length; i++) {
+ query = {_id: clusterParameterNames[i]};
+ simulateSetClusterParameterReplicaSet(conn, query, clusterParametersInsert[i]);
+ runGetClusterParameterReplicaSet(
+ conn, clusterParameterNames[i], [clusterParametersInsert[i]]);
+ }
+
+ // Do the above again to verify that document updates are also handled properly.
+ for (let i = 0; i < clusterParameterNames.length; i++) {
+ query = {_id: clusterParameterNames[i]};
+ simulateSetClusterParameterReplicaSet(conn, query, clusterParametersUpdate[i]);
+ runGetClusterParameterReplicaSet(
+ conn, clusterParameterNames[i], [clusterParametersUpdate[i]]);
+ }
+
+ // Finally, run getClusterParameter in list format and '*' and ensure that they now all
+ // return updated values.
+ runGetClusterParameterReplicaSet(conn, clusterParameterNames, clusterParametersUpdate);
+ runGetClusterParameterReplicaSet(conn, '*', clusterParametersUpdate);
+ } else {
+ // Run getClusterParameter in list format and '*' and ensure it returns all default values
+ // on all nodes in the sharded cluster.
+ runGetClusterParameterSharded(conn, clusterParameterNames, clusterParametersDefault);
+ runGetClusterParameterSharded(conn, '*', clusterParametersDefault);
+
+ // For each parameter, simulate setClusterParameter and verify that getClusterParameter
+ // returns the updated value on all nodes in the sharded cluster.
+ for (let i = 0; i < clusterParameterNames.length; i++) {
+ query = {_id: clusterParameterNames[i]};
+ simulateSetClusterParameterSharded(conn, query, clusterParametersInsert[i]);
+ runGetClusterParameterSharded(
+ conn, clusterParameterNames[i], [clusterParametersInsert[i]]);
+ }
+
+ // Do the above again to verify that document updates are also handled properly.
+ for (let i = 0; i < clusterParameterNames.length; i++) {
+ query = {_id: clusterParameterNames[i]};
+ simulateSetClusterParameterSharded(conn, query, clusterParametersUpdate[i]);
+ runGetClusterParameterSharded(
+ conn, clusterParameterNames[i], [clusterParametersUpdate[i]]);
+ }
+
+ // Finally, run getClusterParameter in list format and '*' and ensure that they now all
+ // return updated values.
+ runGetClusterParameterSharded(conn, clusterParameterNames, clusterParametersUpdate);
+ runGetClusterParameterSharded(conn, '*', clusterParametersUpdate);
+ }
+}
+
+// Tests that invalid uses of getClusterParameter fails
+function testInvalidParametersNode(conn) {
+ const adminDB = conn.getDB('admin');
+ // Assert that specifying a nonexistent parameter returns an error.
+ assert.commandFailedWithCode(adminDB.runCommand({getClusterParameter: "nonexistentParam"}),
+ ErrorCodes.NoSuchKey);
+ assert.commandFailedWithCode(adminDB.runCommand({getClusterParameter: ["nonexistentParam"]}),
+ ErrorCodes.NoSuchKey);
+ assert.commandFailedWithCode(
+ adminDB.runCommand({getClusterParameter: ["testIntClusterParameter", "nonexistentParam"]}),
+ ErrorCodes.NoSuchKey);
+}
+
+// Tests that invalid uses of getClusterParameter fail with the appropriate errors.
+function testInvalidParameters(conn) {
+ if (conn instanceof ReplSetTest) {
+ testInvalidParametersNode(conn.getPrimary());
+ conn.getSecondaries().forEach(function(secondary) {
+ testInvalidParametersNode(secondary);
+ });
+ } else {
+ testInvalidParametersNode(conn.s0);
+ const shards = [conn.rs0, conn.rs1, conn.rs2];
+ shards.forEach(function(shard) {
+ shard.getSecondaries().forEach(function(secondary) {
+ testInvalidParametersNode(secondary);
+ });
+ });
+ }
+}
diff --git a/jstests/replsets/cluster_server_parameter_commands_replset.js b/jstests/replsets/cluster_server_parameter_commands_replset.js
new file mode 100644
index 00000000000..5e296108349
--- /dev/null
+++ b/jstests/replsets/cluster_server_parameter_commands_replset.js
@@ -0,0 +1,39 @@
+/**
+ * Checks that getClusterParameter runs as expected on replica set nodes.
+ *
+ * @tags: [
+ * # Requires all nodes to be running the latest binary.
+ * requires_fcv_60,
+ * featureFlagClusterWideConfig,
+ * does_not_support_stepdowns
+ * ]
+ */
+(function() {
+'use strict';
+
+load('jstests/libs/cluster_server_parameter_utils.js');
+
+// Tests that getClusterParameter works on a non-sharded replica set.
+function runReplSetTest() {
+ const rst = new ReplSetTest({
+ nodes: 3,
+ });
+ rst.startSet();
+ rst.initiate();
+
+ // Setup the necessary logging level for the test.
+ setupReplicaSet(rst);
+
+ // First, ensure that nonexistent parameters and unauthorized users are rejected with the
+ // appropriate error codes.
+ testInvalidParameters(rst);
+
+ // Then, ensure that getClusterParameter returns the expected values for all valid invocations
+ // of getClusterParameter.
+ testValidParameters(rst);
+
+ rst.stopSet();
+}
+
+runReplSetTest();
+})();
diff --git a/jstests/replsets/db_reads_while_recovering_all_commands.js b/jstests/replsets/db_reads_while_recovering_all_commands.js
index 279d167edba..1422d902e2d 100644
--- a/jstests/replsets/db_reads_while_recovering_all_commands.js
+++ b/jstests/replsets/db_reads_while_recovering_all_commands.js
@@ -214,6 +214,7 @@ const allCommands = {
fsyncUnlock: {skip: isNotAUserDataRead},
getAuditConfig: {skip: isNotAUserDataRead},
getChangeStreamOptions: {skip: isNotAUserDataRead},
+ getClusterParameter: {skip: isNotAUserDataRead},
getCmdLineOpts: {skip: isNotAUserDataRead},
getDatabaseVersion: {skip: isNotAUserDataRead},
getDefaultRWConcern: {skip: isNotAUserDataRead},
diff --git a/jstests/sharding/cluster_server_parameter_commands_sharded.js b/jstests/sharding/cluster_server_parameter_commands_sharded.js
new file mode 100644
index 00000000000..9fecae646eb
--- /dev/null
+++ b/jstests/sharding/cluster_server_parameter_commands_sharded.js
@@ -0,0 +1,43 @@
+/**
+ * Checks that getClusterParameter runs as expected on sharded clusters.
+ *
+ * @tags: [
+ * # Requires all nodes to be running the latest binary.
+ * requires_fcv_60,
+ * featureFlagClusterWideConfig,
+ * does_not_support_stepdowns
+ * ]
+ */
+(function() {
+'use strict';
+
+load('jstests/libs/cluster_server_parameter_utils.js');
+
+// Tests that getClusterParameter works on all nodes of a sharded cluster.
+function runShardedTest() {
+ const options = {
+ mongos: 1,
+ config: 1,
+ shards: 3,
+ rs: {
+ nodes: 3,
+ },
+ };
+ const st = new ShardingTest(options);
+
+ // Setup the necessary logging on mongos and the shards.
+ setupSharded(st);
+
+ // First, ensure that nonexistent parameters are rejected with the
+ // appropriate error codes on mongos and all shards.
+ testInvalidParameters(st);
+
+ // Then, ensure that getClusterParameter returns the expected values for all valid invocations
+ // of getClusterParameter.
+ testValidParameters(st);
+
+ st.stop();
+}
+
+runShardedTest();
+})();
diff --git a/jstests/sharding/database_versioning_all_commands.js b/jstests/sharding/database_versioning_all_commands.js
index edd95248a8a..5127c7836ad 100644
--- a/jstests/sharding/database_versioning_all_commands.js
+++ b/jstests/sharding/database_versioning_all_commands.js
@@ -458,6 +458,7 @@ let testCases = {
getAuditConfig: {skip: "not on a user database", conditional: true},
getChangeStreamOptions:
{skip: "executes locally on mongos (not sent to any remote node)", conditional: true},
+ getClusterParameter: {skip: "always targets the config server"},
getCmdLineOpts: {skip: "executes locally on mongos (not sent to any remote node)"},
getDefaultRWConcern: {skip: "executes locally on mongos (not sent to any remote node)"},
getDiagnosticData: {skip: "executes locally on mongos (not sent to any remote node)"},
diff --git a/jstests/sharding/libs/last_lts_mongod_commands.js b/jstests/sharding/libs/last_lts_mongod_commands.js
index f289ba2720d..c25af3a8275 100644
--- a/jstests/sharding/libs/last_lts_mongod_commands.js
+++ b/jstests/sharding/libs/last_lts_mongod_commands.js
@@ -20,6 +20,7 @@ const commandsAddedToMongodSinceLastLTS = [
"clusterGetMore",
"clusterInsert",
"clusterUpdate",
+ "getClusterParameter",
"rotateCertificates",
"setClusterParameter",
"setUserWriteBlockMode",
diff --git a/jstests/sharding/libs/last_lts_mongos_commands.js b/jstests/sharding/libs/last_lts_mongos_commands.js
index 90eb308fa4e..f7a72743e6b 100644
--- a/jstests/sharding/libs/last_lts_mongos_commands.js
+++ b/jstests/sharding/libs/last_lts_mongos_commands.js
@@ -18,6 +18,7 @@ const commandsAddedToMongosSinceLastLTS = [
"commitReshardCollection",
"compactStructuredEncryptionData",
"configureCollectionBalancing",
+ "getClusterParameter",
"moveRange",
"reshardCollection",
"rotateCertificates",
diff --git a/jstests/sharding/read_write_concern_defaults_application.js b/jstests/sharding/read_write_concern_defaults_application.js
index b7804ac5e58..1330131c764 100644
--- a/jstests/sharding/read_write_concern_defaults_application.js
+++ b/jstests/sharding/read_write_concern_defaults_application.js
@@ -476,6 +476,7 @@ let testCases = {
fsyncUnlock: {skip: "does not accept read or write concern"},
getAuditConfig: {skip: "does not accept read or write concern"},
getChangeStreamOptions: {skip: "TODO PM-2502"},
+ getClusterParameter: {skip: "does not accept read or write concern"},
getCmdLineOpts: {skip: "does not accept read or write concern"},
getDatabaseVersion: {skip: "does not accept read or write concern"},
getDefaultRWConcern: {skip: "does not accept read or write concern"},
diff --git a/jstests/sharding/safe_secondary_reads_drop_recreate.js b/jstests/sharding/safe_secondary_reads_drop_recreate.js
index e7fd5f85963..21e887dc4bc 100644
--- a/jstests/sharding/safe_secondary_reads_drop_recreate.js
+++ b/jstests/sharding/safe_secondary_reads_drop_recreate.js
@@ -214,6 +214,7 @@ let testCases = {
fsyncUnlock: {skip: "does not return user data"},
getAuditConfig: {skip: "does not return user data"},
getChangeStreamOptions: {skip: "does not return user data"},
+ getClusterParameter: {skip: "does not return user data"},
getCmdLineOpts: {skip: "does not return user data"},
getDefaultRWConcern: {skip: "does not return user data"},
getDiagnosticData: {skip: "does not return user data"},
diff --git a/jstests/sharding/safe_secondary_reads_single_migration_suspend_range_deletion.js b/jstests/sharding/safe_secondary_reads_single_migration_suspend_range_deletion.js
index da5b4cb9d0d..b7a35ef9d49 100644
--- a/jstests/sharding/safe_secondary_reads_single_migration_suspend_range_deletion.js
+++ b/jstests/sharding/safe_secondary_reads_single_migration_suspend_range_deletion.js
@@ -247,6 +247,7 @@ let testCases = {
fsyncUnlock: {skip: "does not return user data"},
getAuditConfig: {skip: "does not return user data"},
getChangeStreamOptions: {skip: "does not return user data"},
+ getClusterParameter: {skip: "does not return user data"},
getCmdLineOpts: {skip: "does not return user data"},
getDefaultRWConcern: {skip: "does not return user data"},
getDiagnosticData: {skip: "does not return user data"},
diff --git a/jstests/sharding/safe_secondary_reads_single_migration_waitForDelete.js b/jstests/sharding/safe_secondary_reads_single_migration_waitForDelete.js
index 24991db2b9e..4fef3a7cbb8 100644
--- a/jstests/sharding/safe_secondary_reads_single_migration_waitForDelete.js
+++ b/jstests/sharding/safe_secondary_reads_single_migration_waitForDelete.js
@@ -219,6 +219,7 @@ let testCases = {
fsyncUnlock: {skip: "does not return user data"},
getAuditConfig: {skip: "does not return user data"},
getChangeStreamOptions: {skip: "does not return user data"},
+ getClusterParameter: {skip: "does not return user data"},
getCmdLineOpts: {skip: "does not return user data"},
getDefaultRWConcern: {skip: "does not return user data"},
getDiagnosticData: {skip: "does not return user data"},
diff --git a/src/mongo/db/auth/action_type.idl b/src/mongo/db/auth/action_type.idl
index dc11b26fb4a..6cfbd32d0a9 100644
--- a/src/mongo/db/auth/action_type.idl
+++ b/src/mongo/db/auth/action_type.idl
@@ -97,6 +97,7 @@ enums:
forceUUID : "forceUUID"
fsync : "fsync"
getChangeStreamOptions: "getChangeStreamOptions"
+ getClusterParameter: "getClusterParameter"
getDatabaseVersion : "getDatabaseVersion"
getDefaultRWConcern : "getDefaultRWConcern"
getCmdLineOpts : "getCmdLineOpts"
diff --git a/src/mongo/db/auth/builtin_roles.cpp b/src/mongo/db/auth/builtin_roles.cpp
index cbad7142669..70331b72391 100644
--- a/src/mongo/db/auth/builtin_roles.cpp
+++ b/src/mongo/db/auth/builtin_roles.cpp
@@ -255,7 +255,8 @@ MONGO_INITIALIZER(AuthorizationBuiltinRoles)(InitializerContext* context) {
<< ActionType::setFreeMonitoring
<< ActionType::setChangeStreamOptions
<< ActionType::getChangeStreamOptions
- << ActionType::setClusterParameter;
+ << ActionType::setClusterParameter
+ << ActionType::getClusterParameter;
clusterManagerRoleDatabaseActions
<< ActionType::clearJumboFlag
diff --git a/src/mongo/db/commands/SConscript b/src/mongo/db/commands/SConscript
index d28bd5d286b..cd2f7b33a87 100644
--- a/src/mongo/db/commands/SConscript
+++ b/src/mongo/db/commands/SConscript
@@ -322,9 +322,9 @@ env.Library(
)
env.Library(
- target='set_cluster_parameter_idl',
+ target='cluster_server_parameter_cmds_idl',
source=[
- 'set_cluster_parameter.idl',
+ 'cluster_server_parameter_cmds.idl',
],
LIBDEPS=[
'$BUILD_DIR/mongo/base',
@@ -535,6 +535,7 @@ env.Library(
"dbcommands_d.cpp",
"dbhash.cpp",
"driverHelpers.cpp",
+ 'get_cluster_parameter_command.cpp',
"internal_rename_if_options_and_indexes_match_cmd.cpp",
"fle2_compact_cmd.cpp",
"map_reduce_command.cpp",
@@ -638,7 +639,7 @@ env.Library(
LIBDEPS=[
'$BUILD_DIR/mongo/base',
'$BUILD_DIR/mongo/s/write_ops/cluster_write_ops',
- 'set_cluster_parameter_idl'
+ 'cluster_server_parameter_cmds_idl'
],
)
@@ -849,4 +850,4 @@ env.CppUnitTest(
"set_cluster_parameter_invocation",
"standalone",
],
-) \ No newline at end of file
+)
diff --git a/src/mongo/db/commands/set_cluster_parameter.idl b/src/mongo/db/commands/cluster_server_parameter_cmds.idl
index b20af08dc8e..9c768f43f23 100644
--- a/src/mongo/db/commands/set_cluster_parameter.idl
+++ b/src/mongo/db/commands/cluster_server_parameter_cmds.idl
@@ -27,17 +27,34 @@
#
global:
- cpp_namespace: "mongo"
+ cpp_namespace: "mongo"
imports:
- "mongo/idl/basic_types.idl"
+structs:
+ GetClusterParameterReply:
+ description: "Reply to getClusterParameter command"
+ fields:
+ clusterParameters: array<object>
+
commands:
setClusterParameter:
- description: Command to set a ClusterServerParameter
+ description: "Command to set a ClusterServerParameter"
command_name: setClusterParameter
cpp_name: SetClusterParameter
api_version: ""
namespace: type
type: object
strict: true
+
+ getClusterParameter:
+ description: "Retrieves the in-memory value of the specified cluster server parameter(s)"
+ command_name: getClusterParameter
+ cpp_name: GetClusterParameter
+ api_version: ""
+ namespace: type
+ type:
+ variant: [string, array<string>]
+ reply_type: GetClusterParameterReply
+ strict: false
diff --git a/src/mongo/db/commands/get_cluster_parameter_command.cpp b/src/mongo/db/commands/get_cluster_parameter_command.cpp
new file mode 100644
index 00000000000..76f6f91c590
--- /dev/null
+++ b/src/mongo/db/commands/get_cluster_parameter_command.cpp
@@ -0,0 +1,142 @@
+/**
+ * Copyright (C) 2022-present MongoDB, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the Server Side Public License, version 1,
+ * as published by MongoDB, Inc.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * Server Side Public License for more details.
+ *
+ * You should have received a copy of the Server Side Public License
+ * along with this program. If not, see
+ * <http://www.mongodb.com/licensing/server-side-public-license>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the Server Side Public License in all respects for
+ * all of the code used other than as permitted herein. If you modify file(s)
+ * with this exception, you may extend this exception to your version of the
+ * file(s), but you are not obligated to do so. If you do not wish to do so,
+ * delete this exception statement from your version. If you delete this
+ * exception statement from all source files in the program, then also delete
+ * it in the license file.
+ */
+
+#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kCommand
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/db/auth/authorization_session.h"
+#include "mongo/db/commands.h"
+#include "mongo/db/commands/cluster_server_parameter_cmds_gen.h"
+#include "mongo/idl/cluster_server_parameter_gen.h"
+#include "mongo/logv2/log.h"
+
+namespace mongo {
+
+namespace {
+
+class GetClusterParameterCommand final : public TypedCommand<GetClusterParameterCommand> {
+public:
+ using Request = GetClusterParameter;
+ using Reply = GetClusterParameter::Reply;
+ using Map = ServerParameterSet::Map;
+
+ AllowedOnSecondary secondaryAllowed(ServiceContext*) const override {
+ return AllowedOnSecondary::kAlways;
+ }
+
+ bool adminOnly() const override {
+ return true;
+ }
+
+ std::string help() const override {
+ return "Get in-memory cluster parameter value(s) from this node";
+ }
+
+ class Invocation final : public InvocationBase {
+ public:
+ using InvocationBase::InvocationBase;
+
+ Reply typedRun(OperationContext* opCtx) {
+ uassert(
+ ErrorCodes::IllegalOperation,
+ "featureFlagClusterWideConfig not enabled",
+ gFeatureFlagClusterWideConfig.isEnabled(serverGlobalParams.featureCompatibility));
+
+ const stdx::variant<std::string, std::vector<std::string>>& cmdBody =
+ request().getCommandParameter();
+ ServerParameterSet* clusterParameters = ServerParameterSet::getClusterParameterSet();
+ std::vector<BSONObj> parameterValues;
+ std::vector<std::string> parameterNames;
+
+ // For each parameter, generate a BSON representation of it and retrieve its name.
+ auto makeBSON = [&](ServerParameter* requestedParameter) {
+ BSONObjBuilder bob;
+ bob.append("_id"_sd, requestedParameter->name());
+ requestedParameter->append(opCtx, bob, requestedParameter->name());
+ parameterValues.push_back(bob.obj());
+ parameterNames.push_back(requestedParameter->name());
+ };
+
+ stdx::visit(
+ visit_helper::Overloaded{
+ [&](const std::string& strParameterName) {
+ if (strParameterName == "*"_sd) {
+ // Retrieve all cluster parameter values.
+ Map clusterParameterMap = clusterParameters->getMap();
+ parameterValues.reserve(clusterParameterMap.size());
+ parameterNames.reserve(clusterParameterMap.size());
+ for (const auto& param : clusterParameterMap) {
+ makeBSON(param.second);
+ }
+ } else {
+ // Any other string must correspond to a single parameter name.
+ ServerParameter* sp = clusterParameters->get(strParameterName);
+ makeBSON(sp);
+ }
+ },
+ [&](const std::vector<std::string>& listParameterNames) {
+ parameterValues.reserve(listParameterNames.size());
+ parameterNames.reserve(listParameterNames.size());
+ for (const auto& requestedParameterName : listParameterNames) {
+ ServerParameter* sp = clusterParameters->get(requestedParameterName);
+ makeBSON(sp);
+ }
+ }},
+ cmdBody);
+
+ LOGV2_DEBUG(6226100,
+ 2,
+ "Retrieved parameter values for cluster server parameters",
+ "parameterNames"_attr = parameterNames);
+
+ return Reply(parameterValues);
+ }
+
+ private:
+ bool supportsWriteConcern() const override {
+ return false;
+ }
+
+ void doCheckAuthorization(OperationContext* opCtx) const override {
+ auto* authzSession = AuthorizationSession::get(opCtx->getClient());
+ uassert(ErrorCodes::Unauthorized,
+ "Not authorized to retrieve cluster server parameters",
+ authzSession->isAuthorizedForPrivilege(Privilege{
+ ResourcePattern::forClusterResource(), ActionType::getClusterParameter}));
+ }
+
+ NamespaceString ns() const override {
+ return NamespaceString(request().getDbName(), "");
+ }
+ };
+} getClusterParameterCommand;
+
+} // namespace
+} // namespace mongo
diff --git a/src/mongo/db/commands/set_cluster_parameter_command.cpp b/src/mongo/db/commands/set_cluster_parameter_command.cpp
index b5285dbeae3..9d4074ac0bc 100644
--- a/src/mongo/db/commands/set_cluster_parameter_command.cpp
+++ b/src/mongo/db/commands/set_cluster_parameter_command.cpp
@@ -27,13 +27,16 @@
* it in the license file.
*/
+#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kCommand
+
#include "mongo/platform/basic.h"
#include "mongo/db/auth/authorization_session.h"
#include "mongo/db/commands.h"
-#include "mongo/db/commands/set_cluster_parameter_gen.h"
+#include "mongo/db/commands/cluster_server_parameter_cmds_gen.h"
#include "mongo/db/commands/set_cluster_parameter_invocation.h"
#include "mongo/idl/cluster_server_parameter_gen.h"
+#include "mongo/logv2/log.h"
namespace mongo {
@@ -94,5 +97,6 @@ public:
}
};
} setClusterParameterCommand;
+
} // namespace
} // namespace mongo
diff --git a/src/mongo/db/commands/set_cluster_parameter_invocation.cpp b/src/mongo/db/commands/set_cluster_parameter_invocation.cpp
index 4cb1087996a..513ae376564 100644
--- a/src/mongo/db/commands/set_cluster_parameter_invocation.cpp
+++ b/src/mongo/db/commands/set_cluster_parameter_invocation.cpp
@@ -31,10 +31,10 @@
#include "mongo/platform/basic.h"
+#include "mongo/db/commands/set_cluster_parameter_invocation.h"
+
#include "mongo/db/auth/authorization_session.h"
#include "mongo/db/commands.h"
-#include "mongo/db/commands/set_cluster_parameter_gen.h"
-#include "mongo/db/commands/set_cluster_parameter_invocation.h"
#include "mongo/db/vector_clock.h"
#include "mongo/idl/cluster_server_parameter_gen.h"
#include "mongo/logv2/log.h"
diff --git a/src/mongo/db/commands/set_cluster_parameter_invocation.h b/src/mongo/db/commands/set_cluster_parameter_invocation.h
index 6077ccac5d9..35b74530a95 100644
--- a/src/mongo/db/commands/set_cluster_parameter_invocation.h
+++ b/src/mongo/db/commands/set_cluster_parameter_invocation.h
@@ -27,7 +27,9 @@
* it in the license file.
*/
-#include "mongo/db/commands/set_cluster_parameter_gen.h"
+#pragma once
+
+#include "mongo/db/commands/cluster_server_parameter_cmds_gen.h"
#include "mongo/db/dbdirectclient.h"
#include "mongo/db/dbhelpers.h"
diff --git a/src/mongo/db/namespace_string.cpp b/src/mongo/db/namespace_string.cpp
index 2eab32c841f..649423f106b 100644
--- a/src/mongo/db/namespace_string.cpp
+++ b/src/mongo/db/namespace_string.cpp
@@ -162,6 +162,9 @@ const NamespaceString NamespaceString::kUserWritesCriticalSectionsNamespace(
const NamespaceString NamespaceString::kCompactStructuredEncryptionCoordinatorNamespace(
NamespaceString::kConfigDb, "compact_structured_encryption_coordinator");
+const NamespaceString NamespaceString::kClusterParametersNamespace(NamespaceString::kConfigDb,
+ "clusterParameters");
+
bool NamespaceString::isListCollectionsCursorNS() const {
return coll() == listCollectionsCursorCol;
}
diff --git a/src/mongo/db/namespace_string.h b/src/mongo/db/namespace_string.h
index 599f5aac11f..4d1dba82f83 100644
--- a/src/mongo/db/namespace_string.h
+++ b/src/mongo/db/namespace_string.h
@@ -216,6 +216,9 @@ public:
// Namespace used for CompactParticipantCoordinator service.
static const NamespaceString kCompactStructuredEncryptionCoordinatorNamespace;
+ // Namespace used for storing cluster wide parameters.
+ static const NamespaceString kClusterParametersNamespace;
+
/**
* Constructs an empty NamespaceString.
*/
diff --git a/src/mongo/idl/SConscript b/src/mongo/idl/SConscript
index 17520eafd06..a63af90f83a 100644
--- a/src/mongo/idl/SConscript
+++ b/src/mongo/idl/SConscript
@@ -61,7 +61,6 @@ env.Library(
LIBDEPS_PRIVATE=[
'feature_flag',
'idl_parser',
- 'server_parameter',
],
)
diff --git a/src/mongo/idl/cluster_server_parameter.idl b/src/mongo/idl/cluster_server_parameter.idl
index 762f33006ee..dc1b53ee0e6 100644
--- a/src/mongo/idl/cluster_server_parameter.idl
+++ b/src/mongo/idl/cluster_server_parameter.idl
@@ -51,9 +51,47 @@ structs:
In normal operation, the clusterParameterTime will increase as the CSP is updated via
setClusterParameter, but may decrease to a previously-seen value on rollback.
type: logicalTime
+ default: LogicalTime::kUninitialized
+
+ TestIntClusterParameterStorage:
+ description: "Storage used for testIntClusterParameter"
+ inline_chained_structs: true
+ chained_structs:
+ ClusterServerParameter: ClusterServerParameter
+ fields:
+ intData:
+ description: "Some int parameter"
+ type: safeInt64
+ default: 16
+
+ TestStrClusterParameterStorage:
+ description: "Storage used for testStrClusterParameter"
+ inline_chained_structs: true
+ chained_structs:
+ ClusterServerParameter: ClusterServerParameter
+ fields:
+ strData:
+ description: "Some string parameter"
+ type: string
+ default: "\"off\""
feature_flags:
featureFlagClusterWideConfig:
description: Mechanism for cluster-wide configuration options
cpp_varname: gFeatureFlagClusterWideConfig
default: false
+
+server_parameters:
+ testIntClusterParameter:
+ set_at: cluster
+ description: "Test cluster parameter that is only usable if enableTestCommands=true"
+ cpp_vartype: TestIntClusterParameterStorage
+ cpp_varname: intStorage
+ test_only: true
+
+ testStrClusterParameter:
+ set_at: cluster
+ description: "Test cluster parameter that is only usable if enableTestCommands=true"
+ cpp_vartype: TestStrClusterParameterStorage
+ cpp_varname: strStorage
+ test_only: true
diff --git a/src/mongo/s/SConscript b/src/mongo/s/SConscript
index 187e802d613..bfc36af2a0f 100644
--- a/src/mongo/s/SConscript
+++ b/src/mongo/s/SConscript
@@ -234,7 +234,7 @@ env.Library(
LIBDEPS=[
'$BUILD_DIR/mongo/client/connection_string',
'$BUILD_DIR/mongo/db/coll_mod_command_idl',
- '$BUILD_DIR/mongo/db/commands/set_cluster_parameter_idl',
+ '$BUILD_DIR/mongo/db/commands/cluster_server_parameter_cmds_idl',
'$BUILD_DIR/mongo/db/commands/set_user_write_block_mode_idl',
'$BUILD_DIR/mongo/db/common',
'$BUILD_DIR/mongo/db/namespace_string',
diff --git a/src/mongo/s/commands/SConscript b/src/mongo/s/commands/SConscript
index 385824d19f6..d80e09c82d3 100644
--- a/src/mongo/s/commands/SConscript
+++ b/src/mongo/s/commands/SConscript
@@ -60,6 +60,7 @@ env.Library(
'cluster_fle2_compact_cmd.cpp',
'cluster_fsync_cmd.cpp',
'cluster_ftdc_commands.cpp',
+ 'cluster_get_cluster_parameter_cmd.cpp',
'cluster_get_last_error_cmd.cpp',
'cluster_get_shard_version_cmd.cpp',
'cluster_getmore_cmd_s.cpp',
@@ -106,6 +107,7 @@ env.Library(
'$BUILD_DIR/mongo/db/api_parameters',
'$BUILD_DIR/mongo/db/auth/auth_checks',
'$BUILD_DIR/mongo/db/commands/change_stream_options',
+ '$BUILD_DIR/mongo/db/commands/cluster_server_parameter_cmds_idl',
'$BUILD_DIR/mongo/db/commands/core',
'$BUILD_DIR/mongo/db/commands/create_command',
'$BUILD_DIR/mongo/db/commands/current_op_common',
@@ -118,7 +120,6 @@ env.Library(
'$BUILD_DIR/mongo/db/commands/rwc_defaults_commands',
'$BUILD_DIR/mongo/db/commands/server_status',
'$BUILD_DIR/mongo/db/commands/servers',
- '$BUILD_DIR/mongo/db/commands/set_cluster_parameter_idl',
'$BUILD_DIR/mongo/db/commands/set_feature_compatibility_version_idl',
'$BUILD_DIR/mongo/db/commands/set_index_commit_quorum_idl',
'$BUILD_DIR/mongo/db/commands/set_user_write_block_mode_idl',
diff --git a/src/mongo/s/commands/cluster_get_cluster_parameter_cmd.cpp b/src/mongo/s/commands/cluster_get_cluster_parameter_cmd.cpp
new file mode 100644
index 00000000000..7f5022ab989
--- /dev/null
+++ b/src/mongo/s/commands/cluster_get_cluster_parameter_cmd.cpp
@@ -0,0 +1,188 @@
+/**
+ * Copyright (C) 2022-present MongoDB, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the Server Side Public License, version 1,
+ * as published by MongoDB, Inc.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * Server Side Public License for more details.
+ *
+ * You should have received a copy of the Server Side Public License
+ * along with this program. If not, see
+ * <http://www.mongodb.com/licensing/server-side-public-license>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the Server Side Public License in all respects for
+ * all of the code used other than as permitted herein. If you modify file(s)
+ * with this exception, you may extend this exception to your version of the
+ * file(s), but you are not obligated to do so. If you do not wish to do so,
+ * delete this exception statement from your version. If you delete this
+ * exception statement from all source files in the program, then also delete
+ * it in the license file.
+ */
+
+#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kSharding
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/db/auth/authorization_session.h"
+#include "mongo/db/commands.h"
+#include "mongo/db/commands/cluster_server_parameter_cmds_gen.h"
+#include "mongo/idl/cluster_server_parameter_gen.h"
+#include "mongo/logv2/log.h"
+#include "mongo/s/cluster_commands_helpers.h"
+#include "mongo/s/grid.h"
+#include "mongo/s/request_types/sharded_ddl_commands_gen.h"
+
+namespace mongo {
+namespace {
+
+class GetClusterParameterCmd final : public TypedCommand<GetClusterParameterCmd> {
+public:
+ using Request = GetClusterParameter;
+ using Reply = GetClusterParameter::Reply;
+ using Map = ServerParameterSet::Map;
+
+ AllowedOnSecondary secondaryAllowed(ServiceContext*) const override {
+ return AllowedOnSecondary::kAlways;
+ }
+
+ bool adminOnly() const override {
+ return true;
+ }
+
+ std::string help() const override {
+ return "Get majority-written cluster parameter value(s) from the config servers";
+ }
+
+ class Invocation final : public InvocationBase {
+ public:
+ using InvocationBase::InvocationBase;
+
+ Reply typedRun(OperationContext* opCtx) {
+ uassert(
+ ErrorCodes::IllegalOperation,
+ "featureFlagClusterWideConfig not enabled",
+ gFeatureFlagClusterWideConfig.isEnabled(serverGlobalParams.featureCompatibility));
+
+ // For now, the mongos implementation retrieves the names of the requested cluster
+ // server parameters and queries them from the config.clusterParameters namespace on
+ // the config servers. This may change after SERVER-62264, when cluster server
+ // parameters will be cached on mongoses as well.
+ auto configServers = Grid::get(opCtx)->shardRegistry()->getConfigShard();
+
+ // Create the query document such that all documents in config.clusterParmeters with _id
+ // in the requested list of ServerParameters are returned.
+ const stdx::variant<std::string, std::vector<std::string>>& cmdBody =
+ request().getCommandParameter();
+ ServerParameterSet* clusterParameters = ServerParameterSet::getClusterParameterSet();
+
+ std::vector<std::string> requestedParameterNames;
+ BSONObjBuilder queryDocBuilder;
+ BSONObjBuilder inObjBuilder = queryDocBuilder.subobjStart("_id"_sd);
+ BSONArrayBuilder parameterNameBuilder = inObjBuilder.subarrayStart("$in"_sd);
+
+ stdx::visit(
+ visit_helper::Overloaded{
+ [&](const std::string& strParameterName) {
+ if (strParameterName == "*"_sd) {
+ // Append all cluster parameter names.
+ Map clusterParameterMap = clusterParameters->getMap();
+ requestedParameterNames.reserve(clusterParameterMap.size());
+ for (const auto& param : clusterParameterMap) {
+ parameterNameBuilder.append(param.first);
+ requestedParameterNames.push_back(param.first);
+ }
+ } else {
+ parameterNameBuilder.append(strParameterName);
+ requestedParameterNames.push_back(strParameterName);
+ }
+ },
+ [&](const std::vector<std::string>& listParameterNames) {
+ requestedParameterNames.reserve(listParameterNames.size());
+ for (const auto& requestedParameterName : listParameterNames) {
+ parameterNameBuilder.append(requestedParameterName);
+ requestedParameterNames.push_back(requestedParameterName);
+ }
+ }},
+ cmdBody);
+
+ parameterNameBuilder.doneFast();
+ inObjBuilder.doneFast();
+
+ // Perform the majority read on the config server primary.
+ BSONObj query = queryDocBuilder.obj();
+ LOGV2(6226101, "Querying config servers for cluster parameters", "query"_attr = query);
+ auto findResponse = uassertStatusOK(configServers->exhaustiveFindOnConfig(
+ opCtx,
+ ReadPreferenceSetting{ReadPreference::PrimaryOnly},
+ repl::ReadConcernLevel::kMajorityReadConcern,
+ NamespaceString::kClusterParametersNamespace,
+ query,
+ BSONObj(),
+ boost::none));
+
+ // Any parameters that are not included in the response don't have a cluster parameter
+ // document yet, which means they still are using the default value.
+ std::vector<BSONObj> retrievedParameters = std::move(findResponse.docs);
+ if (retrievedParameters.size() < requestedParameterNames.size()) {
+ std::vector<std::string> onDiskParameterNames;
+ onDiskParameterNames.reserve(retrievedParameters.size());
+ std::transform(retrievedParameters.begin(),
+ retrievedParameters.end(),
+ std::back_inserter(onDiskParameterNames),
+ [&](const auto& onDiskParameter) {
+ return onDiskParameter["_id"_sd].String();
+ });
+
+ // Sort and find the set difference of the requested parameters and the parameters
+ // returned.
+ std::vector<std::string> defaultParameterNames;
+ defaultParameterNames.reserve(requestedParameterNames.size() -
+ onDiskParameterNames.size());
+ std::sort(onDiskParameterNames.begin(), onDiskParameterNames.end());
+ std::set_difference(requestedParameterNames.begin(),
+ requestedParameterNames.end(),
+ onDiskParameterNames.begin(),
+ onDiskParameterNames.end(),
+ std::back_inserter(defaultParameterNames));
+
+ for (const auto& defaultParameterName : defaultParameterNames) {
+ auto defaultParameter = clusterParameters->get(defaultParameterName);
+ BSONObjBuilder bob;
+ bob.append("_id"_sd, defaultParameterName);
+ defaultParameter->append(opCtx, bob, defaultParameterName);
+ retrievedParameters.push_back(bob.obj());
+ }
+ }
+
+ return Reply(retrievedParameters);
+ }
+
+ private:
+ bool supportsWriteConcern() const override {
+ return false;
+ }
+
+ void doCheckAuthorization(OperationContext* opCtx) const final {
+ auto* authzSession = AuthorizationSession::get(opCtx->getClient());
+ uassert(ErrorCodes::Unauthorized,
+ "Not authorized to retrieve cluster parameters",
+ authzSession->isAuthorizedForPrivilege(Privilege{
+ ResourcePattern::forClusterResource(), ActionType::getClusterParameter}));
+ }
+
+ NamespaceString ns() const override {
+ return NamespaceString(request().getDbName(), "");
+ }
+ };
+} getClusterParameterCmd;
+
+} // namespace
+} // namespace mongo
diff --git a/src/mongo/s/commands/cluster_set_cluster_parameter_cmd.cpp b/src/mongo/s/commands/cluster_set_cluster_parameter_cmd.cpp
index 6b5d4ce6e9e..32b304b903a 100644
--- a/src/mongo/s/commands/cluster_set_cluster_parameter_cmd.cpp
+++ b/src/mongo/s/commands/cluster_set_cluster_parameter_cmd.cpp
@@ -33,7 +33,7 @@
#include "mongo/db/auth/authorization_session.h"
#include "mongo/db/commands.h"
-#include "mongo/db/commands/set_cluster_parameter_gen.h"
+#include "mongo/db/commands/cluster_server_parameter_cmds_gen.h"
#include "mongo/s/cluster_commands_helpers.h"
#include "mongo/s/grid.h"
#include "mongo/s/request_types/sharded_ddl_commands_gen.h"