summaryrefslogtreecommitdiff
path: root/jstests/sharding/mongod_returns_no_cluster_time_without_keys.js
blob: 3c9cf3e6af71e7f890de11b54db3ecfe39e4a179 (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
/**
 * Tests that mongod does not gossip cluster time metadata and operation time until at least one key
 * is created on the
 * config server.
*  @tags: [requires_persistence]
 */

(function() {
    "use strict";

    load("jstests/multiVersion/libs/multi_rs.js");

    // TODO SERVER-32672: remove this flag.
    TestData.skipGossipingClusterTime = true;
    const keyFile = 'jstests/libs/key1';
    const adminUser = {db: "admin", username: "foo", password: "bar"};
    const rUser = {db: "test", username: "r", password: "bar"};

    function assertContainsValidLogicalTime(res) {
        assert.hasFields(res, ["$clusterTime"]);
        assert.hasFields(res.$clusterTime, ["signature", "clusterTime"]);
        // clusterTime must be greater than the uninitialzed value.
        assert.hasFields(res.$clusterTime.signature, ["hash", "keyId"]);
        // The signature must have been signed by a key with a valid generation.
        assert(res.$clusterTime.signature.keyId > NumberLong(0));

        assert.hasFields(res, ["operationTime"]);
        assert(Object.prototype.toString.call(res.operationTime) === "[object Timestamp]",
               "operationTime must be a timestamp");
    }

    let st = new ShardingTest({shards: {rs0: {nodes: 2}}, other: {keyFile: keyFile}});

    jsTestLog("Started ShardingTest");

    var adminDB = st.s.getDB("admin");
    adminDB.createUser({user: adminUser.username, pwd: adminUser.password, roles: ["__system"]});

    adminDB.auth(adminUser.username, adminUser.password);
    assert(st.s.getDB("admin").system.keys.count() >= 2);

    let priRSConn = st.rs0.getPrimary().getDB("admin");
    priRSConn.createUser({user: rUser.username, pwd: rUser.password, roles: ["root"]});

    // TODO: SERVER-34964
    sleep(30000);

    priRSConn.auth(rUser.username, rUser.password);
    const resWithKeys = priRSConn.runCommand({isMaster: 1});
    assertContainsValidLogicalTime(resWithKeys);

    // 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"}));
    }

    var priCSConn = st.configRS.getPrimary();
    authutil.asCluster(priCSConn, keyFile, function() {
        priCSConn.getDB("admin").system.keys.remove({purpose: "HMAC"});
    });

    assert(adminDB.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'}"}});

    // bounce rs0 to clean the key cache
    st.rs0.stopSet(null /* signal */, true /* forRestart */);
    st.rs0.startSet({restart: true});

    priRSConn.auth(rUser.username, rUser.password);
    const resNoKeys = priRSConn.runCommand({isMaster: 1});
    assert.commandWorked(resNoKeys);

    assert.eq(resNoKeys.hasOwnProperty("$clusterTime"), false);
    assert.eq(resNoKeys.hasOwnProperty("operationTime"), false);

    st.stop();
})();