def test_lvdisplay(self): """Test display of LVM volume information. """ treadmill.subproc.check_output.return_value = ( ' /dev/test/test-lv:test:3:1:-1:0:24576:' '3:-1:0:-1:253:5\n') lv = lvm.lvdisplay('test-lv', 'test') treadmill.subproc.check_output.assert_called_with([ 'lvm', 'lvdisplay', '--colon', 'test/test-lv', ]) self.assertEqual( lv, { 'block_dev': '/dev/test/test-lv', 'dev_major': 253, 'dev_minor': 5, 'extent_alloc': -1, 'extent_size': 3, 'group': 'test', 'name': 'test-lv', 'open_count': 0, }, )
def _destroy_volume(self, uniqueid): """Try destroy a volume from LVM. """ # Remove it from state (if present) self._volumes.pop(uniqueid, None) try: lvm.lvdisplay(uniqueid, group=self._vg_name) except subproc.CalledProcessError: _LOGGER.warning('Ignoring unknow volume %r', uniqueid) return False # This should not fail. lvm.lvremove(uniqueid, group=self._vg_name) _LOGGER.info('Destroyed volume %r', uniqueid) return True
def _destroy_volume(self, uniqueid): """Try destroy a volume from LVM. """ # Remove it from state (if present) self._volumes.pop(uniqueid, None) try: lvm.lvdisplay(uniqueid, group=self._vg_name) except subproc.CalledProcessError: _LOGGER.warning('Ignoring unknown volume %r', uniqueid) return False # This should not fail. while True: # XXX: Workaround AFSClient delayed cleanup. try: lvm.lvremove(uniqueid, group=self._vg_name) break except subproc.CalledProcessError: _LOGGER.critical('Ignoring volume %r deletion error', uniqueid) time.sleep(1) _LOGGER.info('Destroyed volume %r', uniqueid) return True
def on_create_request(self, rsrc_id, rsrc_data): app_unique_name = rsrc_id size = rsrc_data['size'] read_bps = self._default_read_bps write_bps = self._default_write_bps read_iops = self._default_read_iops write_iops = self._default_write_iops with lc.LogContext(_LOGGER, rsrc_id, adapter_cls=lc.ContainerAdapter) as log: log.info('Processing request') size_in_bytes = utils.size_to_bytes(size) uniqueid = _uniqueid(app_unique_name) # Create the logical volume existing_volume = uniqueid in self._volumes if not existing_volume: needed = math.ceil(size_in_bytes / self._vg_status['extent_size']) if needed > self._vg_status['extent_free']: # If we do not have enough space, delay the creation until # another volume is deleted. log.info( 'Delaying request %r until %d extents are free.' ' Current volumes: %r', rsrc_id, needed, self._volumes) self._pending.append(rsrc_id) return None lvm.lvcreate( volume=uniqueid, group=self._vg_name, size_in_bytes=size_in_bytes, ) # We just created a volume, refresh cached status from LVM self._vg_status = localdiskutils.refresh_vg_status( self._vg_name) lv_info = lvm.lvdisplay(volume=uniqueid, group=self._vg_name) # Configure block device using cgroups (this is idempotent) # FIXME(boysson): The unique id <-> cgroup relation should be # captured in the cgroup module. cgrp = os.path.join('treadmill', 'apps', app_unique_name) cgutils.create('blkio', cgrp) major, minor = lv_info['dev_major'], lv_info['dev_minor'] cgroups.set_value( 'blkio', cgrp, 'blkio.throttle.write_bps_device', '{major}:{minor} {bps}'.format( major=major, minor=minor, bps=utils.size_to_bytes(write_bps), )) cgroups.set_value( 'blkio', cgrp, 'blkio.throttle.read_bps_device', '{major}:{minor} {bps}'.format( major=major, minor=minor, bps=utils.size_to_bytes(read_bps), )) cgroups.set_value( 'blkio', cgrp, 'blkio.throttle.write_iops_device', '{major}:{minor} {iops}'.format(major=major, minor=minor, iops=write_iops)) cgroups.set_value( 'blkio', cgrp, 'blkio.throttle.read_iops_device', '{major}:{minor} {iops}'.format(major=major, minor=minor, iops=read_iops)) volume_data = { k: lv_info[k] for k in ['name', 'block_dev', 'dev_major', 'dev_minor', 'extent_size'] } # Record existence of the volume. self._volumes[lv_info['name']] = volume_data return volume_data