From 00c6b7f0a9371df0212dbe84abb1f95c162609a0 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Wed, 15 Apr 2015 17:55:02 +0100 Subject: [PATCH] boot: Allow template to specify custom libvirt XML. --- mclu.pod | 36 ++++++++++++++++++++++++ mclu_boot.ml | 90 ++++++++++++++++++++++++++++++++++++++++++++++++------------ template.ml | 6 +++- template.mli | 1 + 4 files changed, 114 insertions(+), 19 deletions(-) diff --git a/mclu.pod b/mclu.pod index aeff24b..54bc6f0 100644 --- a/mclu.pod +++ b/mclu.pod @@ -324,6 +324,42 @@ The template MAY print the recommended amount of memory (RAM), used if the user does not select any other value. Abbreviations like C<2G> are supported. +=item xml + +The template MAY specify custom libvirt XML. Usually you should +I specify this. It is only used when you need very odd guest +configuration (especially when emulating other architectures). + +The following environment variables are passed to the template: + +=over 4 + +=item C<$name> + +The guest name. + +=item C<$format> + +The disk format (eg. C). + +=item C<$output> + +The disk file name. + +=item C<$memory_kb> + +The size of the RAM in kilobytes. + +=item C<$vcpus> + +The number of virtual CPUs. + +=item C<$mac_addr> + +The MAC address. + +=back + =back =head1 ENVIRONMENT VARIABLES diff --git a/mclu_boot.ml b/mclu_boot.ml index 451beb8..16b8ac9 100644 --- a/mclu_boot.ml +++ b/mclu_boot.ml @@ -163,6 +163,7 @@ Try: `mclu on %s'\n" hostname hostname; let format, extension = "qcow2", "qcow2" 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. *) @@ -174,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 @@ -202,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" @@ -216,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 "\ @@ -239,7 +243,7 @@ Try: `mclu on %s'\n" hostname hostname; " mac_addr network_model in - let xml = xml ^ "\ + let xml = xml ^ "\ @@ -255,6 +259,56 @@ Try: `mclu on %s'\n" hostname hostname; " in + xml + + 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 = diff --git a/template.ml b/template.ml index 29af293..428ffe4 100644 --- a/template.ml +++ b/template.ml @@ -78,6 +78,7 @@ type template_info = { minimum_size : int64 option; disk_bus : string option; network_model : string option; + has_xml_target : bool; } let probe ?(verbose = false) filename = @@ -135,9 +136,12 @@ let probe ?(verbose = false) filename = | Some [answer] -> Some answer | _ -> None in + let has_xml_target = run_template ~verbose filename "xml" [] <> None in + { base_image = base_image; minimum_memory = minimum_memory; recommended_memory = recommended_memory; minimum_size = minimum_size; disk_bus = disk_bus; - network_model = network_model } + network_model = network_model; + has_xml_target = has_xml_target } diff --git a/template.mli b/template.mli index 635ca55..470baeb 100644 --- a/template.mli +++ b/template.mli @@ -31,6 +31,7 @@ type template_info = { minimum_size : int64 option; disk_bus : string option; network_model : string option; + has_xml_target : bool; } val probe : ?verbose:bool -> string -> template_info -- 1.8.3.1