# Storage certification job. # # A PersistentVolumeClaim is not a filesystem contract. Whether an atomic rename, a same-file-store # guarantee, or symlink refusal actually holds depends on the CSI driver, the StorageClass, the # access mode, the backend, and the mount options — so this job records all five alongside the probe # result. A certification without that tuple is not transferable to another cluster. # # The job writes a machine-readable result to the claim itself so the evidence lives with the volume # it describes. # # kubectl apply -f infra/fileserver/kubernetes/pvc-certification-job.yaml # kubectl logs job/fileserver-pvc-certification --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: fileserver-certification labels: app.kubernetes.io/name: fileserver app.kubernetes.io/component: certification spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi # Left unset on purpose: the certification is only meaningful for the class it actually ran on, # so the operator names it explicitly rather than inheriting a cluster default. storageClassName: "" --- apiVersion: batch/v1 kind: Job metadata: name: fileserver-pvc-certification labels: app.kubernetes.io/name: fileserver app.kubernetes.io/component: certification spec: backoffLimit: 0 template: metadata: labels: app.kubernetes.io/name: fileserver app.kubernetes.io/component: certification spec: restartPolicy: Never securityContext: runAsNonRoot: true runAsUser: 10001 fsGroup: 10001 containers: - name: certify image: eclipse-temurin:21-jdk env: - name: FILESERVER_STORAGE_ROOT value: /var/lib/backend/files - name: KUBERNETES_VERSION valueFrom: fieldRef: fieldPath: metadata.annotations['certification.fileserver/kubernetes-version'] - name: CSI_DRIVER valueFrom: fieldRef: fieldPath: metadata.annotations['certification.fileserver/csi-driver'] - name: STORAGE_CLASS valueFrom: fieldRef: fieldPath: metadata.annotations['certification.fileserver/storage-class'] - name: ACCESS_MODE value: ReadWriteOnce command: - /bin/bash - -c - | set -euo pipefail ROOT="${FILESERVER_STORAGE_ROOT}" mkdir -p "${ROOT}/staging" "${ROOT}/content" # Atomic rename within one file store is the property the publish path depends on. echo probe > "${ROOT}/staging/probe" if mv "${ROOT}/staging/probe" "${ROOT}/content/probe" 2>/dev/null; then ATOMIC_MOVE=true else ATOMIC_MOVE=false fi # Same device means a rename is a metadata operation rather than a copy. STAGING_DEV=$(stat -c %d "${ROOT}/staging") CONTENT_DEV=$(stat -c %d "${ROOT}/content") [ "${STAGING_DEV}" = "${CONTENT_DEV}" ] && SAME_STORE=true || SAME_STORE=false # O_EXCL create is what makes a publish create-only rather than an overwrite. if (set -o noclobber; echo x > "${ROOT}/content/excl") 2>/dev/null; then ATOMIC_CREATE=true else ATOMIC_CREATE=false fi cat > "${ROOT}/certification-result.json" <