Comments that pointed at other YAML as `file.yaml:N` went stale on any edit above the cited line; three drift fixes had been merged by hand (REN-181). The cited block now carries `# anchor: <name>` and the comment cites `path.yaml#<name>`. - Sweep: all 32 line-number citations in YAML comments converted. Several were already stale at head and now point at the right block (see PR). Vendored files (Flux gotk-components, IMC CRD) get no anchor; those two citations name the object/schema path instead. - Guard: scripts/ci/yaml-citations.sh in ci-manifests-test.yml; fails on a line-number citation or a path#name whose file/anchor is gone. Self-test in ci-scripts-test.yml. - CONTRIBUTING.md: the convention in three lines. Comment-only under kubernetes/: every file parses to identical objects before and after, so Flux applies nothing and no ConfigMap data changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
228 lines
6.4 KiB
YAML
228 lines
6.4 KiB
YAML
# Lidarr as a read-mostly "what is missing" view over the Navidrome library.
|
|
# No download client or indexer is configured.
|
|
apiVersion: v1
|
|
kind: PersistentVolumeClaim
|
|
metadata:
|
|
name: lidarr-config
|
|
namespace: navidrome
|
|
annotations:
|
|
kustomize.toolkit.fluxcd.io/prune: disabled
|
|
spec:
|
|
accessModes:
|
|
- ReadWriteOnce
|
|
storageClassName: ceph-block
|
|
resources:
|
|
requests:
|
|
storage: 5Gi
|
|
---
|
|
# Applied on every pod start, before the root folder exists: no renames, no tag
|
|
# writes, no deletes. Adding /music as root folder starts Lidarr's library import.
|
|
apiVersion: v1
|
|
kind: ConfigMap
|
|
metadata:
|
|
name: lidarr-reconcile
|
|
namespace: navidrome
|
|
data:
|
|
# anchor: reconcile-script
|
|
reconcile.sh: |
|
|
set -eu
|
|
API=http://localhost:8686/api/v1
|
|
until curl -sf http://localhost:8686/ping >/dev/null; do sleep 5; done
|
|
KEY=$(sed -n 's:.*<ApiKey>\(.*\)</ApiKey>.*:\1:p' /config/config.xml)
|
|
if [ -z "$KEY" ]; then
|
|
echo "FATAL: no ApiKey in /config/config.xml" >&2
|
|
exit 1
|
|
fi
|
|
H="X-Api-Key: $KEY"
|
|
|
|
put() {
|
|
cur=$(curl -sf -H "$H" "$API/$1")
|
|
id=$(printf '%s' "$cur" | jq -r '.id')
|
|
printf '%s' "$cur" | jq -c "$2" \
|
|
| curl -sf -X PUT -H "$H" -H 'Content-Type: application/json' -d @- "$API/$1/$id" >/dev/null
|
|
echo "reconciled $1"
|
|
}
|
|
|
|
put config/naming '.renameTracks = false'
|
|
put config/metadataprovider '.writeAudioTags = "no" | .scrubAudioTags = false | .embedCoverArt = false'
|
|
put config/mediamanagement '.deleteEmptyFolders = false | .createEmptyArtistFolders = false
|
|
| .recycleBin = "" | .setPermissionsLinux = false | .importExtraFiles = false
|
|
| .skipFreeSpaceCheckWhenImporting = true'
|
|
|
|
roots=$(curl -sf -H "$H" "$API/rootfolder" | jq '[.[] | select(.path == "/music")] | length')
|
|
if [ "$roots" = "0" ]; then
|
|
qp=$(curl -sf -H "$H" "$API/qualityprofile" | jq '.[0].id')
|
|
mp=$(curl -sf -H "$H" "$API/metadataprofile" | jq '([.[] | select(.name == "Standard")][0].id) // .[0].id')
|
|
jq -nc --argjson qp "$qp" --argjson mp "$mp" '{
|
|
name: "Music", path: "/music",
|
|
defaultQualityProfileId: $qp, defaultMetadataProfileId: $mp,
|
|
defaultMonitorOption: "all", defaultNewItemMonitorOption: "all",
|
|
defaultTags: []
|
|
}' \
|
|
| curl -sf -X POST -H "$H" -H 'Content-Type: application/json' -d @- "$API/rootfolder" >/dev/null
|
|
echo "added root folder /music"
|
|
fi
|
|
|
|
echo "reconcile done"
|
|
while true; do sleep 3600; done
|
|
---
|
|
apiVersion: apps/v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: lidarr
|
|
namespace: navidrome
|
|
labels:
|
|
app.kubernetes.io/name: lidarr
|
|
spec:
|
|
replicas: 1
|
|
strategy:
|
|
type: Recreate
|
|
selector:
|
|
matchLabels:
|
|
app.kubernetes.io/name: lidarr
|
|
template:
|
|
metadata:
|
|
labels:
|
|
app.kubernetes.io/name: lidarr
|
|
spec:
|
|
enableServiceLinks: false
|
|
securityContext:
|
|
fsGroup: 1000
|
|
fsGroupChangePolicy: OnRootMismatch
|
|
seccompProfile:
|
|
type: RuntimeDefault
|
|
containers:
|
|
- name: lidarr
|
|
image: lscr.io/linuxserver/lidarr:3.1.0.4875-ls42 # {"$imagepolicy": "flux-system:lidarr"}
|
|
env:
|
|
- name: PUID
|
|
value: "1000"
|
|
- name: PGID
|
|
value: "1000"
|
|
- name: TZ
|
|
value: Europe/Berlin
|
|
# Identity is enforced by the lidarr-gate outpost.
|
|
- name: LIDARR__AUTH__METHOD
|
|
value: External
|
|
ports:
|
|
- name: http
|
|
containerPort: 8686
|
|
volumeMounts:
|
|
- name: config
|
|
mountPath: /config
|
|
- name: music
|
|
mountPath: /music
|
|
# anchor: kubelet-probes
|
|
livenessProbe:
|
|
httpGet:
|
|
path: /ping
|
|
port: http
|
|
initialDelaySeconds: 60
|
|
periodSeconds: 30
|
|
timeoutSeconds: 10
|
|
readinessProbe:
|
|
httpGet:
|
|
path: /ping
|
|
port: http
|
|
initialDelaySeconds: 20
|
|
periodSeconds: 10
|
|
timeoutSeconds: 5
|
|
resources:
|
|
requests:
|
|
cpu: 100m
|
|
memory: 512Mi
|
|
limits:
|
|
memory: 4Gi
|
|
securityContext:
|
|
runAsNonRoot: false
|
|
allowPrivilegeEscalation: true
|
|
capabilities:
|
|
drop: ["ALL"]
|
|
add: ["CHOWN", "DAC_OVERRIDE", "FOWNER", "SETGID", "SETUID"]
|
|
- name: reconcile
|
|
image: lscr.io/linuxserver/lidarr:3.1.0.4875-ls42 # {"$imagepolicy": "flux-system:lidarr"}
|
|
command: ["sh", "/scripts/reconcile.sh"]
|
|
volumeMounts:
|
|
- name: config
|
|
mountPath: /config
|
|
readOnly: true
|
|
- name: reconcile
|
|
mountPath: /scripts
|
|
readOnly: true
|
|
resources:
|
|
requests:
|
|
cpu: 10m
|
|
memory: 16Mi
|
|
limits:
|
|
memory: 64Mi
|
|
securityContext:
|
|
runAsNonRoot: true
|
|
runAsUser: 1000
|
|
runAsGroup: 1000
|
|
allowPrivilegeEscalation: false
|
|
capabilities:
|
|
drop: ["ALL"]
|
|
volumes:
|
|
- name: config
|
|
persistentVolumeClaim:
|
|
claimName: lidarr-config
|
|
- name: music
|
|
persistentVolumeClaim:
|
|
claimName: navidrome-music-bulk
|
|
- name: reconcile
|
|
configMap:
|
|
name: lidarr-reconcile
|
|
---
|
|
apiVersion: v1
|
|
kind: Service
|
|
metadata:
|
|
name: lidarr
|
|
namespace: navidrome
|
|
spec:
|
|
selector:
|
|
app.kubernetes.io/name: lidarr
|
|
ports:
|
|
- name: http
|
|
port: 80
|
|
targetPort: http
|
|
---
|
|
apiVersion: v1
|
|
kind: Service
|
|
metadata:
|
|
name: ak-outpost-lidarr-gate
|
|
namespace: navidrome
|
|
spec:
|
|
type: ExternalName
|
|
externalName: ak-outpost-lidarr-gate.authentik.svc.cluster.local
|
|
ports:
|
|
- port: 9000
|
|
targetPort: 9000
|
|
---
|
|
apiVersion: networking.k8s.io/v1
|
|
kind: Ingress
|
|
metadata:
|
|
name: lidarr
|
|
namespace: navidrome
|
|
labels:
|
|
dns.renner.uno/public: "true"
|
|
annotations:
|
|
cert-manager.io/cluster-issuer: letsencrypt-cluster
|
|
spec:
|
|
ingressClassName: traefik
|
|
rules:
|
|
- host: lidarr.renner.uno
|
|
http:
|
|
paths:
|
|
- path: /
|
|
pathType: Prefix
|
|
# anchor: lidarr-gate
|
|
backend:
|
|
service:
|
|
name: ak-outpost-lidarr-gate
|
|
port:
|
|
number: 9000
|
|
tls:
|
|
- secretName: lidarr-tls
|
|
hosts:
|
|
- lidarr.renner.uno
|