@@ -547,7 +547,7 @@ def toggleUEFISecureBoot(c):
547547 UEFIKeyPress (c , KEY_DOWN )
548548 UEFIKeyPress (c , KEY_RETURN )
549549
550- def BOOTLOADERchooseSerialConsole (child , live : bool ) -> None :
550+ def BOOTLOADERchooseSerialConsole (child , live : bool , log = None ) -> None :
551551 """ Select GRUB boot entry that uses the serial console. This differs
552552 between a LIVE ISO image and an already installed system. """
553553 BOOTLOADER_TMO = 40
@@ -596,39 +596,58 @@ def BOOTLOADERchooseSerialConsole(child, live: bool) -> None:
596596 # Wait for GRUB
597597 child .expect (GRUB_STRING , timeout = BOOTLOADER_TMO )
598598
599- # Unlike the live ISO menus (10s timeout), the installed system's
600- # top-level menu auto-boots its default entry after ~BOOTLOADER_LOAD_TMO
601- # seconds - the same delay this script would otherwise sleep before
602- # sending any key. Under host load that leaves no margin: GRUB can
603- # auto-boot before "Boot options" is ever selected. Send the first
604- # navigation key immediately to cancel the countdown, then give the
605- # screen time to settle.
606- # Select GRUB serial console
607- # Boot options
608- child .send (KEY_DOWN )
609- time .sleep (BOOTLOADER_LOAD_TMO )
610- child .send (KEY_RETURN )
611- time .sleep (BOOTLOADER_SLEEP )
612- # GRUB submenus never time out on their own, so confirm we actually
613- # landed on this submenu before navigating further - otherwise a
614- # dropped keypress leaves the VM stuck here until the login wait
615- # elsewhere expires
616- child .expect ('Select console type' , timeout = BOOTLOADER_TMO )
617-
618- # Select console type
619- child .send (KEY_DOWN )
620- time .sleep (BOOTLOADER_SLEEP )
621- child .send (KEY_RETURN )
622- time .sleep (BOOTLOADER_SLEEP )
623- child .expect (r'ttyS \(serial\)' , timeout = BOOTLOADER_TMO )
624-
625- # *ttyS (serial)
626- child .send (KEY_DOWN )
627- time .sleep (BOOTLOADER_SLEEP )
628- child .send (KEY_RETURN )
629- time .sleep (BOOTLOADER_SLEEP )
630- # Boot
631- child .send (KEY_RETURN )
599+ # The installed system's top-level menu auto-boots its default
600+ # entry after ~BOOTLOADER_LOAD_TMO seconds, timed from when GRUB
601+ # itself draws the menu - not from when this script's regex match
602+ # on GRUB_STRING returns. Under host load the menu text can reach
603+ # us well after that internal countdown already started, so there
604+ # is no reliable amount of "send a key fast enough" that wins this
605+ # race every time.
606+ #
607+ # That's fine to lose: the installer always answers 'S' (serial)
608+ # to "What console should be used by default?", so the default
609+ # entry GRUB auto-boots already targets the right console.
610+ # waitForLogin()/loginVM(), called after this function returns,
611+ # already tolerate landing straight on the GRUB countdown or the
612+ # login prompt. So treat this submenu navigation as best-effort:
613+ # if we don't land in "Boot options" in time, stop navigating and
614+ # let the default entry (which is already auto-booting) carry on,
615+ # instead of raising and aborting the whole test.
616+ try :
617+ # Select GRUB serial console
618+ # Boot options
619+ child .send (KEY_DOWN )
620+ time .sleep (BOOTLOADER_LOAD_TMO )
621+ child .send (KEY_RETURN )
622+ time .sleep (BOOTLOADER_SLEEP )
623+ # GRUB submenus never time out on their own, so confirm we actually
624+ # landed on this submenu before navigating further - otherwise a
625+ # dropped keypress leaves the VM stuck here until the login wait
626+ # elsewhere expires
627+ child .expect ('Select console type' , timeout = BOOTLOADER_TMO )
628+ except pexpect .TIMEOUT :
629+ if log is not None :
630+ log .warning ('GRUB auto-booted the default entry before "Boot '
631+ 'options" navigation completed; continuing since '
632+ 'the default entry already boots the serial '
633+ 'console selected during install' )
634+ else :
635+ # We're inside the submenu, so a timeout past this point is a
636+ # real navigation bug, not the auto-boot race - let it propagate.
637+ # Select console type
638+ child .send (KEY_DOWN )
639+ time .sleep (BOOTLOADER_SLEEP )
640+ child .send (KEY_RETURN )
641+ time .sleep (BOOTLOADER_SLEEP )
642+ child .expect (r'ttyS \(serial\)' , timeout = BOOTLOADER_TMO )
643+
644+ # *ttyS (serial)
645+ child .send (KEY_DOWN )
646+ time .sleep (BOOTLOADER_SLEEP )
647+ child .send (KEY_RETURN )
648+ time .sleep (BOOTLOADER_SLEEP )
649+ # Boot
650+ child .send (KEY_RETURN )
632651
633652 return None
634653
904923 log .info ('Disable UEFI Secure Boot for initial installation' )
905924 toggleUEFISecureBoot (c )
906925
907- BOOTLOADERchooseSerialConsole (c , live = (not args .cloud_init ))
926+ BOOTLOADERchooseSerialConsole (c , live = (not args .cloud_init ), log = log )
908927 loginVM (c , log )
909928
910929 #################################################
@@ -1070,7 +1089,7 @@ try:
10701089 # Booting installed system
10711090 #################################################
10721091 log .info ('Booting installed system' )
1073- BOOTLOADERchooseSerialConsole (c , live = False )
1092+ BOOTLOADERchooseSerialConsole (c , live = False , log = log )
10741093
10751094 #################################################
10761095 # Logging into VyOS system
0 commit comments