@@ -2540,6 +2540,65 @@ v2k_cloud_windows_winpe_bootstrap() {
25402540 v2k_windows_winpe_bootstrap_libvirt " ${tmp_manifest} " " ${tmp_vm} " " ${winpe_iso} " " ${virtio_iso} " " ${winpe_timeout} " 1
25412541}
25422542
2543+ v2k_bootstrap_fallback_enabled () {
2544+ local policy=" ${1:- sata} "
2545+ case " ${policy} " in
2546+ sata|auto|" " ) return 0 ;;
2547+ off|none|false|0) return 1 ;;
2548+ * )
2549+ echo " Invalid bootstrap fallback policy: ${policy} " >&2
2550+ return 2
2551+ ;;
2552+ esac
2553+ }
2554+
2555+ v2k_select_bootstrap_fallback () {
2556+ local manifest=" $1 " phase=" $2 " code=" $3 " reason=" $4 " policy=" ${5:- sata} "
2557+ local bus=" sata"
2558+
2559+ if ! v2k_bootstrap_fallback_enabled " ${policy} " ; then
2560+ return 1
2561+ fi
2562+
2563+ v2k_manifest_runtime_set " ${manifest} " " .bootstrap_fallback" \
2564+ " $( jq -nc \
2565+ --arg bus " ${bus} " \
2566+ --arg phase " ${phase} " \
2567+ --arg reason " ${reason} " \
2568+ --argjson code " ${code} " \
2569+ ' {enabled:true,bus:$bus,phase:$phase,code:$code,reason:$reason}' ) " || true
2570+ v2k_event WARN " cutover" " " " bootstrap_fallback_selected" \
2571+ " $( jq -nc \
2572+ --arg bus " ${bus} " \
2573+ --arg phase " ${phase} " \
2574+ --arg reason " ${reason} " \
2575+ --argjson code " ${code} " \
2576+ ' {bus:$bus,phase:$phase,code:$code,reason:$reason}' ) " || true
2577+ if [[ " ${V2K_JSON_OUT:- 0} " -ne 1 ]]; then
2578+ echo " [v2k] ${reason} . Falling back to SATA disk controller."
2579+ fi
2580+ return 0
2581+ }
2582+
2583+ v2k_libvirt_redefine_with_bootstrap_fallback () {
2584+ local manifest=" $1 " vcpu=" $2 " memory=" $3 " bridge=" $4 " vlan=" $5 " network=" $6 "
2585+ local vm xml_path
2586+ vm=" $( jq -r ' .target.libvirt.name' " ${manifest} " ) "
2587+ v2k_target_undefine_libvirt " ${vm} " || true
2588+ if [[ -n " ${bridge} " ]]; then
2589+ xml_path=" $( v2k_target_generate_libvirt_xml " ${manifest} " \
2590+ --vcpu " ${vcpu} " --memory " ${memory} " \
2591+ --bridge " ${bridge} " $( [[ -n " ${vlan} " ]] && echo --vlan " ${vlan} " ) \
2592+ ) "
2593+ else
2594+ xml_path=" $( v2k_target_generate_libvirt_xml " ${manifest} " \
2595+ --vcpu " ${vcpu} " --memory " ${memory} " \
2596+ --network " ${network} " \
2597+ ) "
2598+ fi
2599+ v2k_target_define_libvirt " ${xml_path} "
2600+ }
2601+
25432602v2k_cmd_cutover () {
25442603 v2k_require_manifest
25452604 v2k_load_runtime_flags_from_manifest
@@ -2561,6 +2620,7 @@ v2k_cmd_cutover() {
25612620 local vcpu_set=0 memory_set=0
25622621 local network=" default" bridge=" " vlan=" "
25632622 local force_cleanup=0
2623+ local bootstrap_fallback=" ${V2K_BOOTSTRAP_FALLBACK:- sata} "
25642624
25652625 # Linux bootstrap (host-chroot initramfs rebuild)
25662626 local linux_bootstrap=-1
@@ -2600,6 +2660,18 @@ v2k_cmd_cutover() {
26002660 linux_bootstrap=0
26012661 shift 1
26022662 ;;
2663+ --bootstrap-fallback)
2664+ bootstrap_fallback=" ${2:- } "
2665+ case " ${bootstrap_fallback} " in
2666+ sata|auto|off|none|false|0) ;;
2667+ * ) echo " Invalid --bootstrap-fallback: ${bootstrap_fallback} " >&2 ; exit 2 ;;
2668+ esac
2669+ shift 2
2670+ ;;
2671+ --no-bootstrap-fallback)
2672+ bootstrap_fallback=" off"
2673+ shift 1
2674+ ;;
26032675 --target-provider) target_provider=" ${2:- } " ; target_provider_arg_set=1; shift 2;;
26042676 --cloud-endpoint) cloud_endpoint=" ${2:- } " ; cloud_config_arg_set=1; shift 2;;
26052677 --cloud-api-key) cloud_api_key=" ${2:- } " ; shift 2;;
@@ -2794,19 +2866,21 @@ v2k_cmd_cutover() {
27942866 if [[ " ${V2K_JSON_OUT:- 0} " -ne 1 ]]; then
27952867 echo " [v2k] Cloud Linux bootstrap(initramfs) requested (guestFamily=linuxGuest)"
27962868 fi
2797- v2k_linux_bootstrap_initramfs " ${V2K_MANIFEST} "
2798- local rc=$?
2799- if [[ " ${rc} " -ne 0 ]]; then
2869+ if v2k_linux_bootstrap_initramfs " ${V2K_MANIFEST} " ; then
2870+ v2k_event INFO " cutover" " " " cloud_linux_bootstrap_done" " {}"
2871+ if [[ " ${V2K_JSON_OUT:- 0} " -ne 1 ]]; then
2872+ echo " [v2k] Cloud Linux bootstrap(initramfs) done (guestFamily=linuxGuest)"
2873+ fi
2874+ else
2875+ local rc=$?
28002876 v2k_event ERROR " cutover" " " " cloud_linux_bootstrap_failed" " {\" code\" :${rc} }"
28012877 if [[ " ${V2K_JSON_OUT:- 0} " -ne 1 ]]; then
28022878 echo " [v2k] Cloud Linux bootstrap(initramfs) failed (guestFamily=linuxGuest)"
28032879 fi
2804- echo " Cloud Linux bootstrap (initramfs rebuild) failed. code=${rc} " >&2
2805- exit 74
2806- fi
2807- v2k_event INFO " cutover" " " " cloud_linux_bootstrap_done" " {}"
2808- if [[ " ${V2K_JSON_OUT:- 0} " -ne 1 ]]; then
2809- echo " [v2k] Cloud Linux bootstrap(initramfs) done (guestFamily=linuxGuest)"
2880+ if ! v2k_select_bootstrap_fallback " ${V2K_MANIFEST} " " linux_bootstrap" " ${rc} " " Cloud Linux bootstrap(initramfs) failed" " ${bootstrap_fallback} " ; then
2881+ echo " Cloud Linux bootstrap (initramfs rebuild) failed. code=${rc} " >&2
2882+ exit 74
2883+ fi
28102884 fi
28112885 else
28122886 v2k_event INFO " cutover" " " " cloud_linux_bootstrap_skipped" " {\" reason\" :\" cli_or_policy\" }"
@@ -2817,16 +2891,18 @@ v2k_cmd_cutover() {
28172891 if [[ " ${V2K_JSON_OUT:- 0} " -ne 1 ]]; then
28182892 echo " [v2k] Cloud Windows WinPE bootstrap requested (guestFamily=windowsGuest)"
28192893 fi
2820- v2k_cloud_windows_winpe_bootstrap " ${winpe_iso} " " ${virtio_iso} " " ${winpe_timeout} "
2821- local rc=$?
2822- if [[ " ${rc} " -ne 0 ]]; then
2894+ if v2k_cloud_windows_winpe_bootstrap " ${winpe_iso} " " ${virtio_iso} " " ${winpe_timeout} " ; then
2895+ v2k_event INFO " cutover" " " " cloud_winpe_bootstrap_done" " {}"
2896+ if [[ " ${V2K_JSON_OUT:- 0} " -ne 1 ]]; then
2897+ echo " [v2k] Cloud Windows WinPE bootstrap done (guestFamily=windowsGuest)"
2898+ fi
2899+ else
2900+ local rc=$?
28232901 v2k_event ERROR " cutover" " " " cloud_winpe_bootstrap_failed" " {\" code\" :${rc} }"
2824- echo " Cloud Windows WinPE bootstrap failed. code=${rc} " >&2
2825- exit " ${rc} "
2826- fi
2827- v2k_event INFO " cutover" " " " cloud_winpe_bootstrap_done" " {}"
2828- if [[ " ${V2K_JSON_OUT:- 0} " -ne 1 ]]; then
2829- echo " [v2k] Cloud Windows WinPE bootstrap done (guestFamily=windowsGuest)"
2902+ if ! v2k_select_bootstrap_fallback " ${V2K_MANIFEST} " " winpe_bootstrap" " ${rc} " " Cloud Windows WinPE bootstrap failed" " ${bootstrap_fallback} " ; then
2903+ echo " Cloud Windows WinPE bootstrap failed. code=${rc} " >&2
2904+ exit " ${rc} "
2905+ fi
28302906 fi
28312907 fi
28322908
@@ -2876,19 +2952,21 @@ v2k_cmd_cutover() {
28762952 if [[ " ${V2K_JSON_OUT:- 0} " -ne 1 ]]; then
28772953 echo " [v2k] Linux bootstrap(initramfs) requested (guestFamily=linuxGuest)"
28782954 fi
2879- v2k_linux_bootstrap_initramfs " ${V2K_MANIFEST} "
2880- local rc=$?
2881- if [[ " ${rc} " -ne 0 ]]; then
2955+ if v2k_linux_bootstrap_initramfs " ${V2K_MANIFEST} " ; then
2956+ v2k_event INFO " cutover" " " " linux_bootstrap_done" " {}"
2957+ if [[ " ${V2K_JSON_OUT:- 0} " -ne 1 ]]; then
2958+ echo " [v2k] Linux bootstrap(initramfs) done (guestFamily=linuxGuest)"
2959+ fi
2960+ else
2961+ local rc=$?
28822962 v2k_event ERROR " cutover" " " " linux_bootstrap_failed" " {\" code\" :${rc} }"
28832963 if [[ " ${V2K_JSON_OUT:- 0} " -ne 1 ]]; then
28842964 echo " [v2k] Linux bootstrap(initramfs) failed (guestFamily=linuxGuest)"
28852965 fi
2886- echo " Linux bootstrap (initramfs rebuild) failed. code=${rc} " >&2
2887- exit 74
2888- fi
2889- v2k_event INFO " cutover" " " " linux_bootstrap_done" " {}"
2890- if [[ " ${V2K_JSON_OUT:- 0} " -ne 1 ]]; then
2891- echo " [v2k] Linux bootstrap(initramfs) done (guestFamily=linuxGuest)"
2966+ if ! v2k_select_bootstrap_fallback " ${V2K_MANIFEST} " " linux_bootstrap" " ${rc} " " Linux bootstrap(initramfs) failed" " ${bootstrap_fallback} " ; then
2967+ echo " Linux bootstrap (initramfs rebuild) failed. code=${rc} " >&2
2968+ exit 74
2969+ fi
28922970 fi
28932971 else
28942972 v2k_event INFO " cutover" " " " linux_bootstrap_skipped" " {\" reason\" :\" cli_or_policy\" }"
@@ -2941,7 +3019,21 @@ v2k_cmd_cutover() {
29413019 if [[ " ${winpe_bootstrap} " -eq 1 ]]; then
29423020 local vm
29433021 vm=" $( jq -r ' .target.libvirt.name' " ${V2K_MANIFEST} " ) "
2944- v2k_windows_winpe_bootstrap_libvirt " ${V2K_MANIFEST} " " ${vm} " " ${winpe_iso} " " ${virtio_iso} " " ${winpe_timeout} " 0
3022+ if v2k_windows_winpe_bootstrap_libvirt " ${V2K_MANIFEST} " " ${vm} " " ${winpe_iso} " " ${virtio_iso} " " ${winpe_timeout} " 0; then
3023+ :
3024+ else
3025+ local rc=$?
3026+ v2k_event ERROR " cutover" " " " libvirt_winpe_bootstrap_failed" " {\" code\" :${rc} }"
3027+ if v2k_select_bootstrap_fallback " ${V2K_MANIFEST} " " winpe_bootstrap" " ${rc} " " Windows WinPE bootstrap failed" " ${bootstrap_fallback} " ; then
3028+ if ! v2k_libvirt_redefine_with_bootstrap_fallback " ${V2K_MANIFEST} " " ${vcpu} " " ${memory} " " ${bridge} " " ${vlan} " " ${network} " ; then
3029+ echo " libvirt redefine with SATA fallback failed." >&2
3030+ exit 65
3031+ fi
3032+ else
3033+ echo " Windows WinPE bootstrap failed. code=${rc} " >&2
3034+ exit " ${rc} "
3035+ fi
3036+ fi
29453037 fi
29463038
29473039 # WinPE may trigger host-side auto-unmap on guest shutdown. Re-prepare persistent RBD maps before the final boot.
0 commit comments