summaryrefslogtreecommitdiff
path: root/jstests/sharding/addshard2.js
blob: 1ad94e3113f9d133edc3cd3cefacf73fb27805ec (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
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
(function() {

    var addShardRes;
    var rst;

    var 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.
    var 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) {
            assert.eq(null,
                      st.s.getDB('config').shards.findOne({_id: shardName}),
                      "addShard for " + shardName +
                          " reported failure, but shard shows up in config.shards");
        }
    };

    var removeShardWithName = function(shardName) {
        var res = st.s.adminCommand({removeShard: shardName});
        assert.commandWorked(res);
        assert.eq('started', res.state);
        assert.soon(function() {
            res = st.s.adminCommand({removeShard: shardName});
            assert.commandWorked(res);
            return ('completed' === res.state);
        }, "removeShard never completed for shard " + shardName);
    };

    // Enable the failpoint that prevents the config server from upserting a shardIdentity on new
    // shards so that the same shard host can be re-used for multiple addShard calls without being
    // restarted in between each addShard (the shardIdentity cannot be deleted while the shard host
    // is running with --shardsvr).
    var st = new ShardingTest({
        shards: 0,
        mongos: 1,
        other: {
            configOptions: {
                setParameter: "failpoint.dontUpsertShardIdentityOnNewShards={'mode':'alwaysOn'}"
            }
        }
    });

    // Add one shard since the last shard cannot be removed.
    var normalShard = MongoRunner.runMongod({shardsvr: ''});
    st.s.adminCommand({addShard: normalShard.name, name: 'normalShard'});

    // Allocate a port that can be used to test adding invalid hosts.
    var portWithoutHostRunning = allocatePort();

    // 1. Test adding a *standalone*

    // 1.a. with or without specifying the shardName.

    var standalone = MongoRunner.runMongod({shardsvr: ''});

    jsTest.log("Adding a standalone *without* a specified shardName should succeed.");
    addShardRes = st.s.adminCommand({addshard: standalone.name});
    assertAddShardSucceeded(addShardRes);
    removeShardWithName(addShardRes.shardAdded);

    jsTest.log("Adding a standalone *with* a specified shardName should succeed.");
    addShardRes = st.s.adminCommand({addshard: standalone.name, name: "shardName"});
    assertAddShardSucceeded(addShardRes, "shardName");
    removeShardWithName(addShardRes.shardAdded);

    MongoRunner.stopMongod(standalone);

    // 1.b. with an invalid hostname.

    jsTest.log("Adding a standalone with a non-existing host should fail.");
    addShardRes = st.s.adminCommand({addShard: getHostName() + ":" + portWithoutHostRunning});
    assertAddShardFailed(addShardRes);

    // 2. Test adding a *replica set* with an ordinary set name

    // 2.a. with or without specifying the shardName.

    rst = new ReplSetTest({nodes: 1});
    rst.startSet({shardsvr: ''});
    rst.initiate();

    jsTest.log("Adding a replica set without a specified shardName should succeed.");
    addShardRes = st.s.adminCommand({addShard: rst.getURL()});
    assertAddShardSucceeded(addShardRes);
    assert.eq(rst.name, addShardRes.shardAdded);
    removeShardWithName(addShardRes.shardAdded);

    jsTest.log(
        "Adding a replica set with a specified shardName that matches the set's name should succeed.");
    addShardRes = st.s.adminCommand({addShard: rst.getURL(), name: rst.name});
    assertAddShardSucceeded(addShardRes, rst.name);
    removeShardWithName(addShardRes.shardAdded);

    jsTest.log(
        "Adding a replica set with a specified shardName that differs from the set's name should succeed.");
    addShardRes = st.s.adminCommand({addShard: rst.getURL(), name: "differentShardName"});
    assertAddShardSucceeded(addShardRes, "differentShardName");
    removeShardWithName(addShardRes.shardAdded);

    jsTest.log("Adding a replica with a specified shardName of 'config' should fail.");
    addShardRes = st.s.adminCommand({addShard: rst.getURL(), name: "config"});
    assertAddShardFailed(addShardRes, "config");

    // 2.b. with invalid hostnames.

    jsTest.log("Adding a replica set with only non-existing hosts should fail.");
    addShardRes =
        st.s.adminCommand({addShard: rst.name + "/NonExistingHost:" + portWithoutHostRunning});
    assertAddShardFailed(addShardRes);

    jsTest.log("Adding a replica set with mixed existing/non-existing hosts should fail.");
    addShardRes = st.s.adminCommand({
        addShard:
            rst.name + "/" + rst.getPrimary().name + ",NonExistingHost:" + portWithoutHostRunning
    });
    assertAddShardFailed(addShardRes);

    rst.stopSet();

    // 3. Test adding a replica set whose *set name* is "config" with or without specifying the
    // shardName.

    rst = new ReplSetTest({name: "config", nodes: 1});
    rst.startSet({shardsvr: ''});
    rst.initiate();

    jsTest.log(
        "Adding a replica set whose setName is config without specifying shardName should fail.");
    addShardRes = st.s.adminCommand({addShard: rst.getURL()});
    assertAddShardFailed(addShardRes);

    jsTest.log(
        "Adding a replica set whose setName is config with specified shardName 'config' should fail.");
    addShardRes = st.s.adminCommand({addShard: rst.getURL(), name: rst.name});
    assertAddShardFailed(addShardRes, rst.name);

    jsTest.log(
        "Adding a replica set whose setName is config with a non-'config' shardName should succeed");
    addShardRes = st.s.adminCommand({addShard: rst.getURL(), name: "nonConfig"});
    assertAddShardSucceeded(addShardRes, "nonConfig");
    removeShardWithName(addShardRes.shardAdded);

    rst.stopSet();

    // 4. Test that a replica set whose *set name* is "admin" can be written to (SERVER-17232).

    rst = new ReplSetTest({name: "admin", nodes: 1});
    rst.startSet({shardsvr: ''});
    rst.initiate();

    jsTest.log("A replica set whose set name is 'admin' should be able to be written to.");
    addShardRes = st.s.adminCommand({addShard: rst.getURL()});
    assertAddShardSucceeded(addShardRes);
    assert.writeOK(st.s.getDB('test').foo.insert({x: 1}));

    rst.stopSet();

    // 5. Test adding a --configsvr replica set.

    var configRS = new ReplSetTest({nodes: 1});
    configRS.startSet({configsvr: '', storageEngine: 'wiredTiger'});
    configRS.initiate();

    jsTest.log("Adding a config server replica set without a specified shardName should fail.");
    addShardRes = st.s.adminCommand({addShard: configRS.getURL()});
    assertAddShardFailed(addShardRes);

    jsTest.log(
        "Adding a config server replica set  with a shardName that matches the set's name should fail.");
    addShardRes = st.s.adminCommand({addShard: configRS.getURL(), name: configRS.name});
    assertAddShardFailed(addShardRes, configRS.name);

    jsTest.log(
        "Adding a config server replica set even with a non-'config' shardName should fail.");
    addShardRes = st.s.adminCommand({addShard: configRS.getURL(), name: "nonConfig"});
    assertAddShardFailed(addShardRes, "nonConfig");

    configRS.stopSet();

    st.stop();

})();