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
74
75
76
77
78
79
80
81
82
83
|
/**
* Tests that mongos does not gossip cluster time metadata until at least one key is created on the
* config server, and that it does not block waiting for keys at startup.
*/
(function() {
"use strict";
load("jstests/multiVersion/libs/multi_rs.js");
load("jstests/multiVersion/libs/multi_cluster.js"); // For restartMongoses.
function assertContainsValidLogicalTime(res, check) {
assert.hasFields(res, ["$clusterTime"]);
assert.hasFields(res.$clusterTime, ["signature", "clusterTime"]);
// clusterTime must be greater than the uninitialzed value.
// TODO: SERVER-31986 this check can be done only for authenticated connections that do not
// have advance_cluster_time privilege.
if (check) {
assert.eq(bsonWoCompare(res.$clusterTime.clusterTime, Timestamp(0, 0)), 1);
}
assert.hasFields(res.$clusterTime.signature, ["hash", "keyId"]);
// The signature must have been signed by a key with a valid generation.
if (check) {
assert(res.$clusterTime.signature.keyId > NumberLong(0));
}
}
let st = new ShardingTest({shards: {rs0: {nodes: 2}}});
// Verify there are keys in the config server eventually, since mongos doesn't block for keys at
// startup, and that once there are, mongos sends $clusterTime with a signature in responses.
assert.soonNoExcept(function() {
assert(st.s.getDB("admin").system.keys.count() >= 2);
let res = assert.commandWorked(st.s.getDB("test").runCommand({hello: 1}));
assertContainsValidLogicalTime(res, false);
return true;
}, "expected keys to be created and for mongos to send signed cluster times");
// Enable the failpoint, remove all keys, and restart the config servers with the failpoint
// still enabled to guarantee there are no keys.
for (let i = 0; i < st.configRS.nodes.length; i++) {
assert.commandWorked(st.configRS.nodes[i].adminCommand(
{"configureFailPoint": "disableKeyGeneration", "mode": "alwaysOn"}));
}
let res = st.configRS.getPrimary().getDB("admin").system.keys.remove({purpose: "HMAC"});
assert(res.nRemoved >= 2);
assert(st.s.getDB("admin").system.keys.count() == 0,
"expected there to be no keys on the config server");
st.configRS.stopSet(null /* signal */, true /* forRestart */);
st.configRS.startSet(
{restart: true, setParameter: {"failpoint.disableKeyGeneration": "{'mode':'alwaysOn'}"}});
// Limit the max time between refreshes on the config server, so new keys are created quickly.
st.configRS.getPrimary().adminCommand({
"configureFailPoint": "maxKeyRefreshWaitTimeOverrideMS",
"mode": "alwaysOn",
"data": {"overrideMS": 1000}
});
// Disable the failpoint.
for (let i = 0; i < st.configRS.nodes.length; i++) {
assert.commandWorked(st.configRS.nodes[i].adminCommand(
{"configureFailPoint": "disableKeyGeneration", "mode": "off"}));
}
// Mongos should restart with no problems.
st.restartMongoses();
// Eventually mongos will discover the new keys, and start signing cluster times.
assert.soonNoExcept(function() {
assertContainsValidLogicalTime(st.s.getDB("test").runCommand({hello: 1}), false);
return true;
}, "expected mongos to eventually start signing cluster times", 60 * 1000); // 60 seconds.
// There may be a delay between the creation of the first and second keys, but mongos will start
// signing after seeing the first key, so there is only guaranteed to be one at this point.
assert(st.s.getDB("admin").system.keys.count() >= 1,
"expected there to be at least one generation of keys on the config server");
st.stop();
})();
|