Richard W.M. Jones
2014-Jan-10 16:58 UTC
[Libguestfs] [PATCH 0/3] Timezone and keyboard layout settings in virt-builder and virt-sysprep.
Setting timezone is easy. It turns out to be almost impossible to set keyboard layout in virt-builder sanely, so I have added some examples instead. Coming up next, setting languages in virt-builder (clue: very very very hard). Rich.
Richard W.M. Jones
2014-Jan-10 16:58 UTC
[Libguestfs] [PATCH 1/3] sysprep, builder: Add --timezone option to set timezone of guest.
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
Richard W.M. Jones
2014-Jan-10 16:58 UTC
[Libguestfs] [PATCH 2/3] builder: docs: Remove confusing reference to timezone.
--- builder/virt-builder.pod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builder/virt-builder.pod b/builder/virt-builder.pod index a703346..6db3dd9 100644 --- a/builder/virt-builder.pod +++ b/builder/virt-builder.pod @@ -1233,8 +1233,8 @@ least one character of whitespace (even on blank lines): notes=This image was prepared using the following kickstart script: <-- one space at beginning of line - timezone Europe/London part /boot --fstype ext3 + ... =item C<hidden=true> -- 1.8.4.2
Richard W.M. Jones
2014-Jan-10 16:58 UTC
[Libguestfs] [PATCH 3/3] builder: Document how to change keyboard layout.
This is too complex to implement directly in virt-builder. Instead we just document how to do it for some common Linux distros using --run-command, --edit etc. --- builder/virt-builder.pod | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/builder/virt-builder.pod b/builder/virt-builder.pod index 6db3dd9..f81c556 100644 --- a/builder/virt-builder.pod +++ b/builder/virt-builder.pod @@ -779,6 +779,46 @@ 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 KEYBOARD LAYOUT + +Because there are so many different ways to set the keyboard layout in +Linux distributions, virt-builder does not yet attempt to have a +simple command line option. This section describes how to set the +keyboard for some common Linux distributions. + +=head3 Keyboard layout with systemd + +For distros that use systemd C<localectl>, use a command like this: + + virt-builder fedora-20 \ + --firstboot-command 'localectl set-keymap uk' + +See L<localectl(1)> and +L<https://www.happyassassin.net/2013/11/23/keyboard-layouts-in-fedora-20-and-previously/> +for more details. + +=head3 Keyboard layout using C</etc/sysconfig/keyboard> + +For RHEL E<le> 6, Fedora E<le> 18 and similar, upload or modify the +keyboard configuration file using the I<--upload>, I<--write> or +I<--edit> options. For example: + + virt-builder centos-6 \ + --edit '/etc/sysconfig/keyboard: s/^KEYTABLE=.*/KEYTABLE="uk"/' + +The format of this file can be found documented in many places online. + +=head3 Keyboard layout with Debian-derived distros + +For Debian-derived distros using C</etc/default/keyboard>, upload or +modify the keyboard file using the I<--upload>, I<--write> or +I<--edit> options. For example: + + virt-builder debian-7 \ + --edit '/etc/default/keyboard: s/^XKBLAYOUT=.*/XKBLAYOUT="gb"/' + +See L<https://wiki.debian.org/Keyboard>. + =head2 LOG FILE Scripts and package installation that runs at build time (I<--run>, -- 1.8.4.2
Reasonably Related Threads
- [PATCH] customize: Move virt-customize-related code to a separate
- [PATCH] customize: Add --ssh-inject option for injecting SSH keys.
- [PATCH 0/2] Build mllib and customize into libraries.
- [PATCH v2 0/2] basic subscription-manager support in virt-customize
- Re: enable build for ocaml bytecode