Skip to content

Commit 7a77f43

Browse files
committed
feat: add listShards helper
1 parent b2e18f8 commit 7a77f43

File tree

4 files changed

+125
-21
lines changed

4 files changed

+125
-21
lines changed

packages/i18n/src/locales/en_US.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2148,6 +2148,12 @@ const translations: Catalog = {
21482148
'Abort the current unshardCollection operation on a given collection',
21492149
example: 'sh.abortUnshardCollection(ns)',
21502150
},
2151+
listShards: {
2152+
link: 'https://docs.mongodb.com/manual/reference/method/sh.listShards',
2153+
description:
2154+
'Returns a list of the configured shards in a sharded cluster',
2155+
example: 'sh.listShards()',
2156+
},
21512157
isConfigShardEnabled: {
21522158
link: 'https://docs.mongodb.com/manual/reference/method/sh.isConfigShardEnabled',
21532159
description:

packages/shell-api/src/helpers.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -683,21 +683,23 @@ export async function getPrintableShardStatus(
683683
return result;
684684
}
685685

686+
export type ShardInfo = {
687+
_id: string;
688+
host: string;
689+
state: number;
690+
tags?: string[];
691+
topologyTime: Timestamp;
692+
replSetConfigVersion: Long;
693+
};
694+
686695
export type ShardingStatusResult = {
687696
shardingVersion: {
688697
_id: number;
689698
clusterId: ObjectId;
690699
/** This gets deleted when it is returned from getPrintableShardStatus */
691700
currentVersion?: number;
692701
};
693-
shards: {
694-
_id: string;
695-
host: string;
696-
state: number;
697-
tags: string[];
698-
topologyTime: Timestamp;
699-
replSetConfigVersion: Long;
700-
}[];
702+
shards: ShardInfo[];
701703
[mongoses: `${string} mongoses`]:
702704
| 'none'
703705
| {

packages/shell-api/src/shard.spec.ts

Lines changed: 97 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2109,6 +2109,75 @@ describe('Shard', function () {
21092109
});
21102110
});
21112111

2112+
describe('listShards', function () {
2113+
this.beforeEach(function () {
2114+
serviceProvider.runCommandWithCheck.resolves({
2115+
ok: 1,
2116+
msg: 'isdbgrid',
2117+
});
2118+
});
2119+
2120+
it('calls serviceProvider.runCommandWithCheck', async function () {
2121+
await shard.listShards();
2122+
2123+
expect(serviceProvider.runCommandWithCheck).to.have.been.calledWith(
2124+
ADMIN_DB,
2125+
{
2126+
listShards: 1,
2127+
}
2128+
);
2129+
});
2130+
2131+
it('returns the shards returned by runCommandWithCheck', async function () {
2132+
serviceProvider.runCommandWithCheck.resolves({
2133+
ok: 1,
2134+
msg: 'isdbgrid',
2135+
shards: [
2136+
{
2137+
_id: 'shard1',
2138+
host: 'shard1/foo.bar:27017',
2139+
},
2140+
{
2141+
_id: 'shard2',
2142+
host: 'shard2/foo.bar:27018',
2143+
},
2144+
],
2145+
});
2146+
const result = await shard.listShards();
2147+
expect(result).to.deep.equal([
2148+
{
2149+
_id: 'shard1',
2150+
host: 'shard1/foo.bar:27017',
2151+
},
2152+
{
2153+
_id: 'shard2',
2154+
host: 'shard2/foo.bar:27018',
2155+
},
2156+
]);
2157+
});
2158+
2159+
it('returns empty array when shards field is not present', async function () {
2160+
const result = await shard.listShards();
2161+
expect(result).to.deep.equal([]);
2162+
});
2163+
2164+
it('throws if serviceProvider.runCommandWithCheck rejects', async function () {
2165+
const expectedError = new Error('unreachable');
2166+
serviceProvider.runCommandWithCheck.rejects(expectedError);
2167+
const caughtError = await shard.listShards().catch((e) => e);
2168+
expect(caughtError).to.equal(expectedError);
2169+
});
2170+
2171+
it('throws if not mongos', async function () {
2172+
serviceProvider.runCommandWithCheck.resolves({
2173+
ok: 1,
2174+
msg: 'not dbgrid',
2175+
});
2176+
await shard.listShards();
2177+
expect(warnSpy.calledOnce).to.be.true;
2178+
});
2179+
});
2180+
21122181
describe('isConfigShardEnabled', function () {
21132182
this.beforeEach(function () {
21142183
serviceProvider.runCommandWithCheck.resolves({
@@ -2193,6 +2262,7 @@ describe('Shard', function () {
21932262
},
21942263
],
21952264
});
2265+
21962266
const result = await shard.isConfigShardEnabled();
21972267
expect(result).to.deep.equal({
21982268
enabled: true,
@@ -2207,13 +2277,14 @@ describe('Shard', function () {
22072277
const caughtError = await shard.isConfigShardEnabled().catch((e) => e);
22082278
expect(caughtError).to.equal(expectedError);
22092279
});
2280+
22102281
it('throws if not mongos', async function () {
22112282
serviceProvider.runCommandWithCheck.resolves({
22122283
ok: 1,
22132284
msg: 'not dbgrid',
22142285
});
22152286
await shard.isConfigShardEnabled();
2216-
expect(warnSpy.calledOnce).to.equal(true);
2287+
expect(warnSpy.calledOnce).to.be.true;
22172288
});
22182289
});
22192290
});
@@ -2463,15 +2534,11 @@ describe('Shard', function () {
24632534
describe('tags', function () {
24642535
it('creates a zone', async function () {
24652536
expect((await sh.addShardTag(`${shardId}-1`, 'zone1')).ok).to.equal(1);
2466-
expect((await sh.status()).value.shards[1]?.tags).to.deep.equal([
2467-
'zone1',
2468-
]);
2537+
expect((await sh.listShards())[1]?.tags).to.deep.equal(['zone1']);
24692538
expect((await sh.addShardToZone(`${shardId}-0`, 'zone0')).ok).to.equal(
24702539
1
24712540
);
2472-
expect((await sh.status()).value.shards[0]?.tags).to.deep.equal([
2473-
'zone0',
2474-
]);
2541+
expect((await sh.listShards())[0]?.tags).to.deep.equal(['zone0']);
24752542
});
24762543
it('sets a zone key range', async function () {
24772544
expect(
@@ -2516,11 +2583,11 @@ describe('Shard', function () {
25162583
expect(
25172584
(await sh.removeShardFromZone(`${shardId}-1`, 'zone1')).ok
25182585
).to.equal(1);
2519-
expect((await sh.status()).value.shards[1].tags).to.deep.equal([]);
2586+
expect((await sh.listShards())[1].tags).to.deep.equal([]);
25202587
expect((await sh.removeShardTag(`${shardId}-0`, 'zone0')).ok).to.equal(
25212588
1
25222589
);
2523-
expect((await sh.status()).value.shards[0].tags).to.deep.equal([]);
2590+
expect((await sh.listShards())[0].tags).to.deep.equal([]);
25242591
});
25252592
it('shows a full tag list when there are 20 or less tags', async function () {
25262593
const db = instanceState.currentDb.getSiblingDB(dbName);
@@ -3281,6 +3348,27 @@ describe('Shard', function () {
32813348
expect(await cursor.toArray()).to.deep.equal([]);
32823349
});
32833350
});
3351+
3352+
describe('listShards', function () {
3353+
it('returns the list of shards', async function () {
3354+
const result = await sh.listShards();
3355+
expect(result).to.be.an('array');
3356+
expect(result).to.have.lengthOf(2);
3357+
3358+
expect(result[0]._id).to.equal(`${shardId}-0`);
3359+
expect(result[0].host).to.contain(`${shardId}-0`);
3360+
3361+
expect(result[1]._id).to.equal(`${shardId}-1`);
3362+
expect(result[1].host).to.contain(`${shardId}-1`);
3363+
});
3364+
3365+
it('matches the output of status().shards', async function () {
3366+
const listShardsResult = await sh.listShards();
3367+
const statusResultShards = (await sh.status()).value.shards;
3368+
3369+
expect(listShardsResult).to.deep.equal(statusResultShards);
3370+
});
3371+
});
32843372
});
32853373

32863374
describe('integration chunks', function () {

packages/shell-api/src/shard.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import type {
1212
Document,
1313
CheckMetadataConsistencyOptions,
1414
} from '@mongosh/service-provider-core';
15-
import type { ShardingStatusResult } from './helpers';
15+
import type { ShardInfo, ShardingStatusResult } from './helpers';
1616
import {
1717
assertArgsDefinedType,
1818
getConfigDB,
@@ -812,16 +812,24 @@ export default class Shard extends ShellApiWithMongoClass {
812812
});
813813
}
814814

815+
@apiVersions([])
816+
@returnsPromise
817+
async listShards(): Promise<ShardInfo[]> {
818+
this._emitShardApiCall('listShards', {});
819+
await getConfigDB(this._database);
820+
821+
return (await this._database.adminCommand({ listShards: 1 })).shards ?? [];
822+
}
823+
815824
@serverVersions(['8.0.0', ServerVersions.latest])
816825
@apiVersions([])
817826
@returnsPromise
818827
async isConfigShardEnabled(): Promise<Document> {
819828
this._emitShardApiCall('isConfigShardEnabled', {});
820829
await getConfigDB(this._database);
821830

822-
const shards = (await this._database.adminCommand({ listShards: 1 }))[
823-
'shards'
824-
] as Document[] | undefined;
831+
const shards = (await this._database.adminCommand({ listShards: 1 }))
832+
.shards as Document[] | undefined;
825833
const configShard = shards?.find((s) => s._id === 'config');
826834
if (!configShard) {
827835
return { enabled: false };

0 commit comments

Comments
 (0)