X-Git-Url: http://git.annexia.org/?a=blobdiff_plain;f=mclu_boot.ml;h=16b8ac9305356b5d3dd9d03fd3cee42cb7b6d1a6;hb=00c6b7f0a9371df0212dbe84abb1f95c162609a0;hp=6927363ba8245a904ad3a221493eaaa7ce45c996;hpb=b29a837444aa5827b683bee5a7457fbb32305ae5;p=mclu.git diff --git a/mclu_boot.ml b/mclu_boot.ml index 6927363..16b8ac9 100644 --- a/mclu_boot.ml +++ b/mclu_boot.ml @@ -33,13 +33,28 @@ let set_memory s = eprintf "mclu: don't understand --memory parameter '%s' Try something like --memory 1G\n" s; exit 1 +let size = ref 0L (* 0 = default *) +let set_size s = + try size := bytes_of_human_size s + with Not_found -> + eprintf "mclu: don't understand --size parameter '%s' +Try something like --size 20G\n" s; + exit 1 +let timezone = ref "" (* "" = no timezone set *) let vcpus = ref 0 (* 0 = choose for me *) +let open_console = ref false +let open_viewer = ref false + let get_arg_speclist () = Arg.align [ + "--console", Arg.Set open_console, " Open the serial console"; "--cpus", Arg.Set_int vcpus, "n Number of virtual CPUs"; "--memory", Arg.String set_memory, "nnG Amount of RAM to give guest"; "--ram", Arg.String set_memory, "nnG Amount of RAM to give guest"; + "--size", Arg.String set_size, "nnG Size of disk to give guest"; + "--timezone", Arg.Set_string timezone, "TZ Set timezone of guest"; "--vcpus", Arg.Set_int vcpus, "n Number of virtual CPUs"; + "--viewer", Arg.Set open_viewer, " Open the graphical console"; ] let boot ~verbose template name = @@ -56,6 +71,18 @@ Try `mclu list --templates' to list all known templates.\n" template; (* Probe the template for various features. *) let template_info = Template.probe ~verbose template_filename in + (* Check --size is not too small. *) + let size = + match !size, template_info.Template.minimum_size with + | 0L, None -> 0L (* virt-builder default *) + | 0L, Some min_size -> (* go with template minimum size *) + min_size + | size, Some min_size when size < min_size -> + eprintf "mclu: --size parameter is smaller than the minimum specified by the template (%s).\n" + (human_size min_size); + exit 1 + | size, _ -> size in (* go with user-specified size *) + (* Decide how much RAM we will give the guest. This affects our * choice of node, so do it early. *) @@ -134,7 +161,9 @@ Try: `mclu on %s'\n" hostname hostname; (* Where we upload the template and image on remote. *) let format, extension = "qcow2", "qcow2" in - let remote_filename = sprintf "/tmp/mclu%s.sh" (string_random8 ()) in + let remote_template = sprintf "/tmp/mclu%s.sh" (string_random8 ()) in + let remote_template_wrapper = sprintf "/tmp/mclu%s.sh" (string_random8 ()) in + let xml_template_wrapper = sprintf "/tmp/mclu%s.sh" (string_random8 ()) in let remote_image = sprintf "/var/tmp/%s.%s" name extension in (* Get ready to generate the guest XML. *) @@ -146,8 +175,10 @@ Try: `mclu on %s'\n" hostname hostname; sprintf "52:54:00:%02x:%02x:%02x" (Random.int 256) (Random.int 256) (Random.int 256) in - (* Generate the guest XML. XXX Quoting. *) - let xml = sprintf "\ + (* Generate the guest XML. *) + let generate_standard_xml () = + (* XXX Better quoting. *) + let xml = sprintf "\ %s %Ld @@ -174,12 +205,12 @@ Try: `mclu on %s'\n" hostname hostname; " name (memory /^ 1024L) (memory /^ 1024L) vcpus in - let xml = xml ^ sprintf "\ + let xml = xml ^ sprintf "\ " format remote_image in - let xml = xml ^ + let xml = xml ^ match template_info.Template.disk_bus with | Some "ide" -> " \n" @@ -188,22 +219,23 @@ Try: `mclu on %s'\n" hostname hostname; | Some bus -> eprintf "mclu: unknown disk-bus: %s\n" bus; exit 1 in - let xml = xml ^ "\ + let xml = xml ^ "\ " in - let xml = xml ^ - if template_info.Template.disk_bus = Some "virtio-scsi" then - " \n" - else - "" in - - (* XXX Don't hard-code bridge name here. *) - let network_model = - match template_info with - | { Template.network_model = None } -> "virtio" - | { Template.network_model = Some d } -> d in - let xml = xml ^ sprintf "\ + let xml = + xml ^ + if template_info.Template.disk_bus = Some "virtio-scsi" then + " \n" + else + "" in + + (* XXX Don't hard-code bridge name here. *) + let network_model = + match template_info with + | { Template.network_model = None } -> "virtio" + | { Template.network_model = Some d } -> d in + let xml = xml ^ sprintf "\ @@ -211,9 +243,12 @@ Try: `mclu on %s'\n" hostname hostname; " mac_addr network_model in - let xml = xml ^ "\ + let xml = xml ^ "\ + + + - + @@ -224,22 +259,104 @@ Try: `mclu on %s'\n" hostname hostname; " in + xml - (* Copy the template to remote and build the guest. *) + and generate_custom_xml () = + (* Generate a wrapper script to make passing the variables + * to the template easier. + *) + let () = + let chan = open_out xml_template_wrapper in + let fpf fs = fprintf chan fs in + fpf "#!/bin/sh\n"; + fpf "export format=%s\n" (quote format); + fpf "export mac_addr=%s\n" (quote mac_addr); + fpf "export memory_kb=%Ld\n" (memory /^ 1024L); + fpf "export name=%s\n" (quote name); + fpf "export output=%s\n" (quote remote_image); + fpf "export vcpus=%d\n" vcpus; + fpf "%s xml\n" template_filename; + close_out chan; + Unix.chmod xml_template_wrapper 0o755 in + + if verbose then printf "%s\n%!" xml_template_wrapper; + let chan = Unix.open_process_in xml_template_wrapper in + let lines = ref [] in + (try while true do lines := input_line chan :: !lines done + with End_of_file -> ()); + let stat = Unix.close_process_in chan in + (match stat with + | Unix.WEXITED 0 -> () + | Unix.WEXITED i -> + eprintf "mclu: template '%s' subcmd xml exited with error %d\n" + template_filename i; + exit 1 + | Unix.WSIGNALED i -> + eprintf "mclu: template '%s' subcmd xml killed by signal %d\n" + template_filename i; + exit 1 + | Unix.WSTOPPED i -> + eprintf "mclu: template '%s' subcmd xml stopped by signal %d\n" + template_filename i; + exit 1 + ); + let xml = String.concat "\n" (List.rev !lines) in + xml + in + + let xml = + if not template_info.Template.has_xml_target then + generate_standard_xml () + else + generate_custom_xml () in + + (* Copy the template to remote. *) let cmd = sprintf "scp %s root@%s:%s" - (quote template_filename) (quote hostname) remote_filename in + (quote template_filename) (quote hostname) remote_template in if verbose then printf "%s\n%!" cmd; if Sys.command cmd <> 0 then ( eprintf "mclu: scp template to remote failed\n"; exit 1 ); - let cmd = + + (* Create a wrapper script that sets the variables and runs the + * template. This just avoids complex quoting. + *) + let () = + let chan = open_out remote_template_wrapper in + let fpf fs = fprintf chan fs in + fpf "#!/bin/sh\n"; (* XXX Don't hard-code network_bridge here. *) - sprintf "ssh root@%s LIBGUESTFS_BACKEND_SETTINGS=network_bridge=br0 %s build %s %s %s" - (quote hostname) remote_filename - (quote template_info.Template.base_image) (quote remote_image) - format in + fpf "export LIBGUESTFS_BACKEND_SETTINGS=network_bridge=br0\n"; + fpf "export base_image=%s\n" (quote template_info.Template.base_image); + fpf "export format=%s\n" (quote format); + fpf "export name=%s\n" (quote name); + fpf "export output=%s\n" (quote remote_image); + (match size with + | 0L -> () + | size -> fpf "export size=%s\n" (quote (sprintf "--size %Ldb" size)) + ); + (match !timezone with + | "" -> () + | tz -> fpf "export timezone=%s\n" (quote (sprintf "--timezone %s" tz)) + ); + fpf "%s build\n" remote_template; + close_out chan; + Unix.chmod remote_template_wrapper 0o755 in + + let cmd = + sprintf "scp %s root@%s:%s" + (quote remote_template_wrapper) (quote hostname) + (quote remote_template_wrapper) in + if verbose then printf "%s\n%!" cmd; + if Sys.command cmd <> 0 then ( + eprintf "mclu: scp template wrapper to remote failed\n"; + exit 1 + ); + + let cmd = + sprintf "ssh root@%s %s" (quote hostname) (quote remote_template_wrapper) in if verbose then printf "%s\n%!" cmd; if Sys.command cmd <> 0 then ( eprintf "mclu: remote build failed\n"; @@ -247,15 +364,25 @@ Try: `mclu on %s'\n" hostname hostname; ); (* Start the guest. *) - try - let conn = - let name = node.MS.node_status.MS.node.Mclu_conf.libvirt_uri in - C.connect ~name () in - let dom = D.create_xml conn xml [] in - printf "mclu: %s:%s started\n" hostname (D.get_name dom) - with Libvirt.Virterror msg -> - eprintf "mclu: %s: %s\n" hostname (Libvirt.Virterror.to_string msg); - exit 1 + let dom = + try + let conn = + let name = node.MS.node_status.MS.node.Mclu_conf.libvirt_uri in + C.connect ~name () in + let dom = D.create_xml conn xml [] in + printf "mclu: %s:%s started\n" hostname (D.get_name dom); + dom + with Libvirt.Virterror msg -> + eprintf "mclu: %s: %s\n" hostname (Libvirt.Virterror.to_string msg); + exit 1 in + + (* Graphical console? *) + if !open_viewer then + Mclu_viewer.viewer ~verbose ~host:hostname (D.get_name dom); + + (* Serial console? (Interactive, so run it last) *) + if !open_console then + Mclu_console.console ~verbose ~host:hostname (D.get_name dom) let run ~verbose = function | [ template; name ] ->