mongo/jstests/sharding/add_shard_2.js

171 lines
6.5 KiB
JavaScript

/**
* Tests adding standalones and replica sets as shards under a variety of configurations (setName,
* valid and invalid hosts, shardName matching or not matching a setName, etc).
*/
import {ReplSetTest} from "jstests/libs/replsettest.js";
import {ShardingTest} from "jstests/libs/shardingtest.js";
import {removeShard} from "jstests/sharding/libs/remove_shard_util.js";
// TODO SERVER-50144 Remove this and allow orphan checking.
// This test calls removeShard which can leave docs in config.rangeDeletions in state "pending",
// therefore preventing orphans from being cleaned up.
TestData.skipCheckOrphans = true;
let addShardRes;
const assertAddShardSucceeded = function (res, shardName) {
assert.commandWorked(res);
// If a shard name was specified, make sure that the name the addShard command reports the
// shard was added with matches the specified name.
if (shardName) {
assert.eq(shardName, res.shardAdded, "name returned by addShard does not match name specified in addShard");
}
// Make sure the shard shows up in config.shards with the shardName reported by the
// addShard command.
assert.neq(
null,
st.s.getDB("config").shards.findOne({_id: res.shardAdded}),
"newly added shard " + res.shardAdded + " not found in config.shards",
);
};
// Note: this method expects that the failure is *not* that the specified shardName is already
// the shardName of an existing shard.
const assertAddShardFailed = function (res, shardName) {
assert.commandFailed(res);
// If a shard name was specified in the addShard, make sure no shard with its name shows up
// in config.shards.
if (shardName) {
if (TestData.configShard && shardName === "config") {
// In config shard mode there's always an entry for config for the config server.
assert.neq(null, st.s.getDB("config").shards.findOne({_id: shardName}));
} else {
assert.eq(
null,
st.s.getDB("config").shards.findOne({_id: shardName}),
"addShard for " + shardName + " reported failure, but shard shows up in config.shards",
);
}
}
};
const st = new ShardingTest({
shards: TestData.configShard ? 1 : 0,
mongos: 1,
});
// Add one shard since the last shard cannot be removed.
const normalShard = new ReplSetTest({name: "add_shard_2-1", nodes: 1, nodeOptions: {shardsvr: ""}});
normalShard.startSet();
normalShard.initiate();
st.s.adminCommand({addShard: normalShard.getURL(), name: "normalShard"});
// Allocate a port that can be used to test adding invalid hosts.
const portWithoutHostRunning = allocatePort();
// 1. Test adding a *replica set* with an ordinary set name
// 1.a. with or without specifying the shardName.
jsTest.log("Adding a replica set without a specified shardName should succeed.");
const rst1 = new ReplSetTest({nodes: 1});
rst1.startSet({shardsvr: ""});
rst1.initiate();
addShardRes = st.s.adminCommand({addShard: rst1.getURL()});
assertAddShardSucceeded(addShardRes);
assert.eq(rst1.name, addShardRes.shardAdded);
removeShard(st, addShardRes.shardAdded);
rst1.stopSet();
jsTest.log("Adding a replica set with a specified shardName that matches the set's name should succeed.");
const rst2 = new ReplSetTest({nodes: 1});
rst2.startSet({shardsvr: ""});
rst2.initiate();
addShardRes = st.s.adminCommand({addShard: rst2.getURL(), name: rst2.name});
assertAddShardSucceeded(addShardRes, rst2.name);
removeShard(st, addShardRes.shardAdded);
rst2.stopSet();
let rst3 = new ReplSetTest({nodes: 1});
rst3.startSet({shardsvr: ""});
rst3.initiate();
jsTest.log("Adding a replica set with a specified shardName that differs from the set's name should succeed.");
addShardRes = st.s.adminCommand({addShard: rst3.getURL(), name: "differentShardName"});
assertAddShardSucceeded(addShardRes, "differentShardName");
removeShard(st, addShardRes.shardAdded);
jsTest.log("Adding a replica with a specified shardName of 'config' should fail.");
addShardRes = st.s.adminCommand({addShard: rst3.getURL(), name: "config"});
assertAddShardFailed(addShardRes, "config");
// 1.b. with invalid hostnames.
jsTest.log("Adding a replica set with only non-existing hosts should fail.");
addShardRes = st.s.adminCommand({addShard: rst3.name + "/NonExistingHost:" + portWithoutHostRunning});
assertAddShardFailed(addShardRes);
jsTest.log("Adding a replica set with mixed existing/non-existing hosts should fail.");
addShardRes = st.s.adminCommand({
addShard: rst3.name + "/" + rst3.getPrimary().name + ",NonExistingHost:" + portWithoutHostRunning,
});
assertAddShardFailed(addShardRes);
rst3.stopSet();
// 2. Test adding a replica set whose *set name* is "config" with or without specifying the
// shardName.
let rst4 = new ReplSetTest({name: "config", nodes: 1});
rst4.startSet({shardsvr: ""});
rst4.initiate();
jsTest.log("Adding a replica set whose setName is config without specifying shardName should fail.");
addShardRes = st.s.adminCommand({addShard: rst4.getURL()});
assertAddShardFailed(addShardRes);
jsTest.log("Adding a replica set whose setName is config with specified shardName 'config' should fail.");
addShardRes = st.s.adminCommand({addShard: rst4.getURL(), name: rst4.name});
assertAddShardFailed(addShardRes, rst4.name);
jsTest.log("Adding a replica set whose setName is config with a non-'config' shardName should succeed");
addShardRes = st.s.adminCommand({addShard: rst4.getURL(), name: "nonConfig"});
assertAddShardSucceeded(addShardRes, "nonConfig");
removeShard(st, addShardRes.shardAdded);
rst4.stopSet();
// 3. Test that a replica set whose *set name* is "admin" can be written to (SERVER-17232).
let rst5 = new ReplSetTest({name: "admin", nodes: 1});
rst5.startSet({shardsvr: ""});
rst5.initiate();
jsTest.log("A replica set whose set name is 'admin' should be able to be written to.");
addShardRes = st.s.adminCommand({addShard: rst5.getURL()});
assertAddShardSucceeded(addShardRes);
// Ensure the write goes to the newly added shard.
assert.commandWorked(st.s.adminCommand({enableSharding: "test", primaryShard: addShardRes.shardAdded}));
assert.commandWorked(st.s.getDB("test").runCommand({create: "foo"}));
const res = st.s.getDB("config").getCollection("databases").findOne({_id: "test"});
assert.neq(null, res);
assert.eq(res.primary, addShardRes.shardAdded);
assert.commandWorked(st.s.getDB("test").foo.insert({x: 1}));
assert.neq(null, rst5.getPrimary().getDB("test").foo.findOne());
assert.commandWorked(st.s.getDB("test").runCommand({dropDatabase: 1}));
removeShard(st, addShardRes.shardAdded);
rst5.stopSet();
st.stop();
normalShard.stopSet();