summaryrefslogtreecommitdiff
path: root/jstests/sharding/auth_slaveok_routing.js
blob: 2ba8bec2b7995c11ab928fb0dfd3ee80f2f6e3b1 (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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
/**
 * This tests whether slaveOk reads are properly routed through mongos in
 * an authenticated environment. This test also includes restarting the
 * entire set, then querying afterwards.
 */

/**
 * Checks if a query to the given collection will be routed to the secondary.
 *
 * @param {DBCollection} coll
 * @param {Object} query
 *
 * @return {boolean} true if query was routed to a secondary node.
 */
function doesRouteToSec( coll, query ) {
    var explain = coll.find( query ).explain();
    var conn = new Mongo( explain.server );
    var cmdRes = conn.getDB( 'admin' ).runCommand({ isMaster: 1 });

    jsTest.log('isMaster: ' + tojson(cmdRes));

    return cmdRes.secondary;
}

var rsOpts = { oplogSize: 10 };
var st = new ShardingTest({ keyFile: 'jstests/libs/key1', shards: 1,
    rs: rsOpts, other: { nopreallocj: 1 }});

var mongos = st.s;
var replTest = st.rs0;
var testDB = mongos.getDB( 'AAAAA' );
var coll = testDB.user;
var nodeCount = replTest.nodes.length;

/* Add an admin user to the replica member to simulate connecting from
 * remote location. This is because mongod allows unautheticated
 * connections to access the server from localhost connections if there
 * is no admin user.
 */
var adminDB = mongos.getDB( 'admin' )
adminDB.createUser({user: 'user', pwd: 'password', roles: jsTest.adminUserRoles});
adminDB.auth( 'user', 'password' );
var priAdminDB = replTest.getPrimary().getDB( 'admin' );
priAdminDB.createUser({user:  'user', pwd: 'password', roles: jsTest.adminUserRoles},
                      {w: 3, wtimeout: 30000});

coll.drop();
coll.setSlaveOk( true );

/* Secondaries should be up here, but they can still be in RECOVERY
 * state, which will make the ReplicaSetMonitor mark them as
 * ok = false and not eligible for slaveOk queries.
 */
ReplSetTest.awaitRSClientHosts( mongos, replTest.getSecondaries(),
   { ok : true, secondary : true });

for ( var x = 0; x < 20; x++ ) {
    coll.insert({ v: x, k: 10 });
}

coll.runCommand({ getLastError: 1, w: nodeCount });

/* Although mongos never caches query results, try to do a different query
 * everytime just to be sure.
 */
var vToFind = 0;

jsTest.log( 'First query to SEC' );
assert( doesRouteToSec( coll, { v: vToFind++ }));

var SIG_TERM = 15;
replTest.stopSet( SIG_TERM, true, { auth: { user: 'user', pwd: 'password' }});

for ( var n = 0; n < nodeCount; n++ ) {
    replTest.restart( n, rsOpts );
}

replTest.awaitSecondaryNodes();

coll.setSlaveOk( true );

/* replSetMonitor does not refresh the nodes information when getting secondaries.
 * A node that is previously labeled as secondary can now be a primary, so we
 * wait for the replSetMonitorWatcher thread to refresh the nodes information.
 */
ReplSetTest.awaitRSClientHosts( mongos, replTest.getSecondaries(),
    { ok : true, secondary : true });
//
// We also need to wait for the primary, it's possible that the mongos may think a node is a 
// secondary but it actually changed to a primary before we send our final query.
//
ReplSetTest.awaitRSClientHosts( mongos, replTest.getPrimary(),
    { ok : true, ismaster : true });

// Recheck if we can still query secondaries after refreshing connections.
jsTest.log( 'Final query to SEC' );
assert( doesRouteToSec( coll, { v: vToFind++ }));

// Cleanup auth so Windows will be able to shutdown gracefully
priAdminDB = replTest.getPrimary().getDB( 'admin' );
priAdminDB.auth( 'user', 'password' );
priAdminDB.dropUser( 'user' );

st.stop();