@@ -19,6 +19,7 @@ package reconciler
19
19
import (
20
20
"context"
21
21
"fmt"
22
+ "sync"
22
23
"testing"
23
24
"time"
24
25
@@ -30,10 +31,13 @@ import (
30
31
"k8s.io/client-go/informers"
31
32
"k8s.io/client-go/tools/record"
32
33
featuregatetesting "k8s.io/component-base/featuregate/testing"
34
+ "k8s.io/component-base/metrics/legacyregistry"
35
+ metricstestutil "k8s.io/component-base/metrics/testutil"
33
36
"k8s.io/klog/v2"
34
37
"k8s.io/klog/v2/ktesting"
35
38
"k8s.io/kubernetes/pkg/controller"
36
39
"k8s.io/kubernetes/pkg/controller/volume/attachdetach/cache"
40
+ "k8s.io/kubernetes/pkg/controller/volume/attachdetach/metrics"
37
41
"k8s.io/kubernetes/pkg/controller/volume/attachdetach/statusupdater"
38
42
controllervolumetesting "k8s.io/kubernetes/pkg/controller/volume/attachdetach/testing"
39
43
"k8s.io/kubernetes/pkg/features"
@@ -51,6 +55,8 @@ const (
51
55
volumeAttachedCheckTimeout = 5 * time .Second
52
56
)
53
57
58
+ var registerMetrics sync.Once
59
+
54
60
// Calls Run()
55
61
// Verifies there are no calls to attach or detach.
56
62
func Test_Run_Positive_DoNothing (t * testing.T ) {
@@ -221,6 +227,9 @@ func Test_Run_Positive_OneDesiredVolumeAttachThenDetachWithUnmountedVolume(t *te
221
227
// Deletes the node/volume/pod tuple from desiredStateOfWorld cache without first marking the node/volume as unmounted.
222
228
// Verifies there is one detach call and no (new) attach calls.
223
229
func Test_Run_Positive_OneDesiredVolumeAttachThenDetachWithMountedVolume (t * testing.T ) {
230
+ registerMetrics .Do (func () {
231
+ legacyregistry .MustRegister (metrics .ForceDetachMetricCounter )
232
+ })
224
233
// Arrange
225
234
volumePluginMgr , fakePlugin := volumetesting .GetTestVolumePluginMgr (t )
226
235
dsw := cache .NewDesiredStateOfWorld (volumePluginMgr )
@@ -287,6 +296,9 @@ func Test_Run_Positive_OneDesiredVolumeAttachThenDetachWithMountedVolume(t *test
287
296
waitForAttachCallCount (t , 1 /* expectedAttachCallCount */ , fakePlugin )
288
297
verifyNewDetacherCallCount (t , false /* expectZeroNewDetacherCallCount */ , fakePlugin )
289
298
waitForDetachCallCount (t , 1 /* expectedDetachCallCount */ , fakePlugin )
299
+
300
+ // Force detach metric due to timeout
301
+ testForceDetachMetric (t , 1 , metrics .ForceDetachReasonTimeout )
290
302
}
291
303
292
304
// Populates desiredStateOfWorld cache with one node/volume/pod tuple.
@@ -852,6 +864,9 @@ func Test_Run_OneVolumeAttachAndDetachTimeoutNodesWithReadWriteOnce(t *testing.T
852
864
// Verifies there is one detach call and no (new) attach calls.
853
865
func Test_Run_OneVolumeDetachOnOutOfServiceTaintedNode (t * testing.T ) {
854
866
defer featuregatetesting .SetFeatureGateDuringTest (t , utilfeature .DefaultFeatureGate , features .NodeOutOfServiceVolumeDetach , true )()
867
+ registerMetrics .Do (func () {
868
+ legacyregistry .MustRegister (metrics .ForceDetachMetricCounter )
869
+ })
855
870
// Arrange
856
871
volumePluginMgr , fakePlugin := volumetesting .GetTestVolumePluginMgr (t )
857
872
dsw := cache .NewDesiredStateOfWorld (volumePluginMgr )
@@ -920,6 +935,9 @@ func Test_Run_OneVolumeDetachOnOutOfServiceTaintedNode(t *testing.T) {
920
935
waitForAttachCallCount (t , 1 /* expectedAttachCallCount */ , fakePlugin )
921
936
verifyNewDetacherCallCount (t , false /* expectZeroNewDetacherCallCount */ , fakePlugin )
922
937
waitForDetachCallCount (t , 1 /* expectedDetachCallCount */ , fakePlugin )
938
+
939
+ // Force detach metric due to out-of-service taint
940
+ testForceDetachMetric (t , 1 , metrics .ForceDetachReasonOutOfService )
923
941
}
924
942
925
943
// Populates desiredStateOfWorld cache with one node/volume/pod tuple.
@@ -1666,3 +1684,16 @@ func retryWithExponentialBackOff(initialDuration time.Duration, fn wait.Conditio
1666
1684
}
1667
1685
return wait .ExponentialBackoff (backoff , fn )
1668
1686
}
1687
+
1688
+ // verifies the force detach metric with reason
1689
+ func testForceDetachMetric (t * testing.T , inputForceDetachMetricCounter int , reason string ) {
1690
+ t .Helper ()
1691
+
1692
+ actualForceDetachMericCounter , err := metricstestutil .GetCounterMetricValue (metrics .ForceDetachMetricCounter .WithLabelValues (reason ))
1693
+ if err != nil {
1694
+ t .Errorf ("Error getting actualForceDetachMericCounter" )
1695
+ }
1696
+ if actualForceDetachMericCounter != float64 (inputForceDetachMetricCounter ) {
1697
+ t .Errorf ("Expected desiredForceDetachMericCounter to be %d, got %v" , inputForceDetachMetricCounter , actualForceDetachMericCounter )
1698
+ }
1699
+ }
0 commit comments