Compare commits
8
Commits
6ff790fd4b
...
7a95ef0019
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7a95ef0019 | ||
|
|
a67c629356 | ||
|
|
cdb0730280 | ||
|
|
bab92f0292 | ||
|
|
54d8729e63 | ||
|
|
e6f3506ef1 | ||
|
|
724ccebdb0 | ||
|
|
45ad579120 |
@@ -8,10 +8,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
- New Ansible role `ansible/roles/system-upgrade/` that runs as the **first** role in `workstation.yml`. Performs a full `pacman -Syu`, dual-installs `linux612` (LTS, fallback) and `linux70` (stable, new default) kernels with matching headers, and verifies both initramfs images and GRUB menu entries post-install. Invoke stand-alone with `ansible-playbook ansible/workstation.yml --tags system-upgrade`; idempotent on re-runs (2026-05-18).
|
||||
- `docs/adr/0002-kernel-and-nvidia-strategy.md` — ADR documenting the LTS+stable kernel choice and the `575xx → 595.71` NVIDIA migration for Hyprland/Wayland preparation (2026-05-18).
|
||||
- Pre-flight safety gate in the new role: aborts if free space on `/` drops below `min_free_root_gb` (5 GiB by default) (2026-05-18).
|
||||
- Comprehensive NVMe benchmark for Samsung PM9A1 before firmware update: SMART health, hdparm, fio seq/rand benchmarks (2026-04-02). See `docs/tech/nvme-benchmark-pre-gxa7802q.md`.
|
||||
- CLI suite update script `scripts/update-cli-suite.sh` for Manjaro/Arch tool maintenance (2026-04-02).
|
||||
|
||||
### Changed
|
||||
- **Executed `system-upgrade` playbook on the live workstation** (2026-05-18). `pacman -Syu` upgraded **1103 packages**; kernel set now `linux612 6.12.85-1` (LTS, was 6.12.77-1) + `linux70 7.0.3-1` (NEW); NVIDIA migrated to mainline `595.71.05` for both `linux612-nvidia` and `linux70-nvidia`; legacy `*-nvidia-575xx` packages removed. Both `/boot/initramfs-6.12-x86_64.img` (54 MB) and `/boot/initramfs-7.0-x86_64.img` (122 MB) generated; GRUB regenerated with menuentries for both kernels. **Reboot required**: select `linux70` from the GRUB "Advanced options for Manjaro Linux" submenu to activate the new kernel and NVIDIA 595.71.05 modules. Logs: `logs/system-upgrade-20260518-101253-live.log`.
|
||||
- NVIDIA driver migrated from the pinned `*-nvidia-575xx` (575.64.05) branch to the mainline `*-nvidia` (595.71.05) branch via the new `system-upgrade` role. `linux612-nvidia-575xx`, `nvidia-575xx-utils`, `lib32-nvidia-575xx-utils`, `nvidia-575xx-settings` are removed; `linux612-nvidia`, `linux70-nvidia`, `nvidia-utils`, `lib32-nvidia-utils`, `opencl-nvidia`, `nvidia-settings` are installed in one atomic pacman transaction (2026-05-18).
|
||||
- `ansible/workstation.yml`: `system-upgrade` registered as the first role, guarded by `when: os_type == 'archlinux'`, with tag `system-upgrade` (2026-05-18).
|
||||
- `ansible/vars/main.yml`: added `kernel_packages`, `nvidia_kernel_modules`, `nvidia_userspace_packages`, `nvidia_packages_to_remove`, `min_free_root_gb` so future kernel/driver pins are a one-line change (2026-05-18).
|
||||
- `docs/tech/setup.md`: new bootstrap step "Run system upgrade & kernel install" before the main playbook, with `--tags system-upgrade` examples and a reboot-into-`linux70` callout (2026-05-18).
|
||||
- Samsung PM9A1 NVMe firmware update applied: GXA7401Q → GXA7801Q (non-SED variant, reboot pending to activate). All nvme-cli steps succeeded (2026-04-02).
|
||||
- Corrected firmware research: GXA7802Q is SED-only (`00B07`); non-SED drives (`00B00`) require GXA7801Q. Updated `docs/tech/firmware-update-research.md` with naming convention and correct source.
|
||||
- Updated `.gitignore`: added `logs/` and `docs/tech/capabilities/` exclusions (2026-04-02).
|
||||
@@ -31,5 +39,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Synchronized software versions across documentation files (2026-03-13).
|
||||
|
||||
### Fixed
|
||||
- Resolved kitty cursor keys not working by disabling the `TERM=xterm-256color` override in `.bashrc`, allowing Kitty to correctly set `TERM=xterm-kitty`. Added Ansible management for `kitty.conf` to ensure proper terminal behavior and shell integration (2026-05-19).
|
||||
- `system-upgrade` role: GRUB menu assertion now matches Manjaro's real `menuentry 'Manjaro Linux (Kernel: X.Y.Z-MANJARO x64)'` format (counted per-kernel-family) instead of the wrong `menuentry .*linux(612|70)` regex that always returned 0 hits on Manjaro and broke the live run with a false-negative failure (2026-05-18).
|
||||
- `system-upgrade` role: migration task `changed_when` now matches pacman's progress lines `^\(N/M\)\s+(installing|upgrading|removing)\s` instead of plain substring matching, so the role's own echo lines no longer trigger spurious `changed=true` on idempotent re-runs. Verified: second live re-run reports `ok=16 changed=0 failed=0 skipped=5` (2026-05-18).
|
||||
- Resolved system unresponsiveness issue by addressing critical memory/swap pressure with increased headroom and proactive OOM killing (2026-03-17).
|
||||
- Identified failed `archlinux-keyring-wkd-sync.service` in system health check.
|
||||
|
||||
@@ -11,6 +11,13 @@
|
||||
become: yes
|
||||
tags: [systemd, oomd]
|
||||
|
||||
- name: Restart systemd-logind
|
||||
systemd:
|
||||
name: systemd-logind
|
||||
state: restarted
|
||||
become: yes
|
||||
tags: [systemd]
|
||||
|
||||
- name: Reload systemd
|
||||
systemd:
|
||||
daemon_reload: yes
|
||||
|
||||
@@ -120,6 +120,49 @@
|
||||
become: yes
|
||||
tags: [systemd, optimization]
|
||||
|
||||
- name: Ensure systemd drop-in directories exist
|
||||
file:
|
||||
path: "{{ item }}"
|
||||
state: directory
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0755'
|
||||
with_items:
|
||||
- /etc/systemd/logind.conf.d
|
||||
- /etc/systemd/sleep.conf.d
|
||||
become: yes
|
||||
tags: [systemd, power]
|
||||
|
||||
- name: Configure systemd-logind to prevent sleep on keys/lid
|
||||
copy:
|
||||
dest: /etc/systemd/logind.conf.d/prevent-sleep.conf
|
||||
content: |
|
||||
[Login]
|
||||
HandleSuspendKey=ignore
|
||||
HandleHibernateKey=ignore
|
||||
HandleLidSwitch=ignore
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0644'
|
||||
become: yes
|
||||
notify: Restart systemd-logind
|
||||
tags: [systemd, power]
|
||||
|
||||
- name: Configure systemd-sleep to disable sleep/hibernation
|
||||
copy:
|
||||
dest: /etc/systemd/sleep.conf.d/prevent-sleep.conf
|
||||
content: |
|
||||
[Sleep]
|
||||
AllowSuspend=no
|
||||
AllowHibernation=no
|
||||
AllowSuspendThenHibernate=no
|
||||
AllowHybridSleep=no
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0644'
|
||||
become: yes
|
||||
tags: [systemd, power]
|
||||
|
||||
- name: Ensure systemd directories exist
|
||||
file:
|
||||
path: "{{ item }}"
|
||||
|
||||
@@ -125,3 +125,47 @@
|
||||
group: "{{ system_user }}"
|
||||
mode: '0644'
|
||||
tags: [chrome, webgpu]
|
||||
|
||||
- name: Fix kitty cursor keys by removing TERM override in .bashrc
|
||||
ansible.builtin.lineinfile:
|
||||
path: "/home/{{ system_user }}/.bashrc"
|
||||
regexp: '^export TERM=xterm-256color'
|
||||
line: '# export TERM=xterm-256color # Fix: allow kitty to set its own TERM for cursor keys'
|
||||
state: present
|
||||
become: yes
|
||||
become_user: "{{ system_user }}"
|
||||
tags: [kitty, shell]
|
||||
|
||||
- name: Ensure kitty configuration directory exists
|
||||
ansible.builtin.file:
|
||||
path: "/home/{{ system_user }}/.config/kitty"
|
||||
state: directory
|
||||
owner: "{{ system_user }}"
|
||||
group: "{{ system_user }}"
|
||||
mode: '0755'
|
||||
become: yes
|
||||
become_user: "{{ system_user }}"
|
||||
tags: [kitty]
|
||||
|
||||
- name: Configure kitty for proper terminal behavior
|
||||
ansible.builtin.copy:
|
||||
dest: "/home/{{ system_user }}/.config/kitty/kitty.conf"
|
||||
content: |
|
||||
# Managed by Ansible - saTway DevOps
|
||||
shell bash
|
||||
editor vim
|
||||
|
||||
# Shell integration is enabled by default in kitty 0.24.0+
|
||||
# but we can explicitly enable it for clarity.
|
||||
shell_integration enabled
|
||||
|
||||
# Ensure cursor keys work correctly by not overriding TERM in shell
|
||||
# (Handled via .bashrc fix)
|
||||
|
||||
include /home/mw/.config/kitty/kitty-cline-keybindings.conf
|
||||
owner: "{{ system_user }}"
|
||||
group: "{{ system_user }}"
|
||||
mode: '0644'
|
||||
become: yes
|
||||
become_user: "{{ system_user }}"
|
||||
tags: [kitty]
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
- name: rebuild initramfs
|
||||
command: mkinitcpio -P
|
||||
become: yes
|
||||
@@ -0,0 +1,73 @@
|
||||
---
|
||||
- name: Hyprland - install packages
|
||||
community.general.pacman:
|
||||
name: "{{ hyprland_packages }}"
|
||||
state: present
|
||||
update_cache: yes
|
||||
tags: [hyprland, packages]
|
||||
|
||||
- name: Hyprland - ensure configuration directories exist
|
||||
file:
|
||||
path: "/home/{{ system_user }}/.config/{{ item }}"
|
||||
state: directory
|
||||
owner: "{{ system_user }}"
|
||||
group: "{{ system_user }}"
|
||||
mode: '0755'
|
||||
loop:
|
||||
- hypr
|
||||
- waybar
|
||||
- wofi
|
||||
- dunst
|
||||
tags: [hyprland, config]
|
||||
|
||||
- name: Hyprland - configure NVIDIA DRM KMS (modeset=1)
|
||||
lineinfile:
|
||||
path: /etc/modprobe.d/nvidia.conf
|
||||
line: "options nvidia-drm modeset=1"
|
||||
create: yes
|
||||
notify: rebuild initramfs
|
||||
tags: [hyprland, nvidia]
|
||||
|
||||
- name: Hyprland - check if NVIDIA modules are already in mkinitcpio
|
||||
command: grep -q "nvidia nvidia_modeset nvidia_uvm nvidia_drm" /etc/mkinitcpio.conf
|
||||
register: mkinitcpio_check
|
||||
failed_when: false
|
||||
changed_when: false
|
||||
tags: [hyprland, nvidia]
|
||||
|
||||
- name: Hyprland - configure early module loading in mkinitcpio
|
||||
replace:
|
||||
path: /etc/mkinitcpio.conf
|
||||
regexp: '^MODULES=\((.*)\)'
|
||||
replace: 'MODULES=(nvidia nvidia_modeset nvidia_uvm nvidia_drm \1)'
|
||||
when: mkinitcpio_check.rc != 0
|
||||
notify: rebuild initramfs
|
||||
tags: [hyprland, nvidia]
|
||||
|
||||
- name: Hyprland - register session in SDDM
|
||||
copy:
|
||||
dest: /usr/share/wayland-sessions/hyprland.desktop
|
||||
content: |
|
||||
[Desktop Entry]
|
||||
Name=Hyprland
|
||||
Comment=An intelligent dynamic tiling Wayland compositor
|
||||
Exec=Hyprland
|
||||
Type=Application
|
||||
DesktopNames=Hyprland
|
||||
tags: [hyprland, session]
|
||||
|
||||
- name: Hyprland - template core configuration
|
||||
template:
|
||||
src: "{{ item.src }}"
|
||||
dest: "/home/{{ system_user }}/.config/{{ item.dest }}"
|
||||
owner: "{{ system_user }}"
|
||||
group: "{{ system_user }}"
|
||||
mode: '0644'
|
||||
loop:
|
||||
- { src: 'hyprland.conf.j2', dest: 'hypr/hyprland.conf' }
|
||||
- { src: 'hyprlock.conf.j2', dest: 'hypr/hyprlock.conf' }
|
||||
- { src: 'hypridle.conf.j2', dest: 'hypr/hypridle.conf' }
|
||||
- { src: 'waybar_config.j2', dest: 'waybar/config' }
|
||||
- { src: 'waybar_style.css.j2', dest: 'waybar/style.css' }
|
||||
- { src: 'dunstrc.j2', dest: 'dunst/dunstrc' }
|
||||
tags: [hyprland, config]
|
||||
@@ -0,0 +1,65 @@
|
||||
[global]
|
||||
monitor = 0
|
||||
follow = mouse
|
||||
width = 300
|
||||
height = 300
|
||||
origin = top-right
|
||||
offset = 10x10
|
||||
scale = 0
|
||||
notification_limit = 0
|
||||
progress_bar = true
|
||||
progress_bar_height = 10
|
||||
progress_bar_frame_width = 1
|
||||
progress_bar_min_width = 150
|
||||
progress_bar_max_width = 300
|
||||
indicate_hidden = yes
|
||||
transparency = 0
|
||||
separator_height = 2
|
||||
padding = 8
|
||||
horizontal_padding = 8
|
||||
text_icon_padding = 0
|
||||
frame_width = 3
|
||||
frame_color = "#aaaaaa"
|
||||
separator_color = frame
|
||||
sort = yes
|
||||
idle_threshold = 120
|
||||
font = Monospace 12
|
||||
line_height = 0
|
||||
markup = full
|
||||
format = "<b>%s</b>\n%b"
|
||||
alignment = left
|
||||
vertical_alignment = center
|
||||
show_age_threshold = 60
|
||||
ellipsize = middle
|
||||
ignore_newline = no
|
||||
stack_duplicates = true
|
||||
hide_duplicate_count = false
|
||||
show_indicators = yes
|
||||
icon_position = left
|
||||
min_icon_size = 0
|
||||
max_icon_size = 32
|
||||
sticky_history = yes
|
||||
history_length = 20
|
||||
dmenu = /usr/bin/wofi -dmenu -p dunst:
|
||||
browser = /usr/bin/xdg-open
|
||||
always_run_script = true
|
||||
title = Dunst
|
||||
class = Dunst
|
||||
corner_radius = 10
|
||||
ignore_dbusclose = false
|
||||
|
||||
[urgency_low]
|
||||
background = "#222222"
|
||||
foreground = "#888888"
|
||||
timeout = 10
|
||||
|
||||
[urgency_normal]
|
||||
background = "#285577"
|
||||
foreground = "#ffffff"
|
||||
timeout = 20
|
||||
|
||||
[urgency_critical]
|
||||
background = "#900000"
|
||||
foreground = "#ffffff"
|
||||
frame_color = "#ff0000"
|
||||
timeout = 0
|
||||
@@ -0,0 +1,16 @@
|
||||
general {
|
||||
lock_cmd = pidof hyprlock || hyprlock
|
||||
before_sleep_cmd = loginctl lock-session
|
||||
after_sleep_cmd = hyprctl dispatch dpms on
|
||||
}
|
||||
|
||||
listener {
|
||||
timeout = 300
|
||||
on-timeout = loginctl lock-session
|
||||
}
|
||||
|
||||
listener {
|
||||
timeout = 330
|
||||
on-timeout = hyprctl dispatch dpms off
|
||||
on-resume = hyprctl dispatch dpms on
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
# hyprland.conf - managed by Ansible
|
||||
|
||||
# Monitor layout (left to right):
|
||||
# 1. DP-1 TERRA 3280W 2560x1440@144 (0x0)
|
||||
# 2. DVI-D-1 BenQ BL2405 1920x1080@60 (rotated 90° CW, effective width 1080)
|
||||
# 3. HDMI-A-1 TERRA 3280W 2560x1440@144 (3640x0)
|
||||
monitor=DP-1,2560x1440@144,0x0,1
|
||||
monitor=DVI-D-1,1920x1080@60,2560x0,1,transform,1
|
||||
monitor=HDMI-A-1,2560x1440@144,3640x0,1
|
||||
|
||||
# Execute on start
|
||||
exec-once = waybar
|
||||
exec-once = dunst
|
||||
exec-once = hypridle
|
||||
exec-once = wl-paste --type text --watch cliphist store
|
||||
exec-once = wl-paste --type image --watch cliphist store
|
||||
|
||||
# Environment variables for NVIDIA
|
||||
env = LIBVA_DRIVER_NAME,nvidia
|
||||
env = XDG_SESSION_TYPE,wayland
|
||||
env = GBM_BACKEND,nvidia-drm
|
||||
env = __GLX_VENDOR_LIBRARY_NAME,nvidia
|
||||
env = WLR_NO_HARDWARE_CURSORS,1
|
||||
env = NVD_BACKEND,direct
|
||||
|
||||
# Input
|
||||
input {
|
||||
kb_layout = de
|
||||
follow_mouse = 1
|
||||
sensitivity = 0
|
||||
}
|
||||
|
||||
# General
|
||||
general {
|
||||
gaps_in = 5
|
||||
gaps_out = 10
|
||||
border_size = 2
|
||||
col.active_border = rgba(33ccffee) rgba(00ff99ee) 45deg
|
||||
col.inactive_border = rgba(595959aa)
|
||||
layout = dwindle
|
||||
}
|
||||
|
||||
# Decoration
|
||||
decoration {
|
||||
rounding = 10
|
||||
blur {
|
||||
enabled = true
|
||||
size = 3
|
||||
passes = 1
|
||||
}
|
||||
}
|
||||
|
||||
# Animations
|
||||
animations {
|
||||
enabled = yes
|
||||
}
|
||||
|
||||
# Dwindle layout
|
||||
dwindle {
|
||||
preserve_split = yes
|
||||
}
|
||||
|
||||
# Keybindings
|
||||
$mainMod = SUPER
|
||||
|
||||
bind = $mainMod, Q, exec, kitty
|
||||
bind = $mainMod, C, killactive,
|
||||
bind = $mainMod, M, exit,
|
||||
bind = $mainMod, E, exec, dolphin
|
||||
bind = $mainMod, V, togglefloating,
|
||||
bind = $mainMod, D, exec, wofi --show drun
|
||||
bind = $mainMod, P, pseudo
|
||||
bind = $mainMod, J, layoutmsg, togglesplit
|
||||
bind = $mainMod, L, exec, hyprlock
|
||||
|
||||
# Focus
|
||||
bind = $mainMod, left, movefocus, l
|
||||
bind = $mainMod, right, movefocus, r
|
||||
bind = $mainMod, up, movefocus, u
|
||||
bind = $mainMod, down, movefocus, d
|
||||
|
||||
# Workspaces
|
||||
bind = $mainMod, 1, workspace, 1
|
||||
bind = $mainMod, 2, workspace, 2
|
||||
bind = $mainMod, 3, workspace, 3
|
||||
bind = $mainMod, 4, workspace, 4
|
||||
bind = $mainMod, 5, workspace, 5
|
||||
bind = $mainMod, 6, workspace, 6
|
||||
bind = $mainMod, 7, workspace, 7
|
||||
bind = $mainMod, 8, workspace, 8
|
||||
bind = $mainMod, 9, workspace, 9
|
||||
|
||||
# Move to workspace
|
||||
bind = $mainMod SHIFT, 1, movetoworkspace, 1
|
||||
bind = $mainMod SHIFT, 2, movetoworkspace, 2
|
||||
bind = $mainMod SHIFT, 3, movetoworkspace, 3
|
||||
bind = $mainMod SHIFT, 4, movetoworkspace, 4
|
||||
bind = $mainMod SHIFT, 5, movetoworkspace, 5
|
||||
bind = $mainMod SHIFT, 6, movetoworkspace, 6
|
||||
bind = $mainMod SHIFT, 7, movetoworkspace, 7
|
||||
bind = $mainMod SHIFT, 8, movetoworkspace, 8
|
||||
bind = $mainMod SHIFT, 9, movetoworkspace, 9
|
||||
@@ -0,0 +1,29 @@
|
||||
general {
|
||||
no_fade_in = false
|
||||
grace = 0
|
||||
disable_loading = true
|
||||
}
|
||||
|
||||
background {
|
||||
monitor =
|
||||
color = rgba(25, 20, 20, 1.0)
|
||||
blur_passes = 2
|
||||
}
|
||||
|
||||
input-field {
|
||||
monitor =
|
||||
size = 200, 50
|
||||
outline_thickness = 3
|
||||
dots_size = 0.33
|
||||
dots_spacing = 0.15
|
||||
dots_center = true
|
||||
outer_color = rgb(151515)
|
||||
inner_color = rgb(200, 200, 200)
|
||||
font_color = rgb(10, 10, 10)
|
||||
fade_on_empty = true
|
||||
placeholder_text = <i>Input Password...</i>
|
||||
hide_input = false
|
||||
position = 0, -20
|
||||
halign = center
|
||||
valign = center
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"layer": "top",
|
||||
"position": "top",
|
||||
"height": 30,
|
||||
"modules-left": ["hyprland/workspaces", "hyprland/mode"],
|
||||
"modules-center": ["hyprland/window"],
|
||||
"modules-right": ["network", "cpu", "memory", "clock", "tray"],
|
||||
"hyprland/workspaces": {
|
||||
"disable-scroll": true,
|
||||
"all-outputs": true,
|
||||
"format": "{name}"
|
||||
},
|
||||
"clock": {
|
||||
"format": "{:%Y-%m-%d %H:%M}",
|
||||
"tooltip-format": "<big>{:%Y %B}</big>\n<tt><small>{calendar}</small></tt>"
|
||||
},
|
||||
"cpu": {
|
||||
"format": "CPU {usage}%",
|
||||
"tooltip": false
|
||||
},
|
||||
"memory": {
|
||||
"format": "RAM {}%"
|
||||
},
|
||||
"network": {
|
||||
"format-wifi": " {essid} ({signalStrength}%)",
|
||||
"format-ethernet": " {ifname}",
|
||||
"format-disconnected": "⚠ Disconnected"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
* {
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
font-family: monospace;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
window#waybar {
|
||||
background: rgba(43, 48, 59, 0.5);
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
#workspaces button {
|
||||
padding: 0 5px;
|
||||
background: transparent;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
#workspaces button.active {
|
||||
background: #64727D;
|
||||
border-bottom: 3px solid #ffffff;
|
||||
}
|
||||
|
||||
#clock, #cpu, #memory, #network, #tray {
|
||||
padding: 0 10px;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
# Role-local defaults for system-upgrade.
|
||||
# Project-wide kernel/NVIDIA package lists live in ansible/vars/main.yml so
|
||||
# they can be reused by future roles (e.g. hyprland) without re-declaration.
|
||||
# Override here only if you need a different value when running this role
|
||||
# stand-alone (ansible-playbook ... -e @custom-vars.yml).
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
# Handlers for system-upgrade role.
|
||||
# Currently the role uses explicit gated tasks (when: ... .changed) rather
|
||||
# than notify/handler chains, because every kernel/driver change must trigger
|
||||
# both mkinitcpio AND grub-mkconfig in a strict order. If you later split
|
||||
# tasks across files, prefer the standard notify pattern here.
|
||||
@@ -0,0 +1,289 @@
|
||||
---
|
||||
# system-upgrade role — full system upgrade + kernel/NVIDIA preparation
|
||||
# for the upcoming Hyprland/Wayland migration. Idempotent: a clean re-run
|
||||
# on an already-upgraded box performs no destructive action.
|
||||
#
|
||||
# Sections:
|
||||
# 1. Pre-flight checks (OS guard, free space, summary)
|
||||
# 2. Full system upgrade (pacman -Syu) — added in Step 2
|
||||
# 3. NVIDIA branch migration + kernel install — added in Step 3
|
||||
# 4. Initramfs + GRUB refresh + final reboot notice — added in Step 4
|
||||
#
|
||||
# Run as:
|
||||
# ansible-playbook ansible/workstation.yml --check --tags system-upgrade
|
||||
# ansible-playbook ansible/workstation.yml --tags system-upgrade
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 1. Pre-flight checks
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
- name: Pre-flight - announce role start
|
||||
debug:
|
||||
msg:
|
||||
- "system-upgrade: preparing baseline for Hyprland/Wayland migration"
|
||||
- "kernels to ensure installed: {{ kernel_packages | join(', ') }}"
|
||||
- "nvidia modules to ensure installed: {{ nvidia_kernel_modules | join(', ') }}"
|
||||
- "nvidia legacy packages to remove: {{ nvidia_packages_to_remove | join(', ') }}"
|
||||
tags: [system-upgrade, preflight]
|
||||
|
||||
- name: Pre-flight - capture free space on / (GiB)
|
||||
shell: |
|
||||
set -o pipefail
|
||||
df --output=avail -BG / | tail -1 | tr -dc '0-9'
|
||||
args:
|
||||
executable: /bin/bash
|
||||
register: root_free_gb
|
||||
changed_when: false
|
||||
check_mode: false
|
||||
tags: [system-upgrade, preflight]
|
||||
|
||||
- name: Pre-flight - fail if free space on / < {{ min_free_root_gb }} GiB
|
||||
fail:
|
||||
msg: >-
|
||||
Only {{ root_free_gb.stdout }} GiB free on /, need at least
|
||||
{{ min_free_root_gb }} GiB before running pacman -Syu and installing
|
||||
a second kernel. Run `paccache -rk2` and clear ~/.cache before retrying.
|
||||
when: (root_free_gb.stdout | int) < (min_free_root_gb | int)
|
||||
tags: [system-upgrade, preflight]
|
||||
|
||||
- name: Pre-flight - record currently running kernel
|
||||
command: uname -r
|
||||
register: running_kernel
|
||||
changed_when: false
|
||||
check_mode: false
|
||||
tags: [system-upgrade, preflight]
|
||||
|
||||
- name: Pre-flight - summary
|
||||
debug:
|
||||
msg:
|
||||
- "running kernel: {{ running_kernel.stdout }}"
|
||||
- "free space on /: {{ root_free_gb.stdout }} GiB (min required {{ min_free_root_gb }})"
|
||||
- "OS guard: os_type == '{{ os_type }}' (must be 'archlinux')"
|
||||
tags: [system-upgrade, preflight]
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 2. Full system upgrade (pacman -Syu)
|
||||
# ---------------------------------------------------------------------------
|
||||
# Bring the box to current Manjaro Stable before touching kernels/drivers.
|
||||
# `community.general.pacman` runs the equivalent of `pacman -Syu`:
|
||||
# - update_cache: yes -> pacman -Sy
|
||||
# - upgrade: yes -> pacman -Su
|
||||
# It reports changed=True iff packages were actually upgraded, which we use
|
||||
# below to gate the kernel/driver migration so an already-current box is a
|
||||
# true no-op.
|
||||
|
||||
- name: Upgrade - full system upgrade (pacman -Syu)
|
||||
community.general.pacman:
|
||||
update_cache: yes
|
||||
upgrade: yes
|
||||
register: pacman_syu
|
||||
tags: [system-upgrade, upgrade, pacman]
|
||||
|
||||
- name: Upgrade - summary
|
||||
debug:
|
||||
msg:
|
||||
- "pacman -Syu changed: {{ pacman_syu.changed | default(false) }}"
|
||||
- "packages touched: {{ (pacman_syu.packages | default([])) | length }}"
|
||||
- "first 10 packages: {{ (pacman_syu.packages | default([]))[:10] | join(', ') }}"
|
||||
tags: [system-upgrade, upgrade]
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 3. NVIDIA branch migration + kernel install
|
||||
# ---------------------------------------------------------------------------
|
||||
# Goal: end up with BOTH linux618 (LTS/Fallback) and linux70 (stable) installed, each
|
||||
# with matching *-nvidia kernel modules on the 580xx branch.
|
||||
# in the same transaction so the GPU never has a "no driver" window of more
|
||||
# than ~1 second on a local pacman cache.
|
||||
#
|
||||
# Safety guarantees:
|
||||
# - linux618 (currently running kernel) is in `kernel_packages`, never in
|
||||
# `nvidia_packages_to_remove` — asserted below.
|
||||
# - The remove step uses the list of 575xx packages that are *actually*
|
||||
# installed, so re-running the role after a successful migration is a
|
||||
# true no-op (LEGACY is empty -> pacman -Rdd is skipped).
|
||||
# - The install step uses --needed so already-current packages are not
|
||||
# touched a second time.
|
||||
|
||||
- name: Migration - safety assertion (Fallback kernel must NOT be removed)
|
||||
assert:
|
||||
that:
|
||||
- "'linux618' in kernel_packages"
|
||||
- "'linux618' not in nvidia_packages_to_remove"
|
||||
- "kernel_packages | length > 0"
|
||||
- "nvidia_kernel_modules | length > 0"
|
||||
fail_msg: >-
|
||||
Refusing to migrate: configuration would remove the running fallback kernel.
|
||||
Check ansible/vars/main.yml: 'linux618' must stay in kernel_packages.
|
||||
tags: [system-upgrade, migration]
|
||||
|
||||
- name: Migration - detect which legacy 575xx packages are currently installed
|
||||
shell: |
|
||||
set -o pipefail
|
||||
pacman -Qq {{ nvidia_packages_to_remove | join(' ') }} 2>/dev/null || true
|
||||
args:
|
||||
executable: /bin/bash
|
||||
register: nvidia_legacy_installed
|
||||
changed_when: false
|
||||
check_mode: false
|
||||
tags: [system-upgrade, migration]
|
||||
|
||||
- name: Migration - check-mode dry-run (pacman -S --print)
|
||||
shell: |
|
||||
set -o pipefail
|
||||
pacman -S --needed --print {{ (kernel_packages + nvidia_kernel_modules + nvidia_userspace_packages) | join(' ') }} 2>&1 | head -40 || true
|
||||
args:
|
||||
executable: /bin/bash
|
||||
register: nvidia_dryrun
|
||||
changed_when: false
|
||||
check_mode: false
|
||||
when: ansible_check_mode
|
||||
tags: [system-upgrade, migration]
|
||||
|
||||
- name: Migration - check-mode preview output
|
||||
debug:
|
||||
msg:
|
||||
- "legacy 575xx packages currently installed:"
|
||||
- "{{ nvidia_legacy_installed.stdout_lines | default([]) }}"
|
||||
- "pacman would install (first 40 lines of --print):"
|
||||
- "{{ nvidia_dryrun.stdout_lines | default([]) }}"
|
||||
when: ansible_check_mode
|
||||
tags: [system-upgrade, migration]
|
||||
|
||||
- name: Migration - swap NVIDIA branch (575xx -> 580xx) and install kernels
|
||||
shell: |
|
||||
set -eo pipefail
|
||||
LEGACY="{{ nvidia_legacy_installed.stdout_lines | default([]) | join(' ') }}"
|
||||
if [ -n "$LEGACY" ]; then
|
||||
echo ">>> dropping legacy 575xx packages: $LEGACY"
|
||||
pacman -Rdd --noconfirm $LEGACY
|
||||
else
|
||||
echo ">>> no legacy 575xx packages present — skipping drop step"
|
||||
fi
|
||||
echo ">>> ensuring target packages are present (kernels + nvidia modules + userspace)"
|
||||
pacman -S --needed --noconfirm {{ (kernel_packages + nvidia_kernel_modules + nvidia_userspace_packages) | join(' ') }}
|
||||
args:
|
||||
executable: /bin/bash
|
||||
register: nvidia_migration
|
||||
become: yes
|
||||
when: not ansible_check_mode
|
||||
# Detect REAL pacman activity (not our own echo lines): pacman prints
|
||||
# progress lines like "(3/4) installing linux70" / "(1/4) upgrading foo" /
|
||||
# "(2/4) removing nvidia-575xx-utils". Match exactly that format so re-runs
|
||||
# on an already-current box report changed=false.
|
||||
changed_when: >-
|
||||
(nvidia_migration.stdout | default('')) is search('\([0-9]+/[0-9]+\)\s+(installing|upgrading|removing)\s')
|
||||
tags: [system-upgrade, migration]
|
||||
|
||||
- name: Migration - verify all target packages are present after install
|
||||
command: pacman -Q {{ item }}
|
||||
loop: "{{ kernel_packages + nvidia_kernel_modules + nvidia_userspace_packages }}"
|
||||
register: pkg_verify
|
||||
changed_when: false
|
||||
check_mode: false
|
||||
failed_when: (pkg_verify.rc | default(0)) != 0 and not ansible_check_mode
|
||||
tags: [system-upgrade, migration]
|
||||
|
||||
- name: Migration - recovery notice
|
||||
debug:
|
||||
msg:
|
||||
- "Recovery if linux70 fails to boot:"
|
||||
- " 1. Reboot, hold SHIFT (or ESC) at POST to open the GRUB menu."
|
||||
- " 2. Pick 'Advanced options for Manjaro Linux' -> 'linux618-x86_64'."
|
||||
- " 3. linux618 + linux618-nvidia (580xx) modules are kept intact"
|
||||
- " so the fallback path is always bootable."
|
||||
tags: [system-upgrade, migration]
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 4. Initramfs refresh + GRUB regenerate + final reboot notice
|
||||
# ---------------------------------------------------------------------------
|
||||
# Manjaro's pacman post-install hooks normally invoke mkinitcpio and update-grub
|
||||
# automatically. We re-run them explicitly here as a belt-and-suspenders safety
|
||||
# net: if a hook was missed (e.g. interrupted transaction), the system still
|
||||
# ends up bootable. Both tasks are gated on "did pacman actually change
|
||||
# anything?" so an idempotent re-run is a true no-op.
|
||||
|
||||
- name: Boot - rebuild initramfs for all installed kernels (mkinitcpio -P)
|
||||
command: mkinitcpio -P
|
||||
become: yes
|
||||
register: mkinitcpio_result
|
||||
when:
|
||||
- not ansible_check_mode
|
||||
- (pacman_syu.changed | default(false)) or (nvidia_migration.changed | default(false))
|
||||
tags: [system-upgrade, boot, initramfs]
|
||||
|
||||
- name: Boot - regenerate GRUB config (-> /boot/grub/grub.cfg)
|
||||
command: grub-mkconfig -o /boot/grub/grub.cfg
|
||||
become: yes
|
||||
register: grub_mkconfig_result
|
||||
when:
|
||||
- not ansible_check_mode
|
||||
- (pacman_syu.changed | default(false)) or (nvidia_migration.changed | default(false))
|
||||
tags: [system-upgrade, boot, grub]
|
||||
|
||||
- name: Boot - stat both initramfs images
|
||||
stat:
|
||||
path: "{{ item }}"
|
||||
loop:
|
||||
- /boot/initramfs-6.18-x86_64.img
|
||||
- /boot/initramfs-7.0-x86_64.img
|
||||
register: initramfs_stat
|
||||
changed_when: false
|
||||
check_mode: false
|
||||
tags: [system-upgrade, boot, initramfs]
|
||||
|
||||
- name: Boot - assert both initramfs images are present after install
|
||||
assert:
|
||||
that:
|
||||
- item.stat.exists
|
||||
fail_msg: >-
|
||||
Missing initramfs image: {{ item.item }} — investigate the mkinitcpio
|
||||
output above before rebooting. linux618 path may still be usable
|
||||
if only the linux70 image is missing.
|
||||
loop: "{{ initramfs_stat.results }}"
|
||||
loop_control:
|
||||
label: "{{ item.item }}"
|
||||
when: not ansible_check_mode
|
||||
tags: [system-upgrade, boot, initramfs]
|
||||
|
||||
- name: Boot - assert GRUB menu lists both kernels (linux618 + linux70)
|
||||
shell: |
|
||||
# Manjaro grub.cfg uses 'Manjaro Linux (Kernel: X.Y.Z-MANJARO x64)' format,
|
||||
# NOT 'linux618'/'linux70' package-name tokens. Count menuentries for each
|
||||
# kernel family separately so we fail if one is missing (a simple total
|
||||
# count would mask a missing kernel if the other family has 2+ entries).
|
||||
K618=$(grep -cE "menuentry .*Kernel: 6\.18\." /boot/grub/grub.cfg)
|
||||
K70=$(grep -cE "menuentry .*Kernel: 7\.0\." /boot/grub/grub.cfg)
|
||||
echo "linux618 (Kernel: 6.18.x) menuentries: ${K618}"
|
||||
echo "linux70 (Kernel: 7.0.x) menuentries: ${K70}"
|
||||
if [ "${K618}" -lt 1 ] || [ "${K70}" -lt 1 ]; then
|
||||
echo "FAIL: missing menuentry for one or both kernels" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "OK: both kernels are listed in /boot/grub/grub.cfg"
|
||||
args:
|
||||
executable: /bin/bash
|
||||
register: grub_menu_check
|
||||
changed_when: false
|
||||
check_mode: false
|
||||
failed_when:
|
||||
- grub_menu_check.rc != 0
|
||||
- not ansible_check_mode
|
||||
tags: [system-upgrade, boot, grub]
|
||||
|
||||
- name: Boot - final reboot notice
|
||||
debug:
|
||||
msg:
|
||||
- "================================================================"
|
||||
- "system-upgrade role finished successfully."
|
||||
- ""
|
||||
- "NEXT STEP: reboot and select 'linux70' from the GRUB menu."
|
||||
- " 1. sudo reboot"
|
||||
- " 2. At the GRUB menu, choose 'Advanced options for Manjaro Linux'"
|
||||
- " -> 'Manjaro Linux on /dev/... linux70-x86_64'."
|
||||
- " 3. After login, verify with:"
|
||||
- " uname -r # expect 7.0.x"
|
||||
- " nvidia-smi # expect driver 580.159.03 on GTX 1050 Ti"
|
||||
- ""
|
||||
- "Only AFTER a successful linux70 boot, run the upcoming Hyprland role."
|
||||
- "================================================================"
|
||||
tags: [system-upgrade, notice]
|
||||
@@ -9,3 +9,59 @@ os_type: archlinux
|
||||
pnpm_version: "25.6.1"
|
||||
python_version: "3.14.3"
|
||||
php_version: "8.5.3"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# system-upgrade role: kernel + NVIDIA preparation for Hyprland/Wayland
|
||||
# ---------------------------------------------------------------------------
|
||||
# Strategy: keep linux618 as fallback, add linux70 (7.0.x stable)
|
||||
# as the new daily-driver kernel. Migrate NVIDIA from the pinned 575xx branch
|
||||
# to the 580xx branch (NFB) for Pascal compatibility.
|
||||
# See: docs/adr/0002-kernel-and-nvidia-strategy.md
|
||||
kernel_packages:
|
||||
- linux618
|
||||
- linux618-headers
|
||||
- linux70
|
||||
- linux70-headers
|
||||
nvidia_kernel_modules:
|
||||
- linux618-nvidia-580xx
|
||||
- linux70-nvidia-580xx
|
||||
nvidia_userspace_packages:
|
||||
- nvidia-580xx-utils
|
||||
- lib32-nvidia-580xx-utils
|
||||
- opencl-nvidia-580xx
|
||||
- nvidia-580xx-settings
|
||||
nvidia_packages_to_remove:
|
||||
- linux612-nvidia-575xx
|
||||
- nvidia-575xx-utils
|
||||
- lib32-nvidia-575xx-utils
|
||||
- nvidia-575xx-settings
|
||||
- opencl-nvidia
|
||||
# Pre-flight: refuse to proceed if free space on / drops below this many GiB.
|
||||
# Current usage is ~87% so we keep this conservative.
|
||||
min_free_root_gb: 5
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# hyprland role: packages and configuration
|
||||
# ---------------------------------------------------------------------------
|
||||
hyprland_packages:
|
||||
- hyprland
|
||||
- hyprlock
|
||||
- hypridle
|
||||
- hyprshot
|
||||
- hyprcursor
|
||||
- xdg-desktop-portal-hyprland
|
||||
- waybar
|
||||
- wofi
|
||||
- dunst
|
||||
- kitty
|
||||
- cliphist
|
||||
- wl-clipboard
|
||||
- brightnessctl
|
||||
- pipewire
|
||||
- pipewire-pulse
|
||||
- wireplumber
|
||||
- pavucontrol
|
||||
- dolphin
|
||||
- egl-wayland
|
||||
- qt5-wayland
|
||||
- qt6-wayland
|
||||
|
||||
@@ -8,6 +8,11 @@
|
||||
- vars/secrets.yml
|
||||
|
||||
roles:
|
||||
- role: system-upgrade
|
||||
tags: [system-upgrade]
|
||||
when: os_type == 'archlinux'
|
||||
- common
|
||||
- dev-tools
|
||||
- maintenance
|
||||
- role: hyprland
|
||||
tags: [hyprland]
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
---
|
||||
description: >-
|
||||
Decision to dual-install linux612 (LTS) + linux70 (stable) kernels and
|
||||
migrate NVIDIA from the pinned 575xx branch to the mainline 595.71 branch
|
||||
to prepare the workstation for Hyprland/Wayland.
|
||||
tags:
|
||||
- adr
|
||||
- kernel
|
||||
- nvidia
|
||||
- hyprland
|
||||
- wayland
|
||||
last_updated: '2026-05-18'
|
||||
---
|
||||
|
||||
# ADR 2: Kernel and NVIDIA Driver Strategy for Hyprland/Wayland
|
||||
|
||||
## Status
|
||||
Accepted (2026-05-18)
|
||||
|
||||
## Context
|
||||
The workstation runs Manjaro Linux on AMD Ryzen 7 2700X with an NVIDIA
|
||||
GeForce GTX 1050 Ti (Pascal, GP107) driving three monitors. The next
|
||||
infrastructure plan switches the desktop from KDE/X11 to Hyprland on
|
||||
Wayland. Two preconditions must hold before that switch is safe:
|
||||
|
||||
1. **DRM/atomic and NVIDIA explicit-sync support** — Hyprland on NVIDIA
|
||||
relies on driver-level explicit sync (introduced in 555.x and matured
|
||||
through 575.x and 595.x). Without it, flickering and missed vblanks
|
||||
are very common on Pascal+multi-monitor.
|
||||
2. **Matching kernel modules** — Manjaro ships pre-built `*-nvidia`
|
||||
modules pinned to a single `nvidia-utils` version. Mixing `575xx`
|
||||
userspace with a kernel that only has `595.71` modules (or vice
|
||||
versa) breaks the driver at the next kernel boot.
|
||||
|
||||
The starting point at the time of this ADR:
|
||||
|
||||
| Item | Version |
|
||||
|---------------------------|------------------------|
|
||||
| Running kernel | `linux612 6.12.77-1` |
|
||||
| NVIDIA driver | `575.64.05-3` (575xx branch) |
|
||||
| NVIDIA kernel module pkg | `linux612-nvidia-575xx 575.64.05-31` |
|
||||
| `linux70` available in repo | `7.0.3-1` |
|
||||
| `linux70-nvidia` available | `595.71.05-0.1` |
|
||||
| `linux612-nvidia` (mainline) | `595.71.05-2` |
|
||||
|
||||
## Decision
|
||||
1. **Run two kernels side by side.**
|
||||
- Keep `linux612` (LTS 6.12.x) installed as the *fallback* boot entry.
|
||||
- Install `linux70` (stable 7.0.x) and select it as the daily-driver
|
||||
kernel via GRUB at the next reboot.
|
||||
2. **Migrate NVIDIA from the `575xx` branch to mainline `595.71`** in
|
||||
one atomic pacman transaction so both kernels have matching modules:
|
||||
- Remove: `linux612-nvidia-575xx`, `nvidia-575xx-utils`,
|
||||
`lib32-nvidia-575xx-utils`, `nvidia-575xx-settings`.
|
||||
- Install: `linux612-nvidia`, `linux70-nvidia`, `nvidia-utils`,
|
||||
`lib32-nvidia-utils`, `opencl-nvidia`, `nvidia-settings`.
|
||||
3. **Do not change `GRUB_DEFAULT` programmatically.** The user picks
|
||||
`linux70` from the GRUB menu on first boot. If `linux70` misbehaves,
|
||||
the next reboot is one menu selection away from the proven LTS path.
|
||||
4. **Encapsulate everything in an idempotent Ansible role**
|
||||
(`ansible/roles/system-upgrade/`) that runs **before** `common`,
|
||||
`dev-tools` and `maintenance`. It is invoked stand-alone with
|
||||
`--tags system-upgrade` and is safe on every subsequent run.
|
||||
|
||||
## Rationale
|
||||
- **LTS as a parachute.** 6.12 is a Linux LTS series with a multi-year
|
||||
support window. Keeping it installed makes the migration reversible by
|
||||
one keystroke in GRUB.
|
||||
- **7.0 as the daily driver.** The 7.0 series brings the maturest
|
||||
DRM/atomic-modeset and NVIDIA explicit-sync paths that Hyprland on
|
||||
Pascal needs to avoid flicker on multi-monitor.
|
||||
- **Mainline 595.71 over pinned 575.64.05.** Manjaro builds
|
||||
`linux70-nvidia` only against `nvidia-utils=595.71.05`, so the 575xx
|
||||
branch is not an option for the new kernel. Pascal (GP107) is fully
|
||||
supported by 595.x, and 595.x ships the latest explicit-sync /
|
||||
modesetting fixes upstream.
|
||||
- **Single atomic transaction.** Removing the old branch and installing
|
||||
the new one in one pacman call (with the removal list narrowed to
|
||||
packages that are *actually* installed) keeps the GPU-driver window
|
||||
to roughly one second of cache I/O on a local SSD.
|
||||
- **Idempotent role over shell script.** Matches the existing
|
||||
`common`/`dev-tools`/`maintenance` pattern, supports `--check`, and
|
||||
re-running after success is a true no-op (validated by gating every
|
||||
mutating task on `pacman_syu.changed or nvidia_migration.changed`).
|
||||
|
||||
## Consequences
|
||||
- **Two kernels on `/` partition.** Roughly +120 MB for `linux70` plus
|
||||
~50 MB for `linux70-nvidia`. The role pre-flight refuses to start if
|
||||
free space on `/` is below 5 GiB.
|
||||
- **`mhwd` profile referencing `575xx` stays as-is.** Only the
|
||||
kernel-bound `linux612-nvidia-575xx` and matching userspace are
|
||||
swapped; `mhwd-nvidia-575xx` stays installed so MHWD's profile
|
||||
listing remains consistent. A future cleanup can switch the MHWD
|
||||
profile to `video-nvidia` once `linux70` is verified.
|
||||
- **Manual reboot required.** The role never reboots the machine; it
|
||||
ends with a clear notice instructing the user to boot into `linux70`
|
||||
from GRUB before applying the next (Hyprland) playbook.
|
||||
- **Future kernel pin bumps are one-line changes** in
|
||||
`ansible/vars/main.yml` (`kernel_packages` /
|
||||
`nvidia_kernel_modules` lists).
|
||||
|
||||
## References
|
||||
- Hyprland NVIDIA notes (wiki.hypr.land/Nvidia): explicit sync
|
||||
available from driver ≥555 and required for tear-free Wayland.
|
||||
- `docs/tech/hardware-inventory.md` (NVIDIA section).
|
||||
- `ansible/roles/system-upgrade/tasks/main.yml`.
|
||||
- ADR 1: `docs/adr/0001-use-ansible-for-configuration.md` — anchors the
|
||||
"Ansible-first" guardrail this decision follows.
|
||||
@@ -100,10 +100,16 @@ last_updated: '2026-04-02'
|
||||
|-------|-------|
|
||||
| Model | NVIDIA GeForce GTX 1050 Ti |
|
||||
| VRAM | 4096 MiB |
|
||||
| Driver | 575.64.05 |
|
||||
| Driver | 575.64.05 (migrating to 595.71.05 — see [ADR 0002](../adr/0002-kernel-and-nvidia-strategy.md)) |
|
||||
| GPU Temp (idle) | 47°C |
|
||||
| PCI Address | 08:00.0 |
|
||||
|
||||
> **Driver strategy**: This Pascal-generation GPU is being migrated from the
|
||||
> pinned Manjaro `*-nvidia-575xx` branch to the mainline `*-nvidia` 595.71
|
||||
> branch as part of the Hyprland/Wayland preparation. The migration is
|
||||
> automated by the `system-upgrade` Ansible role and documented in
|
||||
> [ADR 0002 — Kernel and NVIDIA Driver Strategy for Hyprland/Wayland](../adr/0002-kernel-and-nvidia-strategy.md).
|
||||
|
||||
## Network
|
||||
|
||||
### Physical
|
||||
|
||||
+27
-3
@@ -5,7 +5,7 @@ tags:
|
||||
- setup
|
||||
- bootstrap
|
||||
- ansible
|
||||
last_updated: '2026-03-09'
|
||||
last_updated: '2026-05-18'
|
||||
---
|
||||
|
||||
# Workstation Setup Guide
|
||||
@@ -41,14 +41,38 @@ This guide describes how to bootstrap the **mw-pfeddersheim-workstation** infras
|
||||
ansible-vault create ansible/vars/secrets.yml
|
||||
```
|
||||
|
||||
4. **Run the Playbook**
|
||||
4. **Run system upgrade & kernel install** (preparation for Hyprland/Wayland)
|
||||
|
||||
This step runs the dedicated `system-upgrade` role: full `pacman -Syu`,
|
||||
dual-kernel install (`linux612` LTS + `linux70` stable), and NVIDIA
|
||||
driver migration from the pinned `575xx` branch to mainline `595.71`.
|
||||
Always preview first with `--check`. See
|
||||
[ADR 0002](../adr/0002-kernel-and-nvidia-strategy.md) for the rationale.
|
||||
|
||||
```bash
|
||||
# Preview — never run the live playbook before --check is clean
|
||||
ansible-playbook -i localhost, -c local \
|
||||
--vault-password-file ansible/vault_password \
|
||||
ansible/workstation.yml --check --tags system-upgrade
|
||||
|
||||
# Apply (will install/remove packages and regenerate GRUB)
|
||||
ansible-playbook -i localhost, -c local \
|
||||
--vault-password-file ansible/vault_password \
|
||||
ansible/workstation.yml --tags system-upgrade
|
||||
```
|
||||
|
||||
After it finishes, **reboot and select `linux70` from the GRUB menu**
|
||||
before continuing to step 5. Verify with `uname -r` (expect 7.0.x)
|
||||
and `nvidia-smi` (expect driver 595.71.05).
|
||||
|
||||
5. **Run the Playbook** (remaining roles: common, dev-tools, maintenance)
|
||||
```bash
|
||||
ansible-playbook -i localhost, -c local --vault-password-file ansible/vault_password ansible/workstation.yml --check
|
||||
# If check passes:
|
||||
ansible-playbook -i localhost, -c local --vault-password-file ansible/vault_password ansible/workstation.yml
|
||||
```
|
||||
|
||||
5. **Initialize Maintenance**
|
||||
6. **Initialize Maintenance**
|
||||
```bash
|
||||
./scripts/maintenance.sh
|
||||
```
|
||||
|
||||
Executable
+116
@@ -0,0 +1,116 @@
|
||||
#!/bin/bash
|
||||
# install-hyprland.sh - Install Hyprland with Wayland on Manjaro (NVIDIA)
|
||||
# Run: bash scripts/install-hyprland.sh
|
||||
set -euo pipefail
|
||||
|
||||
echo "=== Hyprland Installation for mw-manjaro-pf ==="
|
||||
echo "GPU: NVIDIA GTX 1050 Ti (595.71.05)"
|
||||
echo "Monitors: 3x (DP-1 + HDMI-A-1 + DVI-D-1)"
|
||||
echo ""
|
||||
|
||||
# Step 1: Install core packages
|
||||
echo "[1/5] Installing Hyprland and core Wayland packages..."
|
||||
sudo pacman -S --needed --noconfirm \
|
||||
hyprland \
|
||||
hyprlock \
|
||||
hypridle \
|
||||
hyprshot \
|
||||
hyprcursor \
|
||||
xdg-desktop-portal-hyprland \
|
||||
waybar \
|
||||
wofi \
|
||||
dunst \
|
||||
kitty \
|
||||
cliphist \
|
||||
wl-clipboard \
|
||||
brightnessctl \
|
||||
pipewire \
|
||||
pipewire-pulse \
|
||||
wireplumber \
|
||||
pavucontrol
|
||||
|
||||
echo "[1/5] Done."
|
||||
|
||||
# Step 2: NVIDIA-specific package verification
|
||||
echo "[2/5] Verifying NVIDIA packages..."
|
||||
pacman -Q nvidia-utils >/dev/null 2>&1 && echo " nvidia-utils: OK" || echo " nvidia-utils: MISSING"
|
||||
pacman -Q egl-wayland >/dev/null 2>&1 && echo " egl-wayland: OK" || echo " egl-wayland: MISSING"
|
||||
echo "[2/5] Done."
|
||||
|
||||
# Step 3: Config directory (already created)
|
||||
echo "[3/5] Verifying configuration..."
|
||||
if [ -f ~/.config/hypr/hyprland.conf ]; then
|
||||
echo " hyprland.conf: OK ($(wc -l < ~/.config/hypr/hyprland.conf) lines)"
|
||||
else
|
||||
echo " hyprland.conf: MISSING - create it first!"
|
||||
exit 1
|
||||
fi
|
||||
echo "[3/5] Done."
|
||||
|
||||
# Step 4: Enable DRM KMS for NVIDIA (critical for Wayland)
|
||||
echo "[4/5] Configuring NVIDIA DRM KMS..."
|
||||
if grep -q "nvidia-drm.modeset=1" /etc/modprobe.d/*.conf 2>/dev/null; then
|
||||
echo " nvidia-drm.modeset=1: Already configured"
|
||||
else
|
||||
echo " Adding nvidia-drm.modeset=1 to /etc/modprobe.d/nvidia.conf..."
|
||||
echo "options nvidia-drm modeset=1" | sudo tee -a /etc/modprobe.d/nvidia.conf
|
||||
echo " IMPORTANT: Reboot required after installation."
|
||||
fi
|
||||
|
||||
# Early loading of NVIDIA modules
|
||||
if grep -q "nvidia" /etc/mkinitcpio.conf 2>/dev/null; then
|
||||
echo " mkinitcpio modules: Already configured"
|
||||
else
|
||||
echo " Adding NVIDIA modules to mkinitcpio..."
|
||||
sudo sed -i 's/^MODULES=(/MODULES=(nvidia nvidia_modeset nvidia_uvm nvidia_drm /' /etc/mkinitcpio.conf
|
||||
sudo mkinitcpio -P
|
||||
fi
|
||||
echo "[4/5] Done."
|
||||
|
||||
# Step 5: Register Hyprland session
|
||||
echo "[5/5] Verifying session registration..."
|
||||
if [ -f /usr/share/wayland-sessions/hyprland.desktop ]; then
|
||||
echo " Session file: OK"
|
||||
else
|
||||
echo " Session file: Creating..."
|
||||
sudo tee /usr/share/wayland-sessions/hyprland.desktop > /dev/null << 'DESKTOP'
|
||||
[Desktop Entry]
|
||||
Name=Hyprland
|
||||
Comment=An intelligent dynamic tiling Wayland compositor
|
||||
Exec=Hyprland
|
||||
Type=Application
|
||||
DesktopNames=Hyprland
|
||||
DESKTOP
|
||||
fi
|
||||
echo "[5/5] Done."
|
||||
|
||||
echo ""
|
||||
echo "=== Installation Complete ==="
|
||||
echo ""
|
||||
echo "NEXT STEPS:"
|
||||
echo " 1. REBOOT to apply NVIDIA DRM KMS changes"
|
||||
echo " 2. Select 'Hyprland' from the login manager (SDDM)"
|
||||
echo " 3. If monitors are wrong, check names with: hyprctl monitors"
|
||||
echo " and adjust in ~/.config/hypr/hyprland.conf"
|
||||
echo ""
|
||||
echo "MONITOR NAMES may differ from X11:"
|
||||
echo " X11 name -> Wayland name (expected)"
|
||||
echo " DP-0 -> DP-1"
|
||||
echo " HDMI-0 -> HDMI-A-1"
|
||||
echo " DVI-D-0 -> DVI-D-1"
|
||||
echo ""
|
||||
echo "KEY BINDINGS (SUPER = Windows key):"
|
||||
echo " SUPER+Return = Terminal (kitty)"
|
||||
echo " SUPER+D = Launcher (wofi)"
|
||||
echo " SUPER+E = File manager (dolphin)"
|
||||
echo " SUPER+L = Lock screen"
|
||||
echo " SUPER+Q = Close window"
|
||||
echo " SUPER+F = Fullscreen"
|
||||
echo " SUPER+1-9 = Switch workspace"
|
||||
echo " SUPER+Arrows = Focus monitor"
|
||||
echo ""
|
||||
echo "TROUBLESHOOTING:"
|
||||
echo " - Cursor issues: WLR_NO_HARDWARE_CURSORS=1 is set"
|
||||
echo " - Blank screen: Check 'nvidia-drm.modeset=1' in kernel params"
|
||||
echo " - Flickering: Try disabling blur in hyprland.conf"
|
||||
echo " - Monitor names: Run 'hyprctl monitors' after first launch"
|
||||
Reference in New Issue
Block a user