@@ -55,8 +55,10 @@ import {
55
55
DEFAULT_NETWORK_NODE_NAME ,
56
56
FREEZE_ADMIN_ACCOUNT ,
57
57
HEDERA_NODE_DEFAULT_STAKE_AMOUNT ,
58
- TREASURY_ACCOUNT_ID
58
+ TREASURY_ACCOUNT_ID ,
59
+ LOCAL_HOST
59
60
} from '../core/constants.mjs'
61
+ import { NodeStatusCodes , NodeStatusEnums } from '../core/enumerations.mjs'
60
62
61
63
/**
62
64
* Defines the core functionalities of 'node' command
@@ -360,72 +362,116 @@ export class NodeCommand extends BaseCommand {
360
362
}
361
363
362
364
/**
365
+ * @param {string } namespace
363
366
* @param {string } nodeId
364
- * @param {number } [maxAttempt]
365
- * @param {string } [status]
366
- * @param {string } [logfile]
367
- * @returns {Promise<boolean> }
367
+ * @param {TaskWrapper } task
368
+ * @param {string } title
369
+ * @param {number } index
370
+ * @param {number } [status]
371
+ * @param {number } [maxAttempts]
372
+ * @param {number } [delay]
373
+ * @param {number } [timeout]
374
+ * @returns {Promise<string> }
368
375
*/
369
- async checkNetworkNodeState ( nodeId , maxAttempt = 100 , status = 'ACTIVE' , logfile = 'output/hgcaa.log' ) {
376
+ async checkNetworkNodeActiveness ( namespace , nodeId , task , title , index ,
377
+ status = NodeStatusCodes . ACTIVE , maxAttempts = 120 , delay = 1_000 , timeout = 1_000 ) {
370
378
nodeId = nodeId . trim ( )
371
379
const podName = Templates . renderNetworkPodName ( nodeId )
372
- const logfilePath = `${ constants . HEDERA_HAPI_PATH } /${ logfile } `
380
+ const podPort = 9_999
381
+ const localPort = 19_000 + index
382
+ task . title = `${ title } - status ${ chalk . yellow ( 'STARTING' ) } , attempt ${ chalk . blueBright ( `0/${ maxAttempts } ` ) } `
383
+
384
+ const srv = await this . k8 . portForward ( podName , localPort , podPort )
385
+
373
386
let attempt = 0
374
- let isActive = false
387
+ let success = false
388
+ while ( attempt < maxAttempts ) {
389
+ const controller = new AbortController ( )
390
+
391
+ const timeoutId = setTimeout ( ( ) => {
392
+ task . title = `${ title } - status ${ chalk . yellow ( 'TIMEOUT' ) } , attempt ${ chalk . blueBright ( `${ attempt } /${ maxAttempts } ` ) } `
393
+ controller . abort ( )
394
+ } , timeout )
375
395
376
- this . logger . debug ( `Checking if node ${ nodeId } is ${ status } ...` )
377
- // check log file is accessible
378
- let logFileAccessible = false
379
- while ( attempt ++ < maxAttempt ) {
380
396
try {
381
- if ( await this . k8 . hasFile ( podName , constants . ROOT_CONTAINER , logfilePath ) ) {
382
- logFileAccessible = true
383
- break
397
+ const url = `http://${ LOCAL_HOST } :${ localPort } /metrics`
398
+ const response = await fetch ( url , { signal : controller . signal } )
399
+
400
+ if ( ! response . ok ) {
401
+ task . title = `${ title } - status ${ chalk . yellow ( 'UNKNOWN' ) } , attempt ${ chalk . blueBright ( `${ attempt } /${ maxAttempts } ` ) } `
402
+ clearTimeout ( timeoutId )
403
+ throw new Error ( ) // Guard
384
404
}
385
- } catch ( e ) {
386
- } // ignore errors
387
405
388
- await sleep ( 1000 )
389
- }
406
+ const text = await response . text ( )
407
+ const statusLine = text
408
+ . split ( '\n' )
409
+ . find ( line => line . startsWith ( 'platform_PlatformStatus' ) )
390
410
391
- if ( ! logFileAccessible ) {
392
- throw new FullstackTestingError ( `Logs are not accessible: ${ logfilePath } ` )
393
- }
411
+ if ( ! statusLine ) {
412
+ task . title = `${ title } - status ${ chalk . yellow ( 'STARTING' ) } , attempt: ${ chalk . blueBright ( `${ attempt } /${ maxAttempts } ` ) } `
413
+ clearTimeout ( timeoutId )
414
+ throw new Error ( ) // Guard
415
+ }
394
416
395
- attempt = 0
396
- while ( attempt < maxAttempt ) {
397
- try {
398
- const output = await this . k8 . execContainer ( podName , constants . ROOT_CONTAINER , [ 'tail' , '-100' , logfilePath ] )
399
- if ( output && output . indexOf ( 'Terminating Netty' ) < 0 && // make sure we are not at the beginning of a restart
400
- ( output . indexOf ( `Now current platform status = ${ status } ` ) > 0 ||
401
- output . indexOf ( `Platform Status Change ${ status } ` ) > 0 ||
402
- output . indexOf ( `is ${ status } ` ) > 0 ||
403
- output . indexOf ( `"newStatus":"${ status } "` ) > 0 ) ) {
404
- this . logger . debug ( `Node ${ nodeId } is ${ status } [ attempt: ${ attempt } /${ maxAttempt } ]` )
405
- isActive = true
417
+ const statusNumber = parseInt ( statusLine . split ( ' ' ) . pop ( ) )
418
+
419
+ if ( statusNumber === status ) {
420
+ task . title = `${ title } - status ${ chalk . green ( NodeStatusEnums [ status ] ) } , attempt: ${ chalk . blueBright ( `${ attempt } /${ maxAttempts } ` ) } `
421
+ success = true
422
+ clearTimeout ( timeoutId )
406
423
break
424
+ } else if ( statusNumber === NodeStatusCodes . CATASTROPHIC_FAILURE ) {
425
+ task . title = `${ title } - status ${ chalk . red ( 'CATASTROPHIC_FAILURE' ) } , attempt: ${ chalk . blueBright ( `${ attempt } /${ maxAttempts } ` ) } `
426
+ break
427
+ } else if ( statusNumber ) {
428
+ task . title = `${ title } - status ${ chalk . yellow ( NodeStatusEnums [ statusNumber ] ) } , attempt: ${ chalk . blueBright ( `${ attempt } /${ maxAttempts } ` ) } `
407
429
}
408
- this . logger . debug ( `Node ${ nodeId } is not ${ status } yet. Trying again... [ attempt: ${ attempt } /${ maxAttempt } ]` )
409
- } catch ( e ) {
410
- this . logger . warn ( `error in checking if node ${ nodeId } is ${ status } : ${ e . message } . Trying again... [ attempt: ${ attempt } /${ maxAttempt } ]` )
411
-
412
- // ls the HAPI path for debugging
413
- await this . k8 . execContainer ( podName , constants . ROOT_CONTAINER , `ls -la ${ constants . HEDERA_HAPI_PATH } ` )
430
+ clearTimeout ( timeoutId )
431
+ } catch { } // Catch all guard and fetch errors
414
432
415
- // ls the output directory for debugging
416
- await this . k8 . execContainer ( podName , constants . ROOT_CONTAINER , `ls -la ${ constants . HEDERA_HAPI_PATH } /output` )
417
- }
418
- attempt += 1
419
- await sleep ( 1000 )
433
+ attempt ++
434
+ clearTimeout ( timeoutId )
435
+ await sleep ( delay )
420
436
}
421
437
422
- this . logger . info ( `!> -- Node ${ nodeId } is ${ status } -- <!` )
438
+ await this . k8 . stopPortForward ( srv )
423
439
424
- if ( ! isActive ) {
425
- throw new FullstackTestingError ( `node '${ nodeId } ' is not ${ status } [ attempt = ${ attempt } /${ maxAttempt } ]` )
440
+ if ( ! success ) {
441
+ throw new FullstackTestingError ( `node '${ nodeId } ' is not ${ NodeStatusEnums [ status ] } ` +
442
+ `[ attempt = ${ chalk . blueBright ( `${ attempt } /${ maxAttempts } ` ) } ]` )
426
443
}
427
444
428
- return true
445
+ return podName
446
+ }
447
+
448
+ /**
449
+ * @param {Object } ctx
450
+ * @param {TaskWrapper } task
451
+ * @param {string[] } nodeIds
452
+ * @param {number } [status]
453
+ * @returns {Listr<any, any, any> }
454
+ */
455
+ checkNodeActivenessTask ( ctx , task , nodeIds , status = NodeStatusCodes . ACTIVE ) {
456
+ const { config : { namespace } } = ctx
457
+
458
+ const subTasks = nodeIds . map ( ( nodeId , i ) => {
459
+ const reminder = ( 'debugNodeId' in ctx . config && ctx . config . debugNodeId === nodeId ) ? 'Please attach JVM debugger now.' : ''
460
+ const title = `Check network pod: ${ chalk . yellow ( nodeId ) } ${ chalk . red ( reminder ) } `
461
+
462
+ const subTask = async ( ctx , task ) => {
463
+ ctx . config . podNames [ nodeId ] = await this . checkNetworkNodeActiveness ( namespace , nodeId , task , title , i , status )
464
+ }
465
+
466
+ return { title, task : subTask }
467
+ } )
468
+
469
+ return task . newListr ( subTasks , {
470
+ concurrent : true ,
471
+ rendererOptions : {
472
+ collapseSubtasks : false
473
+ }
474
+ } )
429
475
}
430
476
431
477
/**
@@ -490,67 +536,6 @@ export class NodeCommand extends BaseCommand {
490
536
} )
491
537
}
492
538
493
- /**
494
- *
495
- * @param {string } debugNodeId
496
- * @param {TaskWrapper } task
497
- * @param {string[] } nodeIds
498
- * @return {Listr<any, any, any> }
499
- */
500
- checkNodeActiveTask ( debugNodeId , task , nodeIds ) {
501
- const subTasks = [ ]
502
- for ( const nodeId of nodeIds ) {
503
- let reminder = ''
504
- if ( debugNodeId === nodeId ) {
505
- reminder = ' Please attach JVM debugger now.'
506
- }
507
- if ( this . configManager . getFlag ( flags . app ) !== '' && this . configManager . getFlag ( flags . app ) !== constants . HEDERA_APP_NAME ) {
508
- subTasks . push ( {
509
- title : `Check node: ${ chalk . yellow ( nodeId ) } ${ chalk . red ( reminder ) } ` ,
510
- task : async ( ) => await this . checkNetworkNodeState ( nodeId , 100 , 'ACTIVE' , 'output/swirlds.log' )
511
- } )
512
- } else {
513
- subTasks . push ( {
514
- title : `Check node: ${ chalk . yellow ( nodeId ) } ${ chalk . red ( reminder ) } ` ,
515
- task : async ( ) => await this . checkNetworkNodeState ( nodeId )
516
- } )
517
- }
518
- }
519
-
520
- // set up the sub-tasks
521
- return task . newListr ( subTasks , {
522
- concurrent : true ,
523
- rendererOptions : {
524
- collapseSubtasks : false
525
- }
526
- } )
527
- }
528
-
529
- /**
530
- * Return task for checking for if node is in freeze state
531
- * @param {any } ctx
532
- * @param {TaskWrapper } task
533
- * @param {string[] } nodeIds
534
- * @returns {* }
535
- */
536
- checkNodeFreezeTask ( ctx , task , nodeIds ) {
537
- const subTasks = [ ]
538
- for ( const nodeId of nodeIds ) {
539
- subTasks . push ( {
540
- title : `Check node: ${ chalk . yellow ( nodeId ) } ` ,
541
- task : async ( ) => await this . checkNetworkNodeState ( nodeId , 100 , 'FREEZE_COMPLETE' )
542
- } )
543
- }
544
-
545
- // set up the sub-tasks
546
- return task . newListr ( subTasks , {
547
- concurrent : false ,
548
- rendererOptions : {
549
- collapseSubtasks : false
550
- }
551
- } )
552
- }
553
-
554
539
/**
555
540
* Return task for setup network nodes
556
541
* @param {any } ctx
@@ -1199,7 +1184,7 @@ export class NodeCommand extends BaseCommand {
1199
1184
{
1200
1185
title : 'Check nodes are ACTIVE' ,
1201
1186
task : ( ctx , task ) => {
1202
- return this . checkNodeActiveTask ( ctx . config . debugNodeId , task , ctx . config . nodeIds )
1187
+ return this . checkNodeActivenessTask ( ctx , task , ctx . config . nodeIds )
1203
1188
}
1204
1189
} ,
1205
1190
{
@@ -1533,7 +1518,7 @@ export class NodeCommand extends BaseCommand {
1533
1518
{
1534
1519
title : 'Check nodes are ACTIVE' ,
1535
1520
task : ( ctx , task ) => {
1536
- return this . checkNodeActiveTask ( ctx . config . debugNodeId , task , ctx . config . nodeIds )
1521
+ return this . checkNodeActivenessTask ( ctx , task , ctx . config . nodeIds )
1537
1522
}
1538
1523
} ,
1539
1524
{
@@ -2033,8 +2018,7 @@ export class NodeCommand extends BaseCommand {
2033
2018
{
2034
2019
title : 'Check network nodes are frozen' ,
2035
2020
task : ( ctx , task ) => {
2036
- const config = /** @type {NodeAddConfigClass } **/ ctx . config
2037
- return this . checkNodeFreezeTask ( ctx , task , config . existingNodeIds )
2021
+ return this . checkNodeActivenessTask ( ctx , task , ctx . config . existingNodeIds , NodeStatusCodes . FREEZE_COMPLETE )
2038
2022
}
2039
2023
} ,
2040
2024
{
@@ -2128,7 +2112,7 @@ export class NodeCommand extends BaseCommand {
2128
2112
{
2129
2113
title : 'Check all nodes are ACTIVE' ,
2130
2114
task : async ( ctx , task ) => {
2131
- return this . checkNodeActiveTask ( ctx . config . debugNodeId , task , ctx . config . allNodeIds )
2115
+ return this . checkNodeActivenessTask ( ctx , task , ctx . config . allNodeIds )
2132
2116
}
2133
2117
} ,
2134
2118
{
@@ -2883,8 +2867,7 @@ export class NodeCommand extends BaseCommand {
2883
2867
{
2884
2868
title : 'Check network nodes are frozen' ,
2885
2869
task : ( ctx , task ) => {
2886
- const config = /** @type {NodeUpdateConfigClass } **/ ctx . config
2887
- return this . checkNodeFreezeTask ( ctx , task , config . existingNodeIds )
2870
+ return this . checkNodeActivenessTask ( ctx , task , ctx . config . existingNodeIds , NodeStatusCodes . FREEZE_COMPLETE )
2888
2871
}
2889
2872
} ,
2890
2873
{
@@ -2962,7 +2945,7 @@ export class NodeCommand extends BaseCommand {
2962
2945
{
2963
2946
title : 'Check all nodes are ACTIVE' ,
2964
2947
task : async ( ctx , task ) => {
2965
- return this . checkNodeActiveTask ( ctx . config . debugNodeId , task , ctx . config . allNodeIds )
2948
+ return this . checkNodeActivenessTask ( ctx , task , ctx . config . allNodeIds )
2966
2949
}
2967
2950
} ,
2968
2951
{
@@ -3198,8 +3181,7 @@ export class NodeCommand extends BaseCommand {
3198
3181
{
3199
3182
title : 'Check network nodes are frozen' ,
3200
3183
task : ( ctx , task ) => {
3201
- const config = /** @type {NodeDeleteConfigClass } **/ ctx . config
3202
- return this . checkNodeFreezeTask ( ctx , task , config . existingNodeIds )
3184
+ return this . checkNodeActivenessTask ( ctx , task , ctx . config . existingNodeIds , NodeStatusCodes . FREEZE_COMPLETE )
3203
3185
}
3204
3186
} ,
3205
3187
{
@@ -3269,7 +3251,7 @@ export class NodeCommand extends BaseCommand {
3269
3251
{
3270
3252
title : 'Check all nodes are ACTIVE' ,
3271
3253
task : async ( ctx , task ) => {
3272
- return this . checkNodeActiveTask ( ctx . config . debugNodeId , task , ctx . config . allNodeIds )
3254
+ return this . checkNodeActivenessTask ( ctx , task , ctx . config . allNodeIds )
3273
3255
}
3274
3256
} ,
3275
3257
{
0 commit comments