summaryrefslogtreecommitdiff
path: root/cloudinit
diff options
context:
space:
mode:
Diffstat (limited to 'cloudinit')
-rw-r--r--cloudinit/config/cc_keyboard.py125
-rwxr-xr-xcloudinit/distros/__init__.py15
-rw-r--r--cloudinit/distros/debian.py7
3 files changed, 147 insertions, 0 deletions
diff --git a/cloudinit/config/cc_keyboard.py b/cloudinit/config/cc_keyboard.py
new file mode 100644
index 00000000..17eb9a54
--- /dev/null
+++ b/cloudinit/config/cc_keyboard.py
@@ -0,0 +1,125 @@
+# Copyright (c) 2022 Floris Bos
+#
+# Author: Floris Bos <bos@je-eigen-domein.nl>
+#
+# This file is part of cloud-init. See LICENSE file for license information.
+
+"""keyboard: set keyboard layout"""
+
+from textwrap import dedent
+
+from cloudinit import distros
+from cloudinit import log as logging
+from cloudinit.config.schema import get_meta_doc, validate_cloudconfig_schema
+from cloudinit.settings import PER_INSTANCE
+
+frequency = PER_INSTANCE
+
+# FIXME: setting keyboard layout should be supported by all OSes.
+# But currently only implemented for Linux distributions that use systemd.
+osfamilies = ["arch", "debian", "redhat", "suse"]
+distros = distros.Distro.expand_osfamily(osfamilies)
+
+DEFAULT_KEYBOARD_MODEL = "pc105"
+
+meta = {
+ "id": "cc_keyboard",
+ "name": "Keyboard",
+ "title": "Set keyboard layout",
+ "description": dedent(
+ """\
+ Handle keyboard configuration.
+ """
+ ),
+ "distros": distros,
+ "examples": [
+ dedent(
+ """\
+ # Set keyboard layout to "us"
+ keyboard:
+ layout: us
+ """
+ ),
+ dedent(
+ """\
+ # Set specific keyboard layout, model, variant, options
+ keyboard:
+ layout: de
+ model: pc105
+ variant: nodeadkeys
+ options: compose:rwin
+ """
+ ),
+ ],
+ "frequency": frequency,
+}
+
+
+schema = {
+ "type": "object",
+ "properties": {
+ "keyboard": {
+ "type": "object",
+ "properties": {
+ "layout": {
+ "type": "string",
+ "description": dedent(
+ """\
+ Required. Keyboard layout. Corresponds to XKBLAYOUT.
+ """
+ ),
+ },
+ "model": {
+ "type": "string",
+ "default": DEFAULT_KEYBOARD_MODEL,
+ "description": dedent(
+ """\
+ Optional. Keyboard model. Corresponds to XKBMODEL.
+ """
+ ),
+ },
+ "variant": {
+ "type": "string",
+ "description": dedent(
+ """\
+ Optional. Keyboard variant. Corresponds to XKBVARIANT.
+ """
+ ),
+ },
+ "options": {
+ "type": "string",
+ "description": dedent(
+ """\
+ Optional. Keyboard options. Corresponds to XKBOPTIONS.
+ """
+ ),
+ },
+ },
+ "required": ["layout"],
+ "additionalProperties": False,
+ }
+ },
+}
+
+__doc__ = get_meta_doc(meta, schema)
+
+LOG = logging.getLogger(__name__)
+
+
+def handle(name, cfg, cloud, log, args):
+ if "keyboard" not in cfg:
+ LOG.debug(
+ "Skipping module named %s, no 'keyboard' section found", name
+ )
+ return
+ validate_cloudconfig_schema(cfg, schema)
+ kb_cfg = cfg["keyboard"]
+ layout = kb_cfg["layout"]
+ model = kb_cfg.get("model", DEFAULT_KEYBOARD_MODEL)
+ variant = kb_cfg.get("variant", "")
+ options = kb_cfg.get("options", "")
+ LOG.debug("Setting keyboard layout to '%s'", layout)
+ cloud.distro.set_keymap(layout, model, variant, options)
+
+
+# vi: ts=4 expandtab
diff --git a/cloudinit/distros/__init__.py b/cloudinit/distros/__init__.py
index de000b52..a261c16e 100755
--- a/cloudinit/distros/__init__.py
+++ b/cloudinit/distros/__init__.py
@@ -881,6 +881,21 @@ class Distro(persistence.CloudInitPickleMixin, metaclass=abc.ABCMeta):
cmd = list(init_cmd) + list(cmds[action])
return subp.subp(cmd, capture=True)
+ def set_keymap(self, layout, model, variant, options):
+ if self.uses_systemd():
+ subp.subp(
+ [
+ "localectl",
+ "set-x11-keymap",
+ layout,
+ model,
+ variant,
+ options,
+ ]
+ )
+ else:
+ raise NotImplementedError()
+
def _apply_hostname_transformations_to_url(url: str, transformations: list):
"""
diff --git a/cloudinit/distros/debian.py b/cloudinit/distros/debian.py
index 9effa0a0..6dc1ad40 100644
--- a/cloudinit/distros/debian.py
+++ b/cloudinit/distros/debian.py
@@ -300,6 +300,13 @@ class Distro(distros.Distro):
def get_primary_arch(self):
return util.get_dpkg_architecture()
+ def set_keymap(self, layout, model, variant, options):
+ # Let localectl take care of updating /etc/default/keyboard
+ distros.Distro.set_keymap(self, layout, model, variant, options)
+ # Workaround for localectl not applying new settings instantly
+ # https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=926037
+ self.manage_service("restart", "console-setup")
+
def _get_wrapper_prefix(cmd, mode):
if isinstance(cmd, str):