/
disable_cluster_time_gossiping_in_unreadable_state.js
73 lines (57 loc) · 2.9 KB
/
disable_cluster_time_gossiping_in_unreadable_state.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
/**
* Verifies cluster time metadata is not gossiped or processed by nodes in an unreadable state.
*/
(function() {
"use strict";
function setUpUsers(rst) {
const primaryAdminDB = rst.getPrimary().getDB("admin");
assert.commandWorked(
primaryAdminDB.runCommand({createUser: "admin", pwd: "admin", roles: ["root"]}));
assert.eq(1, primaryAdminDB.auth("admin", "admin"));
assert.commandWorked(primaryAdminDB.getSiblingDB("test").runCommand(
{createUser: "NotTrusted", pwd: "pwd", roles: ["readWrite"]}));
primaryAdminDB.logout();
authutil.asCluster(rst.nodes, "jstests/libs/key1", () => {
rst.awaitLastOpCommitted();
});
}
// Start with auth enabled so cluster times are validated.
const rst = new ReplSetTest({nodes: 2, keyFile: "jstests/libs/key1"});
rst.startSet();
rst.initiate();
setUpUsers(rst);
const secondaryAdminDB = new Mongo(rst.getSecondary().host).getDB("admin");
secondaryAdminDB.auth("admin", "admin");
const secondaryTestDB = rst.getSecondary().getDB("test");
secondaryTestDB.auth("NotTrusted", "pwd");
// Cluster time should be gossipped in the steady state.
let res = assert.commandWorked(secondaryTestDB.runCommand({find: "foo", filter: {}}));
assert.hasFields(res, ["$clusterTime", "operationTime"]);
const validClusterTimeMetadata = res.$clusterTime;
// After entering maintenance mode, cluster time should no longer be gossipped, in or out.
assert.commandWorked(secondaryAdminDB.adminCommand({replSetMaintenance: 1}));
// The find should fail because the node is unreadable.
res = assert.commandFailedWithCode(secondaryTestDB.runCommand({find: "foo", filter: {}}),
ErrorCodes.NotPrimaryOrSecondary);
assert(!res.hasOwnProperty("$clusterTime"), tojson(res));
assert(!res.hasOwnProperty("operationTime"), tojson(res));
// A request with $clusterTime should be ignored. This is verified by sending an invalid
// $clusterTime to emulate situations where valid cluster times would be unable to be verified, e.g.
// when the signing keys have not been cached but cannot be read from admin.system.keys because the
// node is in an unreadable state.
const invalidClusterTimeMetadata = Object.assign(
validClusterTimeMetadata,
{clusterTime: new Timestamp(validClusterTimeMetadata.clusterTime.getTime() + 100, 0)});
res = assert.commandWorked(
secondaryTestDB.runCommand({hello: 1, $clusterTime: invalidClusterTimeMetadata}));
assert.commandWorked(secondaryAdminDB.adminCommand({replSetMaintenance: 0}));
res = assert.commandWorked(secondaryTestDB.runCommand({find: "foo", filter: {}}));
assert.hasFields(res, ["$clusterTime", "operationTime"]);
// A request with invalid cluster time metadata should now be rejected.
assert.commandFailedWithCode(
secondaryTestDB.runCommand({hello: 1, $clusterTime: invalidClusterTimeMetadata}),
ErrorCodes.TimeProofMismatch);
secondaryAdminDB.logout();
secondaryTestDB.logout();
rst.stopSet();
})();