diff --git a/charts/nextcloud-mcp-server/CHANGELOG.md b/charts/nextcloud-mcp-server/CHANGELOG.md index db28458..c8a4243 100644 --- a/charts/nextcloud-mcp-server/CHANGELOG.md +++ b/charts/nextcloud-mcp-server/CHANGELOG.md @@ -14,6 +14,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Configurable resource limits - Grafana dashboard annotations +## [Unreleased] + +### Fixed +- **volumes**: Fix /app/data not writable in basic auth mode due to readOnlyRootFilesystem security context + - Always mount /app/data (uses emptyDir by default, PVC when dataStorage.enabled=true) + - Resolves conflict where multi-user-basic and qdrant tried to mount different PVCs to same path + - Unified dataStorage configuration for all /app/data persistence needs + +### Changed +- **volumes**: Deprecated separate token-storage and qdrant-data PVCs in favor of unified data-storage PVC +- **volumes**: /app/data now always writable regardless of auth mode or features enabled + ## nextcloud-mcp-server-0.57.26 (2026-01-31) ## nextcloud-mcp-server-0.57.25 (2026-01-31) diff --git a/charts/nextcloud-mcp-server/README.md b/charts/nextcloud-mcp-server/README.md index 486f711..477ae9c 100644 --- a/charts/nextcloud-mcp-server/README.md +++ b/charts/nextcloud-mcp-server/README.md @@ -118,6 +118,25 @@ ingress: | `auth.oauth.persistence.enabled` | Enable persistent storage for OAuth | `true` | | `auth.oauth.persistence.size` | Size of OAuth storage PVC | `100Mi` | +#### Data Storage + +The `/app/data` directory is used for application data (token databases, Qdrant persistent storage, etc.). It is always mounted as writable to support the read-only root filesystem security context. + +| Parameter | Description | Default | +|-----------|-------------|---------| +| `dataStorage.enabled` | Enable persistent storage for `/app/data` | `false` | +| `dataStorage.size` | Size of data storage PVC | `1Gi` | +| `dataStorage.storageClass` | Storage class (leave empty for default) | `""` | +| `dataStorage.accessMode` | Access mode | `ReadWriteOnce` | +| `dataStorage.existingClaim` | Use existing PVC | `""` | + +**When to enable persistence:** +- Multi-user basic auth with offline access (stores `tokens.db`) +- Qdrant persistent mode (stores vector database) +- Any feature requiring persistent app data + +**When persistence is disabled:** Uses `emptyDir` (non-persistent, data lost on pod restart, but directory remains writable). + #### MCP Server Configuration | Parameter | Description | Default | diff --git a/charts/nextcloud-mcp-server/templates/_helpers.tpl b/charts/nextcloud-mcp-server/templates/_helpers.tpl index 1dcf194..60680cd 100644 --- a/charts/nextcloud-mcp-server/templates/_helpers.tpl +++ b/charts/nextcloud-mcp-server/templates/_helpers.tpl @@ -127,6 +127,17 @@ Create the name of the PVC to use for Qdrant local persistent storage {{- end }} {{- end }} +{{/* +Create the name of the PVC to use for /app/data storage +*/}} +{{- define "nextcloud-mcp-server.dataStoragePvcName" -}} +{{- if .Values.dataStorage.existingClaim }} +{{- .Values.dataStorage.existingClaim }} +{{- else }} +{{- include "nextcloud-mcp-server.fullname" . }}-data-storage +{{- end }} +{{- end }} + {{/* Return the MCP server port */}} diff --git a/charts/nextcloud-mcp-server/templates/deployment.yaml b/charts/nextcloud-mcp-server/templates/deployment.yaml index 4808f25..884384c 100644 --- a/charts/nextcloud-mcp-server/templates/deployment.yaml +++ b/charts/nextcloud-mcp-server/templates/deployment.yaml @@ -286,14 +286,8 @@ spec: - name: oauth-storage mountPath: /app/.oauth {{- end }} - {{- if and (eq .Values.auth.mode "multi-user-basic") .Values.auth.multiUserBasic.enableOfflineAccess .Values.auth.multiUserBasic.persistence.enabled }} - - name: token-storage + - name: data-storage mountPath: /app/data - {{- end }} - {{- if and (eq .Values.qdrant.mode "persistent") .Values.qdrant.localPersistence.enabled }} - - name: qdrant-data - mountPath: /app/data - {{- end }} {{- with .Values.volumeMounts }} {{- toYaml . | nindent 12 }} {{- end }} @@ -305,15 +299,12 @@ spec: persistentVolumeClaim: claimName: {{ include "nextcloud-mcp-server.oauthPvcName" . }} {{- end }} - {{- if and (eq .Values.auth.mode "multi-user-basic") .Values.auth.multiUserBasic.enableOfflineAccess .Values.auth.multiUserBasic.persistence.enabled }} - - name: token-storage + - name: data-storage + {{- if .Values.dataStorage.enabled }} persistentVolumeClaim: - claimName: {{ include "nextcloud-mcp-server.multiUserBasicPvcName" . }} - {{- end }} - {{- if and (eq .Values.qdrant.mode "persistent") .Values.qdrant.localPersistence.enabled }} - - name: qdrant-data - persistentVolumeClaim: - claimName: {{ include "nextcloud-mcp-server.qdrantPvcName" . }} + claimName: {{ include "nextcloud-mcp-server.dataStoragePvcName" . }} + {{- else }} + emptyDir: {} {{- end }} {{- with .Values.volumes }} {{- toYaml . | nindent 8 }} diff --git a/charts/nextcloud-mcp-server/templates/pvc.yaml b/charts/nextcloud-mcp-server/templates/pvc.yaml index f65a100..aa19990 100644 --- a/charts/nextcloud-mcp-server/templates/pvc.yaml +++ b/charts/nextcloud-mcp-server/templates/pvc.yaml @@ -16,38 +16,20 @@ spec: storage: {{ .Values.auth.oauth.persistence.size }} {{- end }} --- -{{- if and (eq .Values.auth.mode "multi-user-basic") .Values.auth.multiUserBasic.enableOfflineAccess .Values.auth.multiUserBasic.persistence.enabled (not .Values.auth.multiUserBasic.persistence.existingClaim) }} +{{- if and .Values.dataStorage.enabled (not .Values.dataStorage.existingClaim) }} apiVersion: v1 kind: PersistentVolumeClaim metadata: - name: {{ include "nextcloud-mcp-server.fullname" . }}-token-storage + name: {{ include "nextcloud-mcp-server.fullname" . }}-data-storage labels: {{- include "nextcloud-mcp-server.labels" . | nindent 4 }} spec: accessModes: - - {{ .Values.auth.multiUserBasic.persistence.accessMode }} - {{- if .Values.auth.multiUserBasic.persistence.storageClass }} - storageClassName: {{ .Values.auth.multiUserBasic.persistence.storageClass }} + - {{ .Values.dataStorage.accessMode }} + {{- if .Values.dataStorage.storageClass }} + storageClassName: {{ .Values.dataStorage.storageClass }} {{- end }} resources: requests: - storage: {{ .Values.auth.multiUserBasic.persistence.size }} -{{- end }} ---- -{{- if and (eq .Values.qdrant.mode "persistent") .Values.qdrant.localPersistence.enabled (not .Values.qdrant.localPersistence.existingClaim) }} -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: {{ include "nextcloud-mcp-server.fullname" . }}-qdrant-data - labels: - {{- include "nextcloud-mcp-server.labels" . | nindent 4 }} -spec: - accessModes: - - {{ .Values.qdrant.localPersistence.accessMode }} - {{- if .Values.qdrant.localPersistence.storageClass }} - storageClassName: {{ .Values.qdrant.localPersistence.storageClass }} - {{- end }} - resources: - requests: - storage: {{ .Values.qdrant.localPersistence.size }} + storage: {{ .Values.dataStorage.size }} {{- end }} diff --git a/charts/nextcloud-mcp-server/values.yaml b/charts/nextcloud-mcp-server/values.yaml index f624493..7b46811 100644 --- a/charts/nextcloud-mcp-server/values.yaml +++ b/charts/nextcloud-mcp-server/values.yaml @@ -139,6 +139,27 @@ auth: # Use existing PVC existingClaim: "" +# Data Storage Configuration +# Persistent volume for /app/data directory +# Used for: token databases, qdrant persistent storage, and any app data +# When disabled, uses emptyDir (non-persistent, but still writable) +dataStorage: + # Enable persistent storage for /app/data + # Set to true when using: + # - Multi-user basic auth with offline access (stores tokens.db) + # - Qdrant persistent mode (stores vector database) + # - Any feature requiring persistent app data + # Set to false for basic auth without persistence (uses emptyDir) + enabled: false + # Storage class (leave empty for default) + storageClass: "" + accessMode: ReadWriteOnce + # Size for data storage (should accommodate tokens.db and/or qdrant data) + # Recommended: 1Gi minimum, 5Gi for production with qdrant + size: 1Gi + # Use existing PVC + existingClaim: "" + # MCP server configuration mcp: # Transport mode (default: streamable-http for SSE)