@@ -26,7 +26,7 @@ import type {
2626 bson ,
2727} from '@mongosh/service-provider-core' ;
2828import type { ClientSideFieldLevelEncryptionOptions } from './field-level-encryption' ;
29- import { type AutoEncryptionOptions } from 'mongodb' ;
29+ import type { AutoEncryptionOptions , Long , ObjectId , Timestamp } from 'mongodb' ;
3030import { shellApiType } from './enums' ;
3131import type { AbstractCursor } from './abstract-cursor' ;
3232import type ChangeStreamCursor from './change-stream-cursor' ;
@@ -224,10 +224,12 @@ export function processDigestPassword(
224224 * @param verbose
225225 */
226226export async function getPrintableShardStatus (
227- configDB : Database ,
227+ db : Database ,
228228 verbose : boolean
229- ) : Promise < Document > {
230- const result = { } as any ;
229+ ) : Promise < ShardingStatusResult > {
230+ const result = { } as ShardingStatusResult ;
231+
232+ const configDB = await getConfigDB ( db ) ;
231233
232234 // configDB is a DB object that contains the sharding metadata of interest.
233235 const mongosColl = configDB . getCollection ( 'mongos' ) ;
@@ -259,9 +261,12 @@ export async function getPrintableShardStatus(
259261 ) ;
260262 }
261263
262- result . shardingVersion = version ;
264+ result . shardingVersion = version as {
265+ _id : number ;
266+ clusterId : ObjectId ;
267+ } ;
263268
264- result . shards = shards ;
269+ result . shards = shards as ShardingStatusResult [ 'shards' ] ;
265270
266271 // (most recently) active mongoses
267272 const mongosActiveThresholdMs = 60000 ;
@@ -280,9 +285,8 @@ export async function getPrintableShardStatus(
280285 }
281286 }
282287
283- mongosAdjective = `${ mongosAdjective } mongoses` ;
284288 if ( mostRecentMongosTime === null ) {
285- result [ mongosAdjective ] = 'none' ;
289+ result [ ` ${ mongosAdjective } mongoses` ] = 'none' ;
286290 } else {
287291 const recentMongosQuery = {
288292 ping : {
@@ -295,25 +299,27 @@ export async function getPrintableShardStatus(
295299 } ;
296300
297301 if ( verbose ) {
298- result [ mongosAdjective ] = await ( await mongosColl . find ( recentMongosQuery ) )
302+ result [ `${ mongosAdjective } mongoses` ] = await (
303+ await mongosColl . find ( recentMongosQuery )
304+ )
299305 . sort ( { ping : - 1 } )
300306 . toArray ( ) ;
301307 } else {
302- result [ mongosAdjective ] = (
308+ result [ ` ${ mongosAdjective } mongoses` ] = (
303309 ( await (
304310 await mongosColl . aggregate ( [
305311 { $match : recentMongosQuery } ,
306312 { $group : { _id : '$mongoVersion' , num : { $sum : 1 } } } ,
307313 { $sort : { num : - 1 } } ,
308314 ] )
309- ) . toArray ( ) ) as any [ ]
315+ ) . toArray ( ) ) as { _id : string ; num : number } [ ]
310316 ) . map ( ( z : { _id : string ; num : number } ) => {
311317 return { [ z . _id ] : z . num } ;
312318 } ) ;
313319 }
314320 }
315321
316- const balancerRes : Record < string , any > = { } ;
322+ const balancerRes = { } as ShardingStatusResult [ 'balancer' ] ;
317323 await Promise . all ( [
318324 ( async ( ) : Promise < void > => {
319325 // Is autosplit currently enabled
@@ -331,13 +337,13 @@ export async function getPrintableShardStatus(
331337 } ) ( ) ,
332338 ( async ( ) : Promise < void > => {
333339 // Is the balancer currently active
334- let balancerRunning = 'unknown' ;
340+ let balancerRunning : 'yes' | 'no' | 'unknown' = 'unknown' ;
335341 try {
336342 const balancerStatus = await configDB . adminCommand ( {
337343 balancerStatus : 1 ,
338344 } ) ;
339345 balancerRunning = balancerStatus . inBalancerRound ? 'yes' : 'no' ;
340- } catch ( err : any ) {
346+ } catch ( err ) {
341347 // pass, ignore all error messages
342348 }
343349 balancerRes [ 'Currently running' ] = balancerRunning ;
@@ -364,7 +370,9 @@ export async function getPrintableShardStatus(
364370 if ( activeLocks ?. length > 0 ) {
365371 balancerRes [ 'Collections with active migrations' ] = activeLocks . map (
366372 ( lock ) => {
367- return `${ lock . _id } started at ${ lock . when } ` ;
373+ // This type assertion is necessary for the string literal type check
374+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
375+ return `${ lock . _id } started at ${ lock . when } ` as `${string } started at ${string } `;
368376 }
369377 ) ;
370378 }
@@ -418,8 +426,23 @@ export async function getPrintableShardStatus(
418426 const yesterday = new Date ( ) ;
419427 yesterday . setDate ( yesterday . getDate ( ) - 1 ) ;
420428
429+ type MigrationResult =
430+ | {
431+ _id : 'Success' ;
432+ count : number ;
433+ from : never ;
434+ to : never ;
435+ }
436+ // Failed migration
437+ | {
438+ _id : string ;
439+ count : number ;
440+ from : string ;
441+ to : string ;
442+ } ;
443+
421444 // Successful migrations.
422- let migrations = await (
445+ let migrations = ( await (
423446 await changelogColl . aggregate ( [
424447 {
425448 $match : {
@@ -437,11 +460,11 @@ export async function getPrintableShardStatus(
437460 } ,
438461 } ,
439462 ] )
440- ) . toArray ( ) ;
463+ ) . toArray ( ) ) as MigrationResult [ ] ;
441464
442465 // Failed migrations.
443466 migrations = migrations . concat (
444- await (
467+ ( await (
445468 await changelogColl . aggregate ( [
446469 {
447470 $match : {
@@ -472,11 +495,12 @@ export async function getPrintableShardStatus(
472495 } ,
473496 } ,
474497 ] )
475- ) . toArray ( )
498+ ) . toArray ( ) ) as MigrationResult [ ]
476499 ) ;
477500
478- const migrationsRes : Record < number , string > = { } ;
479- migrations . forEach ( ( x : any ) => {
501+ const migrationsRes : ShardingStatusResult [ 'balancer' ] [ 'Migration Results for the last 24 hours' ] =
502+ { } ;
503+ migrations . forEach ( ( x ) => {
480504 if ( x . _id === 'Success' ) {
481505 migrationsRes [ x . count ] = x . _id ;
482506 } else {
@@ -644,10 +668,83 @@ export async function getPrintableShardStatus(
644668 )
645669 ) . filter ( ( dbEntry ) => ! ! dbEntry ) ;
646670
671+ let shardedDataDistribution : ShardedDataDistribution | undefined ;
672+
673+ try {
674+ // Available since 6.0.3
675+ const adminDb = db . getSiblingDB ( 'admin' ) ;
676+ shardedDataDistribution = ( await (
677+ await adminDb . aggregate ( [ { $shardedDataDistribution : { } } ] )
678+ ) . toArray ( ) ) as ShardedDataDistribution ;
679+ } catch ( e ) {
680+ // Pass, most likely an older version.
681+ console . error ( 'shardedDataDistribution Errored:' , e ) ;
682+ }
683+
684+ result . shardedDataDistribution = shardedDataDistribution ;
685+
647686 delete result . shardingVersion . currentVersion ;
648687 return result ;
649688}
650689
690+ type ShardingStatusResult = {
691+ shardingVersion : {
692+ _id : number ;
693+ clusterId : ObjectId ;
694+ /** This gets deleted when it is returned from getPrintableShardStatus */
695+ currentVersion ?: number ;
696+ } ;
697+ shards : {
698+ _id : string ;
699+ host : string ;
700+ state : number ;
701+ topologyTime : Timestamp ;
702+ replSetConfigVersion : Long ;
703+ } [ ] ;
704+ [ mongoses : `${string } mongoses`] :
705+ | 'none'
706+ | {
707+ [ version : string ] :
708+ | number
709+ | {
710+ up : number ;
711+ waiting : boolean ;
712+ } ;
713+ } [ ] ;
714+ autosplit : {
715+ 'Currently enabled' : 'yes' | 'no' ;
716+ } ;
717+ balancer : {
718+ 'Currently enabled' : 'yes' | 'no' ;
719+ 'Currently running' : 'yes' | 'no' | 'unknown' ;
720+ 'Failed balancer rounds in last 5 attempts' : number ;
721+ 'Migration Results for the last 24 hours' :
722+ | 'No recent migrations'
723+ | {
724+ [ count : number ] :
725+ | 'Success'
726+ | `Failed with error '${string } ', from ${string } to ${string } `;
727+ } ;
728+ 'Balancer active window is set between' ?: `${string } and ${string } server local time`;
729+ 'Last reported error' ?: string ;
730+ 'Time of Reported error' ?: string ;
731+ 'Collections with active migrations' ?: `${string } started at ${string } `[ ] ;
732+ } ;
733+ shardedDataDistribution ?: ShardedDataDistribution ;
734+ databases : { database : Document ; collections : Document } [ ] ;
735+ } ;
736+
737+ type ShardedDataDistribution = {
738+ ns : string ;
739+ shards : {
740+ shardName : string ;
741+ numOrphanedDocs : number ;
742+ numOwnedDocuments : number ;
743+ orphanedSizeBytes : number ;
744+ ownedSizeBytes : number ;
745+ } ;
746+ } [ ] ;
747+
651748export async function getConfigDB ( db : Database ) : Promise < Database > {
652749 const helloResult = await db . _maybeCachedHello ( ) ;
653750 if ( helloResult . msg !== 'isdbgrid' ) {
0 commit comments