feat(bootstrap): per-os desktop apps, KDE plasma-login-manager and DM resolution
This commit is contained in:
15
README.md
15
README.md
@@ -301,18 +301,27 @@ On distros with older dracut (no `tpm2-tss` module), clevis is used as a fallbac
|
||||
| ----------------- | ------ | -------------- | ----------------------------------------- |
|
||||
| `enabled` | bool | `false` | Install desktop environment |
|
||||
| `environment` | string | `""` | `gnome`, `kde`, `sway`, or `hyprland` |
|
||||
| `display_manager` | string | auto-detected | Override DM: `gdm`, `sddm`, or `greetd` |
|
||||
| `display_manager` | string | auto-detected | Override DM: `gdm`, `sddm`, `plasma-login-manager`, `greetd`, or `ly` |
|
||||
| `autologin` | bool \| string | `false` | `false` to disable, or a username from `system.users` to auto-login that user |
|
||||
| `session` | string | auto-from-environment | Session to autologin into; overrides the per-environment default (sddm `.desktop` basename / greetd command) |
|
||||
| `groups` | list | `[]` | Opt-in package groups installed on top of the base set (keys of `desktop_package_groups`, e.g. `dev`) |
|
||||
|
||||
All desktop environments are Wayland-only. `sway` and `hyprland` are available on Arch only;
|
||||
`gnome` and `kde` are available on all three families.
|
||||
`gnome` and `kde` are available on all three families. On enterprise Linux
|
||||
(almalinux/rocky/rhel) the base desktop installs browser, PDF and image viewers but no
|
||||
video player - none is packaged in the EL base repositories, and no third-party repo is
|
||||
pulled in; add one from rpmfusion/flatpak if you need it.
|
||||
|
||||
When `enabled: true`, the bootstrap installs the desktop environment packages, enables the display manager
|
||||
and bluetooth services, and sets the systemd default target to `graphical.target`.
|
||||
|
||||
Display manager auto-detection: gnome to gdm, kde to sddm, sway to greetd, hyprland to greetd.
|
||||
Display manager auto-detection: gnome to gdm; kde to plasma-login-manager on Arch and
|
||||
Fedora 44+ (Plasma 6.6), else sddm; sway and hyprland to greetd.
|
||||
|
||||
`ly` is an explicit-only override (never auto-selected), available on Arch only,
|
||||
and is desktop-agnostic - it can front any environment. It runs on `tty2` with
|
||||
`getty@tty2` masked, and its autologin is written to `/etc/ly/config.ini`; set `session`
|
||||
to the target session's `.desktop` basename (sway and hyprland resolve automatically).
|
||||
|
||||
When `autologin` names a user, the matching display manager is configured to log that user in without a
|
||||
password prompt. `session` is resolved automatically per environment when left empty (gdm picks its default,
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
_family_pkgs: "{{ bootstrap_desktop_packages[os_family] | default({}) }}"
|
||||
_de_config: "{{ _family_pkgs[_de] | default({}) }}"
|
||||
_base: "{{ bootstrap_desktop_base_packages[os_family] | default([]) }}"
|
||||
_dm: "{{ system_cfg.features.desktop.display_manager | default('') }}"
|
||||
_dm_override_pkg: "{{ (bootstrap_dm_override_packages[_dm] | default({}))[os_family] | default('') }}"
|
||||
_requested_groups: "{{ system_cfg.features.desktop.groups | default([]) }}"
|
||||
_group_pkgs: >-
|
||||
{{
|
||||
@@ -20,16 +22,10 @@
|
||||
| sum(start=[])
|
||||
}}
|
||||
ansible.builtin.set_fact:
|
||||
# GNOME ships under different dnf environment groups: Fedora uses
|
||||
# workstation-product-environment, enterprise RHEL/Rocky/Alma use
|
||||
# graphical-server-environment ("Server with GUI").
|
||||
_desktop_groups: >-
|
||||
{{ ['graphical-server-environment']
|
||||
if (_de == 'gnome' and os_family == 'RedHat' and os != 'fedora')
|
||||
else (_de_config.groups | default([])) }}
|
||||
_desktop_groups: "{{ _de_config.groups | default([]) }}"
|
||||
_desktop_packages: >-
|
||||
{{
|
||||
((_de_config.packages | default([])) + _base + _group_pkgs)
|
||||
((_de_config.packages | default([])) + _base + _group_pkgs + [_dm_override_pkg])
|
||||
| reject('equalto', '')
|
||||
| unique
|
||||
| list
|
||||
@@ -61,7 +57,8 @@
|
||||
{{ chroot_command }} dnf --releasever={{ os_version_major }}
|
||||
--setopt=install_weak_deps=False install -y {{ _desktop_packages | join(' ') }}
|
||||
Debian: >-
|
||||
{{ chroot_command }} apt install -y --install-recommends {{ _desktop_packages | join(' ') }}
|
||||
{{ chroot_command }} env DEBIAN_FRONTEND=noninteractive
|
||||
apt install -y --install-recommends {{ _desktop_packages | join(' ') }}
|
||||
Archlinux: >-
|
||||
pacstrap /mnt {{ _desktop_packages | join(' ') }}
|
||||
ansible.builtin.command: "{{ _install_commands[os_family] }}"
|
||||
|
||||
@@ -1,16 +1,41 @@
|
||||
---
|
||||
# Per-family desktop environment package definitions.
|
||||
# Keyed by os_family -> environment -> groups (dnf group install) / packages.
|
||||
# Wayland only: gnome, kde, sway, hyprland. No X11/xorg-server, no X11-only DEs.
|
||||
# DE sets carry the session bits + the DE-specific xdg portal backend; the
|
||||
# shared base below (fonts/audio/portal core/power/viewer apps) is layered on
|
||||
# top for every DE via bootstrap_desktop_base_packages.
|
||||
|
||||
# plasma-login-manager on Arch/Fedora44+ (Plasma 6.6), else sddm.
|
||||
bootstrap_kde_login_manager: >-
|
||||
{{
|
||||
'plasma-login-manager'
|
||||
if (os == 'archlinux' or (os == 'fedora' and (os_version | int) >= 44))
|
||||
else 'sddm'
|
||||
}}
|
||||
|
||||
# Native DMs ride in each DE's package set; only explicit non-native overrides
|
||||
# need a package here. ly is Arch-only (validation rejects it elsewhere first).
|
||||
bootstrap_dm_override_packages:
|
||||
ly:
|
||||
Archlinux: ly
|
||||
|
||||
# EL = non-fedora RedHat.
|
||||
bootstrap_os_is_el: "{{ os in ['almalinux', 'rocky', 'rhel'] }}"
|
||||
bootstrap_os_is_el10: "{{ bootstrap_os_is_el | bool and (os_version | default('0') | int) >= 10 }}"
|
||||
# EL10 renames (evince->papers, eog->loupe, ppd->tuned-ppd); fira-code + mpv absent on EL.
|
||||
bootstrap_desktop_browser: "{{ 'firefox-esr' if os == 'debian' else 'firefox' }}"
|
||||
bootstrap_desktop_pdf: "{{ 'papers' if bootstrap_os_is_el10 | bool else 'evince' }}"
|
||||
bootstrap_desktop_image: "{{ 'loupe' if bootstrap_os_is_el10 | bool else 'eog' }}"
|
||||
bootstrap_desktop_power: "{{ 'tuned-ppd' if bootstrap_os_is_el10 | bool else 'power-profiles-daemon' }}"
|
||||
bootstrap_desktop_redhat_codefont: "{{ '' if bootstrap_os_is_el | bool else 'fira-code-fonts' }}"
|
||||
bootstrap_desktop_redhat_video: "{{ '' if bootstrap_os_is_el | bool else 'mpv' }}"
|
||||
|
||||
bootstrap_desktop_packages:
|
||||
RedHat:
|
||||
gnome:
|
||||
groups:
|
||||
- workstation-product-environment
|
||||
packages: []
|
||||
groups: []
|
||||
packages:
|
||||
- gnome-shell
|
||||
- gnome-control-center
|
||||
- nautilus
|
||||
- gnome-session
|
||||
- gdm
|
||||
kde:
|
||||
groups: []
|
||||
packages:
|
||||
@@ -18,7 +43,7 @@ bootstrap_desktop_packages:
|
||||
- plasma-nm
|
||||
- plasma-pa
|
||||
- plasma-systemmonitor
|
||||
- sddm
|
||||
- "{{ bootstrap_kde_login_manager }}"
|
||||
- konsole
|
||||
- dolphin
|
||||
- kate
|
||||
@@ -41,7 +66,7 @@ bootstrap_desktop_packages:
|
||||
- plasma-desktop
|
||||
- plasma-nm
|
||||
- plasma-pa
|
||||
- sddm
|
||||
- "{{ bootstrap_kde_login_manager }}"
|
||||
- konsole
|
||||
- dolphin
|
||||
- kate
|
||||
@@ -62,7 +87,7 @@ bootstrap_desktop_packages:
|
||||
- plasma-desktop
|
||||
- plasma-nm
|
||||
- plasma-pa
|
||||
- sddm
|
||||
- "{{ bootstrap_kde_login_manager }}"
|
||||
- konsole
|
||||
- dolphin
|
||||
- kate
|
||||
@@ -102,26 +127,23 @@ bootstrap_desktop_packages:
|
||||
- qt6-wayland
|
||||
- bluez
|
||||
|
||||
# Shared desktop base, installed for EVERY DE whenever desktop.enabled.
|
||||
# Fonts (noto + emoji + one nerd font), audio stack (pipewire + wireplumber +
|
||||
# pipewire-pulse), xdg portal core, power-profiles-daemon, and viewer-only base
|
||||
# apps (browser, PDF/image/video viewers). DE metas (gnome/plasma) bundle their
|
||||
# own file manager + settings, so no file manager is added here - the wlroots
|
||||
# DE sets above carry their own (nautilus).
|
||||
# Installed for EVERY DE whenever desktop.enabled. No file manager here: DE metas
|
||||
# bundle their own and the wlroots sets above carry nautilus.
|
||||
bootstrap_desktop_base_packages:
|
||||
RedHat:
|
||||
- google-noto-sans-fonts
|
||||
- google-noto-emoji-fonts
|
||||
- fira-code-fonts
|
||||
- "{{ bootstrap_desktop_redhat_codefont }}"
|
||||
- pipewire
|
||||
- wireplumber
|
||||
- pipewire-pulseaudio
|
||||
- xdg-desktop-portal
|
||||
- power-profiles-daemon
|
||||
- "{{ bootstrap_desktop_power }}"
|
||||
- bluez
|
||||
- firefox
|
||||
- evince
|
||||
- eog
|
||||
- mpv
|
||||
- "{{ bootstrap_desktop_pdf }}"
|
||||
- "{{ bootstrap_desktop_image }}"
|
||||
- "{{ bootstrap_desktop_redhat_video }}"
|
||||
Debian:
|
||||
- fonts-noto
|
||||
- fonts-noto-color-emoji
|
||||
@@ -131,7 +153,8 @@ bootstrap_desktop_base_packages:
|
||||
- pipewire-pulse
|
||||
- xdg-desktop-portal
|
||||
- power-profiles-daemon
|
||||
- firefox-esr
|
||||
- bluez
|
||||
- "{{ bootstrap_desktop_browser }}"
|
||||
- evince
|
||||
- eog
|
||||
- mpv
|
||||
@@ -144,14 +167,14 @@ bootstrap_desktop_base_packages:
|
||||
- pipewire-pulse
|
||||
- xdg-desktop-portal
|
||||
- power-profiles-daemon
|
||||
- bluez
|
||||
- firefox
|
||||
- evince
|
||||
- loupe
|
||||
- mpv
|
||||
|
||||
# Opt-in package groups, selected per host via features.desktop.groups (a list
|
||||
# of group names). _desktop.yml installs the union of the requested groups'
|
||||
# packages. Empty selection by default.
|
||||
# Opt-in groups selected per host via features.desktop.groups; the union of the
|
||||
# requested groups' packages is installed. Empty selection by default.
|
||||
desktop_package_groups:
|
||||
dev:
|
||||
RedHat:
|
||||
|
||||
@@ -4,11 +4,20 @@
|
||||
vars:
|
||||
_autologin: "{{ system_cfg.features.desktop.autologin | default(false) }}"
|
||||
ansible.builtin.set_fact:
|
||||
# KDE resolves to the plasmalogin unit on Arch/Fedora44+ (Plasma 6.6), else sddm.
|
||||
_desktop_dm: >-
|
||||
{{
|
||||
system_cfg.features.desktop.display_manager
|
||||
('plasmalogin'
|
||||
if system_cfg.features.desktop.display_manager == 'plasma-login-manager'
|
||||
else system_cfg.features.desktop.display_manager)
|
||||
if (system_cfg.features.desktop.display_manager | length > 0)
|
||||
else (configuration_desktop_dm_map[system_cfg.features.desktop.environment] | default(''))
|
||||
else (
|
||||
('plasmalogin'
|
||||
if (os == 'archlinux' or (os == 'fedora' and (os_version | int) >= 44))
|
||||
else 'sddm')
|
||||
if system_cfg.features.desktop.environment == 'kde'
|
||||
else (configuration_desktop_dm_map[system_cfg.features.desktop.environment] | default(''))
|
||||
)
|
||||
}}
|
||||
_desktop_session: "{{ system_cfg.features.desktop.session | default('') }}"
|
||||
# Explicit session wins, else the per-environment command. Single source of
|
||||
@@ -52,6 +61,7 @@
|
||||
- _configuration_platform.init_system == 'systemd'
|
||||
- system_cfg.features.desktop.enabled | bool
|
||||
- _desktop_dm | length > 0
|
||||
- _desktop_dm != 'ly'
|
||||
ansible.builtin.command: "{{ chroot_command }} systemctl enable {{ _desktop_dm }}"
|
||||
register: configuration_enable_dm_result
|
||||
changed_when: configuration_enable_dm_result.rc == 0
|
||||
@@ -70,14 +80,40 @@
|
||||
register: _ufw_enable_result
|
||||
changed_when: _ufw_enable_result.rc == 0
|
||||
failed_when: false
|
||||
|
||||
- name: Set default systemd target to graphical
|
||||
- name: Enable ly on its tty
|
||||
when:
|
||||
- _configuration_platform.init_system == 'systemd'
|
||||
- system_cfg.features.desktop.enabled | bool
|
||||
ansible.builtin.command: "{{ chroot_command }} systemctl set-default graphical.target"
|
||||
register: _desktop_target_result
|
||||
changed_when: _desktop_target_result.rc == 0
|
||||
- _desktop_dm == 'ly'
|
||||
vars:
|
||||
_ly_tty: tty2
|
||||
block:
|
||||
- name: Enable ly display manager
|
||||
ansible.builtin.command: "{{ chroot_command }} systemctl enable ly@{{ _ly_tty }}.service"
|
||||
register: configuration_enable_ly_result
|
||||
changed_when: configuration_enable_ly_result.rc == 0
|
||||
failed_when: >-
|
||||
configuration_enable_ly_result.rc != 0
|
||||
or 'No such file or directory' in (configuration_enable_ly_result.stderr | default(''))
|
||||
or 'does not exist' in (configuration_enable_ly_result.stderr | default(''))
|
||||
|
||||
# ly drives the VT itself; mask getty so logind never spawns a login on that tty.
|
||||
- name: Mask getty on ly's tty
|
||||
ansible.builtin.command: "{{ chroot_command }} systemctl mask getty@{{ _ly_tty }}.service"
|
||||
register: configuration_mask_getty_result
|
||||
changed_when: configuration_mask_getty_result.rc == 0
|
||||
failed_when: >-
|
||||
configuration_mask_getty_result.rc != 0
|
||||
and 'No such file or directory' not in (configuration_mask_getty_result.stderr | default(''))
|
||||
and 'does not exist' not in (configuration_mask_getty_result.stderr | default(''))
|
||||
|
||||
- name: Set default systemd target
|
||||
when: _configuration_platform.init_system == 'systemd'
|
||||
vars:
|
||||
_default_target: "{{ 'graphical.target' if system_cfg.features.desktop.enabled | bool else 'multi-user.target' }}"
|
||||
ansible.builtin.command: "{{ chroot_command }} systemctl set-default {{ _default_target }}"
|
||||
register: _set_default_target_result
|
||||
changed_when: _set_default_target_result.rc == 0
|
||||
|
||||
- name: Enable PipeWire user services globally
|
||||
when:
|
||||
@@ -134,8 +170,7 @@
|
||||
- _desktop_dm == 'gdm'
|
||||
- _desktop_autologin_user | length > 0
|
||||
vars:
|
||||
# Debian's gdm3 reads /etc/gdm3/daemon.conf; RedHat/Arch GDM read
|
||||
# /etc/gdm/custom.conf. The keys are identical, only the path differs.
|
||||
# Debian gdm3 reads daemon.conf; RedHat/Arch gdm read custom.conf.
|
||||
_gdm_dir: "/mnt/etc/{{ 'gdm3' if os_family == 'Debian' else 'gdm' }}"
|
||||
_gdm_conf: "{{ 'daemon.conf' if os_family == 'Debian' else 'custom.conf' }}"
|
||||
block:
|
||||
@@ -151,16 +186,20 @@
|
||||
dest: "{{ _gdm_dir }}/{{ _gdm_conf }}"
|
||||
mode: "0644"
|
||||
|
||||
- name: Configure SDDM autologin
|
||||
# SDDM and plasma-login-manager share the [Autologin] format and the KDE Wayland
|
||||
# session; only the config dir differs (sddm.conf.d vs plasmalogin.conf.d).
|
||||
- name: Configure SDDM / plasma-login-manager autologin
|
||||
when:
|
||||
- _configuration_platform.init_system == 'systemd'
|
||||
- system_cfg.features.desktop.enabled | bool
|
||||
- _desktop_dm == 'sddm'
|
||||
- _desktop_dm in ['sddm', 'plasmalogin']
|
||||
- _desktop_autologin_user | length > 0
|
||||
vars:
|
||||
_autologin_conf_dir: "/mnt/etc/{{ 'plasmalogin.conf.d' if _desktop_dm == 'plasmalogin' else 'sddm.conf.d' }}"
|
||||
block:
|
||||
- name: Ensure SDDM config directory exists
|
||||
- name: Ensure KDE login-manager config directory exists
|
||||
ansible.builtin.file:
|
||||
path: /mnt/etc/sddm.conf.d
|
||||
path: "{{ _autologin_conf_dir }}"
|
||||
state: directory
|
||||
mode: "0755"
|
||||
|
||||
@@ -179,8 +218,29 @@
|
||||
{%- set names = _kde_wayland_sessions.files | map(attribute='path') | map('basename') | list -%}
|
||||
{{ 'plasma.desktop' if 'plasma.desktop' in names else (names | first | default('')) }}
|
||||
|
||||
- name: Write SDDM autologin drop-in
|
||||
- name: Write KDE login-manager autologin drop-in
|
||||
ansible.builtin.template:
|
||||
src: sddm-autologin.conf.j2
|
||||
dest: /mnt/etc/sddm.conf.d/10-autologin.conf
|
||||
dest: "{{ _autologin_conf_dir }}/10-autologin.conf"
|
||||
mode: "0644"
|
||||
|
||||
# ly ships a flat (sectionless) config.ini; edit it in place to keep upstream
|
||||
# defaults. Both keys are required: an unresolved session writes 'null', which
|
||||
# disables autologin rather than leaving it half-configured.
|
||||
- name: Configure ly autologin
|
||||
when:
|
||||
- _configuration_platform.init_system == 'systemd'
|
||||
- system_cfg.features.desktop.enabled | bool
|
||||
- _desktop_dm == 'ly'
|
||||
- _desktop_autologin_user | length > 0
|
||||
community.general.ini_file:
|
||||
path: /mnt/etc/ly/config.ini
|
||||
option: "{{ item.key }}"
|
||||
value: "{{ item.value }}"
|
||||
create: false
|
||||
mode: "0644"
|
||||
loop:
|
||||
- key: auto_login_user
|
||||
value: "{{ _desktop_autologin_user }}"
|
||||
- key: auto_login_session
|
||||
value: "{{ _greetd_session if (_greetd_session | length > 0) else 'null' }}"
|
||||
|
||||
@@ -43,9 +43,7 @@ configuration_desktop_dm_map:
|
||||
sway: greetd
|
||||
hyprland: greetd
|
||||
|
||||
# Per-environment session command for greetd-launched compositors (sway/hyprland):
|
||||
# the executable greetd starts. kde/gnome use a display manager (sddm/gdm) whose
|
||||
# Wayland session is resolved separately, so they are not in this map.
|
||||
# greetd session commands for sway/hyprland (gnome/kde use a DM instead).
|
||||
configuration_desktop_session_cmd_map:
|
||||
sway: sway
|
||||
hyprland: Hyprland
|
||||
|
||||
@@ -128,7 +128,7 @@ system_defaults:
|
||||
desktop:
|
||||
enabled: false
|
||||
environment: "" # gnome|kde|sway|hyprland
|
||||
display_manager: "" # auto from environment when empty; override: gdm|sddm|greetd
|
||||
display_manager: "" # auto from environment when empty; override: gdm|sddm|greetd|plasma-login-manager|ly
|
||||
autologin: false # false | username from system.users
|
||||
session: "" # session name/command for the autologin user
|
||||
groups: [] # opt-in package groups (keys of desktop_package_groups)
|
||||
|
||||
@@ -262,7 +262,7 @@
|
||||
or os_family_map[os] | default('') == "Archlinux"
|
||||
- >-
|
||||
system_cfg.features.desktop.display_manager | default('') | length == 0
|
||||
or system_cfg.features.desktop.display_manager in ["gdm", "sddm", "greetd", "plasma-login-manager"]
|
||||
or system_cfg.features.desktop.display_manager in ["gdm", "sddm", "greetd", "plasma-login-manager", "ly"]
|
||||
- >-
|
||||
system_cfg.features.desktop.display_manager | default('') != "greetd"
|
||||
or system_cfg.features.desktop.environment in ["sway", "hyprland"]
|
||||
@@ -275,6 +275,9 @@
|
||||
- >-
|
||||
system_cfg.features.desktop.display_manager | default('') != "plasma-login-manager"
|
||||
or os == "archlinux" or (os == "fedora" and (os_version | int) >= 44)
|
||||
- >-
|
||||
system_cfg.features.desktop.display_manager | default('') != "ly"
|
||||
or os == "archlinux"
|
||||
fail_msg: >-
|
||||
Invalid desktop config: environment '{{ system_cfg.features.desktop.environment }}'
|
||||
for os_family '{{ os_family_map[os] | default('Unknown') }}',
|
||||
@@ -282,7 +285,8 @@
|
||||
gnome and kde are available on all families; sway and hyprland are Archlinux only.
|
||||
display_manager must be empty (auto) or match the environment's native DM:
|
||||
gnome->gdm, kde->plasma-login-manager on Arch/Fedora44+ else sddm,
|
||||
sway/hyprland->greetd. Only that DM's package is installed, so a mismatched
|
||||
sway/hyprland->greetd. ly is an explicit override on Arch only and may
|
||||
front any environment. Only that DM's package is installed, so a mismatched
|
||||
override fails at enable time.
|
||||
quiet: true
|
||||
|
||||
|
||||
Reference in New Issue
Block a user