def test_is_swap_device_read_offsets(self, mock_util, mock_resource): """swap.is_swap_device() checks offsets based on system pagesize""" path = '/mydev/dummydisk' # 4k and 64k page size for pagesize in [4096, 65536]: magic_offset = pagesize - 10 mock_resource.getpagesize.return_value = pagesize swap.is_swap_device(path) mock_util.load_file.assert_called_with(path, read_len=10, offset=magic_offset, decode=False)
def test_identify_swap_true(self, mock_util, mock_resource): """swap.is_swap_device() returns true on swap magic strings""" path = '/mydev/dummydisk' for magic in [b'SWAPSPACE2', b'SWAP-SPACE']: mock_util.load_file.return_value = magic is_swap = swap.is_swap_device(path) self.assertTrue(is_swap)
def test_identify_swap_false(self, mock_getpagesize): """swap.is_swap_device() returns false on non swap content""" pagesize = mock_getpagesize() path = self.tmp_path("notswap1") # this is just arbitrary content that is not swap content. blob = b'\x00\x00c\x05\x00\x00\x11\x19' util.write_file(path, int(pagesize * 2 / len(blob)) * blob, omode="wb") self.assertFalse(swap.is_swap_device(path))
def test_is_swap_device_read_offsets(self, mock_getpagesize): """swap.is_swap_device() correctly identifies swap content.""" tmpd = self.tmp_dir() for num, (pagesize, content) in enumerate(self._valid_swap_contents()): path = self.tmp_path("swap-file-%02d" % num, tmpd) util.write_file(path, content, omode="wb") mock_getpagesize.return_value = pagesize self.assertTrue(swap.is_swap_device(path))
def wipe_superblock(device): """ Wrapper for block.wipe_volume compatible with shutdown function interface """ blockdev = block.sysfs_to_devpath(device) # when operating on a disk that used to have a dos part table with an # extended partition, attempting to wipe the extended partition will fail try: if not block.is_online(blockdev): LOG.debug("Device is not online (size=0), so skipping:" " '%s'", blockdev) return if block.is_extended_partition(blockdev): LOG.info( "extended partitions do not need wiping, so skipping:" " '%s'", blockdev) return except OSError as e: if util.is_file_not_found_exc(e): LOG.debug('Device to wipe disappeared: %s', e) LOG.debug('/proc/partitions says: %s', util.load_file('/proc/partitions')) (parent, partnum) = block.get_blockdev_for_partition(blockdev) out, _e = util.subp(['sfdisk', '-d', parent], capture=True, combine_capture=True) LOG.debug('Disk partition info:\n%s', out) return else: raise e # gather any partitions partitions = block.get_sysfs_partitions(device) # release zfs member by exporting the pool if zfs.zfs_supported() and block.is_zfs_member(blockdev): poolname = zfs.device_to_poolname(blockdev) # only export pools that have been imported if poolname in zfs.zpool_list(): try: zfs.zpool_export(poolname) except util.ProcessExecutionError as e: LOG.warning('Failed to export zpool "%s": %s', poolname, e) if is_swap_device(blockdev): shutdown_swap(blockdev) # some volumes will be claimed by the bcache layer but do not surface # an actual /dev/bcacheN device which owns the parts (backing, cache) # The result is that some volumes cannot be wiped while bcache claims # the device. Resolve this by stopping bcache layer on those volumes # if present. for bcache_path in ['bcache', 'bcache/set']: stop_path = os.path.join(device, bcache_path) if os.path.exists(stop_path): LOG.debug('Attempting to release bcache layer from device: %s:%s', device, stop_path) if stop_path.endswith('set'): rp = os.path.realpath(stop_path) bcache.stop_cacheset(rp) else: bcache._stop_device(stop_path) _wipe_superblock(blockdev) # if we had partitions, make sure they've been removed if partitions: LOG.debug('%s had partitions, issuing partition reread', device) retries = [.5, .5, 1, 2, 5, 7] for attempt, wait in enumerate(retries): try: # only rereadpt on wiped device block.rescan_block_devices(devices=[blockdev]) # may raise IOError, OSError due to wiped partition table curparts = block.get_sysfs_partitions(device) if len(curparts) == 0: return except (IOError, OSError): if attempt + 1 >= len(retries): raise LOG.debug( "%s partitions still present, rereading pt" " (%s/%s). sleeping %ss before retry", device, attempt + 1, len(retries), wait) time.sleep(wait) # multipath partitions are separate block devices (disks) if multipath.is_mpath_partition(blockdev): multipath.remove_partition(blockdev) # multipath devices must be hidden to utilize a single member (path) elif multipath.is_mpath_device(blockdev): mp_id = multipath.find_mpath_id(blockdev) if mp_id: multipath.remove_map(mp_id) else: raise RuntimeError('Failed to find multipath id for %s' % blockdev)
def test_identify_swap_false(self, mock_util, mock_resource): """swap.is_swap_device() returns false on non swap magic""" mock_util.load_file.return_value = ( b'\x00\x00c\x05\x00\x00\x11\x00\x19\x00') is_swap = swap.is_swap_device('ignored') self.assertFalse(is_swap)
def test_identify_zeros_are_swap(self, mock_getpagesize): """swap.is_swap_device() returns false on all zeros""" pagesize = mock_getpagesize() path = self.tmp_path("notswap0") util.write_file(path, pagesize * 2 * b'\0', omode="wb") self.assertFalse(swap.is_swap_device(path))
def test_identify_swap_false_if_tiny(self, mock_getpagesize): """small files do not trip up is_swap_device().""" path = self.tmp_path("tiny") util.write_file(path, b'tinystuff', omode='wb') self.assertFalse(swap.is_swap_device(path))