diff --git a/paperless-ngx/.helmignore b/paperless-ngx/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/paperless-ngx/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/paperless-ngx/Chart.yaml b/paperless-ngx/Chart.yaml new file mode 100644 index 0000000..eea96d6 --- /dev/null +++ b/paperless-ngx/Chart.yaml @@ -0,0 +1,12 @@ +apiVersion: v2 +name: paperless-ngx +description: A Helm chart to deploy Paperless-NGX on Kubernetes + +type: application + +version: 4.4.0+up2.20.6 + +appVersion: 2.20.6 + +maintainers: + - name: jklein \ No newline at end of file diff --git a/paperless-ngx/templates/db-connection.secret.yaml b/paperless-ngx/templates/db-connection.secret.yaml new file mode 100644 index 0000000..9157a32 --- /dev/null +++ b/paperless-ngx/templates/db-connection.secret.yaml @@ -0,0 +1,6 @@ +apiVersion: onepassword.com/v1 +kind: OnePasswordItem +metadata: + name: {{ .Release.Name }}-{{ .Chart.Name }}-db-secret +spec: + itemPath: {{ required "A secret-reference for the DB-Secret must be provided" .Values.secrets.databaseRef }} diff --git a/paperless-ngx/templates/paperless-consume.cronjob.yaml b/paperless-ngx/templates/paperless-consume.cronjob.yaml new file mode 100644 index 0000000..a449204 --- /dev/null +++ b/paperless-ngx/templates/paperless-consume.cronjob.yaml @@ -0,0 +1,35 @@ +{{- if .Values.smbConnection.enabled }} +apiVersion: batch/v1 +kind: CronJob +metadata: + name: {{ .Release.Name }}-{{ .Chart.Name }}-consume-cronjob +spec: + schedule: {{ .Values.smbConnection.cronJob }} + jobTemplate: + spec: + template: + spec: + containers: + - name: paperless-consume-cronjob + image: busybox:1.28 + imagePullPolicy: IfNotPresent + command: + - /bin/sh + - -c + - if [ "$(find /mnt/smb -maxdepth 1 -name "*.pdf" -print)" ]; then mv /mnt/smb/*.pdf /mnt/consume; fi + volumeMounts: + - name: smb-share + mountPath: "/mnt/smb" + readOnly: false + - name: consume-folder + mountPath: "/mnt/consume" + readOnly: false + restartPolicy: Never + volumes: + - name: smb-share + persistentVolumeClaim: + claimName: {{ .Release.Name }}-{{ .Chart.Name }}-smb-volume-claim + - name: consume-folder + persistentVolumeClaim: + claimName: {{ .Release.Name }}-{{ .Chart.Name }}-consume-volume-claim +{{- end }} \ No newline at end of file diff --git a/paperless-ngx/templates/paperless-consume.pvc.yaml b/paperless-ngx/templates/paperless-consume.pvc.yaml new file mode 100644 index 0000000..3e03ccc --- /dev/null +++ b/paperless-ngx/templates/paperless-consume.pvc.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ .Release.Name }}-{{ .Chart.Name }}-consume-volume-claim +spec: + accessModes: + - ReadWriteMany + resources: + requests: + storage: 1Gi + storageClassName: longhorn \ No newline at end of file diff --git a/paperless-ngx/templates/paperless-server.secret.yaml b/paperless-ngx/templates/paperless-server.secret.yaml new file mode 100644 index 0000000..919c485 --- /dev/null +++ b/paperless-ngx/templates/paperless-server.secret.yaml @@ -0,0 +1,6 @@ +apiVersion: onepassword.com/v1 +kind: OnePasswordItem +metadata: + name: {{ .Release.Name }}-{{ .Chart.Name }}-secret +spec: + itemPath: {{ required "A secret-reference for the Paperless-Secret must be provided" .Values.secrets.paperlessRef }} diff --git a/paperless-ngx/templates/paperless-server.sfs.yaml b/paperless-ngx/templates/paperless-server.sfs.yaml new file mode 100644 index 0000000..238ac3a --- /dev/null +++ b/paperless-ngx/templates/paperless-server.sfs.yaml @@ -0,0 +1,190 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: {{ .Release.Name }}-{{ .Chart.Name }}-sfs + labels: + app: {{ .Release.Name }}-{{ .Chart.Name }}-sfs +spec: + replicas: 1 + serviceName: {{ .Release.Name }}-{{ .Chart.Name }}-service + selector: + matchLabels: + app: {{ .Release.Name }}-{{ .Chart.Name }}-sfs + template: + metadata: + name: {{ .Release.Name }}-{{ .Chart.Name }}-sfs + labels: + app: {{ .Release.Name }}-{{ .Chart.Name }}-sfs + spec: + automountServiceAccountToken: false + containers: + - name: {{ .Release.Name }}-{{ .Chart.Name }}-sfs + image: "ghcr.io/paperless-ngx/paperless-ngx:{{ .Chart.AppVersion }}" + imagePullPolicy: IfNotPresent + ports: + - containerPort: 8000 + protocol: TCP + name: paperless-port + env: + - name: PAPERLESS_REDIS + valueFrom: + secretKeyRef: + name: {{ .Release.Name }}-{{ .Chart.Name }}-redis-secret + key: redis-connection-url + - name: PAPERLESS_REDIS_PREFIX + valueFrom: + secretKeyRef: + name: {{ .Release.Name }}-{{ .Chart.Name }}-redis-secret + key: key-prefix + - name: PAPERLESS_DBENGINE + value: "postgresql" + - name: PAPERLESS_DBHOST + valueFrom: + secretKeyRef: + name: {{ .Release.Name }}-{{ .Chart.Name }}-db-secret + key: server + - name: PAPERLESS_DBPORT + valueFrom: + secretKeyRef: + name: {{ .Release.Name }}-{{ .Chart.Name }}-db-secret + key: port + - name: PAPERLESS_DBNAME + valueFrom: + secretKeyRef: + name: {{ .Release.Name }}-{{ .Chart.Name }}-db-secret + key: database + - name: PAPERLESS_DBUSER + valueFrom: + secretKeyRef: + name: {{ .Release.Name }}-{{ .Chart.Name }}-db-secret + key: username + - name: PAPERLESS_DBPASS + valueFrom: + secretKeyRef: + name: {{ .Release.Name }}-{{ .Chart.Name }}-db-secret + key: password + - name: PAPERLESS_ADMIN_USER + valueFrom: + secretKeyRef: + name: {{ .Release.Name }}-{{ .Chart.Name }}-secret + key: username + - name: PAPERLESS_ADMIN_MAIL + valueFrom: + secretKeyRef: + name: {{ .Release.Name }}-{{ .Chart.Name }}-secret + key: username + - name: PAPERLESS_ADMIN_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Release.Name }}-{{ .Chart.Name }}-secret + key: password + - name: PAPERLESS_SECRET_KEY + valueFrom: + secretKeyRef: + name: {{ .Release.Name }}-{{ .Chart.Name }}-secret + key: paperless-secret-key + - name: PAPERLESS_OCR_LANGUAGE + value: "{{ .Values.paperless.ocr.languages }}" + - name: PAPERLESS_OCR_MODE + value: "{{ .Values.paperless.ocr.mode }}" + - name: PAPERLESS_OCR_ROTATE_PAGES + value: "{{ .Values.paperless.ocr.rotate_pages }}" + - name: PAPERLESS_OCR_OUTPUT_TYPE + value: "{{ .Values.paperless.ocr.output_type }}" + - name: PAPERLESS_FILENAME_FORMAT + value: "{{ .Values.paperless.files.filenameFormat }}" + - name: PAPERLESS_URL + value: "https://{{ .Values.ingress.domain }}" + - name: PAPERLESS_CONSUMER_ENABLE_ASN_BARCODE + value: "{{ .Values.paperless.files.barcodes.asn.enabled }}" + - name: PAPERLESS_CONSUMER_ENABLE_BARCODES + value: "{{ .Values.paperless.files.barcodes.enabled }}" + - name: PAPERLESS_CONSUMER_BARCODE_STRING + value: "{{ .Values.paperless.files.barcodes.barcodeString }}" + - name: PAPERLESS_CONSUMER_BARCODE_RETAIN_SPLIT_PAGES + value: "{{ .Values.paperless.files.barcodes.retainBarcodePage }}" + - name: PAPERLESS_CONSUMER_BARCODE_SCANNER + value: "{{ .Values.paperless.files.barcodes.scanner }}" + {{- if .Values.paperless.files.tikaGotenberg.enabled }} + - name: PAPERLESS_TIKA_ENABLED + value: "{{ .Values.paperless.files.tikaGotenberg.enabled }}" + - name: PAPERLESS_TIKA_ENDPOINT + value: "http://{{ required "If Tika is enabled, a Tika-Endpoint must be provided" .Values.paperless.files.tikaGotenberg.tikaEndpoint }}" + - name: PAPERLESS_TIKA_GOTENBERG_ENDPOINT + value: "http://{{ required "If Tika is enabled, a Gotenberg-Endpoint must be provided" .Values.paperless.files.tikaGotenberg.gotenbergEndpoint }}" + {{- end }} + {{- if .Values.oidc.enabled }} + - name: PAPERLESS_APPS + value: "allauth.socialaccount.providers.openid_connect" + - name: PAPERLESS_SOCIALACCOUNT_PROVIDERS + value: |- + { + "openid_connect": { + "OAUTH_PKCE_ENABLED": true, + "APPS": [ + { + "provider_id": "{{ required "A OIDC-provider-id must be provided" .Values.oidc.provider.id }}", + "name": "{{ required "A OIDC-provider-name must be provided" .Values.oidc.provider.name }}", + "client_id": "{{ required "A OIDC-client-id must be provided" .Values.oidc.provider.clientId }}", + "settings": { + "fetch_userinfo": true, + "oauth_pkce_enabled": true, + "server_url": "{{ required "A OIDC-discovery-document-url must be provided" .Values.oidc.provider.discoveryUrl }}", + "uid_field": "sub" + } + } + ] + } + } + - name: PAPERLESS_REDIRECT_LOGIN_TO_SSO + value: "{{ .Values.oidc.autoLoginWithProvider }}" + - name: PAPERLESS_DISABLE_REGULAR_LOGIN + value: "{{ .Values.oidc.disableRegularLogin }}" + {{- end }} + volumeMounts: + - mountPath: "/usr/src/paperless/data" + name: "paperless-volume" + subPath: data/ + - mountPath: "/usr/src/paperless/media" + name: "paperless-volume" + subPath: media/ + - mountPath: "/usr/src/paperless/export" + name: "paperless-volume" + subPath: export/ + - mountPath: "/usr/src/paperless/consume" + name: "paperless-consume-volume" + resources: + requests: + memory: "{{ .Values.paperless.resources.requests.memory }}" + cpu: "{{ .Values.paperless.resources.requests.cpu }}" + ephemeral-storage: "{{ .Values.paperless.resources.requests.ephemeralStorage }}" + limits: + memory: "{{ .Values.paperless.resources.limits.memory }}" + cpu: "{{ .Values.paperless.resources.limits.cpu }}" + ephemeral-storage: "{{ .Values.paperless.resources.limits.ephemeralStorage }}" + readinessProbe: + httpGet: + path: / + port: 8000 + initialDelaySeconds: 30 + periodSeconds: 10 + failureThreshold: 3 + successThreshold: 1 + timeoutSeconds: 5 + livenessProbe: + httpGet: + path: / + port: 8000 + initialDelaySeconds: 90 + periodSeconds: 30 + failureThreshold: 3 + successThreshold: 1 + timeoutSeconds: 5 + restartPolicy: Always + volumes: + - name: paperless-volume + persistentVolumeClaim: + claimName: {{ .Release.Name }}-{{ .Chart.Name }}-volume-claim + - name: paperless-consume-volume + persistentVolumeClaim: + claimName: {{ .Release.Name }}-{{ .Chart.Name }}-consume-volume-claim \ No newline at end of file diff --git a/paperless-ngx/templates/paperless-smb-connector.pv.yaml b/paperless-ngx/templates/paperless-smb-connector.pv.yaml new file mode 100644 index 0000000..834759b --- /dev/null +++ b/paperless-ngx/templates/paperless-smb-connector.pv.yaml @@ -0,0 +1,29 @@ +{{- if .Values.smbConnection.enabled }} +apiVersion: v1 +kind: PersistentVolume +metadata: + annotations: + pv.kubernetes.io/provisioned-by: smb.csi.k8s.io + name: {{ .Release.Name }}-{{ .Chart.Name }}-smb-pv + namespace: {{ .Release.Namespace }} +spec: + capacity: + storage: 1Gi + accessModes: + - ReadWriteMany + persistentVolumeReclaimPolicy: Retain + storageClassName: smb + mountOptions: + - dir_mode=0777 + - file_mode=0777 + csi: + driver: smb.csi.k8s.io + # volumeHandle format: {smb-server-address}#{sub-dir-name}#{share-name} + # make sure this value is unique for every share in the cluster + volumeHandle: "{{ .Values.smbConnection.server }}##" + volumeAttributes: + source: "//{{ .Values.smbConnection.server }}" + nodeStageSecretRef: + name: "{{ .Release.Name }}-{{ .Chart.Name }}-smb-secret" + namespace: {{ .Release.Namespace }} +{{- end }} \ No newline at end of file diff --git a/paperless-ngx/templates/paperless-smb-connector.pvc.yaml b/paperless-ngx/templates/paperless-smb-connector.pvc.yaml new file mode 100644 index 0000000..ab9361d --- /dev/null +++ b/paperless-ngx/templates/paperless-smb-connector.pvc.yaml @@ -0,0 +1,14 @@ +{{- if .Values.smbConnection.enabled }} +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ .Release.Name }}-{{ .Chart.Name }}-smb-volume-claim +spec: + accessModes: + - ReadWriteMany + resources: + requests: + storage: 1Gi + storageClassName: smb + volumeName: {{ .Release.Name }}-{{ .Chart.Name }}-smb-pv +{{- end }} diff --git a/paperless-ngx/templates/paperless-smb-connector.secret.yaml b/paperless-ngx/templates/paperless-smb-connector.secret.yaml new file mode 100644 index 0000000..4431c6d --- /dev/null +++ b/paperless-ngx/templates/paperless-smb-connector.secret.yaml @@ -0,0 +1,8 @@ +{{- if .Values.smbConnection.enabled }} +apiVersion: onepassword.com/v1 +kind: OnePasswordItem +metadata: + name: {{ .Release.Name }}-{{ .Chart.Name }}-smb-secret +spec: + itemPath: {{ required "A secret-reference for the SMB-Connection-Secret must be provided" .Values.secrets.smbConnectionSecretRef }} +{{- end }} \ No newline at end of file diff --git a/paperless-ngx/templates/paperless.ingress.yaml b/paperless-ngx/templates/paperless.ingress.yaml new file mode 100644 index 0000000..432cedd --- /dev/null +++ b/paperless-ngx/templates/paperless.ingress.yaml @@ -0,0 +1,25 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ .Release.Name }}-{{ .Chart.Name }}-ingress + annotations: + 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 }} +spec: + ingressClassName: nginx + rules: + - host: {{ required "A Domain/Host must be provided" .Values.ingress.domain }} + http: + paths: + - backend: + service: + name: {{ .Release.Name }}-{{ .Chart.Name }}-service + port: + name: pless-s-port + path: / + pathType: Prefix + tls: + - hosts: + - {{ required "A Domain/Host must be provided" .Values.ingress.domain }} + secretName: tls-{{ .Release.Name }}-{{ .Chart.Name }}-{{ .Values.ingress.domain }}-ingress \ No newline at end of file diff --git a/paperless-ngx/templates/paperless.pvc.yaml b/paperless-ngx/templates/paperless.pvc.yaml new file mode 100644 index 0000000..5c6607a --- /dev/null +++ b/paperless-ngx/templates/paperless.pvc.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ .Release.Name }}-{{ .Chart.Name }}-volume-claim +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: {{ .Values.paperless.files.storage }} + storageClassName: longhorn diff --git a/paperless-ngx/templates/paperless.service.yaml b/paperless-ngx/templates/paperless.service.yaml new file mode 100644 index 0000000..7daa4e2 --- /dev/null +++ b/paperless-ngx/templates/paperless.service.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Release.Name }}-{{ .Chart.Name }}-service +spec: + selector: + app: {{ .Release.Name }}-{{ .Chart.Name }}-sfs + ports: + - protocol: TCP + port: 80 + targetPort: paperless-port + name: pless-s-port + type: ClusterIP diff --git a/paperless-ngx/templates/pre-post-consumption-scripts.config-map.yaml b/paperless-ngx/templates/pre-post-consumption-scripts.config-map.yaml new file mode 100644 index 0000000..c6c3e08 --- /dev/null +++ b/paperless-ngx/templates/pre-post-consumption-scripts.config-map.yaml @@ -0,0 +1,53 @@ +{{- if false }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Release.Name }}-{{ .Chart.Name }}-pre-post-consumption-scripts +data: + pre-consume-script: |- + #!/bin/sh + set -x + + # Pre-Consumption Scripts: + {{- range $key, $value := .Values.paperless.scripts.preConsumptionScripts }} + /scripts/{{ $value }} + {{- end }} + + post-consume-script: |- + #!/bin/sh + set -x + + # Post-Consumption Scripts: + {{- range $key, $value := .Values.paperless.scripts.postConsumptionScripts }} + /scripts/{{ $value }} + {{- end }} + + remove-blank-lines: |- + #!/bin/bash + set -e -o pipefail + export LC_ALL=C + + #IN="$1" + IN="$DOCUMENT_WORKING_PATH" + + PAGES=$(pdfinfo "$IN" | grep ^Pages: | tr -dc '0-9') + THRESHOLD=0.002 + + non_blank() { + for i in $(seq 1 $PAGES) ; do + PERCENT=$(gs -o - -dFirstPage=${i} -dLastPage=${i} -sDEVICE=inkcov "${IN}" | grep CMYK | nawk 'BEGIN { sum=0; } {sum += $1 + $2 + $3 + $4;} END { printf "%.5f\n", sum } ') + if awk "BEGIN { exit !($PERCENT > $THRESHOLD) }"; then + echo $i + else + >&2 echo Color-sum is $PERCENT: will remove blank page $i of $IN + fi + done + } + + NON_BLANK=$(non_blank) + + if [ -n "$NON_BLANK" ]; then + NON_BLANK=$(echo $NON_BLANK | tr ' ' ",") + qpdf "$IN" --replace-input --pages . $NON_BLANK -- + fi + {{- end }} \ No newline at end of file diff --git a/paperless-ngx/templates/redis-connection.secret.yaml b/paperless-ngx/templates/redis-connection.secret.yaml new file mode 100644 index 0000000..04cfaae --- /dev/null +++ b/paperless-ngx/templates/redis-connection.secret.yaml @@ -0,0 +1,6 @@ +apiVersion: onepassword.com/v1 +kind: OnePasswordItem +metadata: + name: {{ .Release.Name }}-{{ .Chart.Name }}-redis-secret +spec: + itemPath: {{ required "A secret-reference for the Redis-Secret must be provided" .Values.secrets.redisRef }} diff --git a/paperless-ngx/values.yaml b/paperless-ngx/values.yaml new file mode 100644 index 0000000..11936b8 --- /dev/null +++ b/paperless-ngx/values.yaml @@ -0,0 +1,57 @@ +secrets: + redisRef: null + databaseRef: null + paperlessRef: null + smbConnectionSecretRef: null + oidcSecretRef: null + +ingress: + clusterIssuer: "letsencrypt-issuer" + domain: null + +paperless: + ocr: + languages: "eng" + mode: "skip" + rotate_pages: "true" + output_type: "pdfa" + files: + filenameFormat: "{{ created_year }}/{{ correspondent }}/{{ title }}" + storage: 20Gi + maxUploadFileSize: 10m + barcodes: + enabled: true + barcodeString: "PATCHT" + retainBarcodePage: false + asn: + enabled: true + scanner: PYZBAR + tikaGotenberg: + enabled: false + tikaEndpoint: null + gotenbergEndpoint: null + scripts: + postConsumptionScripts: [] + preConsumptionScripts: [] + resources: + requests: + cpu: 0.2 + memory: 1024Mi + ephemeralStorage: 200Mi + limits: + cpu: 1 + memory: 2048Mi + ephemeralStorage: 400Mi +smbConnection: + enabled: false + server: null + cronJob: "0 0,12 * * *" +oidc: + enabled: false + autoLoginWithProvider: false + disableRegularLogin: false + provider: + id: null + name: null + clientId: null + discoveryUrl: null