Files
home-network-k3s-impl/decisions/2026-10-01-arr-to-plex.md
T
jakman85 8a094c46f7
gate / gate (pull_request) Successful in 1m41s
gate / conformance (pull_request) Has been skipped
Added decision record for allowing arr apps to connect to plex
2026-10-01 23:09:08 -05:00

6.2 KiB

date, branch, title
date branch title
2026-10-01 bugfix/arr-to-plex Radarr and Sonarr may now reach Plex on 32400 — the network path only, not the Plex connection itself

What changed

Radarr and Sonarr had no route to Plex. The media library lives on NFS (/mnt/Storage/plex, the ZFS dataset Storage/plex on ${BULK_NFS_SERVER}), and NFS does not deliver filesystem CRUD notifications, so Plex never learns that an arr has written a new file. Without a push from the arrs, the library only reflects new media when somebody scans it by hand. That is the bug this branch addresses.

The fix is one dependencies: entry per app, added to the catalog — the source of truth:

- to: plex
  port: 32400
  protocol: tcp

in both catalog/radarr.yaml and catalog/sonarr.yaml (these two are the arr suite here; jackett, qbittorrent and seerr are different roles and are untouched).

The renderer expands each entry into a pair of Cilium policies, which is why a three-line catalog change produces 88 lines under apps/:

Side Policy File
egress radarr-allow-plex-32400 apps/wave-1/radarr.yaml
egress sonarr-allow-plex-32400 apps/wave-1/sonarr.yaml
reciprocal ingress plex-allow-radarr-32400 apps/wave-0/plex.yaml
reciprocal ingress plex-allow-sonarr-32400 apps/wave-0/plex.yaml

Three commits, and the middle two are worth recording because both were self-inflicted gate failures rather than design changes:

  • 753c48b — the catalog edit alone, with apps/ left unrendered.
  • 9048c2f — re-rendered apps/ from the catalog, which render==golden requires.
  • 58f02fe — removed 20 trailing spaces on catalog/radarr.yaml:103, left behind as comment-alignment padding when the comment moved down to the port: line. Sonarr's equivalent line kept its comment in place, which is why only radarr tripped.

What I verified

The lint failure, root-caused. Gate run 193 on 9048c2f failed with [fail] lint: FAILED -> blocks merge, and lint was the only failing stage. yamllint emitted 419 findings, but 418 were line-length, which ci/yamllint.yaml pins at level: warning and which therefore cannot change the exit code. The single error-level finding in the entire repository was:

catalog/radarr.yaml
  103:13    error    trailing spaces  (trailing-spaces)

trailing-spaces inherits the default severity (error), so that one line returned rc 1. After the fix, git grep -nIE ' +$' -- '*.yaml' '*.yml' matches nothing repo-wide.

Gate run 195 on 58f02fe (read from the job log, not from the status tick):

[ ok ] approval-policy: green     [ ok ] l0: green
[ ok ] gitea-settings: green      [ ok ] render-golden: green
[ ok ] decisions-log: green       [ ok ] l1: green
[ ok ] lint: green
[fail] MERGE GATE: UNDETERMINED — greenness was NOT ESTABLISHED.
[fail]   Stages that did not run: spec-immutability

The Gitea check reports success / "Successful in 1m41s", but the gate's own verdict is UNDETERMINED (rc 3), not PASS. That tick is gate.yml tolerating exit 3 for the one stage it documents as unverifiable on this runner (the spec repo is not checked out there). Nothing else produced a 3.

render==golden green on 58f02fe, so apps/ is a faithful canonical render of catalog/ — the four generated policies are not hand-written drift.

DNS egress was already open and is not a new gap: apps/wave-1/radarr.yaml carries an existing allow for port 53 UDP+TCP, so resolving the Plex service name does not need anything added here.

Live branch protection on main, measured against /api/v1/repos/Home-Network/home-network-k3s-impl/branches/main rather than assumed: protected: true, user_can_push: false, enable_status_check: true, status_check_contexts: ['gate / gate (pull_request)'], required_approvals: 1.

What I did NOT verify

This change does not accomplish what the PR set out to do. It opens the network path and nothing else. Triggering a library update also requires each arr's Settings → Connect → Plex Media Server entry plus a Plex token, and none of that exists anywhere in catalog/ or apps/ — I grepped both for plex, token and connect and found only NFS paths, a uid and a timezone. Radarr's and Sonarr's config lives on a 5Gi Longhorn PVC mounted at /config, so that connection is UI-only state that exists solely on the PVC and never in git, in the same way Crafty's local login does. Until somebody adds it in each app's UI, Plex still will not see library updates, and this branch will look like it did nothing. That follow-up is not tracked by any file in this PR.

L2/L3 conformance never ran. CLUSTER_AVAILABLE is unset on the runner, so the eight requirements this diff touches — R-NET-01, R-NET-05, R-NET-06, R-NET-07, R-IDP-02, R-IDP-06, R-GITOPS-02, R-PLAT-02 — are UNVERIFIED. That gap is unusually load-bearing here: the entire substance of this change is four CiliumNetworkPolicies, and no test has confirmed that traffic from the radarr or sonarr namespaces actually reaches plex:32400. The green gate proves the offline render subset only.

spec-immutability did not run (R-TEST-06 not verified), for the documented reason — the sibling spec repo is absent from the runner.

Nothing was checked on the cluster. I ran no kubectl, so I did not confirm that the plex Service exposes 32400 as the arrs would address it, that the pod labels the policies select (app.kubernetes.io/name, k8s:io.kubernetes.pod.namespace) match the running pods, or that Cilium accepted the four new objects. Flux has not applied any of this: the branch is unmerged, so .status.lastAppliedRevision does not contain it.

I did not verify Plex's own side — whether its library-update endpoint on 32400 is the right target for the arrs' notification, or whether Plex requires "Update my library automatically" enabled to act on one.

I am not the approver and did not approve this PR. required_approvals: 1 is live, and the only credential on the authoring workstation belongs to the PR's author (jakman85), whose own review Gitea does not count. Per CLAUDE.md §1 the merge is a human action regardless.