-
Notifications
You must be signed in to change notification settings - Fork 5.6k
/
Copy pathnative_tenant_data_isolation_initial_sync.js
132 lines (106 loc) · 4.99 KB
/
native_tenant_data_isolation_initial_sync.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
/**
* Tests that initial sync works correctly when multitenancySupport is enabled.
*/
import {arrayEq} from "jstests/aggregation/extras/utils.js";
import {FeatureFlagUtil} from "jstests/libs/feature_flag_util.js";
import {ReplSetTest} from "jstests/libs/replsettest.js";
const kVTSKey = 'secret';
const rst = new ReplSetTest({
nodes: 1,
nodeOptions: {
auth: '',
setParameter: {
multitenancySupport: true,
featureFlagSecurityToken: true,
testOnlyValidatedTenancyScopeKey: kVTSKey,
}
}
});
rst.startSet({keyFile: 'jstests/libs/key1'});
rst.initiate();
const primary = rst.getPrimary();
const kTenant1 = ObjectId();
const kTenant2 = ObjectId();
const kDbName = "test";
const kCollName = "foo";
const primaryConn = new Mongo(primary.host);
const primaryDB = primaryConn.getDB(kDbName);
// Create users for two different tenants.
const adminDb = primary.getDB('admin');
assert.commandWorked(adminDb.runCommand({createUser: 'admin', pwd: 'pwd', roles: ['root']}));
assert(adminDb.auth('admin', 'pwd'));
const featureFlagRequireTenantId = FeatureFlagUtil.isEnabled(adminDb, "RequireTenantID");
const securityToken1 =
_createSecurityToken({user: "userTenant1", db: '$external', tenant: kTenant1}, kVTSKey);
primary._setSecurityToken(_createTenantToken({tenant: kTenant1}));
assert.commandWorked(primary.getDB('$external').runCommand({
createUser: "userTenant1",
roles: [{role: 'dbAdminAnyDatabase', db: 'admin'}, {role: 'readWriteAnyDatabase', db: 'admin'}]
}));
const securityToken2 =
_createSecurityToken({user: "userTenant2", db: '$external', tenant: kTenant2}, kVTSKey);
primary._setSecurityToken(_createTenantToken({tenant: kTenant2}));
assert.commandWorked(primary.getDB('$external').runCommand({
createUser: "userTenant2",
roles: [{role: 'dbAdminAnyDatabase', db: 'admin'}, {role: 'readWriteAnyDatabase', db: 'admin'}]
}));
primary._setSecurityToken(undefined);
// Logout the root user to avoid multiple authentication.
primaryConn.getDB("admin").logout();
// Create a collection, insert some data, and create indexes on the collection for tenant1.
primaryConn._setSecurityToken(securityToken1);
const tenant1Docs = [{_id: 0, a: 1, b: 1}, {_id: 1, a: 2, b: 3}];
assert.commandWorked(primaryDB.runCommand({insert: kCollName, documents: tenant1Docs}));
const tenant1Idxs = [{key: {a: 1}, name: "indexA"}, {key: {b: 1}, name: "indexB"}];
let res =
assert.commandWorked(primaryDB.runCommand({createIndexes: kCollName, indexes: tenant1Idxs}));
assert.eq(3, res.numIndexesAfter, tojson(res));
// Create a collections, insert some data, and create indexes on the collection for tenant2.
primaryConn._setSecurityToken(securityToken2);
const tenant2Docs = [{_id: 10, a: 10, b: 10}, {_id: 11, a: 20, b: 30}];
assert.commandWorked(primaryDB.runCommand({insert: kCollName, documents: tenant2Docs}));
const tenant2Idxs = [{key: {a: -1}, name: "indexA"}, {key: {b: -1}, name: "indexB"}];
res = assert.commandWorked(primaryDB.runCommand({createIndexes: kCollName, indexes: tenant2Idxs}));
assert.eq(3, res.numIndexesAfter, tojson(res));
// Add a new secondary to the replica set and wait for initial sync to finish.
const secondary = rst.add({
setParameter: {
multitenancySupport: true,
featureFlagSecurityToken: true,
testOnlyValidatedTenancyScopeKey: kVTSKey,
}
});
rst.reInitiate();
rst.awaitReplication();
rst.awaitSecondaryNodes();
// Check that we find the data for each tenant on the newly synced secondary.
const secondaryConn = new Mongo(secondary.host);
const secondaryDB = secondaryConn.getDB(kDbName);
secondaryConn.setSecondaryOk();
// Look for tenant1's data and indexes.
secondaryConn._setSecurityToken(securityToken1);
const findTenant1Res = assert.commandWorked(secondaryDB.runCommand({find: kCollName, filter: {}}));
assert(arrayEq(tenant1Docs, findTenant1Res.cursor.firstBatch), tojson(findTenant1Res));
res = assert.commandWorked(secondaryDB.runCommand({listIndexes: kCollName}));
assert.eq(3, res.cursor.firstBatch.length, tojson(res.cursor.firstBatch));
assert(arrayEq(tenant1Idxs.concat([
{key: {"_id": 1}, name: "_id_"},
]),
res.cursor.firstBatch.map(function(index) {
return {key: index.key, name: index.name};
})),
tojson(res.cursor.firstBatch));
// Look for tenant2's data and indexes.
secondaryConn._setSecurityToken(securityToken2);
const findTenant2Res = assert.commandWorked(secondaryDB.runCommand({find: kCollName, filter: {}}));
assert(arrayEq(tenant2Docs, findTenant2Res.cursor.firstBatch), tojson(findTenant2Res));
res = assert.commandWorked(secondaryDB.runCommand({listIndexes: kCollName}));
assert.eq(3, res.cursor.firstBatch.length, tojson(res.cursor.firstBatch));
assert(arrayEq(tenant2Idxs.concat([
{key: {"_id": 1}, name: "_id_"},
]),
res.cursor.firstBatch.map(function(index) {
return {key: index.key, name: index.name};
})),
tojson(res.cursor.firstBatch));
rst.stopSet();