mongo/jstests/sharding/direct_shard_connection_aut...

171 lines
6.4 KiB
JavaScript

/**
* Tests that direct shard connections are correctly allowed and disallowed using authentication.
*
* @tags: [requires_fcv_73]
*/
import {configureFailPoint} from "jstests/libs/fail_point_util.js";
import {ShardingTest} from "jstests/libs/shardingtest.js";
const st = new ShardingTest({
name: jsTestName(),
keyFile: "jstests/libs/key1",
shards: 2,
// Disallow chaining so that when testing replSetAbortPrimaryCatchUp we have the guarantee that
// the secondary is syncing from the primary.
rs0: {nodes: 3, settings: {chainingAllowed: false}},
// By default, our test infrastructure sets the election timeout to a very high value (24
// hours). For this test, we need a shorter election timeout because it relies on nodes running
// an election when they do not detect an active primary. Therefore, we are setting the
// electionTimeoutMillis to its default value.
initiateWithDefaultElectionTimeout: true,
});
const shardConn = st.rs0.getPrimary();
const shardAdminDB = shardConn.getDB("admin");
jsTest.log("Setup users for test");
shardAdminDB.createUser({user: "admin", pwd: "x", roles: ["root"]});
assert(shardAdminDB.auth("admin", "x"), "Authentication failed");
assert.commandWorked(
shardAdminDB.runCommand({
setParameter: 1,
logComponentVerbosity: {sharding: {verbosity: 2}, assert: {verbosity: 1}},
}),
);
// The replSetStateChange action type is needed for this test
shardAdminDB.createUser({user: "user", pwd: "y", roles: ["clusterManager"]});
shardAdminDB.logout();
function awaitReplication(rst) {
let nodes = rst.nodes;
authutil.asCluster(nodes, "jstests/libs/key1", function () {
rst.awaitReplication();
});
}
function setupConn(conn, user, pwd) {
let newConn = new Mongo(conn.host);
assert(newConn.getDB("admin").auth(user, pwd), "Authentication failed");
return newConn;
}
function runAsAdminUser(conn, cmd, database) {
let newConn = setupConn(conn, "admin", "x");
let res = assert.commandWorked(newConn.getDB(database).runCommand(cmd));
newConn.close();
return res;
}
jsTest.log("Await replication to ensure the user is created on all nodes");
awaitReplication(st.rs0);
jsTest.log("Testing replSetStepDown and replSetStepUp");
{
let secondaryConn = setupConn(st.rs0.getSecondary(), "user", "y");
assert.commandWorked(secondaryConn.adminCommand({replSetStepUp: 1}));
authutil.asCluster(st.rs0.nodes, "jstests/libs/key1", function () {
st.rs0.awaitNodesAgreeOnPrimary();
st.rs0.awaitSecondaryNodes();
});
assert.soonNoExcept(() => {
// {replSetStepDown: 0} defaults to 60 seconds rather than 0, so specify 1 here and unfreeze
// the node later in the test if it will be stepped up to primary.
return secondaryConn.adminCommand({replSetStepDown: 1, force: true}).ok;
}, `failed attempt to step down node ${secondaryConn.host}`);
authutil.asCluster(st.rs0.nodes, "jstests/libs/key1", function () {
st.rs0.awaitNodesAgreeOnPrimary();
st.rs0.awaitSecondaryNodes();
});
secondaryConn.close();
}
jsTest.log("Testing replSetFreeze");
{
let secondaryConn = setupConn(st.rs0.getSecondary(), "user", "y");
assert.commandWorked(secondaryConn.adminCommand({replSetFreeze: 1}));
assert.commandWorked(secondaryConn.adminCommand({replSetFreeze: 0}));
secondaryConn.close();
}
jsTest.log("Testing replSetMaintenance");
{
let secondaryConn = setupConn(st.rs0.getSecondary(), "user", "y");
assert.commandWorked(secondaryConn.adminCommand({replSetMaintenance: 1}));
assert.commandWorked(secondaryConn.adminCommand({replSetMaintenance: 0}));
secondaryConn.close();
}
jsTest.log("Testing replSetSyncFrom");
{
let primary = st.rs0.getPrimary();
let secondary1 = st.rs0.getSecondaries()[0];
let secondary2Conn = setupConn(st.rs0.getSecondaries()[1], "user", "y");
assert.commandWorked(secondary2Conn.adminCommand({replSetSyncFrom: secondary1.name}));
assert.commandWorked(secondary2Conn.adminCommand({replSetSyncFrom: primary.name}));
secondary2Conn.close();
}
jsTest.log("Testing replSetAbortPrimaryCatchUp");
{
let primary = st.rs0.getPrimary();
let secondary1 = st.rs0.getSecondaries()[0];
let secondary2 = st.rs0.getSecondaries()[1];
let primaryConn = setupConn(primary, "user", "y");
let secondary1Conn = setupConn(secondary1, "user", "y");
let secondary2Conn = setupConn(secondary2, "user", "y");
// Ensure the secondary we plan to step up isn't frozen from a prior step down
assert.commandWorked(secondary1Conn.adminCommand({replSetFreeze: 0}));
// Reconfig to make the catchup timeout infinite.
let newConfig = assert.commandWorked(primaryConn.adminCommand({replSetGetConfig: 1})).config;
newConfig.version++;
newConfig.settings.catchUpTimeoutMillis = -1;
assert.commandWorked(primaryConn.adminCommand({replSetReconfig: newConfig}));
// Put new secondary into primary catch up
const stopReplProducerFailPoint2 = configureFailPoint(secondary2Conn, "stopReplProducer");
stopReplProducerFailPoint2.wait();
runAsAdminUser(primary, {insert: "catch_up", documents: [{_id: 0}]}, "test");
assert.soon(() => {
let count = runAsAdminUser(
secondary1,
{
count: "catch_up",
readConcern: {level: "local"},
$readPreference: {mode: "secondary"},
},
"test",
).n;
return count == 1;
});
const stopReplProducerFailPoint1 = configureFailPoint(secondary1Conn, "stopReplProducer");
stopReplProducerFailPoint1.wait();
runAsAdminUser(primary, {insert: "catch_up", documents: [{_id: 1}]}, "test");
// Step up the first secondary, it will enter catch up indefinitely
assert.commandWorked(secondary1Conn.adminCommand({replSetStepUp: 1}));
// Now we can abort the catch up
assert.commandWorked(secondary1Conn.adminCommand({replSetAbortPrimaryCatchUp: 1}));
stopReplProducerFailPoint1.off();
stopReplProducerFailPoint2.off();
primaryConn.close();
secondary1Conn.close();
secondary2Conn.close();
authutil.asCluster(st.rs0.nodes, "jstests/libs/key1", function () {
st.rs0.awaitNodesAgreeOnPrimary();
st.rs0.awaitSecondaryNodes();
});
}
let primaryConn = setupConn(st.rs0.getPrimary(), "admin", "x");
let primaryAdminDB = primaryConn.getDB("admin");
primaryAdminDB.dropUser("user");
primaryAdminDB.dropUser("directOperationsUser");
primaryConn.close();
st.stop();