From a0546f5fa67abdac8be7a3cbf7647ac93c9703b3 Mon Sep 17 00:00:00 2001 From: Martin Bauer Date: Fri, 2 Oct 2026 21:22:05 +0200 Subject: [PATCH] Recover from half-done installs and missing devices instead of failing for good - pi_shairport: on trixie systemd.pc moved into systemd-dev, so configure found no unit directory and `make install` died on an empty `install -d` - after it had already installed the binary. `creates:` then saw the binary and never retried, and the next tasks failed on the missing unit. Install systemd-dev on trixie, and key `creates:` on the unit file. - pi_irserver: with the IRTrans receiver unplugged at boot, irserver exited at once and stayed failed. Restart it every 10s with no start limit until the device shows up. - pi_modern_shell_env: get_url sent a conditional request to the oh-my-posh CDN on every run, so a TLS handshake timeout there failed the whole play with the binary already installed. Only download it when it is missing. Co-Authored-By: Claude Opus 5.5 --- roles/pi_irserver/files/irserver.service | 9 +++++++- roles/pi_modern_shell_env/tasks/main.yml | 10 +++++++++ roles/pi_shairport/tasks/main.yml | 26 ++++++++++-------------- 3 files changed, 29 insertions(+), 16 deletions(-) diff --git a/roles/pi_irserver/files/irserver.service b/roles/pi_irserver/files/irserver.service index e1596c5..13048ac 100644 --- a/roles/pi_irserver/files/irserver.service +++ b/roles/pi_irserver/files/irserver.service @@ -1,10 +1,17 @@ [Unit] Description=IR server for IR remotes After=network.target +# Keep retrying rather than giving up: the IRTrans receiver is a USB serial device, and +# when it is missing at boot (unplugged, or enumerated late) irserver exits at once with +# "Error opening COM/USB Port". Without a restart it then stays failed until someone +# notices the remote does nothing. +StartLimitIntervalSec=0 [Service] Type=simple ExecStart=/usr/bin/irserver /dev/ttyUSB0 +Restart=on-failure +RestartSec=10 [Install] -WantedBy=multi-user.target \ No newline at end of file +WantedBy=multi-user.target diff --git a/roles/pi_modern_shell_env/tasks/main.yml b/roles/pi_modern_shell_env/tasks/main.yml index 63f722a..546f00a 100644 --- a/roles/pi_modern_shell_env/tasks/main.yml +++ b/roles/pi_modern_shell_env/tasks/main.yml @@ -17,7 +17,17 @@ dest: /usr/local/bin/bat state: link +- name: Check whether oh-my-posh is already installed + ansible.builtin.stat: + path: /usr/local/bin/oh-my-posh + register: pi_modern_shell_env_ohmyposh + - name: Download oh-my-posh binary + # Only when missing. With the file present get_url still sends a conditional request + # every run, so a CDN that is slow or unreachable from the device (TLS handshake + # timeouts happen) failed the whole play for a prompt that was already installed. + # Delete the binary to pick up a newer release. + when: not pi_modern_shell_env_ohmyposh.stat.exists ansible.builtin.get_url: # The official install script's own curl-based downloads are blocked by # oh-my-posh's CDN on some devices (observed on Raspberry Pi OS's curl diff --git a/roles/pi_shairport/tasks/main.yml b/roles/pi_shairport/tasks/main.yml index d02e702..367f8ba 100644 --- a/roles/pi_shairport/tasks/main.yml +++ b/roles/pi_shairport/tasks/main.yml @@ -3,24 +3,20 @@ ansible.builtin.apt: cache_valid_time: 7200 state: present - name: - - build-essential - - git - - xmltoman - - autoconf - - automake - - libtool - - libpopt-dev - - libconfig-dev - - libasound2-dev - - avahi-daemon - - libavahi-client-dev - - libssl-dev - - libsoxr-dev + # systemd-dev: --with-systemd takes the unit directory from systemd.pc, which trixie + # moved out of the systemd package. Without it `make install` fails right after + # installing the binary, with an empty `install -d`. + name: >- + {{ ['build-essential', 'git', 'xmltoman', 'autoconf', 'automake', 'libtool', + 'libpopt-dev', 'libconfig-dev', 'libasound2-dev', 'avahi-daemon', + 'libavahi-client-dev', 'libssl-dev', 'libsoxr-dev'] + + (['systemd-dev'] if ansible_facts.distribution_major_version | int >= 13 else []) }} - name: Build and Install Shairport sync (may take a while) ansible.builtin.script: "build-shairport-sync.sh ${shairport_sync_version}" args: - creates: /usr/local/bin/shairport-sync + # The unit file rather than the binary: make install puts the binary in place + # first, so a build that failed halfway would otherwise never be retried. + creates: /lib/systemd/system/shairport-sync.service notify: Restart shairport-sync - name: Copy config ansible.builtin.template: