@@ -404,12 +404,42 @@ def _poll_volume_field(self, vol_id, field, target, timeout=120,
404404 time .sleep (interval )
405405 return None
406406
407- def _lun_maps (self ):
408- """Return current LUN-maps for the pool's FlexVol."""
409- if self .__class__ .pool is None :
407+ def _data_lun_name (self , volume = None ):
408+ """
409+ Full ONTAP path of the LUN backing the CloudStack data volume.
410+
411+ UnifiedSANStrategy names the LUN after the CloudStack volume with
412+ hyphens replaced by underscores, inside the pool's FlexVol.
413+ """
414+ volume = volume or self .__class__ .volume
415+ if volume is None or self .__class__ .pool is None :
416+ return None
417+ return "/vol/%s/%s" % (self .__class__ .pool .name ,
418+ volume .name .replace ("-" , "_" ))
419+
420+ def _lun_maps (self , volume = None ):
421+ """
422+ Return LUN-maps belonging to the data volume's LUN only.
423+
424+ The same FlexVol also holds the VM's ROOT LUN whenever the allocator
425+ places the root disk on this pool, so the unfiltered map list is not a
426+ measure of the data volume's accessibility.
427+ """
428+ lun_name = self ._data_lun_name (volume )
429+ if lun_name is None :
430+ return []
431+ return [m for m in self .ontap .list_lun_maps_for_volume (
432+ self .svm_name , self .__class__ .pool .name )
433+ if m .get ("lun" , {}).get ("name" ) == lun_name ]
434+
435+ def _data_luns (self , volume = None ):
436+ """Return LUN records for the data volume's LUN only."""
437+ lun_name = self ._data_lun_name (volume )
438+ if lun_name is None :
410439 return []
411- return self .ontap .list_lun_maps_for_volume (
412- self .svm_name , self .__class__ .pool .name )
440+ return [lun for lun in self .ontap .list_luns_in_volume (
441+ self .svm_name , self .__class__ .pool .name )
442+ if lun .get ("name" ) == lun_name ]
413443
414444 # ==================================================================
415445 # Test steps
@@ -462,12 +492,12 @@ def test_02_create_ontap_data_volume(self):
462492 self .__class__ .volume = vol
463493 self .assertIsNotNone (vol , "createVolume returned None" )
464494
465- luns = self .ontap .list_luns_in_volume (
466- self .svm_name , self .__class__ .pool .name )
495+ luns = self ._data_luns ()
467496 self .assertTrue (
468497 len (luns ) > 0 ,
469- "Expected ≥1 LUN in ONTAP FlexVol '%s' after volume creation, "
470- "found 0" % self .__class__ .pool .name
498+ "Expected the data volume's LUN '%s' in ONTAP FlexVol '%s' after "
499+ "volume creation, found none"
500+ % (self ._data_lun_name (), self .__class__ .pool .name )
471501 )
472502
473503 # ------------------------------------------------------------------
@@ -511,7 +541,7 @@ def test_03_deploy_vm(self):
511541 lun_maps = self ._lun_maps ()
512542 self .assertEqual (
513543 len (lun_maps ), 0 ,
514- "Expected 0 LUN-maps before volume attach, found %d: %s"
544+ "Expected 0 data-volume LUN-maps before volume attach, found %d: %s"
515545 % (len (lun_maps ), lun_maps )
516546 )
517547
@@ -590,16 +620,15 @@ def test_05_stop_vm_lun_unmapped(self):
590620 lun_maps = self ._lun_maps ()
591621 self .assertEqual (
592622 len (lun_maps ), 0 ,
593- "Expected 0 LUN-maps after VM stop, found %d: %s"
623+ "Expected 0 data-volume LUN-maps after VM stop, found %d: %s"
594624 % (len (lun_maps ), lun_maps )
595625 )
596626
597627 # ONTAP: LUN itself must still exist in the FlexVol
598- luns = self .ontap .list_luns_in_volume (
599- self .svm_name , self .__class__ .pool .name )
628+ luns = self ._data_luns ()
600629 self .assertTrue (
601630 len (luns ) > 0 ,
602- "LUN should still exist in ONTAP FlexVol after VM stop"
631+ "Data volume LUN should still exist in ONTAP FlexVol after VM stop"
603632 )
604633
605634 # ------------------------------------------------------------------
@@ -689,16 +718,15 @@ def test_07_detach_volume_from_vm(self):
689718 lun_maps = self ._lun_maps ()
690719 self .assertEqual (
691720 len (lun_maps ), 0 ,
692- "Expected 0 LUN-maps after volume detach, found %d: %s"
721+ "Expected 0 data-volume LUN-maps after volume detach, found %d: %s"
693722 % (len (lun_maps ), lun_maps )
694723 )
695724
696725 # ONTAP: LUN still exists in FlexVol
697- luns = self .ontap .list_luns_in_volume (
698- self .svm_name , self .__class__ .pool .name )
726+ luns = self ._data_luns ()
699727 self .assertTrue (
700728 len (luns ) > 0 ,
701- "LUN should still exist in ONTAP FlexVol after detach"
729+ "Data volume LUN should still exist in ONTAP FlexVol after detach"
702730 )
703731
704732 # ------------------------------------------------------------------
@@ -751,11 +779,11 @@ def test_08_destroy_vm_and_cleanup(self):
751779 self .__class__ .volume = None
752780
753781 # ONTAP: LUN must be removed after volume deletion
754- luns = self .ontap . list_luns_in_volume ( self . svm_name , pool_name )
782+ luns = self ._data_luns ( vol )
755783 self .assertEqual (
756784 len (luns ), 0 ,
757- "Expected 0 LUNs in FlexVol '%s' after volume delete, "
758- "found %d" % (pool_name , len (luns ))
785+ "Expected the data volume's LUN to be gone from FlexVol '%s' "
786+ "after volume delete, found %d" % (pool_name , len (luns ))
759787 )
760788
761789 # Enter maintenance and force-delete the pool
0 commit comments