@@ -511,12 +511,35 @@ export class StarshipClient implements StarshipClientI {
511
511
{ log : false , silent : true }
512
512
) . trim ( ) ;
513
513
514
- const [ phase , readyList , restartCountList , reason ] = result . split ( / \s + / ) ;
514
+ // Ensure the output contains valid fields to split
515
+ const parts = result . split ( / \s + / ) ;
516
+ if ( parts . length < 3 ) {
517
+ this . log (
518
+ chalk . red ( `Unexpected pod status output for ${ podName } : ${ result } ` )
519
+ ) ;
520
+ return ;
521
+ }
522
+
523
+ const [ phase , readyList , restartCountList , reason ] = parts ;
524
+
525
+ // Validate readyList and restartCountList before applying split
526
+ if ( ! readyList || ! restartCountList ) {
527
+ this . log (
528
+ chalk . red (
529
+ `Invalid ready or restart count for pod ${ podName } : ${ result } `
530
+ )
531
+ ) ;
532
+ return ;
533
+ }
534
+
515
535
const ready = readyList . split ( ',' ) . every ( ( state ) => state === 'true' ) ;
516
536
const restarts = restartCountList
517
537
. split ( ',' )
518
538
. reduce ( ( acc , count ) => acc + parseInt ( count , 10 ) , 0 ) ;
519
539
540
+ // check for repeated image pull errors
541
+ this . checkImagePullFailures ( podName ) ;
542
+
520
543
this . podStatuses . set ( podName , {
521
544
phase,
522
545
ready,
@@ -572,6 +595,74 @@ export class StarshipClient implements StarshipClientI {
572
595
} ) ;
573
596
}
574
597
598
+ public checkImagePullFailures ( podName : string ) : void {
599
+ // Fetch events from kubectl describe for the given pod
600
+ const eventLines = this . getPodEventsFromDescribe ( podName ) ;
601
+ const errorPattern = / F a i l e d t o p u l l i m a g e / ;
602
+ const imageErrors : { [ image : string ] : number } = { } ;
603
+
604
+ // Parse through event lines to identify image pull failures
605
+ eventLines . forEach ( ( line ) => {
606
+ const message = line || '' ;
607
+ if ( errorPattern . test ( message ) ) {
608
+ const imageMatch = message . match ( / i m a g e " ( .* ?) " / ) ;
609
+ if ( imageMatch && imageMatch [ 1 ] ) {
610
+ const imageName = imageMatch [ 1 ] ;
611
+ imageErrors [ imageName ] = ( imageErrors [ imageName ] || 0 ) + 1 ;
612
+ }
613
+ }
614
+ } ) ;
615
+
616
+ // Log errors for images that have failed more than twice
617
+ Object . entries ( imageErrors ) . forEach ( ( [ imageName , errorCount ] ) => {
618
+ if ( errorCount >= 3 ) {
619
+ this . log (
620
+ `${ chalk . red (
621
+ `
622
+ Error: Image '${ imageName } ' failed to pull ${ errorCount } times for pod ${ podName } .
623
+ Please check the image name and ensure it is correct.
624
+ Run "starship stop" to stop the deployment which would be in stuck state.
625
+ `
626
+ ) } `
627
+ ) ;
628
+ this . exit ( 1 ) ;
629
+ }
630
+ } ) ;
631
+ }
632
+
633
+ private getPodEventsFromDescribe ( podName : string ) : string [ ] {
634
+ // Execute the 'kubectl describe pod' command
635
+ const result = this . exec (
636
+ [ 'kubectl' , 'describe' , 'pod' , podName , ...this . getArgs ( ) ] ,
637
+ { log : false , silent : true }
638
+ ) ;
639
+
640
+ // Check if the command was successful
641
+ if ( result . code !== 0 ) {
642
+ this . log (
643
+ chalk . red ( `Failed to describe pod ${ podName } : ${ result . stderr } ` )
644
+ ) ;
645
+ return [ ] ;
646
+ }
647
+
648
+ const describeOutput = result . stdout ;
649
+
650
+ // Extract the 'Events' section from the describe output
651
+ const eventsSection = describeOutput . split ( 'Events:' ) [ 1 ] ;
652
+ if ( ! eventsSection ) {
653
+ this . log ( chalk . yellow ( `No events found for pod ${ podName } ` ) ) ;
654
+ return [ ] ;
655
+ }
656
+
657
+ // Split the events section into individual lines
658
+ const eventLines = eventsSection
659
+ . split ( '\n' )
660
+ . filter ( ( line ) => line . trim ( ) !== '' ) ;
661
+ this . log ( `event lints: ${ eventLines . join ( '\n' ) } ` ) ;
662
+
663
+ return eventLines ;
664
+ }
665
+
575
666
private forwardPort (
576
667
chain : Chain ,
577
668
localPort : number ,
0 commit comments