From e2a798662953256a725d92f2d491ed988c9ad0c5 Mon Sep 17 00:00:00 2001 From: Lyndon-Li Date: Thu, 20 Feb 2025 19:19:28 +0800 Subject: [PATCH 1/2] issue 8706: for immediate volumes, get node from volumeattachment Signed-off-by: Lyndon-Li --- pkg/util/kube/pvc_pv.go | 43 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/pkg/util/kube/pvc_pv.go b/pkg/util/kube/pvc_pv.go index a9311cab3..6d29c2e94 100644 --- a/pkg/util/kube/pvc_pv.go +++ b/pkg/util/kube/pvc_pv.go @@ -441,10 +441,34 @@ func GetPVCAttachingNodeOS(pvc *corev1api.PersistentVolumeClaim, nodeClient core return NodeOSLinux, nil } + if pvc.Spec.VolumeName == "" { + log.Warnf("PVC %s/%s is not bound to a PV", pvc.Namespace, pvc.Name) + } + + if pvc.Spec.StorageClassName == nil { + log.Warnf("PVC %s/%s is not with storage class", pvc.Namespace, pvc.Name) + } + + nodeName := "" if value := pvc.Annotations[KubeAnnSelectedNode]; value != "" { - os, err := GetNodeOS(context.Background(), value, nodeClient) + nodeName = value + } + + if nodeName == "" { + if pvc.Spec.VolumeName != "" { + n, err := GetPVAttachedNode(context.Background(), pvc.Spec.VolumeName, storageClient) + if err != nil { + return "", errors.Wrapf(err, "error to get attached node for PVC %s/%s", pvc.Namespace, pvc.Name) + } + + nodeName = n + } + } + + if nodeName != "" { + os, err := GetNodeOS(context.Background(), nodeName, nodeClient) if err != nil { - return "", errors.Wrapf(err, "error to get os from node %s for PVC %s/%s", value, pvc.Namespace, pvc.Name) + return "", errors.Wrapf(err, "error to get os from node %s for PVC %s/%s", nodeName, pvc.Namespace, pvc.Name) } nodeOS = os @@ -474,3 +498,18 @@ func GetPVCAttachingNodeOS(pvc *corev1api.PersistentVolumeClaim, nodeClient core log.Warnf("Cannot deduce node os for PVC %s/%s, default to linux", pvc.Namespace, pvc.Name) return NodeOSLinux, nil } + +func GetPVAttachedNode(ctx context.Context, pv string, storageClient storagev1.StorageV1Interface) (string, error) { + vaList, err := storageClient.VolumeAttachments().List(ctx, metav1.ListOptions{}) + if err != nil { + return "", errors.Wrapf(err, "error listing volumeattachment") + } + + for _, va := range vaList.Items { + if va.Spec.Source.PersistentVolumeName != nil && *va.Spec.Source.PersistentVolumeName == pv { + return va.Spec.NodeName, nil + } + } + + return "", nil +} From bf0d909524785a8ad4d20d1691f0621b5530c30b Mon Sep 17 00:00:00 2001 From: Lyndon-Li Date: Fri, 21 Feb 2025 13:20:25 +0800 Subject: [PATCH 2/2] issue 8706: for immediate volumes, get node from volumeattachment Signed-off-by: Lyndon-Li --- changelogs/unreleased/8715-Lyndon-Li | 1 + pkg/util/kube/pvc_pv_test.go | 88 ++++++++++++++++++++++++++-- 2 files changed, 85 insertions(+), 4 deletions(-) create mode 100644 changelogs/unreleased/8715-Lyndon-Li diff --git a/changelogs/unreleased/8715-Lyndon-Li b/changelogs/unreleased/8715-Lyndon-Li new file mode 100644 index 000000000..f4df18fe4 --- /dev/null +++ b/changelogs/unreleased/8715-Lyndon-Li @@ -0,0 +1 @@ +Fix issue #8706, for immediate volumes, there is no selected-node annotation on PVC, so deduce the attached node from VolumeAttachment CRs \ No newline at end of file diff --git a/pkg/util/kube/pvc_pv_test.go b/pkg/util/kube/pvc_pv_test.go index 59dfc5788..06e8058f2 100644 --- a/pkg/util/kube/pvc_pv_test.go +++ b/pkg/util/kube/pvc_pv_test.go @@ -1594,6 +1594,16 @@ func TestGetPVCAttachingNodeOS(t *testing.T) { }, } + pvcObjWithVolume := &corev1api.PersistentVolumeClaim{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "fake-namespace", + Name: "fake-pvc", + }, + Spec: corev1api.PersistentVolumeClaimSpec{ + VolumeName: "fake-volume-name", + }, + } + pvcObjWithStorageClass := &corev1api.PersistentVolumeClaim{ ObjectMeta: metav1.ObjectMeta{ Namespace: "fake-namespace", @@ -1604,13 +1614,26 @@ func TestGetPVCAttachingNodeOS(t *testing.T) { }, } - pvcObjWithBoth := &corev1api.PersistentVolumeClaim{ + pvName := "fake-volume-name" + pvcObjWithAll := &corev1api.PersistentVolumeClaim{ ObjectMeta: metav1.ObjectMeta{ Namespace: "fake-namespace", Name: "fake-pvc", Annotations: map[string]string{KubeAnnSelectedNode: "fake-node"}, }, Spec: corev1api.PersistentVolumeClaimSpec{ + VolumeName: pvName, + StorageClassName: &storageClass, + }, + } + + pvcObjWithVolumeSC := &corev1api.PersistentVolumeClaim{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "fake-namespace", + Name: "fake-pvc", + }, + Spec: corev1api.PersistentVolumeClaimSpec{ + VolumeName: pvName, StorageClassName: &storageClass, }, } @@ -1628,6 +1651,35 @@ func TestGetPVCAttachingNodeOS(t *testing.T) { Parameters: map[string]string{"csi.storage.k8s.io/fstype": "ntfs"}, } + volAttachEmpty := &storagev1api.VolumeAttachment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "fake-volume-attach-1", + }, + } + + volAttachWithVolume := &storagev1api.VolumeAttachment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "fake-volume-attach-2", + }, + Spec: storagev1api.VolumeAttachmentSpec{ + Source: storagev1api.VolumeAttachmentSource{ + PersistentVolumeName: &pvName, + }, + }, + } + + otherPVName := "other-volume-name" + volAttachWithOtherVolume := &storagev1api.VolumeAttachment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "fake-volume-attach-3", + }, + Spec: storagev1api.VolumeAttachmentSpec{ + Source: storagev1api.VolumeAttachmentSource{ + PersistentVolumeName: &otherPVName, + }, + }, + } + tests := []struct { name string pvc *corev1api.PersistentVolumeClaim @@ -1636,7 +1688,7 @@ func TestGetPVCAttachingNodeOS(t *testing.T) { err string }{ { - name: "no selected node and storage class", + name: "no selected node, volume name and storage class", pvc: pvcObj, expectedNodeOS: NodeOSLinux, }, @@ -1653,11 +1705,27 @@ func TestGetPVCAttachingNodeOS(t *testing.T) { }, expectedNodeOS: NodeOSLinux, }, + { + name: "no attach volume", + pvc: pvcObjWithVolume, + expectedNodeOS: NodeOSLinux, + }, { name: "sc doesn't exist", pvc: pvcObjWithStorageClass, err: "error to get storage class fake-storage-class: storageclasses.storage.k8s.io \"fake-storage-class\" not found", }, + { + name: "volume attachment not exist", + pvc: pvcObjWithVolume, + kubeClientObj: []runtime.Object{ + nodeWindows, + scObjWithFSType, + volAttachEmpty, + volAttachWithOtherVolume, + }, + expectedNodeOS: NodeOSLinux, + }, { name: "sc without fsType", pvc: pvcObjWithStorageClass, @@ -1668,7 +1736,7 @@ func TestGetPVCAttachingNodeOS(t *testing.T) { }, { name: "deduce from node os", - pvc: pvcObjWithBoth, + pvc: pvcObjWithAll, kubeClientObj: []runtime.Object{ nodeWindows, scObjWithFSType, @@ -1677,13 +1745,25 @@ func TestGetPVCAttachingNodeOS(t *testing.T) { }, { name: "deduce from sc", - pvc: pvcObjWithBoth, + pvc: pvcObjWithAll, kubeClientObj: []runtime.Object{ nodeNoOSLabel, scObjWithFSType, }, expectedNodeOS: NodeOSWindows, }, + { + name: "deduce from attached node os", + pvc: pvcObjWithVolumeSC, + kubeClientObj: []runtime.Object{ + nodeWindows, + scObjWithFSType, + volAttachEmpty, + volAttachWithOtherVolume, + volAttachWithVolume, + }, + expectedNodeOS: NodeOSWindows, + }, { name: "block access", pvc: pvcObjBlockMode,