[Libguestfs] [PATCH 1/3] sysprep, builder: Add --timezone option to set timezone of guest.

Richard W.M. Jones rjones at redhat.com
Fri Jan 10 16:58:31 UTC 2014


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




More information about the Libguestfs mailing list