You can use it like this:
virt-sysprep --timezone Europe/London ...
virt-builder --timezone Europe/London ...
---
builder/Makefile.am | 1 +
builder/builder.ml | 12 ++++++-
builder/cmdline.ml | 9 ++++-
builder/test-virt-builder.sh | 1 +
builder/virt-builder.pod | 8 ++++-
mllib/Makefile.am | 3 ++
mllib/timezone.ml | 39 +++++++++++++++++++++
mllib/timezone.mli | 22 ++++++++++++
po/POTFILES-ml | 2 ++
sysprep/Makefile.am | 2 ++
sysprep/sysprep_operation_timezone.ml | 66 +++++++++++++++++++++++++++++++++++
11 files changed, 162 insertions(+), 3 deletions(-)
create mode 100644 mllib/timezone.ml
create mode 100644 mllib/timezone.mli
create mode 100644 sysprep/sysprep_operation_timezone.ml
diff --git a/builder/Makefile.am b/builder/Makefile.am
index 3f35cc6..fc4c552 100644
--- a/builder/Makefile.am
+++ b/builder/Makefile.am
@@ -69,6 +69,7 @@ OBJECTS = \
$(top_builddir)/mllib/urandom.cmx \
$(top_builddir)/mllib/random_seed.cmx \
$(top_builddir)/mllib/hostname.cmx \
+ $(top_builddir)/mllib/timezone.cmx \
$(top_builddir)/mllib/firstboot.cmx \
$(top_builddir)/mllib/crypt-c.o \
$(top_builddir)/mllib/crypt.cmx \
diff --git a/builder/builder.ml b/builder/builder.ml
index 2582f0f..15a721a 100644
--- a/builder/builder.ml
+++ b/builder/builder.ml
@@ -39,7 +39,8 @@ let main () =
attach, cache, check_signature, curl, debug, delete, edit,
firstboot, run, format, gpg, hostname, install, list_long, memsize, mkdirs,
network, output, password_crypto, quiet, root_password, scrub,
- scrub_logfile, size, smp, sources, sync, update, upload, writes =
+ scrub_logfile, size, smp, sources, sync, timezone, update, upload,
+ writes =
parse_cmdline () in
(* Timestamped messages in ordinary, non-debug non-quiet mode. *)
@@ -619,6 +620,15 @@ let main () =
eprintf (f_"%s: warning: hostname could not be set for this type of
guest\n%!") prog
);
+ (* Set the timezone. *)
+ (match timezone with
+ | None -> ()
+ | Some timezone ->
+ msg (f_"Setting the timezone: %s") timezone;
+ if not (Timezone.set_timezone ~prog g root timezone) then
+ eprintf (f_"%s: warning: timezone could not be set for this type of
guest\n%!") prog
+ );
+
(* Root password.
* Note 'None' means that we randomize the root password.
*)
diff --git a/builder/cmdline.ml b/builder/cmdline.ml
index c6a3cd8..99412bb 100644
--- a/builder/cmdline.ml
+++ b/builder/cmdline.ml
@@ -169,6 +169,10 @@ let parse_cmdline () =
let add_source arg = sources := arg :: !sources in
let sync = ref true in
+
+ let timezone = ref None in
+ let set_timezone s = timezone := Some s in
+
let update = ref false in
let upload = ref [] in
@@ -260,6 +264,7 @@ let parse_cmdline () =
"--smp",
Arg.Int set_smp, "vcpus" ^ " " ^
s_"Set number of vCPUs";
"--source", Arg.String add_source, "URL" ^ " " ^
s_"Set source URL";
"--no-sync", Arg.Clear sync, " " ^ s_"Do not
fsync output file on exit";
+ "--timezone",Arg.String set_timezone, "timezone" ^ "
" ^ s_"Set the default timezone";
"--update", Arg.Set update, " " ^ s_"Update core
packages";
"--upload", Arg.String add_upload, "file:dest" ^ "
" ^ s_"Upload file to dest";
"-v", Arg.Set debug, " " ^ s_"Enable
debugging messages";
@@ -321,6 +326,7 @@ read the man page virt-builder(1).
let smp = !smp in
let sources = List.rev !sources in
let sync = !sync in
+ let timezone = !timezone in
let update = !update in
let upload = List.rev !upload in
let writes = List.rev !writes in
@@ -421,4 +427,5 @@ read the man page virt-builder(1).
attach, cache, check_signature, curl, debug, delete, edit,
firstboot, run, format, gpg, hostname, install, list_long, memsize, mkdirs,
network, output, password_crypto, quiet, root_password, scrub,
- scrub_logfile, size, smp, sources, sync, update, upload, writes
+ scrub_logfile, size, smp, sources, sync, timezone, update, upload,
+ writes
diff --git a/builder/test-virt-builder.sh b/builder/test-virt-builder.sh
index 438f2e9..8d2766a 100755
--- a/builder/test-virt-builder.sh
+++ b/builder/test-virt-builder.sh
@@ -53,6 +53,7 @@ $VG ./virt-builder phony-fedora \
-v --no-cache --no-check-signature $no_network \
-o $output --size 2G --format $format \
--hostname
test.example.com \
+ --timezone Europe/London \
--root-password password:123456 \
--mkdir /etc/foo/bar/baz \
--write '/etc/foo/bar/baz/foo:Hello World' \
diff --git a/builder/virt-builder.pod b/builder/virt-builder.pod
index c3f685c..a703346 100644
--- a/builder/virt-builder.pod
+++ b/builder/virt-builder.pod
@@ -17,6 +17,7 @@ virt-builder - Build virtual machine images quickly
[--attach ISOFILE]
[--root-password SELECTOR]
[--hostname HOSTNAME]
+ [--timezone TIMEZONE]
[--update]
[--install PKG,[PKG...]]
[--mkdir DIR]
@@ -583,6 +584,11 @@ Note that you should not point I<--source> to sources that you
don't
trust (unless the source is signed by someone you do trust). See also
the I<--no-network> option.
+=item B<--timezone> TIMEZONE
+
+Set the default timezone of the guest to C<TIMEZONE>. Use a location
+string like C<Europe/London>
+
=item B<--update>
Do the equivalent of C<yum update>, C<apt-get upgrade>, or whatever
@@ -834,7 +840,7 @@ A new random seed is generated for the guest.
=item *
-The hostname is set (I<--hostname>).
+The hostname and timezone are set (I<--hostname>, I<--timezone>).
=item *
diff --git a/mllib/Makefile.am b/mllib/Makefile.am
index 67027d2..5568e02 100644
--- a/mllib/Makefile.am
+++ b/mllib/Makefile.am
@@ -47,6 +47,8 @@ SOURCES = \
progress.ml \
random_seed.mli \
random_seed.ml \
+ timezone.mli \
+ timezone.ml \
tty-c.c \
tTY.mli \
tTY.ml \
@@ -77,6 +79,7 @@ OBJECTS = \
urandom.cmx \
random_seed.cmx \
hostname.cmx \
+ timezone.cmx \
firstboot.cmx \
tTY.cmx \
fsync.cmx \
diff --git a/mllib/timezone.ml b/mllib/timezone.ml
new file mode 100644
index 0000000..8b302d9
--- /dev/null
+++ b/mllib/timezone.ml
@@ -0,0 +1,39 @@
+(* Set timezone in virt-sysprep and virt-builder.
+ * Copyright (C) 2014 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *)
+
+open Common_utils
+
+open Printf
+
+let set_timezone ~prog (g : Guestfs.guestfs) root timezone =
+ let typ = g#inspect_get_type root in
+
+ match typ with
+ (* Every known Linux has /etc/localtime be either a copy of or a
+ * symlink to a timezone file in /usr/share/zoneinfo.
+ * Even systemd didn't fuck this up.
+ *)
+ | "linux" ->
+ let target = sprintf "/usr/share/zoneinfo/%s" timezone in
+ if not (g#exists target) then
+ error ~prog "timezone '%s' does not exist, use a location like
'Europe/London'" timezone;
+ g#ln_sf target "/etc/localtime";
+ true
+
+ | _ ->
+ false
diff --git a/mllib/timezone.mli b/mllib/timezone.mli
new file mode 100644
index 0000000..ad0d4b2
--- /dev/null
+++ b/mllib/timezone.mli
@@ -0,0 +1,22 @@
+(* Set timezone in virt-sysprep and virt-builder.
+ * Copyright (C) 2014 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *)
+
+val set_timezone : prog:string -> Guestfs.guestfs -> string -> string ->
bool
+(** [set_timezone ~prog g root "Europe/London"] sets the default timezone
+ of the guest. Returns [true] if it was able to set the
+ timezone or [false] if not. *)
diff --git a/po/POTFILES-ml b/po/POTFILES-ml
index 9db1017..c714f74 100644
--- a/po/POTFILES-ml
+++ b/po/POTFILES-ml
@@ -21,6 +21,7 @@ mllib/planner.ml
mllib/progress.ml
mllib/random_seed.ml
mllib/tTY.ml
+mllib/timezone.ml
mllib/uRI.ml
mllib/urandom.ml
resize/resize.ml
@@ -63,6 +64,7 @@ sysprep/sysprep_operation_smolt_uuid.ml
sysprep/sysprep_operation_ssh_hostkeys.ml
sysprep/sysprep_operation_ssh_userdir.ml
sysprep/sysprep_operation_sssd_db_log.ml
+sysprep/sysprep_operation_timezone.ml
sysprep/sysprep_operation_tmp_files.ml
sysprep/sysprep_operation_udev_persistent_net.ml
sysprep/sysprep_operation_user_account.ml
diff --git a/sysprep/Makefile.am b/sysprep/Makefile.am
index aa9f984..603a666 100644
--- a/sysprep/Makefile.am
+++ b/sysprep/Makefile.am
@@ -67,6 +67,7 @@ operations = \
ssh_hostkeys \
ssh_userdir \
sssd_db_log \
+ timezone \
tmp_files \
udev_persistent_net \
user_account \
@@ -94,6 +95,7 @@ OBJECTS = \
$(top_builddir)/mllib/password.cmx \
$(top_builddir)/mllib/random_seed.cmx \
$(top_builddir)/mllib/hostname.cmx \
+ $(top_builddir)/mllib/timezone.cmx \
$(top_builddir)/mllib/firstboot.cmx \
$(top_builddir)/mllib/config.cmx \
sysprep_operation.cmx \
diff --git a/sysprep/sysprep_operation_timezone.ml
b/sysprep/sysprep_operation_timezone.ml
new file mode 100644
index 0000000..7557f44
--- /dev/null
+++ b/sysprep/sysprep_operation_timezone.ml
@@ -0,0 +1,66 @@
+(* virt-sysprep
+ * Copyright (C) 2014 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *)
+
+open Printf
+
+open Common_utils
+open Sysprep_operation
+open Common_gettext.Gettext
+
+module G = Guestfs
+
+let timezone = ref None
+
+let timezone_perform (g : Guestfs.guestfs) root =
+ match !timezone with
+ | None -> []
+ | Some tz ->
+ if Timezone.set_timezone ~prog g root tz then [ `Created_files ] else []
+
+let op = {
+ defaults with
+ name = "timezone";
+ enabled_by_default = true;
+ heading = s_"Change the default timezone of the guest";
+
+ pod_description = Some (s_"\
+This operation changes the default timezone of the guest to the value
+given in the I<--timezone> parameter.
+
+If the I<--timezone> parameter is not given, then the timezone is not
+changed.
+
+This parameter affects the default timezone that users see when they log
+in, but they can still change their timezone per-user account.");
+
+ pod_notes = Some (s_"\
+Currently this can only set the timezone on Linux guests.");
+
+ extra_args = [
+ let set_timezone str = timezone := Some str in
+ { extra_argspec = "--timezone", Arg.String set_timezone,
s_"timezone" ^ " " ^ s_"New timezone";
+ extra_pod_argval = Some "TIMEZONE";
+ extra_pod_description = s_"\
+Change the timezone. Use a location string such as C<Europe/London>"
+ }
+ ];
+
+ perform_on_filesystems = Some timezone_perform;
+}
+
+let () = register_operation op
--
1.8.4.2