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