boot: Stop hard-coding the bridge name.
[mclu.git] / mclu_boot.ml
index e0aeef8..9c1cb94 100644 (file)
@@ -26,6 +26,10 @@ open Printf
 
 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
@@ -168,6 +172,71 @@ Try: `mclu on %s'\n" hostname hostname;
   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
@@ -191,9 +260,31 @@ Try: `mclu on %s'\n" hostname hostname;
 
     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
@@ -203,6 +294,11 @@ Try: `mclu on %s'\n" hostname hostname;
 " 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>
@@ -231,6 +327,8 @@ Try: `mclu on %s'\n" hostname hostname;
     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 ->
@@ -247,7 +345,6 @@ Try: `mclu on %s'\n" hostname hostname;
         else
           "" in
 
-    (* XXX Don't hard-code bridge name here. *)
     let network_model =
       match template_info with
       | { Template.network_model = None } -> "virtio"
@@ -255,10 +352,10 @@ Try: `mclu on %s'\n" hostname hostname;
     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'>
@@ -267,6 +364,12 @@ Try: `mclu on %s'\n" hostname hostname;
     <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'/>
@@ -274,6 +377,9 @@ Try: `mclu on %s'\n" hostname hostname;
     <video>
       <model type='cirrus' vram='9216' heads='1'/>
     </video>
+"
+      | _ -> xml in
+    let xml = xml ^ "\
   </devices>
 </domain>" in
     xml
@@ -347,10 +453,10 @@ Try: `mclu on %s'\n" hostname hostname;
     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
@@ -361,6 +467,11 @@ Try: `mclu on %s'\n" hostname hostname;
     | "" -> ()
     | 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);