[Libguestfs] [PATCH] customize: Unconditionally set the machine-id if not set already.

Richard W.M. Jones rjones at redhat.com
Mon Sep 25 12:15:17 UTC 2017


systemd defined an /etc/machine-id file which is supposed to contain a
unique, unchanging ID for the host.  This file is initially zero-sized
and is meant to be set by systemd on the first boot of the system.

In virt-builder Fedora templates, the file is empty.

Unfortunately the Fedora kernel %post script requires the machine-id
to have been set, else the script exits with an error:

  Running scriptlet: kernel-core-4.12.13-300.fc26.x86_64                209/209
  Could not determine your machine ID from /etc/machine-id.
  Please run 'systemd-machine-id-setup' as root. See man:machine-id(5)
  warning: %posttrans(kernel-core-4.12.13-300.fc26.x86_64) scriptlet failed, exit status 1

This also leaves the kernel package half-installed.  The files are
present in the filesystem, but important initialization is not done,
in particular the vmlinuz file is not copied into /boot.

A simple reproducer for this problem is:

  $ virt-builder fedora-26 --update

which will leave the system with a half-installed kernel.

This change makes virt-customize set /etc/machine-id to a random value
if it is zero sized.  This is done unconditionally at the same time as
setting the random seed (a similar issue).
---
 customize/customize_run.ml | 30 ++++++++++++++++++++++++++----
 1 file changed, 26 insertions(+), 4 deletions(-)

diff --git a/customize/customize_run.ml b/customize/customize_run.ml
index 5564684b4..3dcf755eb 100644
--- a/customize/customize_run.ml
+++ b/customize/customize_run.ml
@@ -27,7 +27,9 @@ open Customize_cmdline
 open Password
 open Append_line
 
-let run (g : Guestfs.guestfs) root (ops : ops) =
+module G = Guestfs
+
+let run (g : G.guestfs) root (ops : ops) =
   (* Is the host_cpu compatible with the guest arch?  ie. Can we
    * run commands in this guest?
    *)
@@ -89,7 +91,7 @@ exec >>%s 2>&1
     debug "running command:\n%s" cmd;
     try ignore (g#sh cmd)
     with
-      Guestfs.Error msg ->
+      G.Error msg ->
         debug_logfile ();
         if warn_failed_no_network && not (g#get_network ()) then (
           prerr_newline ();
@@ -194,6 +196,26 @@ exec >>%s 2>&1
   if not (Random_seed.set_random_seed g root) then
     warning (f_"random seed could not be set for this type of guest");
 
+  (* Set the systemd machine ID.  This must be set before performing
+   * --install/--update since (at least in Fedora) the kernel %post
+   * script requires a machine ID and will fail if it is not set.
+   *)
+  let () =
+    let etc_machine_id = "/etc/machine-id" in
+    let statbuf =
+      try Some (g#lstatns etc_machine_id) with G.Error _ -> None in
+    (match statbuf with
+     | Some { G.st_size = 0L; G.st_mode = mode }
+          when (Int64.logand mode 0o170000_L) = 0o100000_L ->
+        message (f_"Setting the machine ID in %s") etc_machine_id;
+        let id = Urandom.urandom_bytes 16 in
+        let id = String.map_chars (fun c -> sprintf "%02x" (Char.code c)) id in
+        let id = String.concat "" id in
+        let id = id ^ "\n" in
+        g#write etc_machine_id id
+     | _ -> ()
+    ) in
+
   (* Store the passwords and set them all at the end. *)
   let passwords = Hashtbl.create 13 in
   let set_password user pw =
@@ -399,8 +421,8 @@ exec >>%s 2>&1
       let uid, gid = statbuf.st_uid, statbuf.st_gid in
       let chown () =
         try g#chown uid gid dest
-        with Guestfs.Error m as e ->
-          if g#last_errno () = Guestfs.Errno.errno_EPERM
+        with G.Error m as e ->
+          if g#last_errno () = G.Errno.errno_EPERM
           then warning "%s" m
           else raise e in
       chown ()
-- 
2.13.2




More information about the Libguestfs mailing list