diff --git a/helm/README.md b/helm/README.md index d73e7a4e8..6dffc1d73 100644 --- a/helm/README.md +++ b/helm/README.md @@ -56,6 +56,8 @@ RustFS helm chart supports **standalone and distributed mode**. For standalone m | config.rustfs.kms.vault.vault_mount_path | string | `"transit"`| The vault mount path, only works if `vault_backend` equals `vault-transit` . | | config.rustfs.kms.vault.default_key | string | `"transit"`| The master key id for RustFS. | | extraEnv | map | `[]` | Extra environment variables for RustFS container. | +| extraVolumes | list | `[]` | Extra volumes to add to the pod spec. Supported in both standalone (Deployment) and distributed (StatefulSet) modes. | +| extraVolumeMounts | list | `[]` | Extra volume mounts to add to the RustFS container. Supported in both standalone (Deployment) and distributed (StatefulSet) modes. | | containerSecurityContext.capabilities.drop[0] | string | `"ALL"` | | | containerSecurityContext.readOnlyRootFilesystem | bool | `true` | | | containerSecurityContext.runAsNonRoot | bool | `true` | | diff --git a/helm/rustfs/templates/deployment.yaml b/helm/rustfs/templates/deployment.yaml index e872989be..dfa27ac60 100644 --- a/helm/rustfs/templates/deployment.yaml +++ b/helm/rustfs/templates/deployment.yaml @@ -127,12 +127,18 @@ spec: mountPath: /opt/tls/client_ca.crt subPath: client_ca.crt {{- end }} + {{- with .Values.extraVolumeMounts }} + {{- toYaml . | nindent 12 }} + {{- end }} - name: logs mountPath: {{ $logDir }} subPath: logs - name: data mountPath: /data volumes: + {{- with .Values.extraVolumes }} + {{- toYaml . | nindent 8 }} + {{- end }} {{- if .Values.mtls.enabled }} - name: server-cert secret: diff --git a/helm/rustfs/templates/statefulset.yaml b/helm/rustfs/templates/statefulset.yaml index b8a59fc32..bd8d900d7 100644 --- a/helm/rustfs/templates/statefulset.yaml +++ b/helm/rustfs/templates/statefulset.yaml @@ -141,6 +141,9 @@ spec: mountPath: /opt/tls/ca.crt subPath: ca.crt {{- end }} + {{- with .Values.extraVolumeMounts }} + {{- toYaml . | nindent 12 }} + {{- end }} - name: logs mountPath: {{ $logDir }} subPath: logs @@ -153,8 +156,9 @@ spec: - name: data mountPath: /data {{- end }} - {{- if .Values.mtls.enabled }} + {{- if or .Values.mtls.enabled .Values.extraVolumes }} volumes: + {{- if .Values.mtls.enabled }} - name: server-cert secret: secretName: rustfs-server-tls @@ -175,6 +179,10 @@ spec: path: client_key.pem - key: ca.crt path: client_ca.crt + {{- end }} + {{- with .Values.extraVolumes }} + {{- toYaml . | nindent 8 }} + {{- end }} {{- end }} volumeClaimTemplates: - metadata: diff --git a/helm/rustfs/values.yaml b/helm/rustfs/values.yaml index 740e71ca4..691ab1059 100644 --- a/helm/rustfs/values.yaml +++ b/helm/rustfs/values.yaml @@ -130,6 +130,9 @@ extraEnv: [] # This is for setting extra environment variables in the rustfs con # value: "EC:4" +extraVolumes: [] +extraVolumeMounts: [] + # This section builds out the service account more information can be found here: https://kubernetes.io/docs/concepts/security/service-accounts/ serviceAccount: # Specifies whether a service account should be created diff --git a/scripts/test_helm_templates.sh b/scripts/test_helm_templates.sh index b9b0edde8..6fdd5bd7d 100755 --- a/scripts/test_helm_templates.sh +++ b/scripts/test_helm_templates.sh @@ -23,6 +23,19 @@ render_standalone_deployment() { ' } +render_distributed_statefulset() { + helm template rustfs "$CHART_DIR" \ + --namespace rustfs \ + --set secret.rustfs.access_key=test-access-key \ + --set secret.rustfs.secret_key=test-secret-key \ + "$@" | + awk ' + /^# Source: rustfs\/templates\/statefulset.yaml$/ { in_statefulset = 1 } + in_statefulset && /^---$/ { exit } + in_statefulset { print } + ' +} + recreate_output=$(render_standalone_deployment --set mode.standalone.strategy.type=Recreate) grep -q "type: Recreate" <<<"$recreate_output" if grep -q "rollingUpdate:" <<<"$recreate_output"; then @@ -118,3 +131,61 @@ if [[ $partial_empty_status -eq 0 ]]; then echo "Partial-empty credentials (only access_key set) must fail rendering" >&2 exit 1 fi + +command -v yq >/dev/null 2>&1 || { echo "yq is required for extra-volumes structural tests" >&2; exit 1; } + +# Structural helpers: verify wiring at the right YAML paths, not just string presence. +assert_extra_volumes_wired() { + local output="$1" label="$2" + + if ! yq eval '.spec.template.spec.volumes[].name' - <<<"$output" | grep -q "^ca-bundle$"; then + echo "ca-bundle not found in spec.template.spec.volumes of $label" >&2 + exit 1 + fi + + local mount_path + mount_path=$(yq eval '.spec.template.spec.containers[0].volumeMounts[] | select(.name == "ca-bundle") | .mountPath' - <<<"$output") + if [[ "$mount_path" != "/etc/ssl/certs/ca.crt" ]]; then + echo "ca-bundle mountPath in containers[0] is '$mount_path', expected /etc/ssl/certs/ca.crt in $label" >&2 + exit 1 + fi + + if yq eval '.spec.template.spec.initContainers[].volumeMounts[].name' - <<<"$output" | grep -q "^ca-bundle$"; then + echo "ca-bundle must not appear in initContainers volumeMounts of $label" >&2 + exit 1 + fi +} + +assert_extra_volumes_absent() { + local output="$1" label="$2" + if yq eval '.spec.template.spec.volumes[].name' - <<<"$output" | grep -q "^ca-bundle$"; then + echo "ca-bundle must not appear in spec.template.spec.volumes of $label with empty extraVolumes" >&2 + exit 1 + fi +} + +# extraVolumes/extraVolumeMounts: structural placement in standalone Deployment. +standalone_extra_output=$(render_standalone_deployment \ + --set 'extraVolumes[0].name=ca-bundle' \ + --set 'extraVolumes[0].configMap.name=ca-bundle' \ + --set 'extraVolumeMounts[0].name=ca-bundle' \ + --set 'extraVolumeMounts[0].mountPath=/etc/ssl/certs/ca.crt' \ + --set 'extraVolumeMounts[0].subPath=ca.crt') +assert_extra_volumes_wired "$standalone_extra_output" "standalone Deployment" + +# Empty extraVolumes must not inject ca-bundle into standalone Deployment volumes. +standalone_default_output=$(render_standalone_deployment) +assert_extra_volumes_absent "$standalone_default_output" "standalone Deployment" + +# extraVolumes/extraVolumeMounts: structural placement in distributed StatefulSet. +distributed_extra_output=$(render_distributed_statefulset \ + --set 'extraVolumes[0].name=ca-bundle' \ + --set 'extraVolumes[0].configMap.name=ca-bundle' \ + --set 'extraVolumeMounts[0].name=ca-bundle' \ + --set 'extraVolumeMounts[0].mountPath=/etc/ssl/certs/ca.crt' \ + --set 'extraVolumeMounts[0].subPath=ca.crt') +assert_extra_volumes_wired "$distributed_extra_output" "distributed StatefulSet" + +# Empty extraVolumes must not inject ca-bundle into distributed StatefulSet volumes. +distributed_default_output=$(render_distributed_statefulset) +assert_extra_volumes_absent "$distributed_default_output" "distributed StatefulSet"