open Utils
+let ws_rex = Pcre.regexp "\\s+"
+let br_rex = Pcre.regexp "^br\\d+"
+let virbr_rex = Pcre.regexp "^virbr\\d+"
+
let memory = ref 0L (* 0 = choose for me *)
let set_memory s =
try memory := bytes_of_human_size s
let remote_external_kernel_dir = sprintf "/var/tmp/%s.boot" name in
let remote_external_kernel = sprintf "/var/tmp/%s.boot/kernel" name in
let remote_external_initrd = sprintf "/var/tmp/%s.boot/initrd" name in
+ let remote_arch = node.MS.node_status.node_info.model in
+
+ (* Guest arch defaults to the node host arch, but can be overridden
+ * in the template.
+ *)
+ let guest_arch =
+ match template_info.Template.guest_arch with
+ | Some arch -> arch
+ | None -> remote_arch in
+
+ (* UEFI firmware and NVRAM on remote, if required. *)
+ let nvram =
+ match guest_arch with
+ | "aarch64" ->
+ Some ("/usr/share/edk2/aarch64/QEMU_EFI-pflash.raw",
+ "/usr/share/edk2/aarch64/vars-template-pflash.raw",
+ remote_image ^ ".nvram")
+ | _ -> None in
+
+ (* Get the name of the remote bridge. *)
+ let bridge =
+ let cmd =
+ sprintf "ssh root@%s brctl show | sort" (quote hostname) in
+ if verbose then printf "%s\n%!" cmd;
+ let chan = Unix.open_process_in cmd 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: 'brctl show' exited with error %d\n" i;
+ exit 1
+ | Unix.WSIGNALED i ->
+ eprintf "mclu: 'brctl show' killed by signal %d\n" i;
+ exit 1
+ | Unix.WSTOPPED i ->
+ eprintf "mclu: 'brctl show' stopped by signal %d\n" i;
+ exit 1
+ );
+ let lines = List.rev !lines in
+ (* A heuristic: Use brX, but if none exist, try virbrX. *)
+ let brname = ref None in
+ let virbrname = ref None in
+ List.iter (
+ fun line ->
+ match Pcre.split ~rex:ws_rex line with
+ | str :: _ when Pcre.pmatch ~rex:br_rex str ->
+ if !brname = None then
+ brname := Some str
+ | str :: _ when Pcre.pmatch ~rex:virbr_rex str ->
+ if !virbrname = None then
+ virbrname := Some str
+ | _ -> ()
+ ) lines;
+
+ match !brname with
+ | Some br -> br
+ | None ->
+ match !virbrname with
+ | Some br -> br
+ | None ->
+ eprintf "mclu: Could not get remote bridge name\n";
+ exit 1 in
(* Get ready to generate the guest XML. *)
let vcpus = !vcpus in
let xml = xml ^ "\
<os>
- <type>hvm</type>
<boot dev='hd'/>
" in
+ let xml =
+ match guest_arch with
+ | "arm" | "armv7" | "armv7l" | "armv7hl" ->
+ xml ^ "\
+ <type arch='armv7l' machine='virt'>hvm</type>
+"
+ | "aarch64" ->
+ xml ^ "\
+ <type machine='virt'>hvm</type>
+"
+ | _ ->
+ xml ^ "\
+ <type>hvm</type>
+" in
+
+ let xml =
+ match nvram with
+ | Some (loader, nvram_template, nvram) ->
+ xml ^ sprintf "\
+ <loader readonly='yes' type='pflash'>%s</loader>
+ <nvram template='%s'>%s</nvram>
+" loader nvram_template nvram
+ | None -> xml in
let xml = xml ^
if template_info.Template.needs_external_kernel then
" remote_external_kernel remote_external_initrd
else "" in
+ let xml = xml ^
+ match template_info.Template.cmdline with
+ | Some cmdline -> sprintf " <cmdline>%s</cmdline>\n" cmdline
+ | None -> "" in
+
let xml = xml ^ "\
</os>
<features>
match template_info.Template.disk_bus with
| Some "ide" ->
" <target dev='sda' bus='ide'/>\n"
+ | Some "virtio" ->
+ " <target dev='vda' bus='virtio'/>\n"
| Some "virtio-scsi" | None ->
" <target dev='sda' bus='scsi'/>\n"
| Some bus ->
else
"" in
- (* XXX Don't hard-code bridge name here. *)
let network_model =
match template_info with
| { Template.network_model = None } -> "virtio"
let xml = xml ^ sprintf "\
<interface type='bridge'>
<mac address='%s'/>
- <source bridge='br0'/>
+ <source bridge='%s'/>
<model type='%s'/>
</interface>
-" mac_addr network_model in
+" mac_addr bridge network_model in
let xml = xml ^ "\
<serial type='pty'>
<console type='pty'>
<target type='serial' port='0'/>
</console>
+" in
+ let xml =
+ match guest_arch with
+ | "i386" | "i486" | "i586" | "i686"
+ | "x86_64" ->
+ xml ^ "\
<input type='tablet' bus='usb'/>
<input type='mouse' bus='ps2'/>
<input type='keyboard' bus='ps2'/>
<video>
<model type='cirrus' vram='9216' heads='1'/>
</video>
+"
+ | _ -> xml in
+ let xml = xml ^ "\
</devices>
</domain>" in
xml
let fpf fs = fprintf chan fs in
fpf "#!/bin/bash\n";
fpf "set -e\n";
- (* XXX Don't hard-code network_bridge here. *)
- fpf "export LIBGUESTFS_BACKEND_SETTINGS=network_bridge=br0\n";
+ fpf "export LIBGUESTFS_BACKEND_SETTINGS=network_bridge=%s\n" bridge;
fpf "export base_image=%s\n" (quote template_info.Template.base_image);
fpf "export format=%s\n" (quote format);
+ fpf "export guest_arch=%s\n" (quote guest_arch);
fpf "export name=%s\n" (quote name);
fpf "export output=%s\n" (quote remote_image);
(match size with
| "" -> ()
| tz -> fpf "export timezone=%s\n" (quote (sprintf "--timezone %s" tz))
);
+ (match nvram with
+ | Some (_, nvram_template, nvram) ->
+ fpf "cp %s %s\n" (quote nvram_template) (quote nvram)
+ | None -> ()
+ );
fpf "%s build\n" remote_template;
if template_info.Template.needs_external_kernel then (
fpf "rm -rf %s\n" (quote remote_external_kernel_dir);