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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
|
// Test copyDatabase command with various combinations of authed/unauthed and single node/replica
// set source and dest.
TestData.authMechanism = "SCRAM-SHA-1"; // SERVER-11428
DB.prototype._defaultAuthenticationMechanism = "SCRAM-SHA-1"; // SERVER-11428
var baseName = "jstests_clone_copyauth";
/*
* Helper to spawn a replica set, sharded cluster, or a single mongod and hide it all behind the
* same interface.
*
* Arguments:
*
* clusterType - type of cluster to start. Options are "sharded", "repl", or "single".
* startWithAuth - whether to start the cluster with authentication.
*
* Member variables:
*
* conn - a connection to the node used to access this cluster, whether it's the mongod, a primary
* mongod in a replica set, or a mongos.
* connString - the full connection string used to connect to this cluster. For a replica set this
* is the full connection string including the replica set name.
*
* Member functions:
*
* stop() - stop and cleanup whatever nodes the helper spawned when it was created.
*/
function ClusterSpawnHelper(clusterType, startWithAuth) {
if (clusterType === "sharded") {
var shardingTestConfig = {
name: baseName + "_source",
mongos: 1,
shards: 1,
config: 1
};
if (startWithAuth) {
shardingTestConfig.auth = "";
shardingTestConfig.keyFile = "jstests/libs/key1";
}
var shardingTest = new ShardingTest(shardingTestConfig);
this.conn = shardingTest.s;
this.connString = this.conn.host;
} else if (clusterType === "repl") {
var replSetTestConfig = {
name: baseName + "_source",
nodes: 3,
nodeOptions: {}
};
if (startWithAuth) {
replSetTestConfig.nodeOptions.auth = "";
replSetTestConfig.nodeOptions.keyFile = "jstests/libs/key1";
}
var replSetTest = new ReplSetTest(replSetTestConfig);
replSetTest.startSet();
replSetTest.initiate();
if (startWithAuth) {
authutil.asCluster(replSetTest.nodes,
replSetTestConfig.nodeOptions.keyFile,
function() {
replSetTest.awaitReplication();
});
} else {
replSetTest.awaitReplication();
}
this.conn = replSetTest.getPrimary();
this.connString = replSetTest.getURL();
} else {
var singleNodeConfig = {};
if (startWithAuth) {
singleNodeConfig.auth = "";
}
this.conn = MongoRunner.runMongod(singleNodeConfig);
this.connString = this.conn.host;
}
this.stop = function() {
if (clusterType === "sharded") {
shardingTest.stop();
} else if (clusterType === "repl") {
replSetTest.stopSet();
} else {
MongoRunner.stopMongod(this.conn.port);
}
};
}
/*
* Helper to test the running the "copydb" command between various kinds of clusters and various
* combinations of authentication on the source and target.
*
* @param {Object} configObj
*
* {
* sourceClusterType {string}: Type of cluster to use as the source of the copy. Options are
* "single", "repl", "sharded".
* isSourceUsingAuth {bool}: Whether to use auth in the source cluster for the copy.
* targetClusterType {string}: Type of cluster to use as the target of the copy. Options are
* "single", "repl", "sharded".
* isTargetUsingAuth {bool}: Whether to use auth in the target cluster for the copy.
* }
*/
function copydbBetweenClustersTest(configObj) {
// First sanity check the arguments in our configObj
var requiredKeys =
['sourceClusterType', 'isSourceUsingAuth', 'targetClusterType', 'isTargetUsingAuth'];
var i;
for (i = 0; i < requiredKeys.length; i++) {
assert(configObj.hasOwnProperty(requiredKeys[i]),
"Missing required key: " + requiredKeys[i] + " in config object");
}
// 1. Get a connection to the source database, insert data and setup auth if applicable
source = new ClusterSpawnHelper(configObj.sourceClusterType, configObj.isSourceUsingAuth);
if (configObj.isSourceUsingAuth) {
// Create a super user so we can create a regular user and not be locked out afterwards
source.conn.getDB("admin")
.createUser({user: "sourceSuperUser", pwd: "sourceSuperUser", roles: ["root"]});
source.conn.getDB("admin").auth("sourceSuperUser", "sourceSuperUser");
source.conn.getDB(baseName)[baseName].save({i: 1});
assert.eq(1, source.conn.getDB(baseName)[baseName].count());
assert.eq(1, source.conn.getDB(baseName)[baseName].findOne().i);
// Insert a document and create a regular user that we will use for the target
// authenticating with the source
source.conn.getDB(baseName).createUser({user: "foo", pwd: "bar", roles: ["dbOwner"]});
source.conn.getDB("admin").logout();
assert.throws(function() {
source.conn.getDB(baseName)[baseName].findOne();
});
} else {
source.conn.getDB(baseName)[baseName].save({i: 1});
assert.eq(1, source.conn.getDB(baseName)[baseName].count());
assert.eq(1, source.conn.getDB(baseName)[baseName].findOne().i);
}
// 2. Get a connection to the target database, and set up auth if necessary
target = new ClusterSpawnHelper(configObj.targetClusterType, configObj.isTargetUsingAuth);
if (configObj.isTargetUsingAuth) {
target.conn.getDB("admin")
.createUser({user: "targetSuperUser", pwd: "targetSuperUser", roles: ["root"]});
assert.throws(function() {
target.conn.getDB(baseName)[baseName].findOne();
});
target.conn.getDB("admin").auth("targetSuperUser", "targetSuperUser");
}
// 3. Run the copydb command
target.conn.getDB(baseName).dropDatabase();
assert.eq(0, target.conn.getDB(baseName)[baseName].count());
if (configObj.isSourceUsingAuth) {
// We only need to pass username and password if the target has to send authentication
// information to the source cluster
assert.commandWorked(target.conn.getDB(baseName).copyDatabase(
baseName, baseName, source.connString, "foo", "bar"));
} else {
// We are copying from a cluster with no auth
assert.commandWorked(
target.conn.getDB(baseName).copyDatabase(baseName, baseName, source.connString));
}
assert.eq(1, target.conn.getDB(baseName)[baseName].count());
assert.eq(1, target.conn.getDB(baseName)[baseName].findOne().i);
// 4. Do any necessary cleanup
source.stop();
target.stop();
}
(function() {
"use strict";
var sourceClusterTypeValues = ["single", "repl", "sharded"];
var isSourceUsingAuthValues = [true, false];
var targetClusterTypeValues = ["single", "repl", "sharded"];
var isTargetUsingAuthValues = [true, false];
for (var i = 0; i < sourceClusterTypeValues.length; i++) {
for (var j = 0; j < isSourceUsingAuthValues.length; j++) {
for (var k = 0; k < targetClusterTypeValues.length; k++) {
for (var l = 0; l < isTargetUsingAuthValues.length; l++) {
if (sourceClusterTypeValues[i] === "sharded" &&
targetClusterTypeValues[k] === "sharded") {
// SERVER-13112
continue;
}
if (sourceClusterTypeValues[i] === "repl" &&
targetClusterTypeValues[k] === "repl") {
// SERVER-13077
continue;
}
if (isSourceUsingAuthValues[j] === true &&
targetClusterTypeValues[k] === "sharded") {
// SERVER-6427
continue;
}
if (sourceClusterTypeValues[i] === "repl" &&
isSourceUsingAuthValues[j] === false &&
targetClusterTypeValues[k] === "sharded" &&
isTargetUsingAuthValues[l] == true) {
// SERVER-18103
continue;
}
var testCase = {
'sourceClusterType': sourceClusterTypeValues[i],
'isSourceUsingAuth': isSourceUsingAuthValues[j],
'targetClusterType': targetClusterTypeValues[k],
'isTargetUsingAuth': isTargetUsingAuthValues[l]
};
print("Running copydb with auth test:");
printjson(testCase);
copydbBetweenClustersTest(testCase);
}
}
}
}
}());
print(baseName + " success!");
|