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  }