X-Git-Url: http://git.annexia.org/?a=blobdiff_plain;f=virt-p2v;h=20baf6228113cacf9c6fa615d7000b5fc8a7db57;hb=91e0946235d4c7e2d1fe7eee01d3705dd81c945b;hp=98febf108c7b7eb0efe4db4ad03d38379f1ab75f;hpb=00dc36e22b4ee9c16d4197886ed9b14581bbf814;p=virt-p2v.git diff --git a/virt-p2v b/virt-p2v index 98febf1..20baf62 100755 --- a/virt-p2v +++ b/virt-p2v @@ -39,6 +39,7 @@ type state = { greeting : bool; remote_directory : string option; remote_username : string option; network : network option; + static_network_config : static_network_config option; devices_to_send : string list option; root_filesystem : partition option; hypervisor : hypervisor option; @@ -46,12 +47,17 @@ type state = { greeting : bool; memory : int option; vcpus : int option; mac_address : string option; } -and network = Auto | Shell +and network = Auto + | Shell + | QEMUUserNet + | Static and partition = Part of string * string (* eg. "hda", "1" *) | LV of string * string (* eg. "VolGroup00", "LogVol00" *) and hypervisor = Xen | QEMU | KVM and architecture = I386 | X86_64 | IA64 | PPC | PPC64 | SPARC | SPARC64 | OtherArch of string | UnknownArch +and static_network_config = string * string * string * string * string + (* interface, address, netmask, gateway, nameserver *) (*----------------------------------------------------------------------*) (* TO MAKE A CUSTOM virt-p2v SCRIPT, adjust the defaults in this section. @@ -81,6 +87,7 @@ let defaults = { devices_to_send = None; root_filesystem = None; network = None; + static_network_config = None; hypervisor = None; architecture = None; memory = None; @@ -159,7 +166,7 @@ and string_of_linux_distro = function * * Returns the exit status (Yes lines | No | Help | Back | Error). *) -let msgbox, yesno, inputbox, radiolist, checklist = +let msgbox, yesno, inputbox, radiolist, checklist, form = (* Internal function to actually run the "dialog" shell command. *) let run_dialog cparams params = let params = cparams @ params in @@ -255,8 +262,25 @@ let msgbox, yesno, inputbox, radiolist, checklist = string_of_int listheight :: items in run_dialog cparams items ) + + (* Form. *) + and form = + with_common ( + fun cparams text height width formheight items -> + let items = List.map ( + fun (label, y, x, item, y', x', flen, ilen) -> + [ label; string_of_int y; string_of_int x; item; + string_of_int y'; string_of_int x'; + string_of_int flen; string_of_int ilen ] + ) items in + let items = List.concat items in + let items = "--form" :: text :: + string_of_int height :: string_of_int width :: + string_of_int formheight :: items in + run_dialog cparams items + ) in - msgbox, yesno, inputbox, radiolist, checklist + msgbox, yesno, inputbox, radiolist, checklist, form (* Print failure dialog and exit. *) let fail_dialog text = @@ -474,6 +498,29 @@ let auto_network state = (* Non-interactive: return the status of /etc/init.d/network start. *) status = 0 +(* Configure the network statically. *) +let static_network state = + match state.static_network_config with + | None -> false (* failed *) + | Some (interface, address, netmask, gateway, nameserver) -> + let do_cmd_or_exit cmd = if shwithstatus cmd <> 0 then raise Exit in + try + do_cmd_or_exit (sprintf "ifconfig %s %s netmask %s" + (quote interface) (quote address) (quote netmask)); + do_cmd_or_exit (sprintf "route add default gw %s %s" + (quote gateway) (quote interface)); + if nameserver <> "" then + do_cmd_or_exit (sprintf "echo nameserver %s > /etc/resolv.conf" + (quote nameserver)); + true (* succeeded *) + with + Exit -> false (* failed *) + +let qemu_network () = + sh "ifconfig eth0 10.0.2.10 netmask 255.255.255.0"; + sh "route add default gw 10.0.2.2 eth0"; + sh "echo nameserver 10.0.2.3 > /etc/resolv.conf" + (* Map local device names to remote devices names. At the moment we * just change sd* to hd* (as device names appear under fullvirt). In * future, lots of complex possibilities. @@ -812,13 +859,42 @@ let rec main ttyname = let ask_network state = match - radiolist "Network configuration" "Network configuration" 10 50 2 [ + radiolist "Network configuration" "Network configuration" 12 50 4 [ "auto", "Automatic configuration", state.network = Some Auto; + "ask", "Ask for fixed IP address and gateway", + state.network = Some Static; "sh", "Configure from the shell", state.network = Some Shell; + "qemu", "QEMU user network (for developers only)", + state.network = Some QEMUUserNet ] with | Yes ("auto"::_) -> Next { state with network = Some Auto } + | Yes ("ask"::_) -> Next { state with network = Some Static } | Yes ("sh"::_) -> Next { state with network = Some Shell } + | Yes ("qemu"::_) -> Next { state with network = Some QEMUUserNet } + | Yes _ | No | Help | Error -> Ask_again + | Back -> Prev + in + + let ask_static_network_config state = + let interface, address, netmask, gateway, nameserver = + match state.static_network_config with + | Some (a,b,c,d,e) -> a,b,c,d,e + | None -> "eth0","","","","" in + match + form "Static network configuration" "Static network configuration" + 13 50 5 [ + "Interface", 1, 0, interface, 1, 12, 8, 0; + "Address", 2, 0, address, 2, 12, 16, 0; + "Netmask", 3, 0, netmask, 3, 12, 16, 0; + "Gateway", 4, 0, gateway, 4, 12, 16, 0; + "Nameserver", 5, 0, nameserver, 5, 12, 16, 0; + ] + with + | Yes (interface::address::netmask::gateway::nameserver::_) -> + Next { state with + static_network_config = Some (interface, address, netmask, + gateway, nameserver) } | Yes _ | No | Help | Error -> Ask_again | Back -> Prev in @@ -978,6 +1054,7 @@ MAC address: %s" (Option.default "" state.remote_directory) (match state.network with | Some Auto -> "Auto-configure" | Some Shell -> "Shell" + | Some Static -> "Static" | Some QEMUUserNet -> "QEMU user net" | None -> "") (String.concat "," (Option.default [] state.devices_to_send)) (Option.map_default dev_of_partition "" state.root_filesystem) @@ -1004,57 +1081,52 @@ MAC address: %s" in (* This is the list of dialogs, in order. The user can go forwards or - * backwards through them. The second parameter in each pair is - * false if we need to skip this dialog (info already supplied in - * 'defaults' above). + * backwards through them. + * + * The second parameter in each tuple is true if we need to skip + * this dialog statically (info already supplied in 'defaults' above). + * + * The third parameter in each tuple is a function that tests whether + * this dialog should be skipped, given other parts of the current state. *) - let dlgs = [| - ask_greeting, (* Initial greeting. *) - defaults.greeting; - ask_hostname, (* Hostname. *) - defaults.remote_host = None; - ask_port, (* Port number. *) - defaults.remote_port = None; - ask_directory, (* Remote directory. *) - defaults.remote_directory = None; - ask_username, (* Remote username. *) - defaults.remote_username = None; - ask_network, (* Network configuration. *) - defaults.network = None; - ask_devices, (* Block devices to send. *) - defaults.devices_to_send = None; - ask_root, (* Root filesystem. *) - defaults.root_filesystem = None; - ask_hypervisor, (* Hypervisor. *) - defaults.hypervisor = None; - ask_architecture, (* Architecture. *) - defaults.architecture = None; - ask_memory, (* Memory. *) - defaults.memory = None; - ask_vcpus, (* VCPUs. *) - defaults.vcpus = None; - ask_mac_address, (* MAC address. *) - defaults.mac_address = None; - ask_verify, (* Verify settings. *) - defaults.greeting + let dlgs = + let dont_skip _ = false in + [| + ask_greeting, not defaults.greeting, dont_skip; + ask_hostname, defaults.remote_host <> None, dont_skip; + ask_port, defaults.remote_port <> None, dont_skip; + ask_directory, defaults.remote_directory <> None, dont_skip; + ask_username, defaults.remote_username <> None, dont_skip; + ask_network, defaults.network <> None, dont_skip; + ask_static_network_config, + defaults.static_network_config <> None, + (function { network = Some Static } -> false | _ -> true); + ask_devices, defaults.devices_to_send <> None, dont_skip; + ask_root, defaults.root_filesystem <> None, dont_skip; + ask_hypervisor, defaults.hypervisor <> None, dont_skip; + ask_architecture, defaults.architecture <> None, dont_skip; + ask_memory, defaults.memory <> None, dont_skip; + ask_vcpus, defaults.vcpus <> None, dont_skip; + ask_mac_address, defaults.mac_address <> None, dont_skip; + ask_verify, not defaults.greeting, dont_skip; |] in (* Loop through the dialogs until we reach the end. *) - let rec loop posn state = - eprintf "dialog loop: posn = %d\n%!" posn; + let rec loop ?(back=false) posn state = + eprintf "dialog loop: posn = %d, back = %b\n%!" posn back; if posn >= Array.length dlgs then state (* Finished all dialogs. *) + else if posn < 0 then loop 0 state else ( - let dlg, no_skip = dlgs.(posn) in - let skip = not no_skip in - if skip then - (* Skip this dialog and move straight to the next one. *) - loop (posn+1) state + let dlg, skip_static, skip_dynamic = dlgs.(posn) in + if skip_static || skip_dynamic state then + (* Skip this dialog. *) + loop ~back (if back then posn-1 else posn+1) state else ( (* Run dialog. *) match dlg state with | Next new_state -> loop (posn+1) new_state (* Forwards. *) - | Prev -> loop (posn-1) state (* Backwards / back button. *) - | Ask_again -> loop posn state (* Repeat the question. *) + | Ask_again -> loop posn state (* Repeat the question. *) + | Prev -> loop ~back:true (posn-1) state (* Backwards / back button. *) ) ) in @@ -1112,6 +1184,15 @@ MAC address: %s" printf "When you have finished, exit the shell with ^D or exit.\n\n%!"; shell () + | Static -> + printf "Trying static network configuration.\n\n%!"; + if not (static_network state) then ( + printf "\nAuto-configuration failed. Starting a shell.\n\n"; + printf "Please configure the network from this shell.\n\n"; + printf "When you have finished, exit the shell with ^D or exit.\n\n"; + shell () + ) + | Auto -> printf "Trying network auto-configuration from root filesystem ...\n\n%!"; @@ -1121,6 +1202,9 @@ MAC address: %s" printf "When you have finished, exit the shell with ^D or exit.\n\n"; shell () ) + | QEMUUserNet -> + printf "Trying QEMU network configuration.\n\n%!"; + qemu_network () ); (* Work out what devices will be called at the remote end. *)