feat: complete wayland desktop deployment (gnome/kde/sway/hyprland)
This commit is contained in:
@@ -8,14 +8,37 @@
|
||||
_de: "{{ system_cfg.features.desktop.environment }}"
|
||||
_family_pkgs: "{{ bootstrap_desktop_packages[os_family] | default({}) }}"
|
||||
_de_config: "{{ _family_pkgs[_de] | default({}) }}"
|
||||
_base: "{{ bootstrap_desktop_base_packages[os_family] | default([]) }}"
|
||||
_requested_groups: "{{ system_cfg.features.desktop.groups | default([]) }}"
|
||||
_group_pkgs: >-
|
||||
{{
|
||||
_requested_groups
|
||||
| select('in', desktop_package_groups)
|
||||
| map('extract', desktop_package_groups)
|
||||
| map(attribute=os_family, default=[])
|
||||
| list
|
||||
| sum(start=[])
|
||||
}}
|
||||
ansible.builtin.set_fact:
|
||||
_desktop_groups: "{{ _de_config.groups | default([]) }}"
|
||||
_desktop_packages: "{{ _de_config.packages | default([]) }}"
|
||||
# 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_packages: >-
|
||||
{{
|
||||
((_de_config.packages | default([])) + _base + _group_pkgs)
|
||||
| reject('equalto', '')
|
||||
| unique
|
||||
| list
|
||||
}}
|
||||
|
||||
- name: Validate desktop environment is supported
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- (_desktop_groups | length > 0) or (_desktop_packages | length > 0)
|
||||
- system_cfg.features.desktop.environment in (bootstrap_desktop_packages[os_family] | default({}))
|
||||
fail_msg: >-
|
||||
Desktop environment '{{ system_cfg.features.desktop.environment }}'
|
||||
is not defined for os_family '{{ os_family }}'.
|
||||
@@ -25,7 +48,7 @@
|
||||
- name: Install desktop package groups
|
||||
when: _desktop_groups | length > 0
|
||||
ansible.builtin.command: >-
|
||||
{{ chroot_command }} dnf --releasever={{ os_version }}
|
||||
{{ chroot_command }} dnf --releasever={{ os_version_major }}
|
||||
--setopt=install_weak_deps=False group install -y {{ _desktop_groups | join(' ') }}
|
||||
register: _desktop_group_result
|
||||
changed_when: _desktop_group_result.rc == 0
|
||||
@@ -35,14 +58,12 @@
|
||||
vars:
|
||||
_install_commands:
|
||||
RedHat: >-
|
||||
{{ chroot_command }} dnf --releasever={{ os_version }}
|
||||
{{ chroot_command }} dnf --releasever={{ os_version_major }}
|
||||
--setopt=install_weak_deps=False install -y {{ _desktop_packages | join(' ') }}
|
||||
Debian: >-
|
||||
{{ chroot_command }} apt install -y {{ _desktop_packages | join(' ') }}
|
||||
{{ chroot_command }} apt install -y --install-recommends {{ _desktop_packages | join(' ') }}
|
||||
Archlinux: >-
|
||||
pacstrap /mnt {{ _desktop_packages | join(' ') }}
|
||||
Suse: >-
|
||||
{{ chroot_command }} zypper install -y {{ _desktop_packages | join(' ') }}
|
||||
ansible.builtin.command: "{{ _install_commands[os_family] }}"
|
||||
register: _desktop_pkg_result
|
||||
changed_when: _desktop_pkg_result.rc == 0
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
---
|
||||
# Per-family desktop environment package definitions.
|
||||
# Keyed by os_family -> environment -> groups (dnf groupinstall) / packages.
|
||||
# Kept intentionally minimal: base DE + essential tools, no full suites.
|
||||
# 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.
|
||||
bootstrap_desktop_packages:
|
||||
RedHat:
|
||||
gnome:
|
||||
@@ -24,13 +27,6 @@ bootstrap_desktop_packages:
|
||||
- xdg-user-dirs
|
||||
- xdg-desktop-portal-kde
|
||||
- bluez
|
||||
- pipewire
|
||||
- wireplumber
|
||||
xfce:
|
||||
groups:
|
||||
- xfce-desktop-environment
|
||||
packages:
|
||||
- lightdm
|
||||
Debian:
|
||||
gnome:
|
||||
groups: []
|
||||
@@ -53,15 +49,6 @@ bootstrap_desktop_packages:
|
||||
- xdg-user-dirs
|
||||
- xdg-desktop-portal-kde
|
||||
- bluez
|
||||
- pipewire
|
||||
- wireplumber
|
||||
xfce:
|
||||
groups: []
|
||||
packages:
|
||||
- xfce4
|
||||
- xfce4-goodies
|
||||
- lightdm
|
||||
- xdg-user-dirs
|
||||
Archlinux:
|
||||
gnome:
|
||||
groups: []
|
||||
@@ -84,15 +71,6 @@ bootstrap_desktop_packages:
|
||||
- xdg-user-dirs
|
||||
- xdg-desktop-portal-kde
|
||||
- bluez
|
||||
- pipewire
|
||||
- wireplumber
|
||||
xfce:
|
||||
groups: []
|
||||
packages:
|
||||
- xfce4
|
||||
- xfce4-goodies
|
||||
- lightdm
|
||||
- xdg-user-dirs
|
||||
sway:
|
||||
groups: []
|
||||
packages:
|
||||
@@ -100,12 +78,13 @@ bootstrap_desktop_packages:
|
||||
- waybar
|
||||
- foot
|
||||
- wofi
|
||||
- nautilus
|
||||
- greetd
|
||||
- greetd-tuigreet
|
||||
- xdg-user-dirs
|
||||
- xdg-desktop-portal-wlr
|
||||
- polkit-gnome
|
||||
- bluez
|
||||
- pipewire
|
||||
- wireplumber
|
||||
hyprland:
|
||||
groups: []
|
||||
packages:
|
||||
@@ -113,37 +92,80 @@ bootstrap_desktop_packages:
|
||||
- kitty
|
||||
- wofi
|
||||
- waybar
|
||||
- ly
|
||||
- nautilus
|
||||
- greetd
|
||||
- greetd-tuigreet
|
||||
- xdg-user-dirs
|
||||
- xdg-desktop-portal-hyprland
|
||||
- polkit-kde-agent
|
||||
- qt5-wayland
|
||||
- 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).
|
||||
bootstrap_desktop_base_packages:
|
||||
RedHat:
|
||||
- google-noto-sans-fonts
|
||||
- google-noto-emoji-fonts
|
||||
- fira-code-fonts
|
||||
- pipewire
|
||||
- wireplumber
|
||||
Suse:
|
||||
gnome:
|
||||
groups: []
|
||||
packages:
|
||||
- patterns-gnome-gnome_basic
|
||||
- gdm
|
||||
- xdg-user-dirs
|
||||
kde:
|
||||
groups: []
|
||||
packages:
|
||||
- patterns-kde-kde_plasma
|
||||
- sddm
|
||||
- xdg-user-dirs
|
||||
- pipewire-pulseaudio
|
||||
- xdg-desktop-portal
|
||||
- power-profiles-daemon
|
||||
- firefox
|
||||
- evince
|
||||
- eog
|
||||
- mpv
|
||||
Debian:
|
||||
- fonts-noto
|
||||
- fonts-noto-color-emoji
|
||||
- fonts-firacode
|
||||
- pipewire
|
||||
- wireplumber
|
||||
- pipewire-pulse
|
||||
- xdg-desktop-portal
|
||||
- power-profiles-daemon
|
||||
- firefox-esr
|
||||
- evince
|
||||
- eog
|
||||
- mpv
|
||||
Archlinux:
|
||||
- noto-fonts
|
||||
- noto-fonts-emoji
|
||||
- ttf-nerd-fonts-symbols
|
||||
- pipewire
|
||||
- wireplumber
|
||||
- pipewire-pulse
|
||||
- xdg-desktop-portal
|
||||
- power-profiles-daemon
|
||||
- firefox
|
||||
- evince
|
||||
- loupe
|
||||
- mpv
|
||||
|
||||
# Display manager auto-detection from desktop environment.
|
||||
bootstrap_desktop_dm_map:
|
||||
gnome: gdm
|
||||
kde: sddm
|
||||
xfce: lightdm
|
||||
sway: greetd
|
||||
hyprland: ly@tty2
|
||||
cinnamon: lightdm
|
||||
mate: lightdm
|
||||
lxqt: sddm
|
||||
budgie: gdm
|
||||
# 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.
|
||||
desktop_package_groups:
|
||||
dev:
|
||||
RedHat:
|
||||
- git
|
||||
- "@development-tools"
|
||||
- neovim
|
||||
- python3-pip
|
||||
Debian:
|
||||
- git
|
||||
- build-essential
|
||||
- neovim
|
||||
- python3-pip
|
||||
Archlinux:
|
||||
- git
|
||||
- base-devel
|
||||
- neovim
|
||||
- python-pip
|
||||
|
||||
@@ -1,13 +1,34 @@
|
||||
---
|
||||
- name: Enable systemd services
|
||||
when: _configuration_platform.init_system == 'systemd'
|
||||
- name: Resolve desktop facts
|
||||
when: system_cfg.features.desktop.enabled | bool
|
||||
vars:
|
||||
_autologin: "{{ system_cfg.features.desktop.autologin | default(false) }}"
|
||||
ansible.builtin.set_fact:
|
||||
_desktop_dm: >-
|
||||
{{
|
||||
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(''))
|
||||
}}
|
||||
_desktop_session: "{{ system_cfg.features.desktop.session | default('') }}"
|
||||
# Explicit session wins, else the per-environment command. Single source of
|
||||
# truth for the greetd assert, the config gate, and the template.
|
||||
_greetd_session: >-
|
||||
{{
|
||||
system_cfg.features.desktop.session
|
||||
if (system_cfg.features.desktop.session | default('') | length > 0)
|
||||
else (configuration_desktop_session_cmd_map[system_cfg.features.desktop.environment] | default(''))
|
||||
}}
|
||||
_desktop_autologin_user: >-
|
||||
{{
|
||||
_autologin
|
||||
if (_autologin | string | lower not in ['', 'false'] and _autologin in system_cfg.users)
|
||||
else ''
|
||||
}}
|
||||
|
||||
- name: Enable systemd services
|
||||
when: _configuration_platform.init_system == 'systemd'
|
||||
vars:
|
||||
configuration_systemd_services: >-
|
||||
{{
|
||||
['NetworkManager']
|
||||
@@ -15,7 +36,6 @@
|
||||
+ (['ufw'] if system_cfg.features.firewall.backend == 'ufw' and system_cfg.features.firewall.enabled | bool else [])
|
||||
+ ([_configuration_platform.ssh_service] if system_cfg.features.ssh.enabled | bool else [])
|
||||
+ (['logrotate', 'systemd-timesyncd'] if os == 'archlinux' else [])
|
||||
+ ([_desktop_dm] if system_cfg.features.desktop.enabled | bool and _desktop_dm | length > 0 else [])
|
||||
+ (['bluetooth'] if system_cfg.features.desktop.enabled | bool else [])
|
||||
}}
|
||||
ansible.builtin.command: "{{ chroot_command }} systemctl enable {{ item }}"
|
||||
@@ -27,6 +47,21 @@
|
||||
and 'No such file or directory' not in (configuration_enable_service_result.stderr | default(''))
|
||||
and 'does not exist' not in (configuration_enable_service_result.stderr | default(''))
|
||||
|
||||
- name: Enable display manager for selected desktop
|
||||
when:
|
||||
- _configuration_platform.init_system == 'systemd'
|
||||
- system_cfg.features.desktop.enabled | bool
|
||||
- _desktop_dm | length > 0
|
||||
ansible.builtin.command: "{{ chroot_command }} systemctl enable {{ _desktop_dm }}"
|
||||
register: configuration_enable_dm_result
|
||||
changed_when: configuration_enable_dm_result.rc == 0
|
||||
# Unlike optional services above, a missing/unenabled DM is fatal: chroot
|
||||
# systemctl can exit 0 while only warning on stderr, so check both.
|
||||
failed_when: >-
|
||||
configuration_enable_dm_result.rc != 0
|
||||
or 'No such file or directory' in (configuration_enable_dm_result.stderr | default(''))
|
||||
or 'does not exist' in (configuration_enable_dm_result.stderr | default(''))
|
||||
|
||||
- name: Activate UFW firewall
|
||||
when:
|
||||
- system_cfg.features.firewall.backend == 'ufw'
|
||||
@@ -44,66 +79,108 @@
|
||||
register: _desktop_target_result
|
||||
changed_when: _desktop_target_result.rc == 0
|
||||
|
||||
- name: Enable OpenRC services
|
||||
when: _configuration_platform.init_system == 'openrc'
|
||||
vars:
|
||||
configuration_openrc_services: >-
|
||||
{{
|
||||
['networking']
|
||||
+ (['sshd'] if system_cfg.features.ssh.enabled | bool else [])
|
||||
+ ([system_cfg.features.firewall.backend] if system_cfg.features.firewall.enabled | bool else [])
|
||||
}}
|
||||
- name: Enable PipeWire user services globally
|
||||
when:
|
||||
- _configuration_platform.init_system == 'systemd'
|
||||
- system_cfg.features.desktop.enabled | bool
|
||||
ansible.builtin.command: "{{ chroot_command }} systemctl --global enable {{ item }}"
|
||||
loop: "{{ configuration_desktop_audio_units }}"
|
||||
register: _desktop_audio_result
|
||||
changed_when: _desktop_audio_result.rc == 0
|
||||
failed_when: >-
|
||||
_desktop_audio_result.rc != 0
|
||||
and 'No such file or directory' not in (_desktop_audio_result.stderr | default(''))
|
||||
and 'does not exist' not in (_desktop_audio_result.stderr | default(''))
|
||||
|
||||
- name: Assert greetd has a real session command to launch
|
||||
when:
|
||||
- system_cfg.features.desktop.enabled | bool
|
||||
- _desktop_dm == 'greetd'
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- _greetd_session | length > 0
|
||||
- not (_greetd_session | trim | regex_search('\\.desktop$'))
|
||||
fail_msg: >-
|
||||
greetd needs an executable session command, but the resolved command for desktop
|
||||
environment '{{ system_cfg.features.desktop.environment }}' is
|
||||
'{{ _greetd_session }}'. greetd suits wlroots compositors (sway, hyprland) that
|
||||
launch from a plain command; kde/gnome ship a '.desktop' session and should use
|
||||
their own display manager (sddm, gdm). Set features.desktop.session to an
|
||||
executable, or pick a different display manager.
|
||||
|
||||
- name: Generate greetd configuration
|
||||
when:
|
||||
- _configuration_platform.init_system == 'systemd'
|
||||
- system_cfg.features.desktop.enabled | bool
|
||||
- _desktop_dm == 'greetd'
|
||||
- _greetd_session | length > 0
|
||||
block:
|
||||
- name: Ensure OpenRC runlevel directory exists
|
||||
- name: Ensure greetd config directory exists
|
||||
ansible.builtin.file:
|
||||
path: /mnt/etc/runlevels/default
|
||||
path: /mnt/etc/greetd
|
||||
state: directory
|
||||
mode: "0755"
|
||||
|
||||
- name: Check OpenRC init scripts
|
||||
ansible.builtin.stat:
|
||||
path: "/mnt/etc/init.d/{{ item }}"
|
||||
loop: "{{ configuration_openrc_services }}"
|
||||
register: configuration_openrc_service_stats
|
||||
- name: Write greetd config.toml
|
||||
ansible.builtin.template:
|
||||
src: greetd-config.toml.j2
|
||||
dest: /mnt/etc/greetd/config.toml
|
||||
mode: "0644"
|
||||
|
||||
- name: Enable OpenRC services
|
||||
ansible.builtin.file:
|
||||
src: "/mnt/etc/init.d/{{ item.item }}"
|
||||
dest: "/mnt/etc/runlevels/default/{{ item.item }}"
|
||||
state: link
|
||||
loop: "{{ configuration_openrc_service_stats.results }}"
|
||||
loop_control:
|
||||
label: "{{ item.item }}"
|
||||
when: item.stat.exists
|
||||
|
||||
- name: Enable runit services
|
||||
when: _configuration_platform.init_system == 'runit'
|
||||
- name: Configure GDM autologin
|
||||
when:
|
||||
- _configuration_platform.init_system == 'systemd'
|
||||
- system_cfg.features.desktop.enabled | bool
|
||||
- _desktop_dm == 'gdm'
|
||||
- _desktop_autologin_user | length > 0
|
||||
vars:
|
||||
configuration_runit_services: >-
|
||||
{{
|
||||
['dhcpcd']
|
||||
+ (['sshd'] if system_cfg.features.ssh.enabled | bool else [])
|
||||
+ ([system_cfg.features.firewall.backend] if system_cfg.features.firewall.enabled | bool else [])
|
||||
}}
|
||||
# Debian's gdm3 reads /etc/gdm3/daemon.conf; RedHat/Arch GDM read
|
||||
# /etc/gdm/custom.conf. The keys are identical, only the path differs.
|
||||
_gdm_dir: "/mnt/etc/{{ 'gdm3' if os_family == 'Debian' else 'gdm' }}"
|
||||
_gdm_conf: "{{ 'daemon.conf' if os_family == 'Debian' else 'custom.conf' }}"
|
||||
block:
|
||||
- name: Ensure runit service directory exists
|
||||
- name: Ensure GDM config directory exists
|
||||
ansible.builtin.file:
|
||||
path: /mnt/var/service
|
||||
path: "{{ _gdm_dir }}"
|
||||
state: directory
|
||||
mode: "0755"
|
||||
|
||||
- name: Check runit service definitions
|
||||
ansible.builtin.stat:
|
||||
path: "/mnt/etc/sv/{{ item }}"
|
||||
loop: "{{ configuration_runit_services }}"
|
||||
register: configuration_runit_service_stats
|
||||
- name: Write GDM autologin config
|
||||
ansible.builtin.template:
|
||||
src: gdm-custom.conf.j2
|
||||
dest: "{{ _gdm_dir }}/{{ _gdm_conf }}"
|
||||
mode: "0644"
|
||||
|
||||
- name: Enable runit services
|
||||
- name: Configure SDDM autologin
|
||||
when:
|
||||
- _configuration_platform.init_system == 'systemd'
|
||||
- system_cfg.features.desktop.enabled | bool
|
||||
- _desktop_dm == 'sddm'
|
||||
- _desktop_autologin_user | length > 0
|
||||
block:
|
||||
- name: Ensure SDDM config directory exists
|
||||
ansible.builtin.file:
|
||||
src: "/mnt/etc/sv/{{ item.item }}"
|
||||
dest: "/mnt/var/service/{{ item.item }}"
|
||||
state: link
|
||||
loop: "{{ configuration_runit_service_stats.results }}"
|
||||
loop_control:
|
||||
label: "{{ item.item }}"
|
||||
when: item.stat.exists
|
||||
path: /mnt/etc/sddm.conf.d
|
||||
state: directory
|
||||
mode: "0755"
|
||||
|
||||
# Plasma 6 ships the Wayland session as plasma.desktop; Plasma 5 ships it as
|
||||
# plasmawayland.desktop (plasma.desktop is the X11 session there). Pick the
|
||||
# installed Wayland session so autologin never lands on X11.
|
||||
- name: Discover installed KDE Wayland sessions
|
||||
ansible.builtin.find:
|
||||
paths: /mnt/usr/share/wayland-sessions
|
||||
patterns: "plasma.desktop,plasmawayland.desktop"
|
||||
register: _kde_wayland_sessions
|
||||
|
||||
- name: Resolve the KDE Wayland session file
|
||||
ansible.builtin.set_fact:
|
||||
_sddm_session: >-
|
||||
{%- 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
|
||||
ansible.builtin.template:
|
||||
src: sddm-autologin.conf.j2
|
||||
dest: /mnt/etc/sddm.conf.d/10-autologin.conf
|
||||
mode: "0644"
|
||||
|
||||
4
roles/configuration/templates/gdm-custom.conf.j2
Normal file
4
roles/configuration/templates/gdm-custom.conf.j2
Normal file
@@ -0,0 +1,4 @@
|
||||
[daemon]
|
||||
WaylandEnable=true
|
||||
AutomaticLoginEnable=true
|
||||
AutomaticLogin={{ _desktop_autologin_user }}
|
||||
12
roles/configuration/templates/greetd-config.toml.j2
Normal file
12
roles/configuration/templates/greetd-config.toml.j2
Normal file
@@ -0,0 +1,12 @@
|
||||
[terminal]
|
||||
vt = 1
|
||||
|
||||
[default_session]
|
||||
command = "tuigreet --time --remember --cmd {{ _greetd_session }}"
|
||||
user = "greeter"
|
||||
{% if _desktop_autologin_user | length > 0 %}
|
||||
|
||||
[initial_session]
|
||||
command = "{{ _greetd_session }}"
|
||||
user = "{{ _desktop_autologin_user }}"
|
||||
{% endif %}
|
||||
6
roles/configuration/templates/sddm-autologin.conf.j2
Normal file
6
roles/configuration/templates/sddm-autologin.conf.j2
Normal file
@@ -0,0 +1,6 @@
|
||||
{% set _session = _desktop_session if (_desktop_session | length > 0) else _sddm_session %}
|
||||
[Autologin]
|
||||
User={{ _desktop_autologin_user }}
|
||||
{% if _session | length > 0 %}
|
||||
Session={{ _session }}
|
||||
{% endif %}
|
||||
@@ -35,45 +35,24 @@ configuration_platform_config:
|
||||
grub_mkconfig_prefix: grub-mkconfig
|
||||
locale_gen: true
|
||||
init_system: systemd
|
||||
Suse:
|
||||
user_group: wheel
|
||||
sudo_group: "%wheel"
|
||||
ssh_service: sshd
|
||||
efi_loader: grubx64.efi
|
||||
grub_install: true
|
||||
initramfs_cmd: "/usr/bin/dracut --regenerate-all --force"
|
||||
grub_mkconfig_prefix: grub-mkconfig
|
||||
locale_gen: true
|
||||
init_system: systemd
|
||||
Alpine:
|
||||
user_group: wheel
|
||||
sudo_group: "%wheel"
|
||||
ssh_service: sshd
|
||||
efi_loader: grubx64.efi
|
||||
grub_install: true
|
||||
initramfs_cmd: ""
|
||||
grub_mkconfig_prefix: grub-mkconfig
|
||||
locale_gen: false
|
||||
init_system: openrc
|
||||
Void:
|
||||
user_group: wheel
|
||||
sudo_group: "%wheel"
|
||||
ssh_service: sshd
|
||||
efi_loader: grubx64.efi
|
||||
grub_install: true
|
||||
initramfs_cmd: ""
|
||||
grub_mkconfig_prefix: grub-mkconfig
|
||||
locale_gen: false
|
||||
init_system: runit
|
||||
|
||||
# Display manager auto-detection from desktop environment name.
|
||||
configuration_desktop_dm_map:
|
||||
gnome: gdm
|
||||
kde: sddm
|
||||
xfce: lightdm
|
||||
sway: greetd
|
||||
hyprland: ly@tty2
|
||||
cinnamon: lightdm
|
||||
mate: lightdm
|
||||
lxqt: sddm
|
||||
budgie: gdm
|
||||
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.
|
||||
configuration_desktop_session_cmd_map:
|
||||
sway: sway
|
||||
hyprland: Hyprland
|
||||
|
||||
# PipeWire user units enabled globally when a desktop is installed.
|
||||
# pipewire/pipewire-pulse are socket-activated; wireplumber ships no socket.
|
||||
configuration_desktop_audio_units:
|
||||
- pipewire.socket
|
||||
- pipewire-pulse.socket
|
||||
- wireplumber.service
|
||||
|
||||
@@ -28,21 +28,41 @@
|
||||
memory: "{{ [system_raw.memory | default(0) | int, 0] | max }}"
|
||||
balloon: "{{ [system_raw.balloon | default(0) | int, 0] | max }}"
|
||||
# --- Network ---
|
||||
# Flat fields (bridge, ip, etc.) and interfaces[] are mutually exclusive.
|
||||
# When interfaces[] is set, flat fields are populated from the first
|
||||
# interface in the "Populate primary network fields" task below.
|
||||
# When only flat fields are set, a synthetic interfaces[] entry is built.
|
||||
# Flat fields (bridge, ip, etc.) and interfaces[] express the same primary NIC.
|
||||
# When only flat fields are set, a synthetic interfaces[] entry is built below.
|
||||
# When interfaces[] is set, the flat ip/prefix/gateway are backfilled from
|
||||
# interfaces[0] so consumers reading the flat fields (e.g. the post-reboot
|
||||
# reconnect block) still work.
|
||||
network:
|
||||
bridge: "{{ system_raw.network.bridge | default('') | string }}"
|
||||
bridge: >-
|
||||
{{
|
||||
(system_raw.network.bridge | default('') | string)
|
||||
if (system_raw.network.bridge | default('') | string | length) > 0
|
||||
else (system_raw.network.interfaces[0].bridge | default('') | string
|
||||
if (system_raw.network.interfaces | default([]) | length) > 0 else '')
|
||||
}}
|
||||
vlan: "{{ system_raw.network.vlan | default('') | string }}"
|
||||
ip: "{{ system_raw.network.ip | default('') | string }}"
|
||||
ip: >-
|
||||
{{
|
||||
(system_raw.network.ip | default('') | string)
|
||||
if (system_raw.network.ip | default('') | string | length) > 0
|
||||
else (system_raw.network.interfaces[0].ip | default('') | string
|
||||
if (system_raw.network.interfaces | default([]) | length) > 0 else '')
|
||||
}}
|
||||
prefix: >-
|
||||
{{
|
||||
(system_raw.network.prefix | int | string)
|
||||
if (system_raw.network.prefix | default('') | string | length) > 0
|
||||
else ''
|
||||
else (system_raw.network.interfaces[0].prefix | default('') | string
|
||||
if (system_raw.network.interfaces | default([]) | length) > 0 else '')
|
||||
}}
|
||||
gateway: >-
|
||||
{{
|
||||
(system_raw.network.gateway | default('') | string)
|
||||
if (system_raw.network.gateway | default('') | string | length) > 0
|
||||
else (system_raw.network.interfaces[0].gateway | default('') | string
|
||||
if (system_raw.network.interfaces | default([]) | length) > 0 else '')
|
||||
}}
|
||||
gateway: "{{ system_raw.network.gateway | default('') | string }}"
|
||||
dns:
|
||||
servers: "{{ system_raw.network.dns.servers | default([]) }}"
|
||||
search: "{{ system_raw.network.dns.search | default([]) }}"
|
||||
@@ -148,6 +168,9 @@
|
||||
enabled: "{{ system_raw.features.desktop.enabled | bool }}"
|
||||
environment: "{{ system_raw.features.desktop.environment | default('') | string | lower }}"
|
||||
display_manager: "{{ system_raw.features.desktop.display_manager | default('') | string | lower }}"
|
||||
autologin: "{{ system_raw.features.desktop.autologin | default(false) }}"
|
||||
session: "{{ system_raw.features.desktop.session | default('') | string }}"
|
||||
groups: "{{ system_raw.features.desktop.groups | default([]) }}"
|
||||
secure_boot:
|
||||
enabled: "{{ system_raw.features.secure_boot.enabled | bool }}"
|
||||
method: "{{ system_raw.features.secure_boot.method | default('') | string | lower }}"
|
||||
@@ -169,7 +192,12 @@
|
||||
else (system_raw.features.firmware.microcode | bool)
|
||||
}}
|
||||
gpu:
|
||||
enabled: "{{ system_raw.features.gpu.enabled | bool }}"
|
||||
enabled: >-
|
||||
{{
|
||||
(system_raw.features.desktop.enabled | bool)
|
||||
if (system_raw.features.gpu.enabled | string | lower) == 'auto'
|
||||
else (system_raw.features.gpu.enabled | bool)
|
||||
}}
|
||||
nvidia_driver: "{{ system_raw.features.gpu.nvidia_driver | default('auto') | string | lower }}"
|
||||
peripherals:
|
||||
enabled: >-
|
||||
|
||||
@@ -140,7 +140,7 @@
|
||||
os in ["ubuntu", "ubuntu-lts"]
|
||||
and (os_version | default('') | string | length) == 0
|
||||
) or (
|
||||
os in ["alpine", "archlinux", "opensuse", "void"]
|
||||
os == "archlinux"
|
||||
)
|
||||
fail_msg: "Invalid os/version specified. Please check README.md for supported values."
|
||||
quiet: true
|
||||
@@ -252,6 +252,49 @@
|
||||
peripherals.webcam in [auto|true|false]; hardware.profile must be a dict.
|
||||
quiet: true
|
||||
|
||||
- name: Validate desktop environment
|
||||
when: system_cfg.features.desktop.enabled | bool
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- system_cfg.features.desktop.environment in ["gnome", "kde", "sway", "hyprland"]
|
||||
- >-
|
||||
system_cfg.features.desktop.environment not in ["sway", "hyprland"]
|
||||
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"]
|
||||
- >-
|
||||
system_cfg.features.desktop.display_manager | default('') != "greetd"
|
||||
or system_cfg.features.desktop.environment in ["sway", "hyprland"]
|
||||
- >-
|
||||
system_cfg.features.desktop.environment != "gnome"
|
||||
or system_cfg.features.desktop.display_manager | default('') in ["", "gdm"]
|
||||
- >-
|
||||
system_cfg.features.desktop.environment != "kde"
|
||||
or system_cfg.features.desktop.display_manager | default('') in ["", "sddm"]
|
||||
fail_msg: >-
|
||||
Invalid desktop config: environment '{{ system_cfg.features.desktop.environment }}'
|
||||
for os_family '{{ os_family_map[os] | default('Unknown') }}',
|
||||
display_manager '{{ system_cfg.features.desktop.display_manager | default('') }}'.
|
||||
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->sddm, sway/hyprland->greetd. Only that DM's package is
|
||||
installed, so a mismatched override fails at enable time.
|
||||
quiet: true
|
||||
|
||||
- name: Validate desktop autologin
|
||||
when: system_cfg.features.desktop.enabled | bool
|
||||
vars:
|
||||
_autologin: "{{ system_cfg.features.desktop.autologin | default(false) }}"
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- _autologin is boolean and not _autologin or (_autologin is string and _autologin | length > 0 and _autologin in system_cfg.users)
|
||||
fail_msg: >-
|
||||
desktop.autologin must be false or a username string present in
|
||||
system.users; got '{{ _autologin }}'. Bool true is not accepted - the
|
||||
resolver matches the value against system.users by name.
|
||||
quiet: true
|
||||
|
||||
- name: Validate virtual system sizing
|
||||
when: system_cfg.type == "virtual"
|
||||
ansible.builtin.assert:
|
||||
@@ -262,7 +305,7 @@
|
||||
- (system_cfg.disks[0].size | float) > 0
|
||||
- (system_cfg.disks[0].size | float) >= 20
|
||||
# Btrfs minimum disk: swap_size + 5.5 GiB overhead (subvolumes + metadata).
|
||||
# Swap sizing: memory < 16 GiB → max(memory_GiB, 2); memory >= 16 GiB → memory/2.
|
||||
# Swap sizing: memory < 16 GiB -> max(memory_GiB, 2); memory >= 16 GiB -> memory/2.
|
||||
- >-
|
||||
system_cfg.filesystem != "btrfs"
|
||||
or (
|
||||
|
||||
Reference in New Issue
Block a user