summaryrefslogtreecommitdiff
path: root/jstests/sharding/mongos_does_not_gossip_logical_time_without_keys.js
blob: b24291270418224e3ad43677e276aa069dc1de75 (plain)
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();
})();