# KubeSolo OS — GRUB Configuration # A/B partition boot with automatic rollback # # Partition layout: # (hd0,gpt1) — EFI/Boot (256 MB, FAT32) — contains GRUB + grubenv # (hd0,gpt2) — System A (512 MB, ext4) — vmlinuz + kubesolo-os.gz # (hd0,gpt3) — System B (512 MB, ext4) — vmlinuz + kubesolo-os.gz # (hd0,gpt4) — Data (remaining, ext4) — persistent K8s state # # Environment variables (in grubenv): # active_slot — "A" or "B" (which partition to boot) # boot_counter — 3→2→1→0 (decremented on each failed boot) # boot_success — 0 or 1 (set to 1 by health check post-boot) set default=0 set timeout=3 # Load saved environment load_env # --- A/B Rollback Logic --- # On every boot, check if the last boot was successful. # If not, decrement the counter. If counter hits 0, swap slots. if [ "${boot_success}" != "1" ]; then # Last boot failed — check counter if [ "${boot_counter}" = "0" ]; then # Counter exhausted — rollback to other slot if [ "${active_slot}" = "A" ]; then set active_slot=B else set active_slot=A fi save_env active_slot set boot_counter=3 save_env boot_counter else # Decrement counter (GRUB doesn't have arithmetic) if [ "${boot_counter}" = "3" ]; then set boot_counter=2 elif [ "${boot_counter}" = "2" ]; then set boot_counter=1 elif [ "${boot_counter}" = "1" ]; then set boot_counter=0 fi save_env boot_counter fi fi # Reset boot_success for this boot attempt — health check must set it to 1 set boot_success=0 save_env boot_success # --- Resolve boot partition --- if [ "${active_slot}" = "A" ]; then set root='(hd0,gpt2)' set slot_label="System A" else set root='(hd0,gpt3)' set slot_label="System B" fi # --- Menu Entries --- menuentry "KubeSolo OS (${slot_label})" { echo "Booting KubeSolo OS from ${slot_label}..." echo "Boot counter: ${boot_counter}, Boot success: ${boot_success}" linux /vmlinuz kubesolo.data=LABEL=KSOLODATA quiet initrd /kubesolo-os.gz } menuentry "KubeSolo OS (${slot_label}) — Debug Mode" { echo "Booting KubeSolo OS (debug) from ${slot_label}..." linux /vmlinuz kubesolo.data=LABEL=KSOLODATA kubesolo.debug console=ttyS0,115200n8 initrd /kubesolo-os.gz } menuentry "KubeSolo OS — Emergency Shell" { echo "Booting to emergency shell..." linux /vmlinuz kubesolo.shell console=ttyS0,115200n8 initrd /kubesolo-os.gz } menuentry "KubeSolo OS — Boot Other Slot" { # Manually boot the passive slot (for testing) if [ "${active_slot}" = "A" ]; then set root='(hd0,gpt3)' echo "Booting from System B (passive)..." else set root='(hd0,gpt2)' echo "Booting from System A (passive)..." fi linux /vmlinuz kubesolo.data=LABEL=KSOLODATA kubesolo.debug console=ttyS0,115200n8 initrd /kubesolo-os.gz }