1
16
17 package csi_mock
18
19 import (
20 "context"
21 "fmt"
22 "time"
23
24 "github.com/onsi/ginkgo/v2"
25 "google.golang.org/grpc/codes"
26 "google.golang.org/grpc/status"
27 v1 "k8s.io/api/core/v1"
28 storagev1 "k8s.io/api/storage/v1"
29 apierrors "k8s.io/apimachinery/pkg/api/errors"
30 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
31 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
32 clientset "k8s.io/client-go/kubernetes"
33 "k8s.io/kubernetes/test/e2e/feature"
34 "k8s.io/kubernetes/test/e2e/framework"
35 e2emetrics "k8s.io/kubernetes/test/e2e/framework/metrics"
36 e2epv "k8s.io/kubernetes/test/e2e/framework/pv"
37 e2eskipper "k8s.io/kubernetes/test/e2e/framework/skipper"
38 "k8s.io/kubernetes/test/e2e/storage/drivers"
39 storageframework "k8s.io/kubernetes/test/e2e/storage/framework"
40 "k8s.io/kubernetes/test/e2e/storage/utils"
41 admissionapi "k8s.io/pod-security-admission/api"
42 )
43
44 var _ = utils.SIGDescribe("CSI Mock volume snapshot", func() {
45 f := framework.NewDefaultFramework("csi-mock-volumes-snapshot")
46 f.NamespacePodSecurityLevel = admissionapi.LevelPrivileged
47 m := newMockDriverSetup(f)
48
49 f.Context("CSI Volume Snapshots", feature.VolumeSnapshotDataSource, func() {
50 tests := []struct {
51 name string
52 createSnapshotHook func(counter int64) error
53 }{
54 {
55 name: "volumesnapshotcontent and pvc in Bound state with deletion timestamp set should not get deleted while snapshot finalizer exists",
56 createSnapshotHook: func(counter int64) error {
57 if counter < 8 {
58 return status.Error(codes.DeadlineExceeded, "fake error")
59 }
60 return nil
61 },
62 },
63 }
64 for _, test := range tests {
65 test := test
66 ginkgo.It(test.name, func(ctx context.Context) {
67 var hooks *drivers.Hooks
68 if test.createSnapshotHook != nil {
69 hooks = createPreHook("CreateSnapshot", test.createSnapshotHook)
70 }
71 m.init(ctx, testParameters{
72 disableAttach: true,
73 registerDriver: true,
74 enableSnapshot: true,
75 hooks: hooks,
76 })
77 sDriver, ok := m.driver.(storageframework.SnapshottableTestDriver)
78 if !ok {
79 e2eskipper.Skipf("mock driver %s does not support snapshots -- skipping", m.driver.GetDriverInfo().Name)
80
81 }
82 ctx, cancel := context.WithTimeout(ctx, csiPodRunningTimeout)
83 defer cancel()
84 ginkgo.DeferCleanup(m.cleanup)
85
86 sc := m.driver.GetDynamicProvisionStorageClass(ctx, m.config, "")
87 ginkgo.By("Creating storage class")
88 class, err := m.cs.StorageV1().StorageClasses().Create(context.TODO(), sc, metav1.CreateOptions{})
89 framework.ExpectNoError(err, "Failed to create class: %v", err)
90 m.sc[class.Name] = class
91 claim := e2epv.MakePersistentVolumeClaim(e2epv.PersistentVolumeClaimConfig{
92
93 Name: "snapshot-test-pvc",
94 StorageClassName: &(class.Name),
95 }, f.Namespace.Name)
96
97 ginkgo.By("Creating snapshot")
98
99 parameters := map[string]string{}
100 snapshotClass, snapshot := storageframework.CreateSnapshot(ctx, sDriver, m.config, storageframework.DynamicSnapshotDelete, claim.Name, claim.Namespace, f.Timeouts, parameters)
101 framework.ExpectNoError(err, "failed to create snapshot")
102 m.vsc[snapshotClass.GetName()] = snapshotClass
103 volumeSnapshotName := snapshot.GetName()
104
105 ginkgo.By(fmt.Sprintf("Creating PVC %s/%s", claim.Namespace, claim.Name))
106 claim, err = m.cs.CoreV1().PersistentVolumeClaims(f.Namespace.Name).Create(context.TODO(), claim, metav1.CreateOptions{})
107 framework.ExpectNoError(err, "Failed to create claim: %v", err)
108
109 ginkgo.By(fmt.Sprintf("Wait for finalizer to be added to claim %s/%s", claim.Namespace, claim.Name))
110 err = e2epv.WaitForPVCFinalizer(ctx, m.cs, claim.Name, claim.Namespace, pvcAsSourceProtectionFinalizer, 1*time.Millisecond, 1*time.Minute)
111 framework.ExpectNoError(err)
112
113 ginkgo.By("Wait for PVC to be Bound")
114 _, err = e2epv.WaitForPVClaimBoundPhase(ctx, m.cs, []*v1.PersistentVolumeClaim{claim}, 1*time.Minute)
115 framework.ExpectNoError(err, "Failed to create claim: %v", err)
116
117 ginkgo.By(fmt.Sprintf("Delete PVC %s", claim.Name))
118 err = e2epv.DeletePersistentVolumeClaim(ctx, m.cs, claim.Name, claim.Namespace)
119 framework.ExpectNoError(err, "failed to delete pvc")
120
121 ginkgo.By("Get PVC from API server and verify deletion timestamp is set")
122 claim, err = m.cs.CoreV1().PersistentVolumeClaims(f.Namespace.Name).Get(context.TODO(), claim.Name, metav1.GetOptions{})
123 if err != nil {
124 if !apierrors.IsNotFound(err) {
125 framework.ExpectNoError(err, "Failed to get claim: %v", err)
126 }
127 framework.Logf("PVC not found. Continuing to test VolumeSnapshotContent finalizer")
128 } else if claim.DeletionTimestamp == nil {
129 framework.Failf("Expected deletion timestamp to be set on PVC: %v", claim)
130 }
131
132 ginkgo.By(fmt.Sprintf("Get VolumeSnapshotContent bound to VolumeSnapshot %s", snapshot.GetName()))
133 snapshotContent := utils.GetSnapshotContentFromSnapshot(ctx, m.config.Framework.DynamicClient, snapshot, f.Timeouts.SnapshotCreate)
134 volumeSnapshotContentName := snapshotContent.GetName()
135
136 ginkgo.By(fmt.Sprintf("Verify VolumeSnapshotContent %s contains finalizer %s", snapshot.GetName(), volumeSnapshotContentFinalizer))
137 err = utils.WaitForGVRFinalizer(ctx, m.config.Framework.DynamicClient, utils.SnapshotContentGVR, volumeSnapshotContentName, "", volumeSnapshotContentFinalizer, 1*time.Millisecond, 1*time.Minute)
138 framework.ExpectNoError(err)
139
140 ginkgo.By(fmt.Sprintf("Delete VolumeSnapshotContent %s", snapshotContent.GetName()))
141 err = m.config.Framework.DynamicClient.Resource(utils.SnapshotContentGVR).Delete(ctx, snapshotContent.GetName(), metav1.DeleteOptions{})
142 framework.ExpectNoError(err, "Failed to delete snapshotcontent: %v", err)
143
144 ginkgo.By("Get VolumeSnapshotContent from API server and verify deletion timestamp is set")
145 snapshotContent, err = m.config.Framework.DynamicClient.Resource(utils.SnapshotContentGVR).Get(context.TODO(), snapshotContent.GetName(), metav1.GetOptions{})
146 framework.ExpectNoError(err)
147
148 if snapshotContent.GetDeletionTimestamp() == nil {
149 framework.Failf("Expected deletion timestamp to be set on snapshotcontent")
150 }
151
152
153
154
155 if claim != nil && claim.Spec.VolumeName != "" {
156 ginkgo.By(fmt.Sprintf("Wait for PV %s to be deleted", claim.Spec.VolumeName))
157 err = e2epv.WaitForPersistentVolumeDeleted(ctx, m.cs, claim.Spec.VolumeName, framework.Poll, 3*time.Minute)
158 framework.ExpectNoError(err, fmt.Sprintf("failed to delete PV %s", claim.Spec.VolumeName))
159 }
160
161 ginkgo.By(fmt.Sprintf("Verify VolumeSnapshot %s contains finalizer %s", snapshot.GetName(), volumeSnapshotBoundFinalizer))
162 err = utils.WaitForGVRFinalizer(ctx, m.config.Framework.DynamicClient, utils.SnapshotGVR, volumeSnapshotName, f.Namespace.Name, volumeSnapshotBoundFinalizer, 1*time.Millisecond, 1*time.Minute)
163 framework.ExpectNoError(err)
164
165 ginkgo.By("Delete VolumeSnapshot")
166 err = utils.DeleteAndWaitSnapshot(ctx, m.config.Framework.DynamicClient, f.Namespace.Name, volumeSnapshotName, framework.Poll, framework.SnapshotDeleteTimeout)
167 framework.ExpectNoError(err, fmt.Sprintf("failed to delete VolumeSnapshot %s", volumeSnapshotName))
168
169 ginkgo.By(fmt.Sprintf("Wait for VolumeSnapshotContent %s to be deleted", volumeSnapshotContentName))
170 err = utils.WaitForGVRDeletion(ctx, m.config.Framework.DynamicClient, utils.SnapshotContentGVR, volumeSnapshotContentName, framework.Poll, framework.SnapshotDeleteTimeout)
171 framework.ExpectNoError(err, fmt.Sprintf("failed to delete VolumeSnapshotContent %s", volumeSnapshotContentName))
172 })
173 }
174 })
175
176 f.Context("CSI Volume Snapshots secrets", feature.VolumeSnapshotDataSource, func() {
177
178 var (
179
180 CSISnapshotterSecretName string = "snapshot-secret"
181
182
183 CSISnapshotterSecretNameAnnotation string = "csi.storage.k8s.io/snapshotter-secret-name"
184
185
186 CSISnapshotterSecretNamespaceAnnotation string = "csi.storage.k8s.io/snapshotter-secret-namespace"
187
188
189 annotations interface{}
190 )
191
192 tests := []struct {
193 name string
194 createSnapshotHook func(counter int64) error
195 }{
196 {
197
198 name: "volume snapshot create/delete with secrets",
199
200 createSnapshotHook: func(counter int64) error {
201 if counter < 8 {
202 return status.Error(codes.DeadlineExceeded, "fake error")
203 }
204 return nil
205 },
206 },
207 }
208 for _, test := range tests {
209 test := test
210 ginkgo.It(test.name, func(ctx context.Context) {
211 hooks := createPreHook("CreateSnapshot", test.createSnapshotHook)
212 m.init(ctx, testParameters{
213 disableAttach: true,
214 registerDriver: true,
215 enableSnapshot: true,
216 hooks: hooks,
217 })
218
219 sDriver, ok := m.driver.(storageframework.SnapshottableTestDriver)
220 if !ok {
221 e2eskipper.Skipf("mock driver does not support snapshots -- skipping")
222 }
223 ginkgo.DeferCleanup(m.cleanup)
224
225 var sc *storagev1.StorageClass
226 if dDriver, ok := m.driver.(storageframework.DynamicPVTestDriver); ok {
227 sc = dDriver.GetDynamicProvisionStorageClass(ctx, m.config, "")
228 }
229 ginkgo.By("Creating storage class")
230 class, err := m.cs.StorageV1().StorageClasses().Create(context.TODO(), sc, metav1.CreateOptions{})
231 framework.ExpectNoError(err, "Failed to create storage class: %v", err)
232 m.sc[class.Name] = class
233 pvc := e2epv.MakePersistentVolumeClaim(e2epv.PersistentVolumeClaimConfig{
234 Name: "snapshot-test-pvc",
235 StorageClassName: &(class.Name),
236 }, f.Namespace.Name)
237
238 ginkgo.By(fmt.Sprintf("Creating PVC %s/%s", pvc.Namespace, pvc.Name))
239 pvc, err = m.cs.CoreV1().PersistentVolumeClaims(f.Namespace.Name).Create(context.TODO(), pvc, metav1.CreateOptions{})
240 framework.ExpectNoError(err, "Failed to create claim: %v", err)
241
242 ginkgo.By("Wait for PVC to be Bound")
243 _, err = e2epv.WaitForPVClaimBoundPhase(ctx, m.cs, []*v1.PersistentVolumeClaim{pvc}, 1*time.Minute)
244 framework.ExpectNoError(err, "Failed to create claim: %v", err)
245
246 m.pvcs = append(m.pvcs, pvc)
247
248 ginkgo.By("Creating Secret")
249 secret := &v1.Secret{
250 ObjectMeta: metav1.ObjectMeta{
251 Namespace: f.Namespace.Name,
252 Name: CSISnapshotterSecretName,
253 },
254 Data: map[string][]byte{
255 "secret-data": []byte("secret-value-1"),
256 },
257 }
258
259 if secret, err := m.cs.CoreV1().Secrets(f.Namespace.Name).Create(context.TODO(), secret, metav1.CreateOptions{}); err != nil {
260 framework.Failf("unable to create test secret %s: %v", secret.Name, err)
261 }
262
263 ginkgo.By("Creating snapshot with secrets")
264 parameters := map[string]string{
265 CSISnapshotterSecretNameAnnotation: CSISnapshotterSecretName,
266 CSISnapshotterSecretNamespaceAnnotation: f.Namespace.Name,
267 }
268
269 _, snapshot := storageframework.CreateSnapshot(ctx, sDriver, m.config, storageframework.DynamicSnapshotDelete, pvc.Name, pvc.Namespace, f.Timeouts, parameters)
270 framework.ExpectNoError(err, "failed to create snapshot")
271 snapshotcontent := utils.GetSnapshotContentFromSnapshot(ctx, m.config.Framework.DynamicClient, snapshot, f.Timeouts.SnapshotCreate)
272 if annotations, ok = snapshotcontent.Object["metadata"].(map[string]interface{})["annotations"]; !ok {
273 framework.Failf("Unable to get volume snapshot content annotations")
274 }
275
276
277 checkDeleteSnapshotSecrets(m.cs, annotations)
278
279
280 deleteSnapshot(m.cs, m.config, snapshot)
281 })
282 }
283 })
284
285 f.Context("CSI Snapshot Controller metrics", feature.VolumeSnapshotDataSource, func() {
286 tests := []struct {
287 name string
288 pattern storageframework.TestPattern
289 }{
290 {
291 name: "snapshot controller should emit dynamic CreateSnapshot, CreateSnapshotAndReady, and DeleteSnapshot metrics",
292 pattern: storageframework.DynamicSnapshotDelete,
293 },
294 {
295 name: "snapshot controller should emit pre-provisioned CreateSnapshot, CreateSnapshotAndReady, and DeleteSnapshot metrics",
296 pattern: storageframework.PreprovisionedSnapshotDelete,
297 },
298 }
299 for _, test := range tests {
300 test := test
301 ginkgo.It(test.name, func(ctx context.Context) {
302 m.init(ctx, testParameters{
303 disableAttach: true,
304 registerDriver: true,
305 enableSnapshot: true,
306 })
307
308 sDriver, ok := m.driver.(storageframework.SnapshottableTestDriver)
309 if !ok {
310 e2eskipper.Skipf("mock driver does not support snapshots -- skipping")
311 }
312 ginkgo.DeferCleanup(m.cleanup)
313
314 metricsGrabber, err := e2emetrics.NewMetricsGrabber(ctx, m.config.Framework.ClientSet, nil, f.ClientConfig(), false, false, false, false, false, true)
315 if err != nil {
316 framework.Failf("Error creating metrics grabber : %v", err)
317 }
318
319
320 _, err = metricsGrabber.GrabFromSnapshotController(ctx, framework.TestContext.SnapshotControllerPodName, framework.TestContext.SnapshotControllerHTTPPort)
321 if err != nil {
322 e2eskipper.Skipf("Snapshot controller metrics not found -- skipping")
323 }
324
325 ginkgo.By("getting all initial metric values")
326 metricsTestConfig := newSnapshotMetricsTestConfig("snapshot_controller_operation_total_seconds_count",
327 "count",
328 m.config.GetUniqueDriverName(),
329 "CreateSnapshot",
330 "success",
331 "",
332 test.pattern)
333 createSnapshotMetrics := newSnapshotControllerMetrics(metricsTestConfig, metricsGrabber)
334 originalCreateSnapshotCount, _ := createSnapshotMetrics.getSnapshotControllerMetricValue(ctx)
335 metricsTestConfig.operationName = "CreateSnapshotAndReady"
336 createSnapshotAndReadyMetrics := newSnapshotControllerMetrics(metricsTestConfig, metricsGrabber)
337 originalCreateSnapshotAndReadyCount, _ := createSnapshotAndReadyMetrics.getSnapshotControllerMetricValue(ctx)
338
339 metricsTestConfig.operationName = "DeleteSnapshot"
340 deleteSnapshotMetrics := newSnapshotControllerMetrics(metricsTestConfig, metricsGrabber)
341 originalDeleteSnapshotCount, _ := deleteSnapshotMetrics.getSnapshotControllerMetricValue(ctx)
342
343 ginkgo.By("Creating storage class")
344 var sc *storagev1.StorageClass
345 if dDriver, ok := m.driver.(storageframework.DynamicPVTestDriver); ok {
346 sc = dDriver.GetDynamicProvisionStorageClass(ctx, m.config, "")
347 }
348 class, err := m.cs.StorageV1().StorageClasses().Create(context.TODO(), sc, metav1.CreateOptions{})
349 framework.ExpectNoError(err, "Failed to create storage class: %v", err)
350 m.sc[class.Name] = class
351 pvc := e2epv.MakePersistentVolumeClaim(e2epv.PersistentVolumeClaimConfig{
352 Name: "snapshot-test-pvc",
353 StorageClassName: &(class.Name),
354 }, f.Namespace.Name)
355
356 ginkgo.By(fmt.Sprintf("Creating PVC %s/%s", pvc.Namespace, pvc.Name))
357 pvc, err = m.cs.CoreV1().PersistentVolumeClaims(f.Namespace.Name).Create(context.TODO(), pvc, metav1.CreateOptions{})
358 framework.ExpectNoError(err, "Failed to create claim: %v", err)
359
360 ginkgo.By("Wait for PVC to be Bound")
361 _, err = e2epv.WaitForPVClaimBoundPhase(ctx, m.cs, []*v1.PersistentVolumeClaim{pvc}, 1*time.Minute)
362 framework.ExpectNoError(err, "Failed to create claim: %v", err)
363
364 ginkgo.By("Creating snapshot")
365 parameters := map[string]string{}
366 sr := storageframework.CreateSnapshotResource(ctx, sDriver, m.config, test.pattern, pvc.Name, pvc.Namespace, f.Timeouts, parameters)
367 framework.ExpectNoError(err, "failed to create snapshot")
368
369 ginkgo.By("Checking for CreateSnapshot metrics")
370 createSnapshotMetrics.waitForSnapshotControllerMetric(ctx, originalCreateSnapshotCount+1.0, f.Timeouts.SnapshotControllerMetrics)
371
372 ginkgo.By("Checking for CreateSnapshotAndReady metrics")
373 err = utils.WaitForSnapshotReady(ctx, m.config.Framework.DynamicClient, pvc.Namespace, sr.Vs.GetName(), framework.Poll, f.Timeouts.SnapshotCreate)
374 framework.ExpectNoError(err, "failed to wait for snapshot ready")
375 createSnapshotAndReadyMetrics.waitForSnapshotControllerMetric(ctx, originalCreateSnapshotAndReadyCount+1.0, f.Timeouts.SnapshotControllerMetrics)
376
377
378 deleteSnapshot(m.cs, m.config, sr.Vs)
379
380 ginkgo.By("check for delete metrics")
381 metricsTestConfig.operationName = "DeleteSnapshot"
382 deleteSnapshotMetrics.waitForSnapshotControllerMetric(ctx, originalDeleteSnapshotCount+1.0, f.Timeouts.SnapshotControllerMetrics)
383 })
384 }
385 })
386 })
387
388
389 func checkDeleteSnapshotSecrets(cs clientset.Interface, annotations interface{}) error {
390 ginkgo.By("checking if delete snapshot secrets annotation is applied to the VolumeSnapshotContent")
391
392 var (
393 annDeletionSecretName string
394 annDeletionSecretNamespace string
395 ok bool
396 err error
397
398
399 CSISnapshotterDeleteSecretNameAnnotation string = "snapshot.storage.kubernetes.io/deletion-secret-name"
400
401
402 CSISnapshotterDeleteSecretNamespaceAnnotation string = "snapshot.storage.kubernetes.io/deletion-secret-namespace"
403 )
404
405 annotationsObj, ok := annotations.(map[string]interface{})
406 if !ok {
407 framework.Failf("failed to get annotations from annotations object")
408 }
409
410 if annDeletionSecretName, ok = annotationsObj[CSISnapshotterDeleteSecretNameAnnotation].(string); !ok {
411 framework.Failf("unable to get secret annotation name")
412 }
413 if annDeletionSecretNamespace, ok = annotationsObj[CSISnapshotterDeleteSecretNamespaceAnnotation].(string); !ok {
414 framework.Failf("unable to get secret annotation namespace")
415 }
416
417
418 if _, err = cs.CoreV1().Secrets(annDeletionSecretNamespace).Get(context.TODO(), annDeletionSecretName, metav1.GetOptions{}); err != nil {
419 framework.Failf("unable to get test secret %s: %v", annDeletionSecretName, err)
420 }
421
422 return err
423 }
424
425 func deleteSnapshot(cs clientset.Interface, config *storageframework.PerTestConfig, snapshot *unstructured.Unstructured) {
426
427 dc := config.Framework.DynamicClient
428 err := dc.Resource(utils.SnapshotGVR).Namespace(snapshot.GetNamespace()).Delete(context.TODO(), snapshot.GetName(), metav1.DeleteOptions{})
429 framework.ExpectNoError(err)
430
431
432 _, err = dc.Resource(utils.SnapshotGVR).Get(context.TODO(), snapshot.GetName(), metav1.GetOptions{})
433 framework.ExpectError(err)
434 }
435
436 type snapshotMetricsTestConfig struct {
437
438 metricName string
439 metricType string
440 driverName string
441 operationName string
442 operationStatus string
443 snapshotType string
444 le string
445 }
446
447 type snapshotControllerMetrics struct {
448
449 cfg snapshotMetricsTestConfig
450 metricsGrabber *e2emetrics.Grabber
451
452
453 countMetrics map[string]float64
454 sumMetrics map[string]float64
455 bucketMetrics map[string]float64
456 }
457
458 func newSnapshotMetricsTestConfig(metricName, metricType, driverName, operationName, operationStatus, le string, pattern storageframework.TestPattern) snapshotMetricsTestConfig {
459 var snapshotType string
460 switch pattern.SnapshotType {
461 case storageframework.DynamicCreatedSnapshot:
462 snapshotType = "dynamic"
463
464 case storageframework.PreprovisionedCreatedSnapshot:
465 snapshotType = "pre-provisioned"
466
467 default:
468 framework.Failf("invalid snapshotType: %v", pattern.SnapshotType)
469 }
470
471 return snapshotMetricsTestConfig{
472 metricName: metricName,
473 metricType: metricType,
474 driverName: driverName,
475 operationName: operationName,
476 operationStatus: operationStatus,
477 snapshotType: snapshotType,
478 le: le,
479 }
480 }
481
482 func newSnapshotControllerMetrics(cfg snapshotMetricsTestConfig, metricsGrabber *e2emetrics.Grabber) *snapshotControllerMetrics {
483 return &snapshotControllerMetrics{
484 cfg: cfg,
485 metricsGrabber: metricsGrabber,
486
487 countMetrics: make(map[string]float64),
488 sumMetrics: make(map[string]float64),
489 bucketMetrics: make(map[string]float64),
490 }
491 }
492
493 func (scm *snapshotControllerMetrics) waitForSnapshotControllerMetric(ctx context.Context, expectedValue float64, timeout time.Duration) {
494 metricKey := scm.getMetricKey()
495 if successful := utils.WaitUntil(10*time.Second, timeout, func() bool {
496
497 actualValue, err := scm.getSnapshotControllerMetricValue(ctx)
498 if err != nil {
499 return false
500 }
501
502
503
504 if actualValue < expectedValue {
505 return false
506 }
507
508 return true
509 }); successful {
510 return
511 }
512
513 scm.showMetricsFailure(metricKey)
514 framework.Failf("Unable to get valid snapshot controller metrics after %v", timeout)
515 }
516
517 func (scm *snapshotControllerMetrics) getSnapshotControllerMetricValue(ctx context.Context) (float64, error) {
518 metricKey := scm.getMetricKey()
519
520
521 err := scm.grabSnapshotControllerMetrics(ctx)
522 if err != nil {
523 return 0, err
524 }
525
526 metrics := scm.getMetricsTable()
527 actual, ok := metrics[metricKey]
528 if !ok {
529 return 0, fmt.Errorf("did not find metric for key %s", metricKey)
530 }
531
532 return actual, nil
533 }
534
535 func (scm *snapshotControllerMetrics) getMetricsTable() map[string]float64 {
536 var metrics map[string]float64
537 switch scm.cfg.metricType {
538 case "count":
539 metrics = scm.countMetrics
540
541 case "sum":
542 metrics = scm.sumMetrics
543
544 case "bucket":
545 metrics = scm.bucketMetrics
546 }
547
548 return metrics
549 }
550
551 func (scm *snapshotControllerMetrics) showMetricsFailure(metricKey string) {
552 framework.Logf("failed to find metric key %s inside of the following metrics:", metricKey)
553
554 metrics := scm.getMetricsTable()
555 for k, v := range metrics {
556 framework.Logf("%s: %v", k, v)
557 }
558 }
559
560 func (scm *snapshotControllerMetrics) grabSnapshotControllerMetrics(ctx context.Context) error {
561
562 metrics, err := scm.metricsGrabber.GrabFromSnapshotController(ctx, framework.TestContext.SnapshotControllerPodName, framework.TestContext.SnapshotControllerHTTPPort)
563 if err != nil {
564 return err
565 }
566
567 for method, samples := range metrics {
568
569 for _, sample := range samples {
570 operationName := string(sample.Metric["operation_name"])
571 driverName := string(sample.Metric["driver_name"])
572 operationStatus := string(sample.Metric["operation_status"])
573 snapshotType := string(sample.Metric["snapshot_type"])
574 le := string(sample.Metric["le"])
575 key := snapshotMetricKey(scm.cfg.metricName, driverName, operationName, operationStatus, snapshotType, le)
576
577 switch method {
578 case "snapshot_controller_operation_total_seconds_count":
579 for _, sample := range samples {
580 scm.countMetrics[key] = float64(sample.Value)
581 }
582
583 case "snapshot_controller_operation_total_seconds_sum":
584 for _, sample := range samples {
585 scm.sumMetrics[key] = float64(sample.Value)
586 }
587
588 case "snapshot_controller_operation_total_seconds_bucket":
589 for _, sample := range samples {
590 scm.bucketMetrics[key] = float64(sample.Value)
591 }
592 }
593 }
594 }
595
596 return nil
597 }
598
599 func (scm *snapshotControllerMetrics) getMetricKey() string {
600 return snapshotMetricKey(scm.cfg.metricName, scm.cfg.driverName, scm.cfg.operationName, scm.cfg.operationStatus, scm.cfg.snapshotType, scm.cfg.le)
601 }
602
603 func snapshotMetricKey(metricName, driverName, operationName, operationStatus, snapshotType, le string) string {
604 key := driverName
605
606
607 for _, s := range []string{metricName, operationName, operationStatus, snapshotType, le} {
608 if s != "" {
609 key = fmt.Sprintf("%s_%s", key, s)
610 }
611 }
612
613 return key
614 }
615
View as plain text