builder: Create an install log file, and dump the full log on error.

This should make debugging much simpler, and also provides a
build log in the guest once it's built.
This commit is contained in:
Richard W.M. Jones
2013-10-05 15:00:54 +01:00
parent cc37490e05
commit 7b82580352
2 changed files with 77 additions and 11 deletions

View File

@@ -43,7 +43,7 @@ let mode, arg,
firstboot, run,
format, gpg, hostname, install, list_long, network, output,
password_crypto, quiet, root_password,
size, source, upload =
size, source, upload, wipe_logfile =
let display_version () =
let g = new G.guestfs () in
let version = g#version () in
@@ -163,6 +163,8 @@ let mode, arg,
upload := (file, dest) :: !upload
in
let wipe_logfile = ref false in
let ditto = " -\"-" in
let argspec = Arg.align [
"--attach", Arg.String attach_disk, "iso" ^ " " ^ s_"Attach data disk/ISO during install";
@@ -194,6 +196,7 @@ let mode, arg,
"-l", Arg.Unit list_mode, " " ^ s_"List available templates";
"--list", Arg.Unit list_mode, ditto;
"--long", Arg.Set list_long, ditto;
"--no-logfile", Arg.Set wipe_logfile, " " ^ s_"Wipe build log file";
"--long-options", Arg.Unit display_long_options, " " ^ s_"List long options";
"--network", Arg.Set network, " " ^ s_"Enable appliance network (default)";
"--no-network", Arg.Clear network, " " ^ s_"Disable appliance network";
@@ -252,6 +255,7 @@ read the man page virt-builder(1).
let size = !size in
let source = !source in
let upload = List.rev !upload in
let wipe_logfile = !wipe_logfile in
(* Check options. *)
let arg =
@@ -296,7 +300,7 @@ read the man page virt-builder(1).
firstboot, run,
format, gpg, hostname, install, list_long, network, output,
password_crypto, quiet, root_password,
size, source, upload
size, source, upload, wipe_logfile
(* Timestamped messages in ordinary, non-debug non-quiet mode. *)
let msg fs = make_message_function ~quiet fs
@@ -635,11 +639,21 @@ let () =
| _ ->
eprintf (f_"%s: warning: root password could not be set for this type of guest\n%!") prog
(* Based on the guest type, choose a log file location. *)
let logfile =
match g#inspect_get_type root with
| "windows" | "dos" ->
if g#is_dir "/Temp" then "/Temp/builder.log" else "/builder.log"
| _ ->
if g#is_dir "/tmp" then "/tmp/builder.log" else "/builder.log"
(* Useful wrapper for scripts. *)
let do_run cmd =
let do_run ~display cmd =
(* Add a prologue to the scripts:
* - Pass environment variables through from the host.
* - Send stdout to stderr so we capture all output in error messages.
* - Send stdout and stderr to a log file so we capture all output
* in error messages.
* Also catch errors and dump the log file completely on error.
*)
let env_vars =
filter_map (
@@ -650,13 +664,22 @@ let do_run cmd =
let env_vars = String.concat "\n" env_vars ^ "\n" in
let cmd = sprintf "\
exec 1>&2
exec >>%s 2>&1
%s
%s
" env_vars cmd in
" (quote logfile) env_vars cmd in
if debug then eprintf "running: %s\n%!" cmd;
ignore (g#sh cmd)
if debug then eprintf "running command:\n%s\n%!" cmd;
try ignore (g#sh cmd)
with Guestfs.Error msg ->
(* Cat the log file. *)
(try g#download logfile "/dev/stderr"
with exn ->
eprintf (f_"%s: internal error: could not display the log file: %s\n")
prog (Printexc.to_string exn)
);
eprintf (f_"%s: %s: command exited with an error\n") prog display;
exit 1
let guest_install_command packages =
let quoted_args = String.concat " " (List.map quote packages) in
@@ -689,7 +712,7 @@ let () =
msg (f_"Installing packages: %s") (String.concat " " install);
let cmd = guest_install_command install in
do_run cmd;
do_run ~display:cmd cmd
)
(* Upload files. *)
@@ -729,12 +752,22 @@ let () =
| `Script script ->
msg (f_"Running: %s") script;
let cmd = read_whole_file script in
do_run cmd
do_run ~display:script cmd
| `Command cmd ->
msg (f_"Running: %s") cmd;
do_run cmd
do_run ~display:cmd cmd
) run
(* Wipe the log file. *)
let () =
if wipe_logfile && g#exists logfile then (
msg (f_"Wiping the log file");
(* Try various methods with decreasing complexity. *)
try g#scrub_file logfile
with _ -> g#rm_f logfile
)
(* Unmount everything and we're done! *)
let () =
msg (f_"Finishing off");

View File

@@ -310,6 +310,14 @@ each operating system option.
See also: I<--source>, L</CREATING YOUR OWN TEMPLATES>.
=item B<--no-logfile>
Wipe C<builder.log> (log file from build commands) from the image
after building is complete. If you don't want to reveal precisely how
the image was built, use this option.
See also: L</LOG FILE>.
=item B<--network>
=item B<--no-network>
@@ -569,6 +577,31 @@ The above command will create an C<rjones> account with no password,
and force the user to set a password when they first log in. There
are other ways to manage passwords, see L<useradd(8)> for details.
=head2 LOG FILE
Scripts and package installation that runs at build time (I<--run>,
I<--run-command>, I<--install>, but I<not> firstboot) is logged in one
of the following locations:
=over 4
=item C</tmp/builder.log>
On Linux, BSD and other guests.
=item C<C:\Temp\builder.log>
On Windows, DOS guests.
=item C</builder.log>
If C</tmp> or C<C:\Temp> is missing.
=back
If you don't want the log file to appear in the final image, then
use the I<--no-logfile> command line option.
=head2 INSTALLATION PROCESS
When you invoke virt-builder, installation proceeds as follows: