From f01959bc1157082709de501c902f8af0c263b1a3 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Wed, 13 May 2026 20:19:39 +0300 Subject: f3s/beets-art: fix BEETSDIR being read-only (state.pickle write failure) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ConfigMap mount at /etc/beets is kernel-enforced read-only, so beets could not write its incremental import state file (state.pickle), which broke incremental: yes — every nightly run would re-walk the entire library. Fix: point BEETSDIR at the writable state PVC (/state) and pass -c /etc/beets/config.yaml on every beet invocation so the ConfigMap is still the single source of truth for config. Also fix the Justfile run-now recipe to use a bash shebang so $() works. Amp-Thread-ID: https://ampcode.com/threads/T-019e223a-d137-705e-879b-84130c0e78ea Co-authored-by: Amp --- f3s/beets-art/Justfile | 8 +++++--- f3s/beets-art/helm-chart/templates/cronjob.yaml | 20 +++++++++++++------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/f3s/beets-art/Justfile b/f3s/beets-art/Justfile index 4313a55..c3120c4 100644 --- a/f3s/beets-art/Justfile +++ b/f3s/beets-art/Justfile @@ -33,9 +33,11 @@ logs: # Trigger an ad-hoc run *right now* (does not affect the schedule). # Useful for the initial backfill: the first run will be the slow one. run-now: - @ts=$$(date +%s); \ - kubectl create job --from=cronjob/{{CRONJOB}} -n {{NAMESPACE}} {{CRONJOB}}-manual-$$ts; \ - echo "Created job {{CRONJOB}}-manual-$$ts. Tail with: just logs" + #!/usr/bin/env bash + set -euo pipefail + ts=$(date +%s) + kubectl create job --from=cronjob/{{CRONJOB}} -n {{NAMESPACE}} {{CRONJOB}}-manual-$ts + echo "Created job {{CRONJOB}}-manual-$ts. Tail with: just logs" # Pause the schedule (e.g. while debugging or doing a one-off pass) suspend: diff --git a/f3s/beets-art/helm-chart/templates/cronjob.yaml b/f3s/beets-art/helm-chart/templates/cronjob.yaml index 6f969e9..fb37a7e 100644 --- a/f3s/beets-art/helm-chart/templates/cronjob.yaml +++ b/f3s/beets-art/helm-chart/templates/cronjob.yaml @@ -50,11 +50,14 @@ spec: image: lscr.io/linuxserver/beets:latest imagePullPolicy: IfNotPresent env: - # Tell beets to read config from the ConfigMap mount instead - # of its default ~/.config/beets, so the PVC only stores - # mutable state (library.db, logs). + # BEETSDIR must be writable: beets stores its incremental + # import state (state.pickle) there alongside the config. + # The ConfigMap mount at /etc/beets is read-only (kernel- + # enforced for ConfigMap volumes), so point BEETSDIR at the + # state PVC and pass `-c` on each command to load the + # ConfigMap-supplied config.yaml. - name: BEETSDIR - value: /etc/beets + value: /state # Override the linuxserver s6 entrypoint; we just need the # `beet` CLI for a one-shot job. Running as root (the image # default when s6 is bypassed) so we can write into the NFS @@ -65,20 +68,23 @@ spec: set -u echo "=== $(date -u) beets-art sweep starting ===" + CONF=/etc/beets/config.yaml + BEET="beet -c $CONF" + # 1. Register any new albums. -A skips autotag (we trust # the existing tags); auto fetchart/embedart fire here # for newly imported albums via config. echo "--- import (incremental) ---" - beet import -A -q --quiet-fallback=asis /music || \ + $BEET import -A -q --quiet-fallback=asis /music || \ echo "import returned non-zero (continuing)" # 2. Backfill external cover.jpg for albums missing it. echo "--- fetchart (backfill) ---" - beet fetchart || echo "fetchart returned non-zero (continuing)" + $BEET fetchart || echo "fetchart returned non-zero (continuing)" # 3. Embed art into audio files where missing. echo "--- embedart (backfill) ---" - beet embedart || echo "embedart returned non-zero (continuing)" + $BEET embedart || echo "embedart returned non-zero (continuing)" echo "=== $(date -u) beets-art sweep finished ===" volumeMounts: -- cgit v1.2.3