From 91e0946235d4c7e2d1fe7eee01d3705dd81c945b Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Thu, 1 Jan 1970 00:00:00 +0000 Subject: [PATCH] Add static network configuration option and make work. - Static network configuration. - Documentation. - Fix dialog back button / skipping. --- virt-p2v | 174 +++++++++++++++++++++++++++++++++++++++++++---------------- virt-p2v.pod | 43 +++++++++++++-- 2 files changed, 169 insertions(+), 48 deletions(-) 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. *) diff --git a/virt-p2v.pod b/virt-p2v.pod index cf9cc0a..3018389 100644 --- a/virt-p2v.pod +++ b/virt-p2v.pod @@ -84,6 +84,11 @@ In this mode, the live CD attempts to reuse the network configuration from the physical machine's root filesystem. You should probably try this method even though occasionally it does not work. +=item Ask for fixed IP address and gateway + +In this mode the live CD will ask you for a fixed IP address and +gateway address, and will configure your chosen interface with these. + =item Configure from the shell In this mode you will be dropped into a command shell and you will @@ -99,6 +104,12 @@ interface would be: where C is the IP address and C is the gateway. +=item QEMU user network + +This option configures the network for use inside a QEMU user network +(L). It +should only be used by developers. + =back =item Devices @@ -356,9 +367,35 @@ For a logical volume (eg. C), use: =item C -Set this to the choice for network setup. Use either C or -C for auto-configuration or shell (manual) configuration -respectively. +Set this to the choice for network setup. Use one of: + +=over 4 + +=item C + +for auto-configuration + +=item C + +to specify the interface, address, netmask and gateway statically + +=item C + +to launch a shell + +=item C + +to use a QEMU user network (developers only) + +=back + +=item C + +This setting only applies if C is set to C, +in which case you should set this to the static network settings, +a tuple of (interface, address, netmask, gateway, nameserver): + + Some ("eth0", "192.168.2.5", "255.255.255.0", "192.168.2.1", "192.168.2.1") =item C -- 1.8.3.1