k8s.io/kubernetes@v1.29.3/test/e2e/storage/csi_mock/csi_volume_limit.go (about) 1 /* 2 Copyright 2022 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package csi_mock 18 19 import ( 20 "context" 21 "fmt" 22 "time" 23 24 "github.com/onsi/ginkgo/v2" 25 "github.com/onsi/gomega" 26 storagev1 "k8s.io/api/storage/v1" 27 apierrors "k8s.io/apimachinery/pkg/api/errors" 28 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 29 "k8s.io/apimachinery/pkg/util/wait" 30 clientset "k8s.io/client-go/kubernetes" 31 "k8s.io/kubernetes/test/e2e/framework" 32 e2epod "k8s.io/kubernetes/test/e2e/framework/pod" 33 "k8s.io/kubernetes/test/e2e/storage/utils" 34 admissionapi "k8s.io/pod-security-admission/api" 35 ) 36 37 var _ = utils.SIGDescribe("CSI Mock volume limit", func() { 38 f := framework.NewDefaultFramework("csi-mock-volumes-limit") 39 f.NamespacePodSecurityLevel = admissionapi.LevelPrivileged 40 m := newMockDriverSetup(f) 41 42 ginkgo.Context("CSI volume limit information using mock driver", func() { 43 f.It("should report attach limit when limit is bigger than 0", f.WithSlow(), func(ctx context.Context) { 44 // define volume limit to be 2 for this test 45 var err error 46 m.init(ctx, testParameters{attachLimit: 2}) 47 ginkgo.DeferCleanup(m.cleanup) 48 49 nodeName := m.config.ClientNodeSelection.Name 50 driverName := m.config.GetUniqueDriverName() 51 52 csiNodeAttachLimit, err := checkCSINodeForLimits(nodeName, driverName, m.cs) 53 framework.ExpectNoError(err, "while checking limits in CSINode: %v", err) 54 55 gomega.Expect(csiNodeAttachLimit).To(gomega.BeNumerically("==", 2)) 56 57 _, _, pod1 := m.createPod(ctx, pvcReference) 58 gomega.Expect(pod1).NotTo(gomega.BeNil(), "while creating first pod") 59 60 err = e2epod.WaitForPodNameRunningInNamespace(ctx, m.cs, pod1.Name, pod1.Namespace) 61 framework.ExpectNoError(err, "Failed to start pod1: %v", err) 62 63 _, _, pod2 := m.createPod(ctx, pvcReference) 64 gomega.Expect(pod2).NotTo(gomega.BeNil(), "while creating second pod") 65 66 err = e2epod.WaitForPodNameRunningInNamespace(ctx, m.cs, pod2.Name, pod2.Namespace) 67 framework.ExpectNoError(err, "Failed to start pod2: %v", err) 68 69 _, _, pod3 := m.createPod(ctx, pvcReference) 70 gomega.Expect(pod3).NotTo(gomega.BeNil(), "while creating third pod") 71 err = waitForMaxVolumeCondition(pod3, m.cs) 72 framework.ExpectNoError(err, "while waiting for max volume condition on pod : %+v", pod3) 73 }) 74 75 f.It("should report attach limit for generic ephemeral volume when persistent volume is attached", f.WithSlow(), func(ctx context.Context) { 76 // define volume limit to be 2 for this test 77 var err error 78 m.init(ctx, testParameters{attachLimit: 1}) 79 ginkgo.DeferCleanup(m.cleanup) 80 81 nodeName := m.config.ClientNodeSelection.Name 82 driverName := m.config.GetUniqueDriverName() 83 84 csiNodeAttachLimit, err := checkCSINodeForLimits(nodeName, driverName, m.cs) 85 framework.ExpectNoError(err, "while checking limits in CSINode: %v", err) 86 87 gomega.Expect(csiNodeAttachLimit).To(gomega.BeNumerically("==", 1)) 88 89 _, _, pod1 := m.createPod(ctx, pvcReference) 90 gomega.Expect(pod1).NotTo(gomega.BeNil(), "while creating pod with persistent volume") 91 92 err = e2epod.WaitForPodNameRunningInNamespace(ctx, m.cs, pod1.Name, pod1.Namespace) 93 framework.ExpectNoError(err, "Failed to start pod1: %v", err) 94 95 _, _, pod2 := m.createPod(ctx, genericEphemeral) 96 gomega.Expect(pod2).NotTo(gomega.BeNil(), "while creating pod with ephemeral volume") 97 err = waitForMaxVolumeCondition(pod2, m.cs) 98 framework.ExpectNoError(err, "while waiting for max volume condition on pod : %+v", pod2) 99 }) 100 101 f.It("should report attach limit for persistent volume when generic ephemeral volume is attached", f.WithSlow(), func(ctx context.Context) { 102 // define volume limit to be 2 for this test 103 var err error 104 m.init(ctx, testParameters{attachLimit: 1}) 105 ginkgo.DeferCleanup(m.cleanup) 106 107 nodeName := m.config.ClientNodeSelection.Name 108 driverName := m.config.GetUniqueDriverName() 109 110 csiNodeAttachLimit, err := checkCSINodeForLimits(nodeName, driverName, m.cs) 111 framework.ExpectNoError(err, "while checking limits in CSINode: %v", err) 112 113 gomega.Expect(csiNodeAttachLimit).To(gomega.BeNumerically("==", 1)) 114 115 _, _, pod1 := m.createPod(ctx, genericEphemeral) 116 gomega.Expect(pod1).NotTo(gomega.BeNil(), "while creating pod with persistent volume") 117 118 err = e2epod.WaitForPodNameRunningInNamespace(ctx, m.cs, pod1.Name, pod1.Namespace) 119 framework.ExpectNoError(err, "Failed to start pod1: %v", err) 120 121 _, _, pod2 := m.createPod(ctx, pvcReference) 122 gomega.Expect(pod2).NotTo(gomega.BeNil(), "while creating pod with ephemeral volume") 123 err = waitForMaxVolumeCondition(pod2, m.cs) 124 framework.ExpectNoError(err, "while waiting for max volume condition on pod : %+v", pod2) 125 }) 126 }) 127 }) 128 129 func checkCSINodeForLimits(nodeName string, driverName string, cs clientset.Interface) (int32, error) { 130 var attachLimit int32 131 132 waitErr := wait.PollImmediate(10*time.Second, csiNodeLimitUpdateTimeout, func() (bool, error) { 133 csiNode, err := cs.StorageV1().CSINodes().Get(context.TODO(), nodeName, metav1.GetOptions{}) 134 if err != nil && !apierrors.IsNotFound(err) { 135 return false, err 136 } 137 attachLimit = getVolumeLimitFromCSINode(csiNode, driverName) 138 if attachLimit > 0 { 139 return true, nil 140 } 141 return false, nil 142 }) 143 if waitErr != nil { 144 return 0, fmt.Errorf("error waiting for non-zero volume limit of driver %s on node %s: %v", driverName, nodeName, waitErr) 145 } 146 return attachLimit, nil 147 } 148 149 func getVolumeLimitFromCSINode(csiNode *storagev1.CSINode, driverName string) int32 { 150 for _, d := range csiNode.Spec.Drivers { 151 if d.Name != driverName { 152 continue 153 } 154 if d.Allocatable != nil && d.Allocatable.Count != nil { 155 return *d.Allocatable.Count 156 } 157 } 158 return 0 159 }