diff --git a/roles/bootstrap/tasks/_desktop.yml b/roles/bootstrap/tasks/_desktop.yml new file mode 100644 index 0000000..c635261 --- /dev/null +++ b/roles/bootstrap/tasks/_desktop.yml @@ -0,0 +1,48 @@ +--- +- name: Load desktop package definitions + ansible.builtin.include_vars: + file: desktop.yml + +- name: Resolve desktop packages + vars: + _de: "{{ system_cfg.features.desktop.environment }}" + _family_pkgs: "{{ bootstrap_desktop_packages[os_family] | default({}) }}" + _de_config: "{{ _family_pkgs[_de] | default({}) }}" + ansible.builtin.set_fact: + _desktop_groups: "{{ _de_config.groups | default([]) }}" + _desktop_packages: "{{ _de_config.packages | default([]) }}" + +- name: Validate desktop environment is supported + ansible.builtin.assert: + that: + - (_desktop_groups | length > 0) or (_desktop_packages | length > 0) + fail_msg: >- + Desktop environment '{{ system_cfg.features.desktop.environment }}' + is not defined for os_family '{{ os_family }}'. + Supported: {{ (bootstrap_desktop_packages[os_family] | default({})).keys() | join(', ') }} + quiet: true + +- name: Install desktop package groups + when: _desktop_groups | length > 0 + ansible.builtin.command: >- + {{ chroot_command }} dnf --releasever={{ os_version }} + --setopt=install_weak_deps=False group install -y {{ _desktop_groups | join(' ') }} + register: _desktop_group_result + changed_when: _desktop_group_result.rc == 0 + +- name: Install desktop packages + when: _desktop_packages | length > 0 + vars: + _install_commands: + RedHat: >- + {{ chroot_command }} dnf --releasever={{ os_version }} + --setopt=install_weak_deps=False install -y {{ _desktop_packages | join(' ') }} + Debian: >- + {{ chroot_command }} apt install -y {{ _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 diff --git a/roles/bootstrap/tasks/main.yml b/roles/bootstrap/tasks/main.yml index 4b8ac68..ad38c8b 100644 --- a/roles/bootstrap/tasks/main.yml +++ b/roles/bootstrap/tasks/main.yml @@ -34,6 +34,10 @@ bootstrap_var_key: "{{ 'bootstrap_' + (os | replace('-lts', '') | replace('-', '_')) }}" ansible.builtin.include_tasks: "{{ bootstrap_os_task_map[os] }}" +- name: Install desktop environment packages + when: system_cfg.features.desktop.enabled | bool + ansible.builtin.include_tasks: _desktop.yml + - name: Ensure chroot uses live environment DNS ansible.builtin.file: src: /run/NetworkManager/resolv.conf diff --git a/roles/bootstrap/vars/desktop.yml b/roles/bootstrap/vars/desktop.yml new file mode 100644 index 0000000..6d4fbd2 --- /dev/null +++ b/roles/bootstrap/vars/desktop.yml @@ -0,0 +1,149 @@ +--- +# 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. +bootstrap_desktop_packages: + RedHat: + gnome: + groups: + - workstation-product-environment + packages: [] + kde: + groups: [] + packages: + - plasma-desktop + - plasma-nm + - plasma-pa + - plasma-systemmonitor + - sddm + - konsole + - dolphin + - kate + - kscreen + - kde-gtk-config + - xdg-user-dirs + - xdg-desktop-portal-kde + - bluez + - pipewire + - wireplumber + xfce: + groups: + - xfce-desktop-environment + packages: + - lightdm + Debian: + gnome: + groups: [] + packages: + - gnome-core + - gdm3 + - gnome-tweaks + - xdg-user-dirs + kde: + groups: [] + packages: + - plasma-desktop + - plasma-nm + - plasma-pa + - sddm + - konsole + - dolphin + - kate + - kscreen + - xdg-user-dirs + - xdg-desktop-portal-kde + - bluez + - pipewire + - wireplumber + xfce: + groups: [] + packages: + - xfce4 + - xfce4-goodies + - lightdm + - xdg-user-dirs + Archlinux: + gnome: + groups: [] + packages: + - gnome + - gdm + - xdg-user-dirs + kde: + groups: [] + packages: + - plasma-desktop + - plasma-nm + - plasma-pa + - sddm + - konsole + - dolphin + - kate + - kscreen + - kde-gtk-config + - xdg-user-dirs + - xdg-desktop-portal-kde + - bluez + - pipewire + - wireplumber + xfce: + groups: [] + packages: + - xfce4 + - xfce4-goodies + - lightdm + - xdg-user-dirs + sway: + groups: [] + packages: + - sway + - waybar + - foot + - wofi + - greetd + - xdg-user-dirs + - xdg-desktop-portal-wlr + - bluez + - pipewire + - wireplumber + hyprland: + groups: [] + packages: + - hyprland + - kitty + - wofi + - waybar + - ly + - xdg-user-dirs + - xdg-desktop-portal-hyprland + - polkit-kde-agent + - qt5-wayland + - qt6-wayland + - bluez + - 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 + +# 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 diff --git a/roles/configuration/tasks/services.yml b/roles/configuration/tasks/services.yml index d16ec74..673612f 100644 --- a/roles/configuration/tasks/services.yml +++ b/roles/configuration/tasks/services.yml @@ -2,6 +2,12 @@ - name: Enable systemd services when: _configuration_platform.init_system == 'systemd' vars: + _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('')) + }} configuration_systemd_services: >- {{ ['NetworkManager'] @@ -9,12 +15,31 @@ + (['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 }}" loop: "{{ configuration_systemd_services }}" register: configuration_enable_service_result changed_when: configuration_enable_service_result.rc == 0 +- name: Activate UFW firewall + when: + - system_cfg.features.firewall.backend == 'ufw' + - system_cfg.features.firewall.enabled | bool + ansible.builtin.command: "{{ chroot_command }} ufw --force enable" + register: _ufw_enable_result + changed_when: _ufw_enable_result.rc == 0 + failed_when: false + +- name: Set default systemd target to graphical + 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 + - name: Enable OpenRC services when: _configuration_platform.init_system == 'openrc' vars: diff --git a/roles/configuration/vars/main.yml b/roles/configuration/vars/main.yml index a1d6fce..2199eb6 100644 --- a/roles/configuration/vars/main.yml +++ b/roles/configuration/vars/main.yml @@ -65,3 +65,15 @@ configuration_platform_config: 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 diff --git a/roles/global_defaults/defaults/main.yml b/roles/global_defaults/defaults/main.yml index 4ef8a5b..c969ef7 100644 --- a/roles/global_defaults/defaults/main.yml +++ b/roles/global_defaults/defaults/main.yml @@ -135,6 +135,12 @@ system_defaults: user: "_aur_builder" chroot: tool: "arch-chroot" # arch-chroot|chroot|systemd-nspawn + initramfs: + generator: "" # auto-detected; override: dracut|mkinitcpio|initramfs-tools + desktop: + enabled: false + environment: "" # gnome|kde|xfce|sway|hyprland|cinnamon|mate|lxqt|budgie + display_manager: "" # auto from environment when empty; override: gdm|sddm|lightdm|greetd # Per-hypervisor required fields — drives data-driven validation. # All virtual types additionally require network bridge or interfaces. diff --git a/roles/global_defaults/tasks/_normalize_system.yml b/roles/global_defaults/tasks/_normalize_system.yml index b71b59b..fc4eb59 100644 --- a/roles/global_defaults/tasks/_normalize_system.yml +++ b/roles/global_defaults/tasks/_normalize_system.yml @@ -144,27 +144,13 @@ url: "{{ system_raw.features.rhel_repo.url | default('') | string }}" chroot: tool: "{{ system_raw.features.chroot.tool | string }}" + initramfs: + generator: "{{ system_raw.features.initramfs.generator | default('') | string | lower }}" + desktop: + 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 }}" hostname: "{{ system_name }}" os: "{{ system_os_input if system_os_input | length > 0 else (physical_default_os if system_type == 'physical' else '') }}" os_version: "{{ system_raw.version | default('') | string }}" no_log: true - -- name: Populate primary network fields from first interface - when: - - system_cfg.network.interfaces | length > 0 - - system_cfg.network.bridge | default('') | string | length == 0 - vars: - _primary: "{{ system_cfg.network.interfaces[0] }}" - ansible.builtin.set_fact: - system_cfg: >- - {{ - system_cfg | combine({ - 'network': system_cfg.network | combine({ - 'bridge': _primary.bridge | default(''), - 'vlan': _primary.vlan | default(''), - 'ip': _primary.ip | default(''), - 'prefix': _primary.prefix | default(''), - 'gateway': _primary.gateway | default('') - }) - }, recursive=True) - }}