k8s.io/kubernetes@v1.29.3/pkg/controller/volume/attachdetach/metrics/metrics_test.go (about) 1 /* 2 Copyright 2018 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 metrics 18 19 import ( 20 "testing" 21 22 v1 "k8s.io/api/core/v1" 23 "k8s.io/apimachinery/pkg/api/resource" 24 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 25 k8stypes "k8s.io/apimachinery/pkg/types" 26 utilfeature "k8s.io/apiserver/pkg/util/feature" 27 "k8s.io/client-go/informers" 28 "k8s.io/client-go/kubernetes/fake" 29 csitrans "k8s.io/csi-translation-lib" 30 "k8s.io/klog/v2/ktesting" 31 "k8s.io/kubernetes/pkg/controller" 32 "k8s.io/kubernetes/pkg/controller/volume/attachdetach/cache" 33 controllervolumetesting "k8s.io/kubernetes/pkg/controller/volume/attachdetach/testing" 34 "k8s.io/kubernetes/pkg/volume/csimigration" 35 volumetesting "k8s.io/kubernetes/pkg/volume/testing" 36 "k8s.io/kubernetes/pkg/volume/util/types" 37 ) 38 39 func TestVolumesInUseMetricCollection(t *testing.T) { 40 fakeVolumePluginMgr, _ := volumetesting.GetTestVolumePluginMgr(t) 41 fakeClient := &fake.Clientset{} 42 43 fakeInformerFactory := informers.NewSharedInformerFactory(fakeClient, controller.NoResyncPeriodFunc()) 44 fakePodInformer := fakeInformerFactory.Core().V1().Pods() 45 pod := &v1.Pod{ 46 ObjectMeta: metav1.ObjectMeta{ 47 Name: "metric-test-pod", 48 UID: "metric-test-pod-uid", 49 Namespace: "metric-test", 50 }, 51 Spec: v1.PodSpec{ 52 NodeName: "metric-test-host", 53 Volumes: []v1.Volume{ 54 { 55 Name: "metric-test-volume-name", 56 VolumeSource: v1.VolumeSource{ 57 PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{ 58 ClaimName: "metric-test-pvc", 59 }, 60 }, 61 }, 62 }, 63 }, 64 Status: v1.PodStatus{ 65 Phase: v1.PodPhase("Running"), 66 }, 67 } 68 69 fakePodInformer.Informer().GetStore().Add(pod) 70 pvcInformer := fakeInformerFactory.Core().V1().PersistentVolumeClaims() 71 pvInformer := fakeInformerFactory.Core().V1().PersistentVolumes() 72 73 pvc := &v1.PersistentVolumeClaim{ 74 ObjectMeta: metav1.ObjectMeta{ 75 Name: "metric-test-pvc", 76 Namespace: "metric-test", 77 UID: "metric-test-pvc-1", 78 }, 79 Spec: v1.PersistentVolumeClaimSpec{ 80 AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadOnlyMany, v1.ReadWriteOnce}, 81 Resources: v1.VolumeResourceRequirements{ 82 Requests: v1.ResourceList{ 83 v1.ResourceName(v1.ResourceStorage): resource.MustParse("2G"), 84 }, 85 }, 86 VolumeName: "test-metric-pv-1", 87 }, 88 Status: v1.PersistentVolumeClaimStatus{ 89 Phase: v1.ClaimBound, 90 }, 91 } 92 pv := &v1.PersistentVolume{ 93 ObjectMeta: metav1.ObjectMeta{ 94 UID: "test-metric-pv-1", 95 Name: "test-metric-pv-1", 96 }, 97 Spec: v1.PersistentVolumeSpec{ 98 Capacity: v1.ResourceList{ 99 v1.ResourceName(v1.ResourceStorage): resource.MustParse("5G"), 100 }, 101 PersistentVolumeSource: v1.PersistentVolumeSource{ 102 // Note that as GCE CSI Migration is completed, this is handled by the PD CSI plugin. 103 GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{}, 104 }, 105 AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce, v1.ReadOnlyMany}, 106 // this one we're pretending is already bound 107 ClaimRef: &v1.ObjectReference{UID: "metric-test-pvc-1", Namespace: "metric-test"}, 108 }, 109 } 110 pvcInformer.Informer().GetStore().Add(pvc) 111 pvInformer.Informer().GetStore().Add(pv) 112 pvcLister := pvcInformer.Lister() 113 pvLister := pvInformer.Lister() 114 115 csiTranslator := csitrans.New() 116 metricCollector := newAttachDetachStateCollector( 117 pvcLister, 118 fakePodInformer.Lister(), 119 pvLister, 120 nil, 121 nil, 122 fakeVolumePluginMgr, 123 csimigration.NewPluginManager(csiTranslator, utilfeature.DefaultFeatureGate), 124 csiTranslator) 125 logger, _ := ktesting.NewTestContext(t) 126 nodeUseMap := metricCollector.getVolumeInUseCount(logger) 127 if len(nodeUseMap) < 1 { 128 t.Errorf("Expected one volume in use got %d", len(nodeUseMap)) 129 } 130 testNodeMetric := nodeUseMap["metric-test-host"] 131 pluginUseCount, ok := testNodeMetric["fake-plugin:pd.csi.storage.gke.io"] 132 if !ok { 133 t.Errorf("Expected fake plugin pvc got nothing") 134 } 135 136 if pluginUseCount < 1 { 137 t.Errorf("Expected at least in-use volume metric got %d", pluginUseCount) 138 } 139 } 140 141 func TestTotalVolumesMetricCollection(t *testing.T) { 142 fakeVolumePluginMgr, _ := volumetesting.GetTestVolumePluginMgr(t) 143 dsw := cache.NewDesiredStateOfWorld(fakeVolumePluginMgr) 144 asw := cache.NewActualStateOfWorld(fakeVolumePluginMgr) 145 podName := "pod-uid" 146 volumeName := v1.UniqueVolumeName("volume-name") 147 volumeSpec := controllervolumetesting.GetTestVolumeSpec(string(volumeName), volumeName) 148 nodeName := k8stypes.NodeName("node-name") 149 150 dsw.AddNode(nodeName, false) 151 _, err := dsw.AddPod(types.UniquePodName(podName), controllervolumetesting.NewPod(podName, podName), volumeSpec, nodeName) 152 if err != nil { 153 t.Fatalf("Expected no error, got %v", err) 154 } 155 logger, _ := ktesting.NewTestContext(t) 156 asw.AddVolumeNode(logger, volumeName, volumeSpec, nodeName, "", true) 157 158 csiTranslator := csitrans.New() 159 metricCollector := newAttachDetachStateCollector( 160 nil, 161 nil, 162 nil, 163 asw, 164 dsw, 165 fakeVolumePluginMgr, 166 csimigration.NewPluginManager(csiTranslator, utilfeature.DefaultFeatureGate), 167 csiTranslator) 168 169 totalVolumesMap := metricCollector.getTotalVolumesCount() 170 if len(totalVolumesMap) != 2 { 171 t.Errorf("Expected 2 states, got %d", len(totalVolumesMap)) 172 } 173 174 dswCount, ok := totalVolumesMap["desired_state_of_world"] 175 if !ok { 176 t.Errorf("Expected desired_state_of_world, got nothing") 177 } 178 179 fakePluginCount := dswCount["fake-plugin"] 180 if fakePluginCount != 1 { 181 t.Errorf("Expected 1 fake-plugin volume in DesiredStateOfWorld, got %d", fakePluginCount) 182 } 183 184 aswCount, ok := totalVolumesMap["actual_state_of_world"] 185 if !ok { 186 t.Errorf("Expected actual_state_of_world, got nothing") 187 } 188 189 fakePluginCount = aswCount["fake-plugin"] 190 if fakePluginCount != 1 { 191 t.Errorf("Expected 1 fake-plugin volume in ActualStateOfWorld, got %d", fakePluginCount) 192 } 193 }