From 4f580fef2e3eb3fec8223dad174804e6b5887d7b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=C3=A9bastien=20Bocahu?= <zecrazytux@zecrazytux.net>
Date: Wed, 20 Jul 2011 19:49:20 +0200
Subject: [PATCH] Add support for KVM keymaps
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: SΓ©bastien Bocahu <zecrazytux@zecrazytux.net>
Signed-off-by: Michael Hanselmann <hansmi@google.com>
Reviewed-by: Michael Hanselmann <hansmi@google.com>
---
 lib/constants.py         |  3 +++
 lib/hypervisor/hv_kvm.py | 20 ++++++++++++++++++++
 man/gnt-instance.rst     |  6 ++++++
 3 files changed, 29 insertions(+)

diff --git a/lib/constants.py b/lib/constants.py
index 0e8144cb4..cc32f962e 100644
--- a/lib/constants.py
+++ b/lib/constants.py
@@ -630,6 +630,7 @@ HV_INITRD_PATH = "initrd_path"
 HV_ROOT_PATH = "root_path"
 HV_SERIAL_CONSOLE = "serial_console"
 HV_USB_MOUSE = "usb_mouse"
+HV_KEYMAP = "keymap"
 HV_DEVICE_MODEL = "device_model"
 HV_INIT_SCRIPT = "init_script"
 HV_MIGRATION_PORT = "migration_port"
@@ -671,6 +672,7 @@ HVS_PARAMETER_TYPES = {
   HV_ROOT_PATH: VTYPE_MAYBE_STRING,
   HV_SERIAL_CONSOLE: VTYPE_BOOL,
   HV_USB_MOUSE: VTYPE_STRING,
+  HV_KEYMAP: VTYPE_STRING,
   HV_DEVICE_MODEL: VTYPE_STRING,
   HV_INIT_SCRIPT: VTYPE_STRING,
   HV_MIGRATION_PORT: VTYPE_INT,
@@ -1212,6 +1214,7 @@ HVC_DEFAULTS = {
     HV_DISK_TYPE: HT_DISK_PARAVIRTUAL,
     HV_KVM_CDROM_DISK_TYPE: '',
     HV_USB_MOUSE: '',
+    HV_KEYMAP: "",
     HV_MIGRATION_PORT: 8102,
     HV_MIGRATION_BANDWIDTH: 32, # MiB/s
     HV_MIGRATION_DOWNTIME: 30,  # ms
diff --git a/lib/hypervisor/hv_kvm.py b/lib/hypervisor/hv_kvm.py
index 2e39a1c95..0f6569d1d 100644
--- a/lib/hypervisor/hv_kvm.py
+++ b/lib/hypervisor/hv_kvm.py
@@ -137,6 +137,7 @@ class KVMHypervisor(hv_base.BaseHypervisor):
   _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
   _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
   _NICS_DIR = _ROOT_DIR + "/nic" # contains instances nic <-> tap associations
+  _KEYMAP_DIR = _ROOT_DIR + "/keymap" # contains instances keymaps
   # KVM instances with chroot enabled are started in empty chroot directories.
   _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories
   # After an instance is stopped, its chroot directory is removed.
@@ -177,6 +178,7 @@ class KVMHypervisor(hv_base.BaseHypervisor):
       hv_base.ParamInSet(False, constants.HT_KVM_VALID_DISK_TYPES),
     constants.HV_USB_MOUSE:
       hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
+    constants.HV_KEYMAP: hv_base.NO_CHECK,
     constants.HV_MIGRATION_PORT: hv_base.NET_PORT_CHECK,
     constants.HV_MIGRATION_BANDWIDTH: hv_base.NO_CHECK,
     constants.HV_MIGRATION_DOWNTIME: hv_base.NO_CHECK,
@@ -356,6 +358,13 @@ class KVMHypervisor(hv_base.BaseHypervisor):
     """
     return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
 
+  @classmethod
+  def _InstanceKeymapFile(cls, instance_name):
+    """Returns the name of the file containing the keymap for a given instance
+
+    """
+    return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
+
   @classmethod
   def _TryReadUidFile(cls, uid_file):
     """Try to read a uid file
@@ -380,6 +389,7 @@ class KVMHypervisor(hv_base.BaseHypervisor):
     utils.RemoveFile(cls._InstanceMonitor(instance_name))
     utils.RemoveFile(cls._InstanceSerial(instance_name))
     utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
+    utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
     uid_file = cls._InstanceUidFile(instance_name)
     uid = cls._TryReadUidFile(uid_file)
     utils.RemoveFile(uid_file)
@@ -644,6 +654,16 @@ class KVMHypervisor(hv_base.BaseHypervisor):
     elif vnc_bind_address:
       kvm_cmd.extend(['-usbdevice', constants.HT_MOUSE_TABLET])
 
+    keymap = hvp[constants.HV_KEYMAP]
+    if keymap:
+      keymap_path = self._InstanceKeymapFile(instance.name)
+      # If a keymap file is specified, KVM won't use its internal defaults. By
+      # first including the "en-us" layout, an error on loading the actual
+      # layout (e.g. because it can't be found) won't lead to a non-functional
+      # keyboard. A keyboard with incorrect keys is still better than none.
+      utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
+      kvm_cmd.extend(["-k", keymap_path])
+
     if vnc_bind_address:
       if netutils.IP4Address.IsValid(vnc_bind_address):
         if instance.network_port > constants.VNC_BASE_PORT:
diff --git a/man/gnt-instance.rst b/man/gnt-instance.rst
index 147edec1b..f5233dfb8 100644
--- a/man/gnt-instance.rst
+++ b/man/gnt-instance.rst
@@ -433,6 +433,12 @@ usb\_mouse
     "mouse" or "tablet". When using VNC it's recommended to set it to
     "tablet".
 
+keymap
+    Valid for the KVM hypervisor.
+
+    This option specifies the keyboard mapping to be used. It is only
+    needed when using the VNC console. For example: "fr" or "en-gb".
+
 
 The ``-O (--os-parameters)`` option allows customisation of the OS
 parameters. The actual parameter names and values depends on the OS
-- 
GitLab