@@ -31,6 +31,7 @@ import (
31
31
"sigs.k8s.io/vsphere-csi-driver/v3/pkg/internalapis"
32
32
"sigs.k8s.io/vsphere-csi-driver/v3/pkg/internalapis/cnsoperator/cnsfilevolumeclient/v1alpha1"
33
33
k8s "sigs.k8s.io/vsphere-csi-driver/v3/pkg/kubernetes"
34
+ cnsoperatortypes "sigs.k8s.io/vsphere-csi-driver/v3/pkg/syncer/cnsoperator/types"
34
35
)
35
36
36
37
// FileVolumeClient exposes an interface to support
@@ -49,6 +50,9 @@ type FileVolumeClient interface {
49
50
// clientVMIP for a given file volume. fileVolumeName is used
50
51
// to uniquely identify CnsFileVolumeClient instances.
51
52
RemoveClientVMFromIPList (ctx context.Context , fileVolumeName , clientVMName , clientVMIP string ) error
53
+ // GetVMIPFromVMName returns the VMIP associated with a
54
+ // given client VM name.
55
+ GetVMIPFromVMName (ctx context.Context , fileVolumeName string , clientVMName string ) (string , int , error )
52
56
}
53
57
54
58
// fileVolumeClient maintains a client to the API
@@ -186,6 +190,8 @@ func (f *fileVolumeClient) AddClientVMToIPList(ctx context.Context,
186
190
ObjectMeta : v1.ObjectMeta {
187
191
Name : instanceName ,
188
192
Namespace : instanceNamespace ,
193
+ // Add finalizer so that CnsFileVolumeClient instance doesn't get deleted abruptly
194
+ Finalizers : []string {cnsoperatortypes .CNSFinalizer },
189
195
},
190
196
Spec : v1alpha1.CnsFileVolumeClientSpec {
191
197
ExternalIPtoClientVms : map [string ][]string {
@@ -282,9 +288,24 @@ func (f *fileVolumeClient) RemoveClientVMFromIPList(ctx context.Context,
282
288
delete (instance .Spec .ExternalIPtoClientVms , clientVMIP )
283
289
}
284
290
if len (instance .Spec .ExternalIPtoClientVms ) == 0 {
285
- log .Debugf ("Deleting cnsfilevolumeclient instance %s from API server" , fileVolumeName )
291
+ log .Infof ("Deleting cnsfilevolumeclient instance %s from API server" , fileVolumeName )
292
+ // Remove finalizer from CnsFileVolumeClient instance
293
+ err = removeFinalizer (ctx , f .client , instance )
294
+ if err != nil {
295
+ log .Errorf ("failed to remove finalizer from cnsfilevolumeclient instance %s with error: %+v" ,
296
+ fileVolumeName , err )
297
+ }
286
298
err = f .client .Delete (ctx , instance )
287
299
if err != nil {
300
+ // In case of namespace deletion, we will have deletion timestamp added on the
301
+ // CnsFileVolumeClient instance. So, as soon as we delete finalizer, instance might
302
+ // get deleted immediately. In such cases we will get NotFound error here, return success
303
+ // if instance is already deleted.
304
+ if errors .IsNotFound (err ) {
305
+ log .Infof ("cnsfilevolumeclient instance %s seems to be already deleted." , fileVolumeName )
306
+ f .volumeLock .Delete (fileVolumeName )
307
+ return nil
308
+ }
288
309
log .Errorf ("failed to delete cnsfilevolumeclient instance %s with error: %+v" , fileVolumeName , err )
289
310
return err
290
311
}
@@ -302,3 +323,76 @@ func (f *fileVolumeClient) RemoveClientVMFromIPList(ctx context.Context,
302
323
log .Debugf ("Could not find VM %s in list. Returning." , clientVMName )
303
324
return nil
304
325
}
326
+
327
+ // GetVMIPFromVMName returns the VM IP associated with a
328
+ // given client VM name.
329
+ // Callers need to specify fileVolumeName as a combination of
330
+ // "<SV-namespace>/<SV-PVC-name>". This combination is used to uniquely
331
+ // identify CnsFileVolumeClient instances.
332
+ // Returns an empty string if the instance doesn't exist OR if the
333
+ // input VM name is not present in this instance.
334
+ // Returns an error if any operations fails.
335
+ func (f * fileVolumeClient ) GetVMIPFromVMName (ctx context.Context ,
336
+ fileVolumeName string , clientVMName string ) (string , int , error ) {
337
+ log := logger .GetLogger (ctx )
338
+
339
+ log .Infof ("Fetching VM IP from cnsfilevolumeclient %s for VM name %s" , fileVolumeName , clientVMName )
340
+ actual , _ := f .volumeLock .LoadOrStore (fileVolumeName , & sync.Mutex {})
341
+ instanceLock , ok := actual .(* sync.Mutex )
342
+ if ! ok {
343
+ return "" , 0 , fmt .Errorf ("failed to cast lock for cnsfilevolumeclient instance: %s" , fileVolumeName )
344
+ }
345
+ instanceLock .Lock ()
346
+ defer instanceLock .Unlock ()
347
+
348
+ instance := & v1alpha1.CnsFileVolumeClient {}
349
+ instanceNamespace , instanceName , err := cache .SplitMetaNamespaceKey (fileVolumeName )
350
+ if err != nil {
351
+ log .Errorf ("failed to split key %s with error: %+v" , fileVolumeName , err )
352
+ return "" , 0 , err
353
+ }
354
+ instanceKey := types.NamespacedName {
355
+ Namespace : instanceNamespace ,
356
+ Name : instanceName ,
357
+ }
358
+ err = f .client .Get (ctx , instanceKey , instance )
359
+ if err != nil {
360
+ log .Errorf ("failed to get cnsfilevolumeclient instance %s with error: %+v" , fileVolumeName , err )
361
+ return "" , 0 , err
362
+ }
363
+
364
+ // Verify if input VM name exists in Spec.ExternalIPtoClientVms
365
+ log .Debugf ("Verifying if ExternalIPtoClientVms list has VM name: %s" , clientVMName )
366
+ for vmIP , vmNames := range instance .Spec .ExternalIPtoClientVms {
367
+ for _ , vmName := range vmNames {
368
+ if vmName == clientVMName {
369
+ return vmIP , len (vmNames ), nil
370
+ }
371
+ }
372
+ }
373
+ return "" , 0 , err
374
+ }
375
+
376
+ // removeFinalizer will remove the CNS Finalizer = cns.vmware.com,
377
+ // from a given CnsFileVolumeClient instance.
378
+ func removeFinalizer (ctx context.Context , client client.Client ,
379
+ instance * v1alpha1.CnsFileVolumeClient ) error {
380
+ log := logger .GetLogger (ctx )
381
+ for i , finalizer := range instance .Finalizers {
382
+ if finalizer == cnsoperatortypes .CNSFinalizer {
383
+ log .Debugf ("Removing %q finalizer from CnsFileVolumeClient instance with name: %q on namespace: %q" ,
384
+ cnsoperatortypes .CNSFinalizer , instance .Name , instance .Namespace )
385
+ instance .Finalizers = append (instance .Finalizers [:i ], instance .Finalizers [i + 1 :]... )
386
+ // Update the instance after removing finalizer
387
+ err := client .Update (ctx , instance )
388
+ if err != nil {
389
+ log .Errorf ("failed to update CnsFileVolumeClient instance with name: %q on namespace: %q" ,
390
+ instance .Name , instance .Namespace )
391
+ return err
392
+ }
393
+ break
394
+ }
395
+ }
396
+
397
+ return nil
398
+ }
0 commit comments