<s> """<STR_LIT>""" <EOL> from uuid import UUID , uuid4 <EOL> from subprocess import check_output <EOL> from bitmath import MiB <EOL> from zope . interface import implementer <EOL> from twisted . python . filepath import FilePath <EOL> from twisted . python . components import proxyForInterface <EOL> from . blockdevice import ( <EOL> BlockDeviceVolume , <EOL> IBlockDeviceAPI , <EOL> UnknownInstanceID , <EOL> AlreadyAttachedVolume , <EOL> UnattachedVolume , <EOL> allocated_size , <EOL> get_blockdevice_volume , <EOL> ) <EOL> LOOPBACK_ALLOCATION_UNIT = int ( MiB ( <NUM_LIT:1> ) . to_Byte ( ) . value ) <EOL> LOOPBACK_MINIMUM_ALLOCATABLE_SIZE = int ( MiB ( <NUM_LIT:16> ) . to_Byte ( ) . value ) <EOL> def _blockdevicevolume_from_dataset_id ( dataset_id , size , <EOL> attached_to = None ) : <EOL> """<STR_LIT>""" <EOL> return BlockDeviceVolume ( <EOL> size = size , attached_to = attached_to , <EOL> dataset_id = dataset_id , blockdevice_id = u"<STR_LIT>" . format ( dataset_id ) , <EOL> ) <EOL> def _blockdevicevolume_from_blockdevice_id ( blockdevice_id , size , <EOL> attached_to = None ) : <EOL> """<STR_LIT>""" <EOL> dataset_id = UUID ( blockdevice_id [ <NUM_LIT:6> : ] ) <EOL> return BlockDeviceVolume ( <EOL> size = size , attached_to = attached_to , <EOL> dataset_id = dataset_id , <EOL> blockdevice_id = blockdevice_id , <EOL> ) <EOL> def _losetup_list_parse ( output ) : <EOL> """<STR_LIT>""" <EOL> devices = [ ] <EOL> for line in output . splitlines ( ) : <EOL> parts = line . split ( u"<STR_LIT::>" , <NUM_LIT:2> ) <EOL> if len ( parts ) != <NUM_LIT:3> : <EOL> continue <EOL> device_file , _ , backing_file = parts <EOL> device_file = FilePath ( device_file . strip ( ) . encode ( "<STR_LIT:utf-8>" ) ) <EOL> left_bracket_offset = backing_file . find ( b"<STR_LIT:(>" ) <EOL> backing_file = backing_file [ left_bracket_offset + <NUM_LIT:1> : ] <EOL> right_bracket_offset = backing_file . rfind ( b"<STR_LIT:)>" ) <EOL> backing_file = backing_file [ : right_bracket_offset ] <EOL> expected_suffix_list = [ b"<STR_LIT>" ] <EOL> for suffix in expected_suffix_list : <EOL> offset = backing_file . rfind ( suffix ) <EOL> if offset > - <NUM_LIT:1> : <EOL> backing_file = backing_file [ : offset ] <EOL> backing_file = backing_file . rstrip ( ) <EOL> backing_file = FilePath ( backing_file . encode ( "<STR_LIT:utf-8>" ) ) <EOL> devices . append ( ( device_file , backing_file ) ) <EOL> return devices <EOL> def _losetup_list ( ) : <EOL> """<STR_LIT>""" <EOL> output = check_output ( <EOL> [ "<STR_LIT>" , "<STR_LIT>" ] <EOL> ) . decode ( '<STR_LIT:utf8>' ) <EOL> return _losetup_list_parse ( output ) <EOL> def _device_for_path ( expected_backing_file ) : <EOL> """<STR_LIT>""" <EOL> for device_file , backing_file in _losetup_list ( ) : <EOL> if expected_backing_file == backing_file : <EOL> return device_file <EOL> def check_allocatable_size ( allocation_unit , requested_size ) : <EOL> """<STR_LIT>""" <EOL> actual_size = allocated_size ( allocation_unit , requested_size ) <EOL> if requested_size != actual_size : <EOL> raise ValueError ( <EOL> '<STR_LIT>' . format ( <EOL> requested_size , allocation_unit <EOL> ) <EOL> ) <EOL> DEFAULT_LOOPBACK_PATH = '<STR_LIT>' <EOL> def _backing_file_name ( volume ) : <EOL> """<STR_LIT>""" <EOL> return volume . blockdevice_id . encode ( '<STR_LIT:ascii>' ) + '<STR_LIT:_>' + bytes ( volume . size ) <EOL> @ implementer ( IBlockDeviceAPI ) <EOL> class LoopbackBlockDeviceAPI ( object ) : <EOL> """<STR_LIT>""" <EOL> _attached_directory_name = '<STR_LIT>' <EOL> _unattached_directory_name = '<STR_LIT>' <EOL> def __init__ ( self , root_path , compute_instance_id , allocation_unit = None ) : <EOL> """<STR_LIT>""" <EOL> self . _root_path = root_path <EOL> self . _compute_instance_id = compute_instance_id <EOL> if allocation_unit is None : <EOL> allocation_unit = <NUM_LIT:1> <EOL> self . _allocation_unit = allocation_unit <EOL> @ classmethod <EOL> def from_path ( <EOL> cls , root_path = DEFAULT_LOOPBACK_PATH , compute_instance_id = None , <EOL> allocation_unit = None ) : <EOL> """<STR_LIT>""" <EOL> if compute_instance_id is None : <EOL> compute_instance_id = unicode ( uuid4 ( ) ) <EOL> api = cls ( <EOL> root_path = FilePath ( root_path ) , <EOL> compute_instance_id = compute_instance_id , <EOL> allocation_unit = allocation_unit , <EOL> ) <EOL> api . _initialise_directories ( ) <EOL> return api <EOL> def _initialise_directories ( self ) : <EOL> """<STR_LIT>""" <EOL> self . _unattached_directory = self . _root_path . child ( <EOL> self . _unattached_directory_name ) <EOL> try : <EOL> self . _unattached_directory . makedirs ( ) <EOL> except OSError : <EOL> pass <EOL> self . _attached_directory = self . _root_path . child ( <EOL> self . _attached_directory_name ) <EOL> try : <EOL> self . _attached_directory . makedirs ( ) <EOL> except OSError : <EOL> pass <EOL> def allocation_unit ( self ) : <EOL> return self . _allocation_unit <EOL> def compute_instance_id ( self ) : <EOL> if not self . _compute_instance_id : <EOL> raise UnknownInstanceID ( self ) <EOL> return self . _compute_instance_id <EOL> def _parse_backing_file_name ( self , filename ) : <EOL> """<STR_LIT>""" <EOL> blockdevice_id , size = filename . rsplit ( '<STR_LIT:_>' , <NUM_LIT:1> ) <EOL> size = int ( size ) <EOL> return blockdevice_id , size <EOL> def create_volume ( self , dataset_id , size ) : <EOL> """<STR_LIT>""" <EOL> check_allocatable_size ( self . allocation_unit ( ) , size ) <EOL> volume = _blockdevicevolume_from_dataset_id ( <EOL> size = size , dataset_id = dataset_id , <EOL> ) <EOL> with self . _unattached_directory . child ( <EOL> _backing_file_name ( volume ) <EOL> ) . open ( '<STR_LIT:wb>' ) as f : <EOL> f . truncate ( size ) <EOL> return volume <EOL> def destroy_volume ( self , blockdevice_id ) : <EOL> """<STR_LIT>""" <EOL> volume = get_blockdevice_volume ( self , blockdevice_id ) <EOL> volume_path = self . _unattached_directory . child ( <EOL> _backing_file_name ( volume ) <EOL> ) <EOL> volume_path . remove ( ) <EOL> def _allocate_device ( self , backing_file_path ) : <EOL> """<STR_LIT>""" <EOL> check_output ( [ "<STR_LIT>" , "<STR_LIT>" , backing_file_path . path ] ) <EOL> def attach_volume ( self , blockdevice_id , attach_to ) : <EOL> """<STR_LIT>""" <EOL> volume = get_blockdevice_volume ( self , blockdevice_id ) <EOL> filename = _backing_file_name ( volume ) <EOL> if volume . attached_to is None : <EOL> old_path = self . _unattached_directory . child ( filename ) <EOL> host_directory = self . _attached_directory . child ( <EOL> attach_to . encode ( "<STR_LIT:ascii>" ) , <EOL> ) <EOL> try : <EOL> host_directory . makedirs ( ) <EOL> except OSError : <EOL> pass <EOL> new_path = host_directory . child ( filename ) <EOL> old_path . moveTo ( new_path ) <EOL> self . _allocate_device ( new_path ) <EOL> attached_volume = volume . set ( attached_to = attach_to ) <EOL> return attached_volume <EOL> raise AlreadyAttachedVolume ( blockdevice_id ) <EOL> def detach_volume ( self , blockdevice_id ) : <EOL> """<STR_LIT>""" <EOL> volume = get_blockdevice_volume ( self , blockdevice_id ) <EOL> if volume . attached_to is None : <EOL> raise UnattachedVolume ( blockdevice_id ) <EOL> if self . get_device_path ( blockdevice_id ) is not None : <EOL> check_output ( [ <EOL> b"<STR_LIT>" , b"<STR_LIT>" , <EOL> self . get_device_path ( blockdevice_id ) . path <EOL> ] ) <EOL> filename = _backing_file_name ( volume ) <EOL> volume_path = self . _attached_directory . descendant ( [ <EOL> volume . attached_to . encode ( "<STR_LIT:ascii>" ) , <EOL> filename , <EOL> ] ) <EOL> new_path = self . _unattached_directory . child ( <EOL> filename <EOL> ) <EOL> volume_path . moveTo ( new_path ) <EOL> def list_volumes ( self ) : <EOL> """<STR_LIT>""" <EOL> volumes = [ ] <EOL> for child in self . _root_path . child ( '<STR_LIT>' ) . children ( ) : <EOL> blockdevice_id , size = self . _parse_backing_file_name ( <EOL> child . basename ( ) . decode ( '<STR_LIT:ascii>' ) <EOL> ) <EOL> volume = _blockdevicevolume_from_blockdevice_id ( <EOL> blockdevice_id = blockdevice_id , <EOL> size = size , <EOL> ) <EOL> volumes . append ( volume ) <EOL> for host_directory in self . _root_path . child ( '<STR_LIT>' ) . children ( ) : <EOL> compute_instance_id = host_directory . basename ( ) . decode ( '<STR_LIT:ascii>' ) <EOL> for child in host_directory . children ( ) : <EOL> blockdevice_id , size = self . _parse_backing_file_name ( <EOL> child . basename ( ) . decode ( '<STR_LIT:ascii>' ) <EOL> ) <EOL> volume = _blockdevicevolume_from_blockdevice_id ( <EOL> blockdevice_id = blockdevice_id , <EOL> size = size , <EOL> attached_to = compute_instance_id , <EOL> ) <EOL> volumes . append ( volume ) <EOL> return volumes <EOL> def get_device_path ( self , blockdevice_id ) : <EOL> volume = get_blockdevice_volume ( self , blockdevice_id ) <EOL> if volume . attached_to is None : <EOL> raise UnattachedVolume ( blockdevice_id ) <EOL> volume_path = self . _attached_directory . descendant ( <EOL> [ volume . attached_to . encode ( "<STR_LIT:ascii>" ) , <EOL> _backing_file_name ( volume ) ] <EOL> ) <EOL> path = _device_for_path ( volume_path ) <EOL> if path is None : <EOL> self . _allocate_device ( volume_path ) <EOL> path = _device_for_path ( volume_path ) <EOL> return path <EOL> class EventuallyConsistentBlockDeviceAPI ( <EOL> proxyForInterface ( IBlockDeviceAPI , "<STR_LIT>" ) <EOL> ) : <EOL> """<STR_LIT>""" <EOL> def __init__ ( self , _original ) : <EOL> super ( EventuallyConsistentBlockDeviceAPI , self ) . __init__ ( _original ) <EOL> self . cached_volumes = [ [ ] , [ ] ] <EOL> def list_volumes ( self ) : <EOL> self . cached_volumes . append ( <EOL> self . _original . list_volumes ( ) <EOL> ) <EOL> return self . cached_volumes . pop ( <NUM_LIT:0> ) </s>
