@@ -32,6 +32,7 @@ import (
3232 klog "k8s.io/klog/v2"
3333
3434 crdv1 "github.com/kubernetes-csi/external-snapshotter/client/v3/apis/volumesnapshot/v1beta1"
35+ "github.com/kubernetes-csi/external-snapshotter/v3/pkg/metrics"
3536 "github.com/kubernetes-csi/external-snapshotter/v3/pkg/utils"
3637)
3738
@@ -235,6 +236,20 @@ func (ctrl *csiSnapshotCommonController) syncSnapshot(snapshot *crdv1.VolumeSnap
235236// 2. Call checkandRemoveSnapshotFinalizersAndCheckandDeleteContent() with information obtained from step 1. This function name is very long but the name suggests what it does. It determines whether to remove finalizers on snapshot and whether to delete content.
236237func (ctrl * csiSnapshotCommonController ) processSnapshotWithDeletionTimestamp (snapshot * crdv1.VolumeSnapshot ) error {
237238 klog .V (5 ).Infof ("processSnapshotWithDeletionTimestamp VolumeSnapshot[%s]: %s" , utils .SnapshotKey (snapshot ), utils .GetSnapshotStatusForLogging (snapshot ))
239+ driverName , err := ctrl .getSnapshotDriverName (snapshot )
240+ if err != nil {
241+ klog .Errorf ("failed to getSnapshotDriverName while recording metrics for snapshot %q: %v" , utils .SnapshotKey (snapshot ), err )
242+ }
243+
244+ snapshotProvisionType := metrics .DynamicSnapshotType
245+ if snapshot .Spec .Source .VolumeSnapshotContentName != nil {
246+ snapshotProvisionType = metrics .PreProvisionedSnapshotType
247+ }
248+
249+ // Processing delete, start operation metric
250+ deleteOperationKey := metrics .NewOperationKey (metrics .DeleteSnapshotOperationName , snapshot .UID )
251+ deleteOperationValue := metrics .NewOperationValue (driverName , snapshotProvisionType )
252+ ctrl .metricsManager .OperationStart (deleteOperationKey , deleteOperationValue )
238253
239254 var contentName string
240255 if snapshot .Status != nil && snapshot .Status .BoundVolumeSnapshotContentName != nil {
@@ -269,6 +284,7 @@ func (ctrl *csiSnapshotCommonController) processSnapshotWithDeletionTimestamp(sn
269284 }
270285
271286 klog .V (5 ).Infof ("processSnapshotWithDeletionTimestamp[%s]: delete snapshot content and remove finalizer from snapshot if needed" , utils .SnapshotKey (snapshot ))
287+
272288 return ctrl .checkandRemoveSnapshotFinalizersAndCheckandDeleteContent (snapshot , content , deleteContent )
273289}
274290
@@ -388,6 +404,7 @@ func (ctrl *csiSnapshotCommonController) syncReadySnapshot(snapshot *crdv1.Volum
388404 // snapshot is bound but content is not pointing to the snapshot
389405 return ctrl .updateSnapshotErrorStatusWithEvent (snapshot , v1 .EventTypeWarning , "SnapshotMisbound" , "VolumeSnapshotContent is not bound to the VolumeSnapshot correctly" )
390406 }
407+
391408 // everything is verified, return
392409 return nil
393410}
@@ -396,20 +413,45 @@ func (ctrl *csiSnapshotCommonController) syncReadySnapshot(snapshot *crdv1.Volum
396413func (ctrl * csiSnapshotCommonController ) syncUnreadySnapshot (snapshot * crdv1.VolumeSnapshot ) error {
397414 uniqueSnapshotName := utils .SnapshotKey (snapshot )
398415 klog .V (5 ).Infof ("syncUnreadySnapshot %s" , uniqueSnapshotName )
416+ driverName , err := ctrl .getSnapshotDriverName (snapshot )
417+ if err != nil {
418+ klog .Errorf ("failed to getSnapshotDriverName while recording metrics for snapshot %q: %s" , utils .SnapshotKey (snapshot ), err )
419+ }
420+
421+ snapshotProvisionType := metrics .DynamicSnapshotType
422+ if snapshot .Spec .Source .VolumeSnapshotContentName != nil {
423+ snapshotProvisionType = metrics .PreProvisionedSnapshotType
424+ }
425+
426+ // Start metrics operations
427+ if ! utils .IsSnapshotCreated (snapshot ) {
428+ // Only start CreateSnapshot operation if the snapshot has not been cut
429+ ctrl .metricsManager .OperationStart (
430+ metrics .NewOperationKey (metrics .CreateSnapshotOperationName , snapshot .UID ),
431+ metrics .NewOperationValue (driverName , snapshotProvisionType ),
432+ )
433+ }
434+ ctrl .metricsManager .OperationStart (
435+ metrics .NewOperationKey (metrics .CreateSnapshotAndReadyOperationName , snapshot .UID ),
436+ metrics .NewOperationValue (driverName , snapshotProvisionType ),
437+ )
399438
400439 // Pre-provisioned snapshot
401440 if snapshot .Spec .Source .VolumeSnapshotContentName != nil {
402441 content , err := ctrl .getPreprovisionedContentFromStore (snapshot )
403442 if err != nil {
404443 return err
405444 }
445+
406446 // if no content found yet, update status and return
407447 if content == nil {
408448 // can not find the desired VolumeSnapshotContent from cache store
409449 ctrl .updateSnapshotErrorStatusWithEvent (snapshot , v1 .EventTypeWarning , "SnapshotContentMissing" , "VolumeSnapshotContent is missing" )
410450 klog .V (4 ).Infof ("syncUnreadySnapshot[%s]: snapshot content %q requested but not found, will try again" , utils .SnapshotKey (snapshot ), * snapshot .Spec .Source .VolumeSnapshotContentName )
451+
411452 return fmt .Errorf ("snapshot %s requests an non-existing content %s" , utils .SnapshotKey (snapshot ), * snapshot .Spec .Source .VolumeSnapshotContentName )
412453 }
454+
413455 // Set VolumeSnapshotRef UID
414456 newContent , err := ctrl .checkandBindSnapshotContent (snapshot , content )
415457 if err != nil {
@@ -426,8 +468,10 @@ func (ctrl *csiSnapshotCommonController) syncUnreadySnapshot(snapshot *crdv1.Vol
426468 ctrl .updateSnapshotErrorStatusWithEvent (snapshot , v1 .EventTypeWarning , "SnapshotStatusUpdateFailed" , fmt .Sprintf ("Snapshot status update failed, %v" , err ))
427469 return err
428470 }
471+
429472 return nil
430473 }
474+
431475 // snapshot.Spec.Source.VolumeSnapshotContentName == nil - dynamically creating snapshot
432476 klog .V (5 ).Infof ("getDynamicallyProvisionedContentFromStore for snapshot %s" , uniqueSnapshotName )
433477 contentObj , err := ctrl .getDynamicallyProvisionedContentFromStore (snapshot )
@@ -1094,10 +1138,30 @@ func (ctrl *csiSnapshotCommonController) updateSnapshotStatus(snapshot *crdv1.Vo
10941138 if updated {
10951139 snapshotClone := snapshotObj .DeepCopy ()
10961140 snapshotClone .Status = newStatus
1141+
1142+ // We need to record metrics before updating the status due to a bug causing cache entries after a failed UpdateStatus call.
1143+ // Must meet the following criteria to emit a successful CreateSnapshot status
1144+ // 1. Previous status was nil OR Previous status had a nil CreationTime
1145+ // 2. New status must be non-nil with a non-nil CreationTime
1146+ driverName := content .Spec .Driver
1147+ createOperationKey := metrics .NewOperationKey (metrics .CreateSnapshotOperationName , snapshot .UID )
1148+ if ! utils .IsSnapshotCreated (snapshotObj ) && utils .IsSnapshotCreated (snapshotClone ) {
1149+ ctrl .metricsManager .RecordMetrics (createOperationKey , metrics .NewSnapshotOperationStatus (metrics .SnapshotStatusTypeSuccess ), driverName )
1150+ }
1151+
1152+ // Must meet the following criteria to emit a successful CreateSnapshotAndReady status
1153+ // 1. Previous status was nil OR Previous status had a nil ReadyToUse OR Previous status had a false ReadyToUse
1154+ // 2. New status must be non-nil with a ReadyToUse as true
1155+ if ! utils .IsSnapshotReady (snapshotObj ) && utils .IsSnapshotReady (snapshotClone ) {
1156+ createAndReadyOperation := metrics .NewOperationKey (metrics .CreateSnapshotAndReadyOperationName , snapshot .UID )
1157+ ctrl .metricsManager .RecordMetrics (createAndReadyOperation , metrics .NewSnapshotOperationStatus (metrics .SnapshotStatusTypeSuccess ), driverName )
1158+ }
1159+
10971160 newSnapshotObj , err := ctrl .clientset .SnapshotV1beta1 ().VolumeSnapshots (snapshotClone .Namespace ).UpdateStatus (context .TODO (), snapshotClone , metav1.UpdateOptions {})
10981161 if err != nil {
10991162 return nil , newControllerUpdateError (utils .SnapshotKey (snapshot ), err .Error ())
11001163 }
1164+
11011165 return newSnapshotObj , nil
11021166 }
11031167
@@ -1177,6 +1241,45 @@ func (ctrl *csiSnapshotCommonController) getSnapshotClass(className string) (*cr
11771241 return class , nil
11781242}
11791243
1244+ // getSnapshotDriverName is a helper function to get snapshot driver from the VolumeSnapshot.
1245+ // We try to get the driverName in multiple ways, as snapshot controller metrics depend on the correct driverName.
1246+ func (ctrl * csiSnapshotCommonController ) getSnapshotDriverName (vs * crdv1.VolumeSnapshot ) (string , error ) {
1247+ klog .V (5 ).Infof ("getSnapshotDriverName: VolumeSnapshot[%s]" , vs .Name )
1248+ var driverName string
1249+
1250+ // Pre-Provisioned snapshots have contentName as source
1251+ var contentName string
1252+ if vs .Spec .Source .VolumeSnapshotContentName != nil {
1253+ contentName = * vs .Spec .Source .VolumeSnapshotContentName
1254+ }
1255+
1256+ // Get Driver name from SnapshotContent if we found a contentName
1257+ if contentName != "" {
1258+ content , err := ctrl .contentLister .Get (contentName )
1259+ if err != nil {
1260+ klog .Errorf ("getSnapshotDriverName: failed to get snapshotContent: %v" , contentName )
1261+ } else {
1262+ driverName = content .Spec .Driver
1263+ }
1264+
1265+ if driverName != "" {
1266+ return driverName , nil
1267+ }
1268+ }
1269+
1270+ // Dynamic snapshots will have a snapshotclass with a driver
1271+ if vs .Spec .VolumeSnapshotClassName != nil {
1272+ class , err := ctrl .getSnapshotClass (* vs .Spec .VolumeSnapshotClassName )
1273+ if err != nil {
1274+ klog .Errorf ("getSnapshotDriverName: failed to get snapshotClass: %v" , * vs .Spec .VolumeSnapshotClassName )
1275+ } else {
1276+ driverName = class .Driver
1277+ }
1278+ }
1279+
1280+ return driverName , nil
1281+ }
1282+
11801283// SetDefaultSnapshotClass is a helper function to figure out the default snapshot class.
11811284// For pre-provisioned case, it's an no-op.
11821285// For dynamic provisioning, it gets the default SnapshotClasses in the system if there is any(could be multiple),
0 commit comments