@@ -49,7 +49,7 @@ def setUp(self) -> None:
4949 def tearDown (self ) -> None :
5050 self .remove_stubs ()
5151
52- def create_LVMSR (self , master = False , command = 'foo' , sr_uuid = None ):
52+ def create_LVMSR (self , master = False , command = 'foo' , sr_uuid = None , extra_params = {} ):
5353 srcmd = mock .Mock ()
5454 srcmd .dconf = {'device' : '/dev/bar' }
5555 if master :
@@ -58,6 +58,7 @@ def create_LVMSR(self, master=False, command='foo', sr_uuid=None):
5858 'command' : command ,
5959 'session_ref' : 'some session ref' ,
6060 'sr_ref' : 'test_sr_ref' }
61+ srcmd .params .update (extra_params )
6162 if sr_uuid is None :
6263 sr_uuid = str (uuid .uuid4 ())
6364 return LVMSR .LVMSR (srcmd , sr_uuid )
@@ -184,8 +185,6 @@ def get_vdi_by_uuid(vdi_uuid):
184185 lambda x : get_vdi_data ('name_description' , x ))
185186 mock_session .xenapi .VDI .get_is_a_snapshot .side_effect = (
186187 lambda x : get_vdi_data ('is_a_snapshot' , x ))
187- mock_session .xenapi .VDI .get_snapshot_of .side_effect = (
188- lambda x : get_vdi_data ('snapshot_of' , x ))
189188 mock_session .xenapi .VDI .get_snapshot_time .side_effect = (
190189 lambda x : get_vdi_data ('snapshot_time' , x ))
191190 mock_session .xenapi .VDI .get_type .side_effect = (
@@ -457,6 +456,210 @@ def test_scan_metadata_vdi_not_in_xapi_lv_exists(
457456 call_args = mock_session .xenapi .VDI .db_introduce .call_args
458457 self .assertEqual (call_args [0 ][0 ], new_vdi_uuid )
459458
459+ @mock .patch ('LVMSR.cleanup' , autospec = True )
460+ @mock .patch ('LVMSR.IPCFlag' , autospec = True )
461+ @mock .patch ('LVMSR.lock.Lock' , autospec = True )
462+ @mock .patch ('lvmcowutil.LvmCowUtil.getVolumeInfo' )
463+ @mock .patch ('lvmcowutil.LvmCowUtil.getVDIInfo' )
464+ @mock .patch ('LVMSR.SR.XenAPI' )
465+ @testlib .with_context
466+ def test_snapshotof_success (self ,
467+ context ,
468+ mock_xenapi ,
469+ mock_getVDIInfo ,
470+ mock_getVolumeInfo ,
471+ mock_lock ,
472+ mock_ipc ,
473+ mock_cleanup ):
474+ sr_uuid = str (uuid .uuid4 ())
475+ self .stubout ('LVMSR.lvutil._checkVG' , autospec = True )
476+ mock_lvm_cache = self .stubout ('LVMSR.lvmcache.LVMCache' )
477+ mock_get_vg_stats = self .stubout ('LVMSR.lvutil._getVGstats' , autospec = True )
478+ mock_scsi_get_size = self .stubout ('LVMSR.scsiutil.getsize' , autospec = True )
479+ mock_cowutil_getAllInfoFromVG = self .stubout ("cowutil.CowUtil.getAllInfoFromVG" , autospec = True )
480+ mock_sr_util_pathexists = self .stubout ('LVMSR.util.pathexists' , autospec = True )
481+ mock_sr_util_gen_uuid = self .stubout ('LVMSR.util.gen_uuid' , autospec = True )
482+ mock_cleanup .SR .TMP_RENAME_PREFIX = cleanup .SR .TMP_RENAME_PREFIX
483+
484+ device_size = 100 * 1024 * 1024
485+ device_free = 10 * 1024 * 1024
486+ mock_get_vg_stats .return_value = {
487+ 'physical_size' : device_size ,
488+ 'physical_utilisation' : device_free ,
489+ 'freespace' : device_size - device_free }
490+ mock_scsi_get_size .return_value = device_size
491+ mock_lvm_cache .return_value .checkLV .return_value = False
492+ mock_lvm_cache .return_value .getSize .return_value = 10240
493+
494+ mock_session = mock_xenapi .xapi_local .return_value
495+ mock_session .xenapi .SR .get_sm_config .return_value = {
496+ 'allocation' : 'thick' ,
497+ 'use_vhd' : 'true'
498+ }
499+ vdi_data = {
500+ 'vdi1_ref' : {
501+ 'uuid' : str (uuid .uuid4 ()),
502+ 'name_label' : "VDI1" ,
503+ 'name_description' : "First VDI" ,
504+ 'is_a_snapshot' : False ,
505+ 'snapshot_of' : None ,
506+ 'snapshot_time' : None ,
507+ 'type' : 'User' ,
508+ 'metadata-of-pool' : None ,
509+ 'sm-config' : {
510+ 'vdi_type' : 'vhd'
511+ }
512+ }
513+ }
514+ metadata = {}
515+
516+ def get_vdis (sr_ref ):
517+ return list (vdi_data .keys ())
518+
519+ def get_vdi_data (vdi_key , vdi_ref ):
520+ return vdi_data [vdi_ref ][vdi_key ]
521+
522+ def get_vdi_by_uuid (vdi_uuid ):
523+ return [v for v in vdi_data if vdi_data [v ]['uuid' ] == vdi_uuid ][0 ]
524+
525+ def db_introduce (uuid , label , description , sr_ref , ty , shareable , read_only , other_config , location , xenstore_data , sm_config , managed , size , utilisation , metadata_of_pool , is_a_snapshot , snapshot_time , snapshot_of , cbt_enabled ):
526+ vdi_data .update ({
527+ 'vdi3_ref' : {
528+ 'uuid' : uuid ,
529+ 'name_label' : label ,
530+ 'name_description' : description ,
531+ 'is_a_snapshot' : is_a_snapshot ,
532+ 'snapshot_of' : snapshot_of ,
533+ 'snapshot_time' : snapshot_time ,
534+ 'type' : ty ,
535+ 'metadata-of-pool' : metadata_of_pool ,
536+ 'sm-config' : {
537+ 'vdi_type' : 'vhd'
538+ }
539+ }})
540+ return 'vdi3_ref'
541+
542+ mock_session .xenapi .VDI .get_uuid .side_effect = (
543+ lambda x : get_vdi_data ('uuid' , x ))
544+ mock_session .xenapi .VDI .get_name_label .side_effect = (
545+ lambda x : get_vdi_data ('name_label' , x ))
546+ mock_session .xenapi .VDI .get_name_description .side_effect = (
547+ lambda x : get_vdi_data ('name_description' , x ))
548+ mock_session .xenapi .VDI .get_is_a_snapshot .side_effect = (
549+ lambda x : get_vdi_data ('is_a_snapshot' , x ))
550+ mock_session .xenapi .VDI .get_snapshot_of .side_effect = (
551+ lambda x : get_vdi_data ('snapshot_of' , x ))
552+ mock_session .xenapi .VDI .get_snapshot_time .side_effect = (
553+ lambda x : get_vdi_data ('snapshot_time' , x ))
554+ mock_session .xenapi .VDI .get_type .side_effect = (
555+ lambda x : get_vdi_data ('type' , x ))
556+ mock_session .xenapi .VDI .get_metadata_of_pool .side_effect = (
557+ lambda x : get_vdi_data ('metadata-of-pool' , x ))
558+ mock_session .xenapi .VDI .get_sm_config .side_effect = (
559+ lambda x : get_vdi_data ('sm-config' , x ))
560+ mock_session .xenapi .SR .get_VDIs .side_effect = get_vdis
561+ mock_session .xenapi .VDI .get_by_uuid .side_effect = get_vdi_by_uuid
562+ mock_session .xenapi .VDI .db_introduce .side_effect = db_introduce
563+
564+ sr = self .create_LVMSR (master = True , command = 'sr_attach' ,
565+ sr_uuid = sr_uuid ,
566+ extra_params = {'driver_params' : {'type' : 'double' }, 'vdi_ref' : 'vdi1_ref' })
567+ os .makedirs (sr .path )
568+
569+ # Act (1)
570+ # This introduces the metadata volume
571+ sr .attach (sr .uuid )
572+
573+ # Create and check snapshot in metadata
574+ vdis_info = {}
575+ def addVdi (vdi_info ):
576+ uuid = vdi_info ['uuid' ]
577+ metadata [uuid ] = {
578+ 'uuid' : uuid ,
579+ 'is_a_snapshot' : vdi_info ['is_a_snapshot' ],
580+ 'snapshot_of' : vdi_info ['snapshot_of' ],
581+ 'vdi_type' : vdi_info ['vdi_type' ],
582+ 'name_label' : vdi_info ['name_label' ],
583+ 'name_description' : vdi_info ['name_description' ],
584+ 'type' : vdi_info ['type' ],
585+ 'read_only' : False ,
586+ 'managed' : True
587+ }
588+ vdi_data ['vdi3_ref' ]['snapshot_of' ] = 'vdi3_ref'
589+ vdi_data ['vdi3_ref' ]['is_a_snapshot' ] = vdi_info ['is_a_snapshot' ]
590+ vdis_info .update ({uuid : lvmcowutil .VDIInfo (uuid )})
591+
592+ def write_metadata (sr_info , vdi_info ):
593+ for item in vdi_info .items ():
594+ metadata [item [0 ]] = {
595+ 'uuid' : item [1 ]['uuid' ],
596+ 'is_a_snapshot' : item [1 ]['is_a_snapshot' ],
597+ 'snapshot_of' : item [1 ]['snapshot_of' ],
598+ 'vdi_type' : item [1 ]['vdi_type' ],
599+ 'name_label' : item [1 ]['name_label' ],
600+ 'name_description' : item [1 ]['name_description' ],
601+ 'type' : item [1 ]['type' ],
602+ 'read_only' : False ,
603+ 'managed' : True ,
604+ }
605+ return metadata
606+
607+ mock_metadata = self .stubout ('LVMSR.LVMMetadataHandler' )
608+ mock_metadata .return_value .addVdi .side_effect = addVdi
609+ mock_metadata .return_value .writeMetadata .side_effect = write_metadata
610+
611+ self .stubout ('journaler.Journaler.create' )
612+ self .stubout ('journaler.Journaler.remove' )
613+ self .stubout ('LVMSR.RefCounter.set' )
614+ self .stubout ('LVMSR.RefCounter.put' )
615+
616+ vdi_uuid = get_vdi_data ('uuid' , 'vdi1_ref' )
617+
618+ for vdi_meta in vdi_data .values ():
619+ vdis_info .update ({vdi_meta ['uuid' ]: lvmcowutil .VDIInfo (vdi_meta ['uuid' ])})
620+ mock_getVDIInfo .return_value = vdis_info
621+
622+ mock_lv = lvutil .LVInfo ('test-lv' )
623+ mock_lv .size = 10240
624+ mock_lv .active = True
625+ mock_lv .hidden = False
626+ mock_lv .vdiType = VdiType .VHD
627+
628+ mock_getVolumeInfo .return_value = {vdi_uuid : mock_lv }
629+
630+ vdiInfo = cowutil .CowImageInfo (vdi_uuid )
631+ vdiInfo .hidden = False
632+
633+ mock_getCowUtil = self .stubout ('LVMSR.getCowUtil' )
634+ mock_cowutil = mock_getCowUtil .return_value
635+ mock_cowutil .getInfo .return_value = vdiInfo
636+
637+ mock_cowutil_getAllInfoFromVG .return_value = {vdiInfo .uuid : vdiInfo }
638+
639+ vdi = sr .vdi (vdi_uuid )
640+ vdi .vdi_type = VdiType .VHD
641+ mock_sr_util_pathexists .return_value = True
642+ def gen_uuid ():
643+ return str (uuid .uuid4 ())
644+ mock_sr_util_gen_uuid .side_effect = gen_uuid
645+ mock_cowutil .getDepth .return_value = 1
646+ mock_cowutil .getMaxChainLength .return_value = 30
647+ mock_cowutil .getDefaultPreallocationSizeVirt .return_value = 0
648+ mock_cowutil .calcOverheadEmpty .return_value = 0
649+ mock_cowutil .calcOverheadBitmap .return_value = 0
650+ mock_cowutil .getSizePhys .return_value = 10240
651+ mock_cowutil .getParentChain .return_value = {vdi_uuid : 'test-lv' }
652+ self .stubout ('LVMSR.LVMSR._ensureSpaceAvailable' )
653+
654+ snap = vdi .snapshot (sr .uuid , vdi_uuid )
655+ snapshot_of = metadata [get_vdi_data ('uuid' , 'vdi3_ref' )]['snapshot_of' ]
656+ self .assertEqual (snapshot_of .startswith ('OpaqueRef:' ), False )
657+
658+ # Update SR metadata and recheck snapshot field
659+ metadata = {}
660+ sr .updateSRMetadata ('thick' )
661+ snapshot_of = metadata [get_vdi_data ('uuid' , 'vdi3_ref' )]['snapshot_of' ]
662+ self .assertEqual (snapshot_of .startswith ('OpaqueRef:' ), False )
460663
461664class TestLVMVDI (unittest .TestCase , Stubs ):
462665 @override
0 commit comments