@@ -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,20 @@ 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 = removeFinalizerFromCRDInstance (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
+ if errors .IsNotFound (err ) {
301
+ log .Infof ("cnsfilevolumeclient instance %s seems to be already deleted." , fileVolumeName )
302
+ f .volumeLock .Delete (fileVolumeName )
303
+ return nil
304
+ }
288
305
log .Errorf ("failed to delete cnsfilevolumeclient instance %s with error: %+v" , fileVolumeName , err )
289
306
return err
290
307
}
@@ -302,3 +319,81 @@ func (f *fileVolumeClient) RemoveClientVMFromIPList(ctx context.Context,
302
319
log .Debugf ("Could not find VM %s in list. Returning." , clientVMName )
303
320
return nil
304
321
}
322
+
323
+ // GetVMIPFromVMName returns the VM IP associated with a
324
+ // given client VM name.
325
+ // Callers need to specify fileVolumeName as a combination of
326
+ // "<SV-namespace>/<SV-PVC-name>". This combination is used to uniquely
327
+ // identify CnsFileVolumeClient instances.
328
+ // Returns an empty string if the instance doesn't exist OR if the
329
+ // input VM name is not present in this instance.
330
+ // Returns an error if any operations fails.
331
+ func (f * fileVolumeClient ) GetVMIPFromVMName (ctx context.Context ,
332
+ fileVolumeName string , clientVMName string ) (string , int , error ) {
333
+ log := logger .GetLogger (ctx )
334
+
335
+ log .Infof ("Fetching VM IP from cnsfilevolumeclient %s for VM name %s" , fileVolumeName , clientVMName )
336
+ actual , _ := f .volumeLock .LoadOrStore (fileVolumeName , & sync.Mutex {})
337
+ instanceLock , ok := actual .(* sync.Mutex )
338
+ if ! ok {
339
+ return "" , 0 , fmt .Errorf ("failed to cast lock for cnsfilevolumeclient instance: %s" , fileVolumeName )
340
+ }
341
+ instanceLock .Lock ()
342
+ defer instanceLock .Unlock ()
343
+
344
+ instance := & v1alpha1.CnsFileVolumeClient {}
345
+ instanceNamespace , instanceName , err := cache .SplitMetaNamespaceKey (fileVolumeName )
346
+ if err != nil {
347
+ log .Errorf ("failed to split key %s with error: %+v" , fileVolumeName , err )
348
+ return "" , 0 , err
349
+ }
350
+ instanceKey := types.NamespacedName {
351
+ Namespace : instanceNamespace ,
352
+ Name : instanceName ,
353
+ }
354
+ err = f .client .Get (ctx , instanceKey , instance )
355
+ if err != nil {
356
+ if errors .IsNotFound (err ) {
357
+ // If the get() on the instance fails, then we return empty string.
358
+ log .Infof ("Cnsfilevolumeclient instance %s not found. Returning empty string" , fileVolumeName )
359
+ return "" , 0 , nil
360
+ }
361
+ log .Errorf ("failed to get cnsfilevolumeclient instance %s with error: %+v" , fileVolumeName , err )
362
+ return "" , 0 , err
363
+ }
364
+
365
+ // Verify if input VM name exists in Spec.ExternalIPtoClientVms
366
+ log .Debugf ("Verifying if ExternalIPtoClientVms list has VM name: %s" , clientVMName )
367
+ for vmIP , vmNames := range instance .Spec .ExternalIPtoClientVms {
368
+ for _ , vmName := range vmNames {
369
+ if vmName == clientVMName {
370
+ return vmIP , len (vmNames ), nil
371
+ }
372
+ }
373
+ }
374
+ return "" , 0 , nil
375
+ }
376
+
377
+ // removeFinalizerFromCRDInstance will remove the CNS Finalizer = cns.vmware.com,
378
+ // from a given CnsFileVolumeClient instance.
379
+ func removeFinalizerFromCRDInstance (ctx context.Context , client client.Client ,
380
+ instance * v1alpha1.CnsFileVolumeClient ) error {
381
+ log := logger .GetLogger (ctx )
382
+ for i , finalizer := range instance .Finalizers {
383
+ if finalizer == cnsoperatortypes .CNSFinalizer {
384
+ log .Debugf ("Removing %q finalizer from CnsFileVolumeClient instance with name: %q on namespace: %q" ,
385
+ cnsoperatortypes .CNSFinalizer , instance .Name , instance .Namespace )
386
+ instance .Finalizers = append (instance .Finalizers [:i ], instance .Finalizers [i + 1 :]... )
387
+ // Update the instance after removing finalizer
388
+ err := client .Update (ctx , instance )
389
+ if err != nil {
390
+ log .Errorf ("failed to update CnsFileVolumeClient instance with name: %q on namespace: %q" ,
391
+ instance .Name , instance .Namespace )
392
+ return err
393
+ }
394
+ break
395
+ }
396
+ }
397
+
398
+ return nil
399
+ }
0 commit comments