This change forces devices tests to be slightly more realistic in order to pass, so update them as well.
Also make failing test that relied on literal constant value that was supposed to be minimum member size pass again and add a few tests to bracket the minimum member size in case it changes again.
Signed-off-by: mulhern amulhern@redhat.com --- blivet/devicelibs/btrfs.py | 4 ++++ blivet/devices.py | 10 ++++++++++ tests/devicelibs_test/btrfs_test.py | 22 ++++++++++++++++++++-- tests/devices_test.py | 17 ++++++++++------- 4 files changed, 44 insertions(+), 9 deletions(-)
diff --git a/blivet/devicelibs/btrfs.py b/blivet/devicelibs/btrfs.py index ea8a984..1c558ab 100644 --- a/blivet/devicelibs/btrfs.py +++ b/blivet/devicelibs/btrfs.py @@ -26,6 +26,7 @@ import re from . import raid from .. import util from ..errors import BTRFSError, BTRFSValueError +from ..size import Size
import logging log = logging.getLogger("blivet") @@ -33,6 +34,9 @@ log = logging.getLogger("blivet") # this is the volume id btrfs always assigns to the top-level volume/tree MAIN_VOLUME_ID = 5
+# if any component device is less than this size, mkfs.btrfs will fail +MIN_MEMBER_SIZE = Size("16 MiB") + RAID_levels = raid.RAIDLevels(["raid0", "raid1", "raid10", "single"])
metadata_levels = raid.RAIDLevels(["raid0", "raid1", "raid10", "single", "dup"]) diff --git a/blivet/devices.py b/blivet/devices.py index 4fe804b..ec2e7f8 100644 --- a/blivet/devices.py +++ b/blivet/devices.py @@ -5053,6 +5053,12 @@ class BTRFSVolumeDevice(BTRFSDevice, ContainerDevice):
self._defaultSubVolumeID = None
+ def _addParent(self, member): + log_method_call(self, self.name, member=member.name) + if not self.exists and member.size < btrfs.MIN_MEMBER_SIZE: + raise errors.BTRFSValueError("BTRFS member device must have size at least %s." % btrfs.MIN_MEMBER_SIZE) + super(BTRFSVolumeDevice, self)._addParent(member) + def _validateRaidLevel(self, level): """ Returns an error message if the RAID level is invalid for this device, otherwise None. @@ -5244,6 +5250,10 @@ class BTRFSVolumeDevice(BTRFSDevice, ContainerDevice):
return default
+ def _preCreate(self): + if any(p.size < btrfs.MIN_MEMBER_SIZE for p in self.parents): + raise errors.DeviceCreateError("All BTRFS member devices must have size at least %s." % btrfs.MIN_MEMBER_SIZE) + def _create(self): log_method_call(self, self.name, status=self.status) btrfs.create_volume(devices=[d.path for d in self.parents], diff --git a/tests/devicelibs_test/btrfs_test.py b/tests/devicelibs_test/btrfs_test.py index 91950d2..e3f658e 100755 --- a/tests/devicelibs_test/btrfs_test.py +++ b/tests/devicelibs_test/btrfs_test.py @@ -7,7 +7,6 @@ import unittest
import blivet.devicelibs.btrfs as btrfs from blivet.errors import BTRFSError -from blivet.size import Size
from tests import loopbackedtestcase
@@ -165,7 +164,7 @@ class BTRFSAsRootTestCase2(BTRFSMountDevice): class BTRFSAsRootTestCase3(loopbackedtestcase.LoopBackedTestCase):
def __init__(self, methodName='runTest'): - super(BTRFSAsRootTestCase3, self).__init__(methodName=methodName, deviceSpec=[Size("8192 KiB")]) + super(BTRFSAsRootTestCase3, self).__init__(methodName=methodName, deviceSpec=[btrfs.MIN_MEMBER_SIZE, btrfs.MIN_MEMBER_SIZE])
def testSmallDevice(self): """ Creation of a smallish device will result in an error if the @@ -176,5 +175,24 @@ class BTRFSAsRootTestCase3(loopbackedtestcase.LoopBackedTestCase): btrfs.create_volume(self.loopDevices, data="single", metadata="dup") self.assertEqual(btrfs.create_volume(self.loopDevices), 0)
+class BTRFSTooSmallDeviceTestCase(loopbackedtestcase.LoopBackedTestCase): + + def __init__(self, methodName='runTest'): + super(BTRFSTooSmallDeviceTestCase, self).__init__(methodName=methodName, deviceSpec=[btrfs.MIN_MEMBER_SIZE / 2, btrfs.MIN_MEMBER_SIZE]) + + def testTooSmallDevice(self): + """ If just one device is too small mkfs.btrfs will fail. """ + with self.assertRaises(BTRFSError): + btrfs.create_volume(self.loopDevices) + +class BTRFSBigEnoughDeviceTestCase(loopbackedtestcase.LoopBackedTestCase): + + def __init__(self, methodName='runTest'): + super(BTRFSBigEnoughDeviceTestCase, self).__init__(methodName=methodName, deviceSpec=[btrfs.MIN_MEMBER_SIZE]) + + def testBigEnoughDevice(self): + """ If all devices are large enough, mkfs.btrfs will succeed. """ + self.assertEqual(btrfs.create_volume(self.loopDevices), 0) + if __name__ == "__main__": unittest.main() diff --git a/tests/devices_test.py b/tests/devices_test.py index 0e4073d..6fea84d 100644 --- a/tests/devices_test.py +++ b/tests/devices_test.py @@ -20,7 +20,6 @@ from blivet.devices import LVMThinLogicalVolumeDevice from blivet.devices import LVMThinSnapShotDevice from blivet.devices import LVMVolumeGroupDevice from blivet.devices import MDRaidArrayDevice -from blivet.devices import OpticalDevice from blivet.devices import StorageDevice from blivet.devices import ParentList from blivet.devicelibs import btrfs @@ -437,8 +436,9 @@ class BTRFSDeviceTestCase(DeviceStateTestCase): "vol_id" : lambda x, m: self.assertEqual(x, btrfs.MAIN_VOLUME_ID, m)}
self.dev1 = BTRFSVolumeDevice("dev1", - parents=[OpticalDevice("deva", - fmt=blivet.formats.getFormat("btrfs"))]) + parents=[StorageDevice("deva", + fmt=blivet.formats.getFormat("btrfs"), + size=btrfs.MIN_MEMBER_SIZE)])
self.dev2 = BTRFSSubVolumeDevice("dev2", parents=[self.dev1])
@@ -455,7 +455,10 @@ class BTRFSDeviceTestCase(DeviceStateTestCase): """
self.stateCheck(self.dev1, + currentSize=lambda x, m: self.assertEqual(x, btrfs.MIN_MEMBER_SIZE), parents=lambda x, m: self.assertEqual(len(x), 1, m), + maxSize=lambda x, m: self.assertEqual(x, btrfs.MIN_MEMBER_SIZE), + size=lambda x, m: self.assertEqual(x, btrfs.MIN_MEMBER_SIZE), type=lambda x, m: self.assertEqual(x, "btrfs volume", m))
self.stateCheck(self.dev3, @@ -469,11 +472,11 @@ class BTRFSDeviceTestCase(DeviceStateTestCase): BTRFSVolumeDevice("dev")
with self.assertRaisesRegexp(ValueError, "member has wrong format"): - BTRFSVolumeDevice("dev", parents=[OpticalDevice("deva")]) + BTRFSVolumeDevice("dev", parents=[StorageDevice("deva", size=btrfs.MIN_MEMBER_SIZE)])
with self.assertRaisesRegexp(DeviceError, "btrfs subvolume.*must be a BTRFSDevice"): fmt = blivet.formats.getFormat("btrfs") - device = OpticalDevice("deva", fmt=fmt) + device = StorageDevice("deva", fmt=fmt, size=btrfs.MIN_MEMBER_SIZE) BTRFSSubVolumeDevice("dev1", parents=[device])
self.assertEqual(self.dev1.isleaf, False) @@ -502,7 +505,7 @@ class BTRFSDeviceTestCase(DeviceStateTestCase): self.dev1.size = 32
def testBTRFSSnapShotDeviceInit(self): - parents = [StorageDevice("p1", fmt=blivet.formats.getFormat("btrfs"))] + parents = [StorageDevice("p1", fmt=blivet.formats.getFormat("btrfs"), size=btrfs.MIN_MEMBER_SIZE)] vol = BTRFSVolumeDevice("test", parents=parents) with self.assertRaisesRegexp(ValueError, "non-existent btrfs snapshots must have a source"): BTRFSSnapShotDevice("snap1", parents=[vol]) @@ -513,7 +516,7 @@ class BTRFSDeviceTestCase(DeviceStateTestCase): with self.assertRaisesRegexp(ValueError, "btrfs snapshot source must be a btrfs subvolume"): BTRFSSnapShotDevice("snap1", parents=[vol], source=parents[0])
- parents2 = [StorageDevice("p1", fmt=blivet.formats.getFormat("btrfs"))] + parents2 = [StorageDevice("p1", fmt=blivet.formats.getFormat("btrfs"), size=btrfs.MIN_MEMBER_SIZE)] vol2 = BTRFSVolumeDevice("test2", parents=parents2, exists=True) with self.assertRaisesRegexp(ValueError, ".*snapshot and source must be in the same volume"): BTRFSSnapShotDevice("snap1", parents=[vol], source=vol2)