thinkcenter-audio: harden — linger-first + wait runtime dir + rescue fallback for user units, apt retries, user/uid asserts
This commit is contained in:
parent
aca4801744
commit
6fa9505f5a
@ -94,25 +94,44 @@
|
||||
that: inventory_hostname == 'thinkcenter'
|
||||
fail_msg: "Refusing to run — this play is scoped to thinkcenter only."
|
||||
|
||||
- name: "[safety] Assert audio_user resolved from Infisical"
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- audio_user is defined
|
||||
- audio_user | length > 0
|
||||
fail_msg: "audio_user is empty — THINKCENTER_USER not read from Infisical /lc-hosts."
|
||||
|
||||
- name: "[facts] Resolve audio_user UID (for XDG_RUNTIME_DIR)"
|
||||
ansible.builtin.getent:
|
||||
database: passwd
|
||||
key: "{{ audio_user }}"
|
||||
|
||||
- name: "[facts] Assert the user actually exists on the host"
|
||||
ansible.builtin.assert:
|
||||
that: audio_user in ansible_facts.getent_passwd
|
||||
fail_msg: "User '{{ audio_user }}' does not exist on {{ inventory_hostname }}."
|
||||
|
||||
- name: "[facts] Set audio_uid"
|
||||
ansible.builtin.set_fact:
|
||||
audio_uid: "{{ ansible_facts.getent_passwd[audio_user][1] }}"
|
||||
|
||||
- name: "[apt] Update cache"
|
||||
- name: "[apt] Update cache (retry on transient network/lock)"
|
||||
ansible.builtin.apt:
|
||||
update_cache: true
|
||||
cache_valid_time: 3600
|
||||
register: apt_cache
|
||||
until: apt_cache is succeeded
|
||||
retries: 3
|
||||
delay: 10
|
||||
|
||||
- name: "[apt] Install unified PipeWire audio stack + qpwgraph"
|
||||
- name: "[apt] Install unified PipeWire audio stack + qpwgraph (retry on dpkg lock)"
|
||||
ansible.builtin.apt:
|
||||
name: "{{ audio_packages }}"
|
||||
state: present
|
||||
register: pkg_install
|
||||
until: pkg_install is succeeded
|
||||
retries: 3
|
||||
delay: 15
|
||||
|
||||
- name: "[conflict] Detect a STANDALONE pulseaudio daemon package (not the pw-pulse shim)"
|
||||
ansible.builtin.shell: "dpkg -l pulseaudio 2>/dev/null | awk '/^ii/{print $2}'"
|
||||
@ -134,27 +153,59 @@
|
||||
register: mask_pa
|
||||
changed_when: mask_pa.rc == 0
|
||||
|
||||
- name: "[services] Enable PipeWire user services for {{ audio_user }} (lingering + enable)"
|
||||
# --- User-session services: made robust ---------------------------------
|
||||
# systemctl --user needs a live user runtime dir + D-Bus. Enabling linger
|
||||
# FIRST makes systemd create a persistent /run/user/<uid> even with no GUI
|
||||
# login, so this works whether or not steve is currently logged in.
|
||||
- name: "[services] Enable lingering for {{ audio_user }} (persistent user manager)"
|
||||
ansible.builtin.command: "loginctl enable-linger {{ audio_user }}"
|
||||
register: linger
|
||||
changed_when: "'already' not in (linger.stderr | default(''))"
|
||||
failed_when: false
|
||||
changed_when: "linger.rc == 0 and 'already enabled' not in (linger.stderr | default(''))"
|
||||
failed_when: linger.rc != 0 and 'already enabled' not in (linger.stderr | default('') + linger.stdout | default(''))
|
||||
|
||||
- name: "[services] Enable pipewire / pipewire-pulse / wireplumber for the user"
|
||||
become: true
|
||||
become_user: "{{ audio_user }}"
|
||||
ansible.builtin.systemd_service:
|
||||
name: "{{ item }}"
|
||||
scope: user
|
||||
enabled: true
|
||||
loop:
|
||||
- pipewire.socket
|
||||
- pipewire-pulse.socket
|
||||
- wireplumber.service
|
||||
environment:
|
||||
XDG_RUNTIME_DIR: "/run/user/{{ audio_uid }}"
|
||||
failed_when: false
|
||||
register: user_services
|
||||
- name: "[services] Wait for user runtime dir /run/user/{{ audio_uid }} to exist"
|
||||
ansible.builtin.stat:
|
||||
path: "/run/user/{{ audio_uid }}"
|
||||
register: runtime_dir
|
||||
until: runtime_dir.stat.exists
|
||||
retries: 6
|
||||
delay: 5
|
||||
|
||||
- name: "[services] Enable PipeWire user units (with rescue if session bus is not ready)"
|
||||
block:
|
||||
- name: "[services] Enable pipewire / pipewire-pulse / wireplumber for the user"
|
||||
become: true
|
||||
become_user: "{{ audio_user }}"
|
||||
ansible.builtin.systemd_service:
|
||||
name: "{{ item }}"
|
||||
scope: user
|
||||
enabled: true
|
||||
loop:
|
||||
- pipewire.socket
|
||||
- pipewire-pulse.socket
|
||||
- wireplumber.service
|
||||
environment:
|
||||
XDG_RUNTIME_DIR: "/run/user/{{ audio_uid }}"
|
||||
DBUS_SESSION_BUS_ADDRESS: "unix:path=/run/user/{{ audio_uid }}/bus"
|
||||
register: user_services
|
||||
rescue:
|
||||
- name: "[services] FALLBACK — enable units via systemctl --user by uid (no D-Bus dependency)"
|
||||
become: true
|
||||
become_user: "{{ audio_user }}"
|
||||
ansible.builtin.command: "systemctl --user enable {{ item }}"
|
||||
loop:
|
||||
- pipewire.socket
|
||||
- pipewire-pulse.socket
|
||||
- wireplumber.service
|
||||
environment:
|
||||
XDG_RUNTIME_DIR: "/run/user/{{ audio_uid }}"
|
||||
register: user_services_fallback
|
||||
changed_when: "'Created symlink' in (user_services_fallback.stderr | default(''))"
|
||||
failed_when: false
|
||||
|
||||
- name: "[services] Note the fallback path was used"
|
||||
ansible.builtin.debug:
|
||||
msg: "User D-Bus not ready; enabled PipeWire units via the systemctl fallback. They will start on next login/linger."
|
||||
|
||||
- name: "[verify] Which server does pactl report?"
|
||||
become: true
|
||||
@ -162,6 +213,7 @@
|
||||
ansible.builtin.command: pactl info
|
||||
environment:
|
||||
XDG_RUNTIME_DIR: "/run/user/{{ audio_uid }}"
|
||||
DBUS_SESSION_BUS_ADDRESS: "unix:path=/run/user/{{ audio_uid }}/bus"
|
||||
register: pactl_info
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
|
||||
Loading…
Reference in New Issue
Block a user