@@ -549,6 +549,103 @@ async function updatePeers(peers: { name: string; namespace: string }[]) {
549
549
}
550
550
}
551
551
552
+ async function restartOrderers ( orderers : { name : string ; namespace : string } [ ] ) {
553
+ for ( const orderer of orderers ) {
554
+ try {
555
+ console . log ( `Restarting orderer ${ orderer . name } in namespace ${ orderer . namespace } ...` )
556
+ const appsV1Api = kc . makeApiClient ( k8s . AppsV1Api )
557
+
558
+ // Scale down to 0
559
+ const patch = [
560
+ {
561
+ op : 'replace' ,
562
+ path : '/spec/replicas' ,
563
+ value : 0 ,
564
+ } ,
565
+ ]
566
+
567
+ await appsV1Api . patchNamespacedDeployment ( orderer . name , orderer . namespace , patch , undefined , undefined , undefined , undefined , undefined , {
568
+ headers : { 'Content-Type' : 'application/json-patch+json' } ,
569
+ } )
570
+ await new Promise ( ( resolve ) => setTimeout ( resolve , 1000 ) )
571
+ // Wait for scale down by polling the deployment state
572
+ let scaledDown = false
573
+ const maxWaitTime = 10 * 60 * 1000 // 10 minutes in milliseconds
574
+ const pollInterval = 1000 // 1 second
575
+ const startTime = Date . now ( )
576
+
577
+ while ( ! scaledDown && Date . now ( ) - startTime < maxWaitTime ) {
578
+ try {
579
+ const res = await appsV1Api . readNamespacedDeployment ( orderer . name , orderer . namespace )
580
+ const deployment = res . body
581
+ const isReady =
582
+ deployment . status ?. conditions ?. some ( ( condition ) => condition . type === 'Available' && condition . status === 'True' ) &&
583
+ deployment . status ?. readyReplicas === deployment . status ?. replicas
584
+
585
+ if ( isReady ) {
586
+ scaledDown = true
587
+ console . log ( `Orderer ${ orderer . name } in namespace ${ orderer . namespace } has been scaled down to 0` )
588
+ } else {
589
+ const elapsedTime = Math . floor ( ( Date . now ( ) - startTime ) / 1000 )
590
+ console . log ( `Waiting for orderer ${ orderer . name } in namespace ${ orderer . namespace } to scale down (${ elapsedTime } seconds elapsed)...` )
591
+ await new Promise ( ( resolve ) => setTimeout ( resolve , pollInterval ) )
592
+ }
593
+ } catch ( err ) {
594
+ console . error ( `Error checking orderer ${ orderer . name } in namespace ${ orderer . namespace } scale down status:` , err )
595
+ await new Promise ( ( resolve ) => setTimeout ( resolve , pollInterval ) )
596
+ }
597
+ }
598
+
599
+ if ( ! scaledDown ) {
600
+ console . error ( `Orderer ${ orderer . name } in namespace ${ orderer . namespace } did not scale down within the expected time.` )
601
+ continue
602
+ }
603
+
604
+ // Scale back up to 1
605
+ patch [ 0 ] . value = 1
606
+ await appsV1Api . patchNamespacedDeployment ( orderer . name , orderer . namespace , patch , undefined , undefined , undefined , undefined , undefined , {
607
+ headers : { 'Content-Type' : 'application/json-patch+json' } ,
608
+ } )
609
+
610
+ // Wait for the orderer to be back up by polling the deployment state
611
+ let ready = false
612
+ const startTimeUp = Date . now ( )
613
+ await new Promise ( ( resolve ) => setTimeout ( resolve , 1000 ) )
614
+
615
+ while ( ! ready && Date . now ( ) - startTimeUp < maxWaitTime ) {
616
+ try {
617
+ const res = await appsV1Api . readNamespacedDeployment ( orderer . name , orderer . namespace )
618
+ const deployment = res . body
619
+
620
+ const isReady =
621
+ deployment . status ?. conditions ?. some ( ( condition ) => condition . type === 'Available' && condition . status === 'True' ) &&
622
+ deployment . status ?. readyReplicas === deployment . status ?. replicas
623
+
624
+ if ( isReady ) {
625
+ ready = true
626
+ console . log ( `Orderer ${ orderer . name } in namespace ${ orderer . namespace } is back up and ready` )
627
+ } else {
628
+ const elapsedTime = Math . floor ( ( Date . now ( ) - startTimeUp ) / 1000 )
629
+ console . log ( `Waiting for orderer ${ orderer . name } in namespace ${ orderer . namespace } to be back up (${ elapsedTime } seconds elapsed)...` )
630
+ await new Promise ( ( resolve ) => setTimeout ( resolve , pollInterval ) )
631
+ }
632
+ } catch ( err ) {
633
+ console . error ( `Error checking orderer ${ orderer . name } in namespace ${ orderer . namespace } status:` , err )
634
+ await new Promise ( ( resolve ) => setTimeout ( resolve , pollInterval ) )
635
+ }
636
+ }
637
+
638
+ if ( ! ready ) {
639
+ console . error ( `Orderer ${ orderer . name } in namespace ${ orderer . namespace } did not become ready within the expected time.` )
640
+ } else {
641
+ console . log ( `Successfully restarted orderer ${ orderer . name } ` )
642
+ }
643
+ } catch ( err ) {
644
+ console . error ( `Error restarting orderer ${ orderer . name } :` , err )
645
+ }
646
+ }
647
+ }
648
+
552
649
async function main ( ) {
553
650
const channelName = await input ( { message : 'Enter the channel name:' } )
554
651
const channel = await getChannelFromKubernetes ( channelName )
@@ -624,6 +721,15 @@ async function main() {
624
721
await updateChannelToBFT ( channelName )
625
722
}
626
723
724
+ // Add restart confirmation
725
+ const restartConfirmed = await confirm ( {
726
+ message : `Restart the orderers before setting channel to normal state?` ,
727
+ default : true ,
728
+ } )
729
+ if ( restartConfirmed ) {
730
+ await restartOrderers ( selectedOrderers )
731
+ }
732
+
627
733
const stateNormalConfirmed = await confirm ( {
628
734
message : `Set channel ${ channelName } to STATE_NORMAL?` ,
629
735
default : true ,
0 commit comments