customize: Unconditionally set the machine-id if not set already.

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 image with a half-installed kernel.  (Add -v -x
to see the error above amongst the debug output).

This change makes virt-customize set /etc/machine-id to a random value
if the file exists and is zero sized.  This is done unconditionally at
the same time as setting the random seed (a similar issue), and before
running any customize options such as installing or updating packages.
This commit is contained in:
Richard W.M. Jones
2017-09-25 13:09:03 +01:00
parent fa62e3a0cf
commit d5ce659e2c

View File

@@ -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 ()