Ansible vs. locales on desktops and servers

Hi,

I’m currently writing a series of Ansible roles for Rocky Linux 8 on both desktops and servers.

Here’s what the configure_locale role looks like:

---  # tasks file for configure_locale
  
- name: Configure system locale
  ansible.builtin.command:
    cmd: localectl set-locale {{ locale }}
  changed_when: false

- name: Configure console keyboard layout
  ansible.builtin.command:
    cmd: localectl set-keymap --no-convert {{ console_keymap }}
  changed_when: false

- name: Configure X11 keyboard layout
  ansible.builtin.command:
    cmd: >
      localectl set-x11-keymap --no-convert
      {{ x11_keymap_layout }} {{ x11_keymap_model }}
      {{ x11_keymap_variant }} {{ x11_keymap_option }}
  changed_when: false

...

Variables are defined in a corresponding vars.yml file:

---  # group_vars/all/vars.yml

locale: fr_FR.UTF-8
console_keymap: ch-fr
x11_keymap_layout: ch
x11_keymap_model: pc105
x11_keymap_variant: fr
x11_keymap_option: "terminate:ctrl_alt_bksp"

...

I like the idea of modularity, so ideally the role could be used on both desktops and headless servers without a GUI.

The problem is that when I run the playbook on a headless server, I get the following error:

TASK [configure_locale : Configure X11 keyboard layout] ******************************************************
fatal: [rocky-el8.microlinux.lan]: FAILED! => {"changed": false, "cmd": ["localectl", "set-x11-keymap", "--no-convert", "ch", "pc105", "fr", "terminate:ctrl_alt_bksp"], "delta": "0:00:00.010738", "end": "2024-04-29 08:00:43.142798", "msg": "non-zero return code", "rc": 1, "start": "2024-04-29 08:00:43.132060", "stderr": "Failed to set keymap: Local keyboard configuration not supported on this system.", "stderr_lines": ["Failed to set keymap: Local keyboard configuration not supported on this system."], "stdout": "", "stdout_lines": []}

Indeed, there are no keymaps for X11 installed. When I connect directly to the server, I get this:

# localectl list-x11-keymap-layouts
Failed to open keyboard mapping list. No such file or directory

Now here’s my question. I’d like to run the last one of the listed tasks (e. g. Configure X11 keyboard layout) only if the corresponding keyboard mappings are available on the machine. How would I express this when condition?

I assume there is a certain xorg-related package that installs these keyboard mappings, but which one?

Any suggestions?

I’ll answer that myself, since I just found a solution. Turns out X11 keymaps are provided by the single libxkbcommon package. So just making sure this package is installed before running the play does the trick.

I did look at output from strace
strace localectl list-x11-keymap-layouts
and saw access to directory /usr/share/X11/xkb/ that by rpm -qf /usr/share/X11/xkb
comes from package xkeyboard-config

rpm -ql libxkbcommon does show only two *.so libraries, no data files.


I’d rather use a task to check whether package or dir exists, and register the result.
Then use that in condition.


What I do use is hierarchical inventory, where subgroup “desktops” (re)defines variables about GUI. The play uses their presence/value in conditions.

2 Likes

I agree, this would be better to check that libxkbcommon is installed, and if it is run the task. If it’s not installed, means no x11, and so no need to run that task.

Something like this should do it:

- name: Get list of installed packages
  ansible.builtin.package_facts:
    manager: auto

- name: Configure X11 keyboard layout
  ansible.builtin.command:
    cmd: >
      localectl set-x11-keymap --no-convert
      {{ x11_keymap_layout }} {{ x11_keymap_model }}
      {{ x11_keymap_variant }} {{ x11_keymap_option }}
  changed_when: false
  when: "'libxkbcommon' in ansible_facts.packages"
1 Like

This is the way. :sunglasses: