feat(paperless-ngx)!: quote every operator scalar, pin the consume mover, drop oidcSecretRef
Three issues on one chart, bundled because they share values.yaml, values.schema.json and the version line, and because the first half of #11 lives in the same template as #101. Gitea #11, first half: the consume CronJob's schedule was rendered bare, so a schedule in the commonest cron notation there is - a star, a slash, an interval - aborted the render with a YAML parse error pointing at the template while the operator's value appeared nowhere in the message. Quoting it in the values file does not help; Helm passes the content through. Reproduced before the fix, at the line the issue names, and fixed with | quote. Gitea #11, second half: secrets.oidcSecretRef is removed, values and schema both. No template ever read it, so no OnePasswordItem was created and nothing reached the pod - the quiet kind of defect that looks like successful configuration. It is not reimplemented, and the reason is in paperless: the whole OIDC configuration travels in one json environment variable with no _FILE variant, so a secretKeyRef cannot substitute a fragment into it. The operational question is answered by #83 - Keycloak marks a client public per client, so nothing forces a confidential one here. In the same breath, oidc.provider.tokenAuthMethod is restricted to "none". Its comment named client_secret_basic as the example, which asks the provider for an authentication this chart cannot perform: it configures no client secret and cannot. The two values read together looked like a working secret setup, and the symptom was a login dying at the callback with invalid_client. No live release sets it (measured against all three instances). Gitea #112 asked for an extraEnv and the chart already had the standard additive env block - the issue was measured against a deployed 12.2.0 and read only the top-level keys. What was actually broken is the block itself: it rendered its operand bare, so a "*"-leading value aborted the render and "true" or "0755" arrived as a bool or an integer, which the API server rejects after a green render. It is brought to the repository's documented quoted form (template-chart carries the rule), which is what makes an arbitrary PAPERLESS_* variable settable in practice. PAPERLESS_LOGGING_DIR is documented as the worked example, with the cross-reference it needs: the root cause is the NFS-exported RWX data volume in jk-cluster-config #360 and this does not fix it - it only moves the log off that volume. The two Ingress upload-size annotations had the same bare render and are quoted too. Gitea #101: the consume mover now runs on the node of the StatefulSet pod, via a required podAffinity on its label. It mounts the RWX consume volume, and Longhorn's CSI driver refuses that mount unless it finds a workload pod in Pending, so a mover on another node left the StatefulSet node's kubelet retrying every two minutes - 291 events in 10 hours in both releases with SMB on, none in the release without the CronJob. A static nodeSelector would be wrong because the StatefulSet pod is not pinned either, and preferred would reproduce the bug more rarely and harder to find. The cost of a required term is handled rather than left open: concurrencyPolicy: Forbid, a startingDeadlineSeconds that also keeps the controller away from its 100-missed-schedules stop, and an activeDeadlineSeconds that fails a job which cannot be placed instead of leaving one Pending pod per schedule. scaleDown already suspends the CronJob; what remains is paperless.replicas: 0 with SMB on, which now reports a bounded, visible failure. successfulJobsHistoryLimit is deliberately untouched: Longhorn's check asks for the existence of a Pending pod, not the absence of Succeeded ones, so those three pods are the error message's evidence and not its cause. Side defect fixed on the way: every read of smbConnection.cron dereferenced the block directly, so an override that had erased it aborted with a nil-pointer error naming an internal template path instead of falling back to the defaults this chart promises everywhere else. Measured on origin/main; all reads now go through a merged-defaults helper that preserves an explicit false. Major: a value is removed and fails the strict schema afterwards, and runtime placement changes. Fixes #11 Fixes #101 Fixes #112
This commit is contained in:
8 files changed
+427
-42
No files matched your search
@@ -5,7 +5,7 @@ icon: https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/dev/src-ui/s
|
|||||||
|
|
||||||
type: application
|
type: application
|
||||||
|
|
||||||
version: 12.3.0+up3.2.1
|
version: 13.0.0+up3.2.1
|
||||||
|
|
||||||
appVersion: 3.2.1
|
appVersion: 3.2.1
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,9 @@
|
|||||||
{{- $valkeySvc := printf "%s-valkey-service" .Release.Name -}}
|
{{- $valkeySvc := printf "%s-valkey-service" .Release.Name -}}
|
||||||
{{- $pre := default (list) $scripts.preConsumptionScripts -}}
|
{{- $pre := default (list) $scripts.preConsumptionScripts -}}
|
||||||
{{- $post := default (list) $scripts.postConsumptionScripts -}}
|
{{- $post := default (list) $scripts.postConsumptionScripts -}}
|
||||||
|
{{- $cron := fromYaml (include "paperless-ngx.cron.scheduling" .Values.smbConnection.cron) -}}
|
||||||
|
{{- $cronPinned := $cron.pinToServerNode -}}
|
||||||
|
{{- $cronDeadline := include "paperless-ngx.formatNumber" $cron.activeDeadlineSeconds -}}
|
||||||
{{- $httpRoute := .Values.httpRoute | default dict -}}
|
{{- $httpRoute := .Values.httpRoute | default dict -}}
|
||||||
{{- $hostnames := $httpRoute.hostnames | default list -}}
|
{{- $hostnames := $httpRoute.hostnames | default list -}}
|
||||||
{{- if not $hostnames -}}
|
{{- if not $hostnames -}}
|
||||||
@@ -184,15 +187,14 @@ WHAT THE 1PASSWORD ITEMS MUST CONTAIN
|
|||||||
here, so a wrong field name surfaces as a mount failure on the CronJob's
|
here, so a wrong field name surfaces as a mount failure on the CronJob's
|
||||||
pod — a describe on that pod, never a missing variable.
|
pod — a describe on that pod, never a missing variable.
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- if .Values.secrets.oidcSecretRef }}
|
{{- /*
|
||||||
|
The warning that used to stand here - "secrets.oidcSecretRef IS SET AND IS READ
|
||||||
secrets.oidcSecretRef IS SET AND IS READ BY NOTHING
|
BY NOTHING" - is gone with the value itself (13.0.0, Gitea #11). It cannot be
|
||||||
"{{ .Values.secrets.oidcSecretRef }}" — no template in this chart references
|
printed any more and would not be reached: the key is out of values.schema.json
|
||||||
that value. No OnePasswordItem is created for it and no Secret appears. The
|
too, so a release that still sets it fails BEFORE any template renders, with
|
||||||
OIDC client id travels as plain env from oidc.provider.clientId, and no
|
"additional properties 'oidcSecretRef' not allowed". The fix is to delete the
|
||||||
client secret is configured at all (see the OIDC section below). Whatever
|
key; values.yaml says why it is not coming back.
|
||||||
you put in that item has no effect on this release.
|
*/}}
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
CHANGING A SECRET'S CONTENT RESTARTS NOTHING
|
CHANGING A SECRET'S CONTENT RESTARTS NOTHING
|
||||||
Helm never sees the content of a OnePasswordItem, so it cannot hash it, and
|
Helm never sees the content of a OnePasswordItem, so it cannot hash it, and
|
||||||
@@ -340,12 +342,44 @@ HOW DOCUMENTS GET IN
|
|||||||
move, not a copy: once the job has run, the share no longer holds the file
|
move, not a copy: once the job has run, the share no longer holds the file
|
||||||
and the only copy is on the consume volume.
|
and the only copy is on the consume volume.
|
||||||
|
|
||||||
One thing to know before you edit that schedule: it is rendered into the
|
The schedule is quoted on the way into the manifest since 13.0.0, so any
|
||||||
manifest unquoted, so a schedule that STARTS with "*" ("*/15 * * * *")
|
cron notation works — one starting with "*" or an "@daily" macro included.
|
||||||
aborts the render with a YAML parse error on this template — YAML reads the
|
Before that such a schedule aborted the render with a YAML parse error
|
||||||
leading * as an alias. Quoting it in your values file does not help, the
|
pointing at the template, and the advice here was to avoid it; if you are
|
||||||
quotes are gone by then. Use an equivalent that starts with a digit
|
carrying a workaround schedule from that era ("5,20,35,50 * * * *" instead
|
||||||
("5,20,35,50 * * * *"); a "*" anywhere but in first position is fine.
|
of every 15 minutes), you can write what you meant now.
|
||||||
|
{{- if $cronPinned }}
|
||||||
|
|
||||||
|
PLACEMENT: the mover runs on the NODE OF THE STATEFULSET POD, via a
|
||||||
|
required podAffinity on its label (Gitea #101). Without that it lands
|
||||||
|
anywhere, and because it mounts the consume volume — RWX, from Longhorn —
|
||||||
|
the kubelet of the StatefulSet's node then retries the mount every two
|
||||||
|
minutes with "no Pending workload pods for volume ... to be mounted". It
|
||||||
|
was measured at 291 such events in 10 hours.
|
||||||
|
|
||||||
|
THE PRICE, and it is the one thing to know before scaling down: with no
|
||||||
|
StatefulSet pod the mover CANNOT BE SCHEDULED. scaleDown: true suspends
|
||||||
|
this CronJob outright, so that case is covered — but paperless.replicas: 0
|
||||||
|
with SMB still on is not, and there the job fails once per schedule after
|
||||||
|
activeDeadlineSeconds ({{ $cronDeadline }}s) with reason DeadlineExceeded. That is
|
||||||
|
deliberate: a bounded, visible failure rather than a Pending pod per
|
||||||
|
schedule that nobody sees. Switch smbConnection.cron.pinToServerNode to
|
||||||
|
false to go back to unpinned placement — and to the mount errors.
|
||||||
|
|
||||||
|
What the pinning does NOT fix: the consume volume stays RWX with a
|
||||||
|
share-manager behind it. Co-locating the two consumers removes the
|
||||||
|
cross-node mount, not the second consumer.
|
||||||
|
{{- else }}
|
||||||
|
|
||||||
|
PLACEMENT IS OFF (smbConnection.cron.pinToServerNode: false). The mover
|
||||||
|
will be scheduled wherever there is room, and when that is not the node of
|
||||||
|
the StatefulSet pod, Longhorn refuses to mount the shared RWX consume
|
||||||
|
volume there: the kubelet of the StatefulSet's node retries every two
|
||||||
|
minutes with "no Pending workload pods for volume ... to be mounted"
|
||||||
|
(Gitea #101, measured at 291 events in 10 hours). The errors stop when the
|
||||||
|
StatefulSet pod is deleted and comes back Pending, and return with the next
|
||||||
|
firing of this job.
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
The job has NO probes (the documented exception to the chart conventions),
|
The job has NO probes (the documented exception to the chart conventions),
|
||||||
and it cannot fail usefully either: with nothing to move it exits 0, which
|
and it cannot fail usefully either: with nothing to move it exits 0, which
|
||||||
@@ -432,8 +466,13 @@ OIDC IS ON, AND IT IS PKCE-ONLY
|
|||||||
{{- if not .Values.oidc.provider.tokenAuthMethod }}
|
{{- if not .Values.oidc.provider.tokenAuthMethod }}
|
||||||
|
|
||||||
oidc.provider.tokenAuthMethod is unset. Since the allauth update in 3.0 some
|
oidc.provider.tokenAuthMethod is unset. Since the allauth update in 3.0 some
|
||||||
providers need it spelled out (client_secret_basic); the symptom is a login
|
providers need it spelled out, and the symptom when they do is a login that
|
||||||
that dies at the callback with invalid_client.
|
dies at the callback with invalid_client. The only value this chart accepts is
|
||||||
|
"none" — it states the public client explicitly. A method that authenticates
|
||||||
|
WITH a client secret cannot work here and is rejected by the schema (13.0.0,
|
||||||
|
Gitea #11): this release configures no client secret and cannot, because
|
||||||
|
paperless reads the whole OIDC configuration out of one json environment
|
||||||
|
variable with no _FILE variant.
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- if or .Values.oidc.autoLoginWithProvider .Values.oidc.disableRegularLogin }}
|
{{- if or .Values.oidc.autoLoginWithProvider .Values.oidc.disableRegularLogin }}
|
||||||
|
|
||||||
@@ -453,6 +492,20 @@ paperless.scripts IS SET AND DOES NOTHING
|
|||||||
PAPERLESS_PRE_CONSUME_SCRIPT nor PAPERLESS_POST_CONSUME_SCRIPT is set on the
|
PAPERLESS_PRE_CONSUME_SCRIPT nor PAPERLESS_POST_CONSUME_SCRIPT is set on the
|
||||||
container. These values render no object and change no behaviour.
|
container. These values render no object and change no behaviour.
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
{{- if .Values.paperless.env }}
|
||||||
|
|
||||||
|
paperless.env ADDS {{ len .Values.paperless.env }} VARIABLE(S) — AND AN OVERRIDE ONLY BITES AT INSTALL
|
||||||
|
{{ range $i, $e := .Values.paperless.env }}{{ if $i }}, {{ end }}{{ $e.name }}{{ end }}
|
||||||
|
|
||||||
|
These are appended AFTER the variables the chart sets itself, so at INSTALL an
|
||||||
|
entry repeating one of those names wins. On an upgrade of an EXISTING release
|
||||||
|
the same entry is lost: Kubernetes merges env by name, the pair collapses to
|
||||||
|
the chart's own value, and helm upgrade still reports success. Read the value
|
||||||
|
back off the StatefulSet, never off the upgrade's exit code:
|
||||||
|
|
||||||
|
kubectl -n {{ .Release.Namespace }} get statefulset {{ .Release.Name }}-{{ .Chart.Name }}-sfs \
|
||||||
|
-o jsonpath='{.spec.template.spec.containers[0].env}'
|
||||||
|
{{- end }}
|
||||||
{{- if gt (int $replicas) 1 }}
|
{{- if gt (int $replicas) 1 }}
|
||||||
|
|
||||||
paperless.replicas IS {{ $replicas }} — EXPECT ONE POD TO WORK AND THE REST TO WAIT
|
paperless.replicas IS {{ $replicas }} — EXPECT ONE POD TO WORK AND THE REST TO WAIT
|
||||||
|
|||||||
@@ -340,3 +340,41 @@ The same three fallbacks for the SMB consume-mover CronJob. It has no probes
|
|||||||
{{- $merged := fromYaml (include "paperless-ngx.defaultedDict" (dict "defaults" $defaults "given" . "path" "smbConnection.cron.resources")) -}}
|
{{- $merged := fromYaml (include "paperless-ngx.defaultedDict" (dict "defaults" $defaults "given" . "path" "smbConnection.cron.resources")) -}}
|
||||||
{{- include "paperless-ngx.resources" $merged -}}
|
{{- include "paperless-ngx.resources" $merged -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
The whole smbConnection.cron block, merged onto its defaults (YAML; consume
|
||||||
|
with fromYaml).
|
||||||
|
|
||||||
|
Input: .Values.smbConnection.cron (may be nil, empty or partial).
|
||||||
|
|
||||||
|
WHY EVERY READ OF THAT BLOCK GOES THROUGH HERE. The CronJob template used to
|
||||||
|
dereference .Values.smbConnection.cron.<key> directly, so an override that had
|
||||||
|
erased the block - the leftover childless
|
||||||
|
|
||||||
|
cron:
|
||||||
|
|
||||||
|
that issue #61 is about - did not fall back to the defaults the way this chart
|
||||||
|
promises everywhere else. It aborted the render with
|
||||||
|
|
||||||
|
nil pointer evaluating interface {}.securityContext
|
||||||
|
|
||||||
|
naming an internal template path and neither the value nor the cause. Measured
|
||||||
|
on origin/main before 13.0.0, so this is a fix and not a precaution.
|
||||||
|
|
||||||
|
The scalar defaults below MUST stay in sync with the smbConnection.cron block
|
||||||
|
in values.yaml, which stays the documented, user-facing place for them; this
|
||||||
|
copy is only the fallback. The sub-blocks (securityContext, resources, env)
|
||||||
|
keep their own defaults in the helpers above and are only passed through here.
|
||||||
|
|
||||||
|
An explicit "pinToServerNode: false" survives this, which is the whole reason
|
||||||
|
it is not a "default true" pipe: sprig's default would read false as unset and
|
||||||
|
silently turn the pinning back on - the one value whose explicit false has to
|
||||||
|
be obeyed, since it exists to switch off a hard placement rule.
|
||||||
|
*/}}
|
||||||
|
{{- define "paperless-ngx.cron.scheduling" -}}
|
||||||
|
{{- $defaults := dict
|
||||||
|
"pinToServerNode" true
|
||||||
|
"startingDeadlineSeconds" 600
|
||||||
|
"activeDeadlineSeconds" 3600 -}}
|
||||||
|
{{- include "paperless-ngx.defaultedDict" (dict "defaults" $defaults "given" . "path" "smbConnection.cron") -}}
|
||||||
|
{{- end -}}
|
||||||
@@ -1,26 +1,165 @@
|
|||||||
{{- if .Values.smbConnection.enabled }}
|
{{- if .Values.smbConnection.enabled }}
|
||||||
|
{{- /*
|
||||||
|
The cron block, merged onto its defaults, so that an override which erased it
|
||||||
|
falls back instead of aborting with a nil-pointer error naming an internal
|
||||||
|
template path - which is what every direct .Values.smbConnection.cron.<key>
|
||||||
|
read did before 13.0.0. The helper carries the measurement.
|
||||||
|
*/}}
|
||||||
|
{{- $cron := fromYaml (include "paperless-ngx.cron.scheduling" .Values.smbConnection.cron) -}}
|
||||||
apiVersion: batch/v1
|
apiVersion: batch/v1
|
||||||
kind: CronJob
|
kind: CronJob
|
||||||
metadata:
|
metadata:
|
||||||
name: {{ .Release.Name }}-{{ .Chart.Name }}-consume-cronjob
|
name: {{ .Release.Name }}-{{ .Chart.Name }}-consume-cronjob
|
||||||
spec:
|
spec:
|
||||||
schedule: {{ .Values.smbConnection.cronJob }}
|
{{- /*
|
||||||
|
QUOTED, AND THAT IS THE WHOLE OF GITEA #11's FIRST HALF. The default
|
||||||
|
"0 0,12 * * *" renders safely only because it begins with a digit. The most
|
||||||
|
common cron notation of all - a star, a slash and an interval, every 15
|
||||||
|
minutes - begins with "*", which YAML reads as an alias indicator, and the
|
||||||
|
render ABORTS:
|
||||||
|
|
||||||
|
(and the notation cannot be written out in this comment, because the two
|
||||||
|
characters that start it would end a Go template comment right here)
|
||||||
|
|
||||||
|
Error: YAML parse error on paperless-ngx/templates/paperless-consume.cronjob.yaml:
|
||||||
|
error converting YAML to JSON: yaml: line 6: did not find expected
|
||||||
|
alphabetic or numeric character
|
||||||
|
|
||||||
|
The trap is that quoting it in the VALUES does not help: Helm passes the
|
||||||
|
string's content through, and the star stands bare in the manifest again. So
|
||||||
|
the operator writes a correctly quoted value and gets an error that points at
|
||||||
|
this template instead of at their value. "@daily" fails the same way ("@" is
|
||||||
|
a reserved YAML indicator).
|
||||||
|
|
||||||
|
ci/run-yaml-scalar-render-test.sh is the test that would have caught it, and
|
||||||
|
ci/yaml-scalar/paperless-ngx.yaml is the overlay that feeds it a star-leading
|
||||||
|
schedule - needed because this whole template sits behind
|
||||||
|
smbConnection.enabled, which is false in every other fixture, so nothing else
|
||||||
|
in the repository renders this object at all.
|
||||||
|
*/}}
|
||||||
|
schedule: {{ .Values.smbConnection.cronJob | quote }}
|
||||||
|
{{- /*
|
||||||
|
Forbid, hard-wired rather than a value: two movers running at once race on
|
||||||
|
the same files ("mv /mnt/smb/*.pdf" twice over one directory), and the loser
|
||||||
|
reports a file that is already gone. There is no configuration in which
|
||||||
|
overlapping runs of this job are wanted, so there is nothing to configure.
|
||||||
|
*/}}
|
||||||
|
concurrencyPolicy: Forbid
|
||||||
|
{{- /*
|
||||||
|
Bounds how late a missed run may still start, and it is here for a second
|
||||||
|
reason that has nothing to do with lateness: while the CronJob is suspended
|
||||||
|
(scaleDown) or its runs are being suppressed, the controller counts missed
|
||||||
|
schedules, and above 100 it STOPS SCHEDULING ALTOGETHER with only
|
||||||
|
"Cannot determine if job needs to be started: too many missed start times" in
|
||||||
|
the controller log. With this field set, the controller only counts misses
|
||||||
|
inside this window, so that state cannot be reached. The cost is stated in
|
||||||
|
values.yaml: a run that could not start inside the window is skipped, not
|
||||||
|
queued.
|
||||||
|
*/}}
|
||||||
|
startingDeadlineSeconds: {{ include "paperless-ngx.formatNumber" $cron.startingDeadlineSeconds }}
|
||||||
{{- if .Values.scaleDown }}
|
{{- if .Values.scaleDown }}
|
||||||
suspend: true
|
suspend: true
|
||||||
{{- end }}
|
{{- end }}
|
||||||
jobTemplate:
|
jobTemplate:
|
||||||
spec:
|
spec:
|
||||||
|
{{- /*
|
||||||
|
THE SAFETY NET UNDER THE AFFINITY BELOW (Gitea #101). activeDeadlineSeconds
|
||||||
|
counts from the job's start, not from the pod's, so it also bounds a pod
|
||||||
|
that NEVER gets scheduled: when the StatefulSet pod is absent and the
|
||||||
|
required affinity cannot be satisfied, the job fails after this many
|
||||||
|
seconds with reason DeadlineExceeded instead of sitting Pending forever
|
||||||
|
and gaining a sibling every schedule. That turns the one new failure mode
|
||||||
|
this issue's fix could introduce into a visible, self-clearing one -
|
||||||
|
failedJobsHistoryLimit (Kubernetes' default, 1) keeps the evidence.
|
||||||
|
*/}}
|
||||||
|
activeDeadlineSeconds: {{ include "paperless-ngx.formatNumber" $cron.activeDeadlineSeconds }}
|
||||||
template:
|
template:
|
||||||
spec:
|
spec:
|
||||||
|
{{- if $cron.pinToServerNode }}
|
||||||
|
{{- /*
|
||||||
|
GITEA #101: this pod mounts the consume volume, which is RWX and comes
|
||||||
|
from Longhorn. Without a placement rule the scheduler puts it on any
|
||||||
|
node, and Longhorn's CSI driver then refuses the mount on the node
|
||||||
|
where the StatefulSet pod runs:
|
||||||
|
|
||||||
|
MountVolume.SetUp failed ... code = Aborted desc = no Pending
|
||||||
|
workload pods for volume pvc-... to be mounted:
|
||||||
|
map[Running:[...-sfs-0] Succeeded:[...-consume-cronjob-...]]
|
||||||
|
|
||||||
|
Measured at every two minutes, 291 events in 10 hours, in both
|
||||||
|
releases that have SMB switched on; the release with
|
||||||
|
smbConnection.enabled: false and therefore no CronJob produced none of
|
||||||
|
them on identically built volumes.
|
||||||
|
|
||||||
|
WHY podAffinity AND NOT nodeSelector: the StatefulSet pod is not
|
||||||
|
pinned either - it sits wherever the scheduler put it and moves on
|
||||||
|
every restart. A static nodeSelector would be correct exactly until
|
||||||
|
then and silently wrong afterwards. The affinity follows the pod.
|
||||||
|
|
||||||
|
WHY required AND NOT preferred: preferred falls back to another node
|
||||||
|
in the very situation this exists for, which reproduces the bug more
|
||||||
|
rarely and therefore harder to find. The fallback is what went
|
||||||
|
unnoticed for ten hours.
|
||||||
|
|
||||||
|
The label is the one the StatefulSet puts on its pod template
|
||||||
|
(paperless-server.sfs.yaml, metadata.labels.app) and is read off the
|
||||||
|
running pod, not assumed.
|
||||||
|
|
||||||
|
WHAT THIS DOES NOT FIX: the volume stays RWX and keeps its
|
||||||
|
share-manager; co-locating the two consumers removes the CROSS-NODE
|
||||||
|
attach, not the second consumer. The design that removes it is moving
|
||||||
|
the mv into the StatefulSet pod, which cannot be done for the running
|
||||||
|
installations because RWX cannot be taken back off an existing PVC.
|
||||||
|
Gitea #101 names it as the alternative and not as the proposal.
|
||||||
|
*/}}
|
||||||
|
affinity:
|
||||||
|
podAffinity:
|
||||||
|
requiredDuringSchedulingIgnoredDuringExecution:
|
||||||
|
- labelSelector:
|
||||||
|
matchLabels:
|
||||||
|
app: {{ .Release.Name }}-{{ .Chart.Name }}-sfs
|
||||||
|
topologyKey: kubernetes.io/hostname
|
||||||
|
{{- end }}
|
||||||
automountServiceAccountToken: false
|
automountServiceAccountToken: false
|
||||||
securityContext:
|
securityContext:
|
||||||
{{- include "paperless-ngx.cron.podSecurityContext" .Values.smbConnection.cron.securityContext | nindent 12 }}
|
{{- include "paperless-ngx.cron.podSecurityContext" $cron.securityContext | nindent 12 }}
|
||||||
containers:
|
containers:
|
||||||
- name: paperless-consume-cronjob
|
- name: paperless-consume-cronjob
|
||||||
image: "{{ .Values.paperless.busybox.image.repository }}:{{ .Values.paperless.busybox.image.tag }}"
|
image: "{{ .Values.paperless.busybox.image.repository }}:{{ .Values.paperless.busybox.image.tag }}"
|
||||||
imagePullPolicy: IfNotPresent
|
imagePullPolicy: IfNotPresent
|
||||||
securityContext:
|
securityContext:
|
||||||
{{- include "paperless-ngx.cron.containerSecurityContext" .Values.smbConnection.cron.securityContext | nindent 16 }}
|
{{- include "paperless-ngx.cron.containerSecurityContext" $cron.securityContext | nindent 16 }}
|
||||||
|
{{- if $cron.env }}
|
||||||
|
env:
|
||||||
|
{{- range $value := $cron.env }}
|
||||||
|
{{- if $value.value }}
|
||||||
|
{{- /*
|
||||||
|
quote is required, not cosmetic: a value like "8080" or "true"
|
||||||
|
renders unquoted as a YAML number/bool, and the API server then
|
||||||
|
rejects the whole manifest with "cannot unmarshal number into
|
||||||
|
Go struct field EnvVar.value of type string". A template
|
||||||
|
comment and not a "#" one, because a "#" line here is part of
|
||||||
|
the rendered manifest.
|
||||||
|
*/}}
|
||||||
|
- name: {{ $value.name | quote }}
|
||||||
|
value: {{ tpl $value.value $ | quote }}
|
||||||
|
{{- else if $value.valueFrom }}
|
||||||
|
{{- if $value.valueFrom.secretKeyRef }}
|
||||||
|
- name: {{ $value.name }}
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ tpl $value.valueFrom.secretKeyRef.name $ | quote }}
|
||||||
|
key: {{ tpl $value.valueFrom.secretKeyRef.key $ | quote }}
|
||||||
|
{{- else if $value.valueFrom.configMapKeyRef }}
|
||||||
|
- name: {{ $value.name }}
|
||||||
|
valueFrom:
|
||||||
|
configMapKeyRef:
|
||||||
|
name: {{ tpl $value.valueFrom.configMapKeyRef.name $ | quote }}
|
||||||
|
key: {{ tpl $value.valueFrom.configMapKeyRef.key $ | quote }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
command:
|
command:
|
||||||
- /bin/sh
|
- /bin/sh
|
||||||
- -c
|
- -c
|
||||||
@@ -33,7 +172,7 @@ spec:
|
|||||||
mountPath: "/mnt/consume"
|
mountPath: "/mnt/consume"
|
||||||
readOnly: false
|
readOnly: false
|
||||||
resources:
|
resources:
|
||||||
{{- include "paperless-ngx.cron.effectiveResources" .Values.smbConnection.cron.resources | nindent 16 }}
|
{{- include "paperless-ngx.cron.effectiveResources" $cron.resources | nindent 16 }}
|
||||||
restartPolicy: Never
|
restartPolicy: Never
|
||||||
volumes:
|
volumes:
|
||||||
- name: smb-share
|
- name: smb-share
|
||||||
@@ -42,4 +181,4 @@ spec:
|
|||||||
- name: consume-folder
|
- name: consume-folder
|
||||||
persistentVolumeClaim:
|
persistentVolumeClaim:
|
||||||
claimName: {{ .Release.Name }}-{{ .Chart.Name }}-consume-volume-claim
|
claimName: {{ .Release.Name }}-{{ .Chart.Name }}-consume-volume-claim
|
||||||
{{- end }}
|
{{- end }}
|
||||||
@@ -204,23 +204,41 @@ spec:
|
|||||||
- name: PAPERLESS_DISABLE_REGULAR_LOGIN
|
- name: PAPERLESS_DISABLE_REGULAR_LOGIN
|
||||||
value: "{{ .Values.oidc.disableRegularLogin }}"
|
value: "{{ .Values.oidc.disableRegularLogin }}"
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
{{- /*
|
||||||
|
QUOTED SINCE 13.0.0, and it is a fix rather than a tidy-up (Gitea
|
||||||
|
#112, same genus as #11). This block is the chart's additive env
|
||||||
|
interface, and until 13.0.0 it rendered its operand bare. Two
|
||||||
|
measured consequences, both of them the operator's value arriving
|
||||||
|
as something else:
|
||||||
|
|
||||||
|
- a value beginning with "*" aborted the render, with the error
|
||||||
|
pointing at THIS template rather than at the value;
|
||||||
|
- "true" and "0755" rendered as a YAML bool and an integer, and
|
||||||
|
the API server rejects those with "cannot unmarshal number
|
||||||
|
into Go struct field EnvVar.value of type string" - the chart
|
||||||
|
renders, the install fails.
|
||||||
|
|
||||||
|
The quoted form is the repository's documented one
|
||||||
|
(template-chart/templates/xxx.deployment.yaml carries the rule);
|
||||||
|
this chart was one of seven that had not been brought to it.
|
||||||
|
*/}}
|
||||||
{{- range $value := .Values.paperless.env }}
|
{{- range $value := .Values.paperless.env }}
|
||||||
{{- if $value.value }}
|
{{- if $value.value }}
|
||||||
- name: {{ $value.name }}
|
- name: {{ $value.name | quote }}
|
||||||
value: {{ tpl $value.value $ }}
|
value: {{ tpl $value.value $ | quote }}
|
||||||
{{- else if $value.valueFrom }}
|
{{- else if $value.valueFrom }}
|
||||||
{{- if $value.valueFrom.secretKeyRef }}
|
{{- if $value.valueFrom.secretKeyRef }}
|
||||||
- name: {{ $value.name }}
|
- name: {{ $value.name }}
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
name: {{ tpl $value.valueFrom.secretKeyRef.name $ }}
|
name: {{ tpl $value.valueFrom.secretKeyRef.name $ | quote }}
|
||||||
key: {{ tpl $value.valueFrom.secretKeyRef.key $ }}
|
key: {{ tpl $value.valueFrom.secretKeyRef.key $ | quote }}
|
||||||
{{- else if $value.valueFrom.configMapKeyRef }}
|
{{- else if $value.valueFrom.configMapKeyRef }}
|
||||||
- name: {{ $value.name }}
|
- name: {{ $value.name }}
|
||||||
valueFrom:
|
valueFrom:
|
||||||
configMapKeyRef:
|
configMapKeyRef:
|
||||||
name: {{ tpl $value.valueFrom.configMapKeyRef.name $ }}
|
name: {{ tpl $value.valueFrom.configMapKeyRef.name $ | quote }}
|
||||||
key: {{ tpl $value.valueFrom.configMapKeyRef.key $ }}
|
key: {{ tpl $value.valueFrom.configMapKeyRef.key $ | quote }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|||||||
@@ -23,8 +23,16 @@ metadata:
|
|||||||
name: {{ .Release.Name }}-{{ .Chart.Name }}-ingress
|
name: {{ .Release.Name }}-{{ .Chart.Name }}-ingress
|
||||||
annotations:
|
annotations:
|
||||||
cert-manager.io/cluster-issuer: {{ required "A Cluster-Issuer must be provided" .Values.ingress.clusterIssuer }}
|
cert-manager.io/cluster-issuer: {{ required "A Cluster-Issuer must be provided" .Values.ingress.clusterIssuer }}
|
||||||
nginx.ingress.kubernetes.io/proxy-body-size: {{ .Values.paperless.files.maxUploadFileSize }}
|
{{- /*
|
||||||
nginx.org/client-max-body-size: {{ .Values.paperless.files.maxUploadFileSize }}
|
Quoted for the same reason as the env block in the StatefulSet and the
|
||||||
|
schedule in the CronJob (Gitea #11's genus): an annotation value must be a
|
||||||
|
string, maxUploadFileSize is free operator text, and a unit-less "100" -
|
||||||
|
schema-valid, since the schema types it as a string - renders bare as an
|
||||||
|
integer and the API server rejects the whole Ingress. The default "10m"
|
||||||
|
happens to be safe, which is exactly how this survived.
|
||||||
|
*/}}
|
||||||
|
nginx.ingress.kubernetes.io/proxy-body-size: {{ .Values.paperless.files.maxUploadFileSize | quote }}
|
||||||
|
nginx.org/client-max-body-size: {{ .Values.paperless.files.maxUploadFileSize | quote }}
|
||||||
{{- with .Values.ingress.annotations }}
|
{{- with .Values.ingress.annotations }}
|
||||||
{{- toYaml . | nindent 4 }}
|
{{- toYaml . | nindent 4 }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|||||||
@@ -69,9 +69,6 @@
|
|||||||
},
|
},
|
||||||
"smbConnectionSecretRef": {
|
"smbConnectionSecretRef": {
|
||||||
"type": ["string", "null"]
|
"type": ["string", "null"]
|
||||||
},
|
|
||||||
"oidcSecretRef": {
|
|
||||||
"type": ["string", "null"]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -279,13 +276,28 @@
|
|||||||
"type": ["string", "null"]
|
"type": ["string", "null"]
|
||||||
},
|
},
|
||||||
"cronJob": {
|
"cronJob": {
|
||||||
"description": "Cron schedule of the consume-mover job.",
|
"description": "Cron schedule of the consume-mover job. Deliberately without a pattern: cron syntax is richer than a regex here would admit, and the failure this value used to have was not a wrong schedule but a correct one rendered bare into the manifest - fixed at the render site with | quote (Gitea #11), not by narrowing what may be written.",
|
||||||
"type": ["string", "null"]
|
"type": ["string", "null"]
|
||||||
},
|
},
|
||||||
"cron": {
|
"cron": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"pinToServerNode": {
|
||||||
|
"description": "Place the consume-mover pod on the node that carries the StatefulSet pod, via a required podAffinity on its label (Gitea #101). Default true: the mover mounts the RWX consume volume, and Longhorn's CSI driver refuses that mount unless it finds a workload pod in Pending, so a mover on another node leaves the StatefulSet node's kubelet retrying every two minutes. false restores the unpinned behaviour and with it those mount errors.",
|
||||||
|
"type": ["boolean", "null"]
|
||||||
|
},
|
||||||
|
"startingDeadlineSeconds": {
|
||||||
|
"description": "How late a missed run may still start. Also bounds the CronJob controller's missed-schedule count, which above 100 stops this job being scheduled at all, reported only in the controller's own log.",
|
||||||
|
"type": ["integer", "null"]
|
||||||
|
},
|
||||||
|
"activeDeadlineSeconds": {
|
||||||
|
"description": "Hard stop for one mover run, counted from the job's start, so it also bounds a pod that never gets scheduled - with pinToServerNode on and no StatefulSet pod, the job fails with DeadlineExceeded instead of leaving a Pending pod per schedule.",
|
||||||
|
"type": ["integer", "null"]
|
||||||
|
},
|
||||||
|
"env": {
|
||||||
|
"$ref": "#/definitions/env"
|
||||||
|
},
|
||||||
"securityContext": {
|
"securityContext": {
|
||||||
"$ref": "#/definitions/securityContext"
|
"$ref": "#/definitions/securityContext"
|
||||||
},
|
},
|
||||||
@@ -326,8 +338,9 @@
|
|||||||
"type": ["string", "null"]
|
"type": ["string", "null"]
|
||||||
},
|
},
|
||||||
"tokenAuthMethod": {
|
"tokenAuthMethod": {
|
||||||
"description": "Explicit token endpoint auth method (e.g. client_secret_basic). Some providers need this since the allauth update in paperless-ngx 3.0.",
|
"description": "Explicit token endpoint auth method. Restricted to 'none' in 13.0.0 (Gitea #11): this chart registers a PUBLIC client with PKCE and configures no client secret, so a method that authenticates with one cannot work - it produced a login that died at the callback with invalid_client while reading like a working secret setup. null omits the key; 'none' states the public client explicitly, which some providers need spelled out since the allauth update in paperless-ngx 3.0.",
|
||||||
"type": ["string", "null"]
|
"type": ["string", "null"],
|
||||||
|
"enum": ["none", null]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+121
-5
@@ -13,7 +13,26 @@ secrets:
|
|||||||
databaseSecretRef: null
|
databaseSecretRef: null
|
||||||
paperlessSecretRef: null
|
paperlessSecretRef: null
|
||||||
smbConnectionSecretRef: null
|
smbConnectionSecretRef: null
|
||||||
oidcSecretRef: null
|
# REMOVED IN 13.0.0: secrets.oidcSecretRef (Gitea #11). It is gone from the
|
||||||
|
# schema too, so a release that still sets it now fails to render with
|
||||||
|
# additional properties 'oidcSecretRef' not allowed
|
||||||
|
# instead of being ignored - DELETE THE KEY from your values, nothing else is
|
||||||
|
# needed. It never did anything: no template read it, no OnePasswordItem was
|
||||||
|
# created for it, and whatever the item held never reached the pod.
|
||||||
|
#
|
||||||
|
# It is not coming back as a feature, and the reason is in paperless itself:
|
||||||
|
# the whole OIDC configuration travels in ONE json environment variable
|
||||||
|
# (SOCIALACCOUNT_PROVIDERS = json.loads(os.getenv(
|
||||||
|
# "PAPERLESS_SOCIALACCOUNT_PROVIDERS", "{}"))), and there is no _FILE variant
|
||||||
|
# of it. A secretKeyRef cannot substitute a fragment INTO a json variable, so
|
||||||
|
# an honest implementation would have to either inline the secret in the pod
|
||||||
|
# spec or push the complete json into the vault by hand - and the second one
|
||||||
|
# makes every required() in the oidc block below dead wood.
|
||||||
|
#
|
||||||
|
# The operational question behind it is answered rather than dodged: this
|
||||||
|
# chart registers a PUBLIC client with PKCE, Keycloak (Gitea #83) can mark a
|
||||||
|
# client public per client, and so no provider constraint forces a
|
||||||
|
# confidential client here. See the oidc block below.
|
||||||
|
|
||||||
ingress:
|
ingress:
|
||||||
# Set to false to omit the Ingress entirely. NEW in the chart version that
|
# Set to false to omit the Ingress entirely. NEW in the chart version that
|
||||||
@@ -179,7 +198,38 @@ paperless:
|
|||||||
timeoutSeconds: 5
|
timeoutSeconds: 5
|
||||||
# Extra environment variables, appended to the ones the chart always sets.
|
# Extra environment variables, appended to the ones the chart always sets.
|
||||||
# Values are rendered through tpl; value, secretKeyRef and configMapKeyRef
|
# Values are rendered through tpl; value, secretKeyRef and configMapKeyRef
|
||||||
# forms are supported.
|
# forms are supported. paperless-ngx reads around 80 PAPERLESS_* variables and
|
||||||
|
# this chart maps a handful of them explicitly - everything else goes here.
|
||||||
|
#
|
||||||
|
# env:
|
||||||
|
# - name: PAPERLESS_LOGGING_DIR
|
||||||
|
# value: /tmp/paperless-log
|
||||||
|
#
|
||||||
|
# ADDITIVE MEANS ADDITIVE, and the timing matters: an entry repeating a name
|
||||||
|
# the chart already sets reaches the pod twice, and at INSTALL the later one -
|
||||||
|
# yours - wins. On an EXISTING release the same entry is lost, because
|
||||||
|
# Kubernetes merges env by name and the pair collapses to the chart's own
|
||||||
|
# value, while helm upgrade still reports success. Read an override back off
|
||||||
|
# the StatefulSet, never off the upgrade's exit code.
|
||||||
|
#
|
||||||
|
# VALUES MUST BE STRINGS (the schema enforces it) and they are quoted on the
|
||||||
|
# way out since 13.0.0. Before that a value beginning with "*" aborted the
|
||||||
|
# render and "true" or "0755" arrived as a bool or an integer, which the API
|
||||||
|
# server rejects - see the comment at the render site in
|
||||||
|
# templates/paperless-server.sfs.yaml.
|
||||||
|
#
|
||||||
|
# THE WORKED EXAMPLE, PAPERLESS_LOGGING_DIR, AND WHAT IT DOES NOT FIX
|
||||||
|
# (jk-cluster-config #360): with the data directory on an RWX volume that
|
||||||
|
# Longhorn exports over NFS, paperless' concurrent_log_handler cannot hold its
|
||||||
|
# lock file there and fails with "RuntimeError: Cannot acquire lock after 20
|
||||||
|
# attempts" - measured at 45 % of the application log across all three
|
||||||
|
# installations. Pointing PAPERLESS_LOGGING_DIR at a path under the /tmp
|
||||||
|
# emptyDir this pod already mounts takes the log off the NFS share and the
|
||||||
|
# noise stops. It does NOT fix the RWX data volume, which is the actual root
|
||||||
|
# cause and a cluster-config decision (the PVC asks for ReadWriteOnce and was
|
||||||
|
# provisioned ReadWriteMany; taking RWX back means recreating the volume).
|
||||||
|
# A log under /tmp does not survive a pod restart - no loss here, paperless
|
||||||
|
# also writes to stdout, which is what kubectl logs reads.
|
||||||
env: []
|
env: []
|
||||||
resources:
|
resources:
|
||||||
# Limits are optional: memory and ephemeral-storage limits default to
|
# Limits are optional: memory and ephemeral-storage limits default to
|
||||||
@@ -214,8 +264,58 @@ paperless:
|
|||||||
smbConnection:
|
smbConnection:
|
||||||
enabled: false
|
enabled: false
|
||||||
server: null
|
server: null
|
||||||
|
# Cron schedule of the consume mover. Quote it or not as you like - the chart
|
||||||
|
# quotes it on the way into the manifest (since 13.0.0, Gitea #11), which is
|
||||||
|
# what a schedule beginning with "*" or "@" needs. Before that such a
|
||||||
|
# schedule aborted the render with a YAML error pointing at the template.
|
||||||
cronJob: "0 0,12 * * *"
|
cronJob: "0 0,12 * * *"
|
||||||
cron:
|
cron:
|
||||||
|
# Run the mover on the node that carries the StatefulSet pod (Gitea #101).
|
||||||
|
#
|
||||||
|
# WHY IT DEFAULTS TO TRUE: this pod mounts the consume volume, which is RWX
|
||||||
|
# and comes from Longhorn, and Longhorn's CSI driver refuses to mount an RWX
|
||||||
|
# volume unless it finds a workload pod in Pending - a mover pod that ran on
|
||||||
|
# a different node leaves the kubelet of the StatefulSet's node retrying
|
||||||
|
# every two minutes with "no Pending workload pods for volume ... to be
|
||||||
|
# mounted" (291 events in 10 hours, in both releases with SMB on; the
|
||||||
|
# release without the CronJob produced none).
|
||||||
|
#
|
||||||
|
# It is a switch and not a free-form affinity block on purpose: the default
|
||||||
|
# has to name the StatefulSet pod's label, that label contains the RELEASE
|
||||||
|
# NAME, and a values.yaml is never templated - so the useful default cannot
|
||||||
|
# be expressed here at all (the same property that forces
|
||||||
|
# valkey.secrets.authSecretRef to be typed out twice, further down).
|
||||||
|
#
|
||||||
|
# WHAT IT COSTS, AND IT IS A REAL COST: the affinity is required, so with
|
||||||
|
# the StatefulSet pod absent the mover cannot be scheduled. The two ways
|
||||||
|
# that happens are handled rather than left open - scaleDown: true suspends
|
||||||
|
# this CronJob outright, and activeDeadlineSeconds below fails a job that
|
||||||
|
# cannot be placed instead of letting Pending pods pile up. What stays: with
|
||||||
|
# paperless.replicas: 0 and SMB on, the mover does not run and reports one
|
||||||
|
# failed job per schedule. Set this to false to get the old, unpinned
|
||||||
|
# behaviour back - including the mount errors.
|
||||||
|
pinToServerNode: true
|
||||||
|
# How late a missed run may still start. Also keeps the CronJob controller
|
||||||
|
# from reaching "too many missed start times (> 100)", after which it stops
|
||||||
|
# scheduling this job entirely and says so only in its own log - reachable
|
||||||
|
# by leaving scaleDown: true in place for months. The cost of a window: a
|
||||||
|
# run that could not start inside it is skipped, not queued. Must stay well
|
||||||
|
# above 10s, below which the controller may never schedule at all.
|
||||||
|
startingDeadlineSeconds: 600
|
||||||
|
# Hard stop for one mover run, counted from the job's start - so it also
|
||||||
|
# bounds a pod that never gets scheduled (see pinToServerNode). Exceeding it
|
||||||
|
# shows up as a job with reason DeadlineExceeded, which is the point: a
|
||||||
|
# loud, self-clearing failure instead of a Pending pod that nobody sees.
|
||||||
|
# Raise it if a run legitimately moves more than an hour's worth of files;
|
||||||
|
# the mover copies across filesystems, so large scans are not instant.
|
||||||
|
activeDeadlineSeconds: 3600
|
||||||
|
# Extra environment variables for the mover container, same form as
|
||||||
|
# paperless.env above. Deliberately empty: the container is a busybox
|
||||||
|
# running one mv, so this exists for the odd proxy or locale variable and
|
||||||
|
# for the convention that every workload container offers the block - not
|
||||||
|
# because the mover needs configuration. Note that the cron SCHEDULE's time
|
||||||
|
# zone is the controller's and cannot be changed with a TZ entry here.
|
||||||
|
env: []
|
||||||
# The consume mover only shuffles files between the SMB share (mounted
|
# The consume mover only shuffles files between the SMB share (mounted
|
||||||
# with 0777 modes) and the consume PVC, so it runs as the same non-root
|
# with 0777 modes) and the consume PVC, so it runs as the same non-root
|
||||||
# uid/gid as paperless itself with a fully hardened context.
|
# uid/gid as paperless itself with a fully hardened context.
|
||||||
@@ -251,9 +351,25 @@ oidc:
|
|||||||
name: null
|
name: null
|
||||||
clientId: null
|
clientId: null
|
||||||
discoveryUrl: null
|
discoveryUrl: null
|
||||||
# Optional: explicit token endpoint auth method (e.g. client_secret_basic).
|
# Optional: explicit token endpoint auth method. "none" is the only accepted
|
||||||
# Some providers need this since the allauth update in paperless-ngx 3.0
|
# value, and the schema enforces that (Gitea #11).
|
||||||
# (login fails at the callback with invalid_client otherwise).
|
#
|
||||||
|
# WHY IT IS RESTRICTED, since the previous comment here named
|
||||||
|
# client_secret_basic as the example and that was actively misleading: this
|
||||||
|
# chart registers a PUBLIC client and configures NO client secret - it
|
||||||
|
# renders OAUTH_PKCE_ENABLED and nothing else, and secrets.oidcSecretRef was
|
||||||
|
# removed in 13.0.0 because no secret can reach paperless through a json
|
||||||
|
# environment variable anyway. A method that authenticates WITH a client
|
||||||
|
# secret therefore cannot work here; asking for one produced a login that
|
||||||
|
# died at the callback with invalid_client, while the two values read
|
||||||
|
# together looked like a working secret setup.
|
||||||
|
#
|
||||||
|
# So: null omits the key and lets allauth decide, "none" states the public
|
||||||
|
# client explicitly - which is what some providers need spelled out since
|
||||||
|
# the allauth update in paperless-ngx 3.0, and the symptom when they do is
|
||||||
|
# that same invalid_client at the callback. If a future paperless release
|
||||||
|
# supports an auth method that needs no secret, widening the enum is a minor
|
||||||
|
# bump; allowing one that needs a secret is not on the table.
|
||||||
tokenAuthMethod: null
|
tokenAuthMethod: null
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|||||||
Reference in new issue
Block a user