From eb0718f442e3196640b101f7277e36165f05855a Mon Sep 17 00:00:00 2001 From: Niels de Vos Date: Tue, 14 Jun 2022 11:19:57 +0200 Subject: [PATCH] reclaimspace: detect Kubernetes version for right StagingTargetPath Kubernetes 1.24 and newer use a different path for staging the volume. That means the CSI-driver is requested to mount the volume at an other location, compared to previous versions of Kubernetes. CSI-drivers implementing the CSI-Addons NodeReclaimSpace procedure, must receive the correct path, otherwise the driver will not be able to free space and possibly return an error. See-also: kubernetes/kubernetes#107065 See-also: https://bugzilla.redhat.com/2096209 Signed-off-by: Niels de Vos --- internal/sidecar/service/reclaimspace.go | 44 +++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/internal/sidecar/service/reclaimspace.go b/internal/sidecar/service/reclaimspace.go index 6fd3a6fc5..9313a766d 100644 --- a/internal/sidecar/service/reclaimspace.go +++ b/internal/sidecar/service/reclaimspace.go @@ -17,7 +17,10 @@ package service import ( "context" + "crypto/sha256" + "fmt" "path/filepath" + "strconv" kube "github.com/csi-addons/kubernetes-csi-addons/internal/kubernetes" "github.com/csi-addons/kubernetes-csi-addons/internal/proto" @@ -140,7 +143,13 @@ func (rs *ReclaimSpaceServer) NodeReclaimSpace( klog.Errorf("Failed to map access mode: %v", err) return nil, status.Error(codes.InvalidArgument, err.Error()) } - stPath := filepath.Join(rs.stagingPath, "pv", pvName, "globalmount") + + stPath, err := rs.getStagingTargetPath(pv) + if err != nil { + klog.Errorf("Failed to get staging target path: %v", err) + return nil, status.Error(codes.Internal, err.Error()) + } + accessType := csi.VolumeCapability_Mount{ Mount: &csi.VolumeCapability_MountVolume{}, } @@ -189,3 +198,36 @@ func (rs *ReclaimSpaceServer) NodeReclaimSpace( return res, nil } + +// getStagingTargetPath returns the path where the volume is expected to be +// mounted (or the block-device is attached/mapped). Different Kubernetes +// version use different paths. +func (rs *ReclaimSpaceServer) getStagingTargetPath(pv *corev1.PersistentVolume) (string, error) { + // Kubernetes 1.24+ uses a hash of the volume-id in the path name + unique := sha256.Sum256([]byte(pv.Spec.CSI.VolumeHandle)) + targetPath := filepath.Join(rs.stagingPath, pv.Spec.CSI.Driver, fmt.Sprintf("%x", unique), "globalmount") + + version, err := rs.kubeClient.Discovery().ServerVersion() + if err != nil { + return "", fmt.Errorf("failed to detect Kubernetes version: %w", err) + } + + major, err := strconv.Atoi(version.Major) + if err != nil { + return "", fmt.Errorf("failed to convert Kubernetes major version %q to int: %w", version.Major, err) + } + + minor, err := strconv.Atoi(version.Minor) + if err != nil { + return "", fmt.Errorf("failed to convert Kubernetes minor version %q to int: %w", version.Minor, err) + } + + // 'encode' major/minor in a single integer + legacyVersion := 1024 // Kubernetes 1.24 => 1 * 1000 + 24 + if ((major * 1000) + minor) < (legacyVersion) { + // path in Kubernetes < 1.24 + targetPath = filepath.Join(rs.stagingPath, "pv", pv.Name, "globalmount") + } + + return targetPath, nil +}