forked from mongodb/mongo
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathkillop_own_ops.js
153 lines (132 loc) · 5.31 KB
/
killop_own_ops.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
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/**
* Test that a user may $currentOp, and then killOp their own operations.
*
* Theory of operation: Create a long running operation from a user which does not have the killOp
* or inProg privileges. Using the same user, run currentOp to get the opId, and then run killOp
* against it.
* @tags: [requires_sharding]
*/
import {configureFailPoint} from "jstests/libs/fail_point_util.js";
import {FixtureHelpers} from "jstests/libs/fixture_helpers.js";
import {ShardingTest} from "jstests/libs/shardingtest.js";
function runTest(m, failPointName, altFailPointName) {
var db = m.getDB("foo");
var admin = m.getDB("admin");
admin.createUser({user: 'admin', pwd: 'password', roles: jsTest.adminUserRoles});
admin.auth('admin', 'password');
const logReader = {db: 'admin', role: 'clusterMonitor'};
db.createUser({user: 'reader', pwd: 'reader', roles: [{db: 'foo', role: 'read'}, logReader]});
db.createUser({user: 'otherReader', pwd: 'otherReader', roles: [{db: 'foo', role: 'read'}]});
admin.createRole({
role: 'opAdmin',
roles: [],
privileges: [{resource: {cluster: true}, actions: ['inprog', 'killop']}]
});
db.createUser({user: 'opAdmin', pwd: 'opAdmin', roles: [{role: 'opAdmin', db: 'admin'}]});
var t = db.jstests_killop;
t.save({x: 1});
if (!FixtureHelpers.isMongos(db)) {
assert.commandWorked(
db.adminCommand({setParameter: 1, internalQueryExecYieldIterations: 1}));
}
admin.logout();
// Only used for nice error messages.
function getAllLocalOps() {
admin.aggregate([{$currentOp: {allUsers: true, localOps: true}}]).toArray();
}
/**
* This function filters for the operations that we're looking for, based on their state and
* the contents of their query object.
*/
function ops(ownOps = true) {
const ops = admin.aggregate([{$currentOp: {allUsers: !ownOps, localOps: true}}]).toArray();
var ids = [];
for (let o of ops) {
if ((o.active || o.waitingForLock) && o.command &&
o.command.find === "jstests_killop" && o.command.comment === "kill_own_ops") {
ids.push(o.opid);
}
}
return ids;
}
var queryAsReader =
'db = db.getSiblingDB("foo"); db.auth("reader", "reader"); db.jstests_killop.find().comment("kill_own_ops").toArray()';
jsTestLog("Starting long-running operation");
db.auth('reader', 'reader');
const fp = configureFailPoint(m, failPointName);
var s1 = startParallelShell(queryAsReader, m.port);
jsTestLog("Finding ops in $currentOp output");
var o = [];
assert.soon(
function() {
o = ops();
return o.length == 1;
},
() => {
return tojson(getAllLocalOps());
},
60000);
jsTestLog("Checking that another user cannot see or kill the op");
db.logout();
db.auth('otherReader', 'otherReader');
assert.eq([], ops());
assert.commandFailed(db.killOp(o[0]));
db.logout();
db.auth('reader', 'reader');
assert.eq(1, ops().length);
db.logout();
jsTestLog("Checking that originating user can kill operation");
var start = new Date();
db.auth('reader', 'reader');
assert.commandWorked(db.killOp(o[0]));
checkLog.contains(db, '"msg":"Successful killOp"');
fp.off();
jsTestLog("Waiting for ops to terminate");
var exitCode = s1({checkExitSuccess: false});
assert.neq(0,
exitCode,
"expected shell to exit abnormally due to operation execution being terminated");
// don't want to pass if timeout killed the js function.
var end = new Date();
var diff = end - start;
assert.lt(diff, 30000, "Start: " + start + "; end: " + end + "; diff: " + diff);
jsTestLog("Starting a second long-running operation");
const fp2 = configureFailPoint(m, failPointName);
var s2 = startParallelShell(queryAsReader, m.port);
jsTestLog("Finding ops in $currentOp output");
var o2 = [];
assert.soon(
function() {
o2 = ops();
return o2.length == 1;
},
() => {
return tojson(getAllLocalOps());
},
60000);
db.logout();
db.auth('opAdmin', 'opAdmin');
jsTestLog("Checking that an administrative user can find others' operations");
assert.eq(o2, ops(false));
jsTestLog("Checking that an administrative user cannot find others' operations with ownOps");
assert.eq([], ops());
jsTestLog("Checking that an administrative user can kill others' operations");
start = new Date();
assert.commandWorked(db.killOp(o2[0]));
fp2.off();
jsTestLog("Waiting for ops to terminate");
exitCode = s2({checkExitSuccess: false});
assert.neq(
0, exitCode, "expected shell to exit abnormally due to JS execution being terminated");
end = new Date();
diff = end - start;
assert.lt(diff, 30000, "Start: " + start + "; end: " + end + "; diff: " + diff);
}
var conn = MongoRunner.runMongod({auth: ""});
runTest(conn, "setYieldAllLocksHang");
MongoRunner.stopMongod(conn);
var st = new ShardingTest({shards: 1, keyFile: 'jstests/libs/key1'});
// Use a different failpoint in the sharded version, since the mongos does not have a
// setYieldAlllocksHang failpoint.
runTest(st.s, "waitInFindBeforeMakingBatch");
st.stop();