def testMDFactory(self): with self.assertRaisesRegexp(devicefactory.DeviceFactoryError, "must have some RAID level"): devicefactory.get_device_factory( self.b, devicefactory.DEVICE_TYPE_MD, Size("1 GiB")) with self.assertRaisesRegexp(RaidError, "requires at least"): self.factory1._get_device_space() with self.assertRaisesRegexp(RaidError, "requires at least"): self.factory1._configure() self.assertEqual(self.factory1.container_list, []) self.assertIsNone(self.factory1.get_container()) self.assertIsNotNone(self.factory1._get_new_device(parents=[])) with self.assertRaisesRegexp(RaidError, "requires at least"): self.factory2._get_device_space() self.assertEqual(self.factory2.container_list, []) self.assertIsNone(self.factory2.get_container())
def testMDFactory(self): with self.assertRaisesRegex(devicefactory.DeviceFactoryError, "must have some RAID level"): devicefactory.get_device_factory( self.b, devicefactory.DEVICE_TYPE_MD, Size("1 GiB")) with self.assertRaisesRegex(RaidError, "requires at least"): self.factory1._get_device_space() with self.assertRaisesRegex(RaidError, "requires at least"): self.factory1._configure() self.assertEqual(self.factory1.container_list, []) self.assertIsNone(self.factory1.get_container()) parents = [ DiskDevice("name1", fmt=getFormat("mdmember")), DiskDevice("name2", fmt=getFormat("mdmember")) ] self.assertIsNotNone(self.factory1._get_new_device(parents=parents)) with self.assertRaisesRegex(RaidError, "requires at least"): self.factory2._get_device_space() self.assertEqual(self.factory2.container_list, []) self.assertIsNone(self.factory2.get_container())
def test_get_free_disk_space(self): # get_free_disk_space should return the total free space on disks kwargs = self._get_test_factory_args() size = Size("500 MiB") factory = devicefactory.get_device_factory(self.b, self.device_type, size, disks=self.b.disks, **kwargs) # disks contain empty disklabels, so free space is sum of disk sizes self.assertAlmostEqual(factory._get_free_disk_space(), sum(d.size for d in self.b.disks), delta=self._get_size_delta()) factory.configure() device = factory.device device_space = factory._get_device_space() factory = devicefactory.get_device_factory(self.b, self.device_type, size, disks=self.b.disks, **kwargs) # disks contain a 500 MiB device, which includes varying amounts of # metadata and space lost to partition alignment. self.assertAlmostEqual(factory._get_free_disk_space(), sum(d.size for d in self.b.disks) - device_space, delta=self._get_size_delta(devices=[device]))
def test_factory_defaults(self): ctor_kwargs = self._get_test_factory_args() factory = devicefactory.get_device_factory(self.b, self.device_type, **ctor_kwargs) for setting, value in factory._default_settings.items(): if setting not in ctor_kwargs: self.assertEqual(getattr(factory, setting), value) self.assertEqual(factory.fstype, self.b.get_fstype()) kwargs = self._get_test_factory_args() kwargs.update({ "disks": self.b.disks[:], "fstype": "swap", "size": Size("2GiB"), "label": "SWAP" }) device = self._factory_device(self.device_type, **kwargs) factory = devicefactory.get_device_factory(self.b, self.device_type, device=device) self.assertEqual(factory.size, getattr(device, "req_size", device.size)) if self.device_type == devicefactory.DEVICE_TYPE_PARTITION: self.assertIn(device.disk, factory.disks) else: self.assertEqual(factory.disks, device.disks) self.assertEqual(factory.fstype, device.format.type) self.assertEqual(factory.label, device.format.label)
def test_get_free_disk_space(self): # get_free_disk_space should return the total free space on disks kwargs = self._get_test_factory_args() kwargs["size"] = Size("500 MiB") factory = devicefactory.get_device_factory(self.b, self.device_type, disks=self.b.disks, **kwargs) # disks contain empty disklabels, so free space is sum of disk sizes self.assertAlmostEqual(factory._get_free_disk_space(), sum(d.size for d in self.b.disks), delta=self._get_size_delta()) factory.configure() device = factory.device device_space = factory._get_device_space() factory = devicefactory.get_device_factory(self.b, self.device_type, disks=self.b.disks, **kwargs) # disks contain a 500 MiB device, which includes varying amounts of # metadata and space lost to partition alignment. self.assertAlmostEqual(factory._get_free_disk_space(), sum(d.size for d in self.b.disks) - device_space, delta=self._get_size_delta(devices=[device]))
def setUp(self): self.b = blivet.Blivet() self.factory1 = devicefactory.get_device_factory( self.b, devicefactory.DEVICE_TYPE_MD, Size(spec="1 GiB")) self.factory2 = devicefactory.get_device_factory( self.b, devicefactory.DEVICE_TYPE_MD, Size(spec="1 GiB"), raid_level=0)
def setUp(self): self.b = blivet.Blivet() self.factory1 = devicefactory.get_device_factory(self.b, devicefactory.DEVICE_TYPE_MD, Size("1 GiB")) self.factory2 = devicefactory.get_device_factory(self.b, devicefactory.DEVICE_TYPE_MD, Size("1 GiB"), raid_level=0)
def _add_device(self, storage, request: DeviceFactoryRequest, use_existing_container=False): """Add a device to the storage model. :param storage: an instance of Blivet :param request: a device factory request :param use_existing_container: should we use an existing container? :raise: StorageError if the device cannot be created """ # Create the device factory. factory = devicefactory.get_device_factory( storage, device_type=request.device_type, size=Size(request.device_size) if request.device_size else None) # Find a container. container = factory.get_container( allow_existing=use_existing_container) if use_existing_container and not container: raise StorageError("No existing container found.") # Update the device info. if container: # Don't override user-initiated changes to a defined container. request.disks = [d.name for d in container.disks] request.container_encrypted = container.encrypted request.container_raid_level = get_device_raid_level_name( container) request.container_size_policy = get_container_size_policy( container) # The existing container has a name. if use_existing_container: request.container_name = container.name # The container is already encrypted if container.encrypted: request.device_encrypted = False # Create the device. dev_info = get_device_factory_arguments(storage, request) try: storage.factory_device(**dev_info) except StorageError as e: log.error("The device creation has failed: %s", e) raise except OverflowError as e: log.error("Invalid partition size set: %s", str(e)) raise StorageError( "Invalid partition size set. Use a valid integer.") from None
def test_mdfactory(self): factory1 = devicefactory.get_device_factory( self.b, devicefactory.DEVICE_TYPE_MD, size=Size("1 GiB"), raid_level=raid.RAID1) factory2 = devicefactory.get_device_factory( self.b, devicefactory.DEVICE_TYPE_MD, size=Size("1 GiB"), raid_level=0) with six.assertRaisesRegex(self, devicefactory.DeviceFactoryError, "must have some RAID level"): devicefactory.get_device_factory(self.b, devicefactory.DEVICE_TYPE_MD, size=Size("1 GiB")) with six.assertRaisesRegex(self, RaidError, "requires at least"): factory1._get_device_space() with six.assertRaisesRegex(self, RaidError, "requires at least"): factory1._configure() self.assertEqual(factory1.container_list, []) self.assertIsNone(factory1.get_container()) parents = [ DiskDevice("name1", fmt=get_format("mdmember")), DiskDevice("name2", fmt=get_format("mdmember")) ] self.assertIsNotNone(factory1._get_new_device(parents=parents)) with six.assertRaisesRegex(self, RaidError, "requires at least"): factory2._get_device_space() self.assertEqual(factory2.container_list, []) self.assertIsNone(factory2.get_container())
def _add_device(storage, dev_info, use_existing_container=False): """Add a device to the storage model. :param storage: an instance of Blivet :param dev_info: a device info :param use_existing_container: should we use an existing container? :raise: StorageError if the device cannot be created """ # Create the device factory. factory = devicefactory.get_device_factory( storage, device_type=dev_info["device_type"], size=dev_info["size"], ) # Find a container. container = factory.get_container(allow_existing=use_existing_container) if use_existing_container and not container: raise StorageError("No existing container found.") # Update the device info. if container: # Don't override user-initiated changes to a defined container. dev_info["disks"] = container.disks dev_info.update({ "container_encrypted": container.encrypted, "container_raid_level": get_device_raid_level(container), "container_size": getattr(container, "size_policy", container.size) }) # The existing container has a name. if use_existing_container: dev_info["container_name"] = container.name # The container is already encrypted if container.encrypted: dev_info["encrypted"] = False # Create the device. try: storage.factory_device(**dev_info) except StorageError as e: log.error("The device creation has failed: %s", e) raise except OverflowError as e: log.error("Invalid partition size set: %s", str(e)) raise StorageError( "Invalid partition size set. Use a valid integer.") from None
def test_normalize_size(self): # _normalize_size should adjust target size to within the format limits fstype = "ext2" ext2 = get_format(fstype) self.assertTrue(ext2.max_size > Size(0)) size = Size("9 TiB") self.assertTrue(size > ext2.max_size) kwargs = self._get_test_factory_args() kwargs["size"] = size factory = devicefactory.get_device_factory(self.b, self.device_type, disks=self.b.disks, fstype=fstype, **kwargs) factory._normalize_size() self.assertTrue(factory.size <= ext2.max_size) # _normalize_size should convert a size of None to a reasonable guess # at the largest possible size based on disk free space factory.size = None factory._normalize_size() self.assertIsInstance(factory.size, blivet.size.Size) self.assertTrue(factory.size <= ext2.max_size) # Allow some variation in size for metadata, alignment, &c. self.assertAlmostEqual(factory.size, sum(d.size for d in self.b.disks), delta=self._get_size_delta()) # _handle_no_size should also take into account any specified factory # device, in case the factory is to be modifying a defined device # must be a couple MiB smaller than the disk to accommodate # PartitionFactory kwargs["size"] = self.b.disks[0].size - Size("4 MiB") device = self._factory_device(self.device_type, disks=self.b.disks, **kwargs) self.assertAlmostEqual(device.size, kwargs["size"], delta=self._get_size_delta()) factory.size = None factory.device = device factory._normalize_size() self.assertIsInstance(factory.size, blivet.size.Size) self.assertTrue(factory.size <= ext2.max_size) # factory size should be total disk space plus current device space # Allow some variation in size for metadata, alignment, &c. self.assertAlmostEqual(factory.size, sum(d.size for d in self.b.disks), delta=self._get_size_delta(devices=[device]))
def test_factory_defaults(self): ctor_kwargs = self._get_test_factory_args() factory = devicefactory.get_device_factory(self.b, self.device_type, **ctor_kwargs) for setting, value in factory._default_settings.items(): if setting not in ctor_kwargs: self.assertEqual(getattr(factory, setting), value) self.assertEqual(factory.fstype, self.b.get_fstype()) kwargs = self._get_test_factory_args() kwargs.update({"disks": self.b.disks[:], "fstype": "swap", "size": Size("2GiB"), "label": "SWAP"}) device = self._factory_device(self.device_type, **kwargs) factory = devicefactory.get_device_factory(self.b, self.device_type, device=device) self.assertEqual(factory.size, getattr(device, "req_size", device.size)) if self.device_type == devicefactory.DEVICE_TYPE_PARTITION: self.assertIn(device.disk, factory.disks) else: self.assertEqual(factory.disks, device.disks) self.assertEqual(factory.fstype, device.format.type) self.assertEqual(factory.label, device.format.label)
def generate_device_factory_request(storage, device) -> DeviceFactoryRequest: """Generate a device info for the given device. :param storage: an instance of Blivet :param device: a device :return: a device factory request """ device_type = devicefactory.get_device_type(device) if device_type is None: raise UnsupportedDeviceError("Unsupported type of {}.".format( device.name)) # Generate the device data. request = DeviceFactoryRequest() request.device_spec = device.name request.device_name = getattr(device.raw_device, "lvname", device.raw_device.name) request.device_size = device.size.get_bytes() request.device_type = device_type request.reformat = not device.format.exists request.format_type = device.format.type or "" request.device_encrypted = isinstance(device, LUKSDevice) request.luks_version = get_device_luks_version(device) request.label = getattr(device.format, "label", "") or "" request.mount_point = getattr(device.format, "mountpoint", "") or "" request.device_raid_level = get_device_raid_level_name(device) if hasattr(device, "req_disks") and not device.exists: disks = device.req_disks else: disks = device.disks request.disks = [d.name for d in disks] if request.device_type not in CONTAINER_DEVICE_TYPES: return request # Generate the container data. factory = devicefactory.get_device_factory(storage, device_type=device_type, device=device.raw_device) container = factory.get_container() if container: set_container_data(request, container) return request
def test_normalize_size(self): # _normalize_size should adjust target size to within the format limits fstype = "ext2" ext2 = get_format(fstype) self.assertTrue(ext2.max_size > Size(0)) size = Size("9 TiB") self.assertTrue(size > ext2.max_size) kwargs = self._get_test_factory_args() factory = devicefactory.get_device_factory(self.b, self.device_type, size, disks=self.b.disks, fstype=fstype, **kwargs) factory._normalize_size() self.assertTrue(factory.size <= ext2.max_size) # _normalize_size should convert a size of None to a reasonable guess # at the largest possible size based on disk free space factory.size = None factory._normalize_size() self.assertIsInstance(factory.size, blivet.size.Size) self.assertTrue(factory.size <= ext2.max_size) # Allow some variation in size for metadata, alignment, &c. self.assertAlmostEqual(factory.size, sum(d.size for d in self.b.disks), delta=self._get_size_delta()) # _handle_no_size should also take into account any specified factory # device, in case the factory is to be modifying a defined device # must be a couple MiB smaller than the disk to accommodate # PartitionFactory size = self.b.disks[0].size - Size("4 MiB") device = self._factory_device(self.device_type, size, disks=self.b.disks, **kwargs) self.assertAlmostEqual(device.size, size, delta=self._get_size_delta()) factory.size = None factory.device = device factory._normalize_size() self.assertIsInstance(factory.size, blivet.size.Size) self.assertTrue(factory.size <= ext2.max_size) # factory size should be total disk space plus current device space # Allow some variation in size for metadata, alignment, &c. self.assertAlmostEqual(factory.size, sum(d.size for d in self.b.disks), delta=self._get_size_delta(devices=[device]))
def generate_device_info(storage, device): """Generate a device info for the given device. :param storage: an instance of Blivet :param device: a device :return: a device info """ device_type = devicefactory.get_device_type(device) dev_info = dict() dev_info["device"] = device dev_info["name"] = getattr(device.raw_device, "lvname", device.raw_device.name) dev_info["size"] = device.size dev_info["device_type"] = device_type dev_info["fstype"] = device.format.type dev_info["encrypted"] = isinstance(device, LUKSDevice) dev_info["luks_version"] = get_device_luks_version(device) dev_info["label"] = getattr(device.format, "label", "") dev_info["mountpoint"] = getattr(device.format, "mountpoint", None) or None dev_info["raid_level"] = get_device_raid_level(device) if hasattr(device, "req_disks") and not device.exists: disks = device.req_disks else: disks = device.disks dev_info["disks"] = disks factory = devicefactory.get_device_factory(storage, device_type=device_type, device=device.raw_device) container = factory.get_container() if container: dev_info["container_name"] = container.name dev_info["container_encrypted"] = container.encrypted dev_info["container_raid_level"] = get_device_raid_level(container) dev_info["container_size"] = getattr(container, "size_policy", container.size) else: dev_info["container_name"] = None dev_info["container_encrypted"] = False dev_info["container_raid_level"] = None dev_info["container_size"] = devicefactory.SIZE_POLICY_AUTO return dev_info
def get_container(storage, device_type, device=None): """Get a container of the given type. :param storage: an instance of Blivet :param device_type: a device type :param device: a defined factory device or None :return: a container device """ if device_type not in CONTAINER_DEVICE_TYPES: raise StorageError("Invalid device type {}".format(device_type)) if device and devicefactory.get_device_type(device) != device_type: device = None factory = devicefactory.get_device_factory( storage, device_type=device_type, size=Size(0), ) return factory.get_container(device=device)
def test_get_container(self): for disk in self.b.disks: self.b.format_device(disk, get_format("lvmpv")) vg = self.b.new_vg(parents=self.b.disks, name="newvg") self.b.create_device(vg) self.assertEqual(self.b.vgs, [vg]) factory = devicefactory.get_device_factory(self.b, self.device_type, size=Size("500 MiB"), fstype="xfs") # get_container on lvm factory should return the lone non-existent vg self.assertEqual(factory.get_container(), vg) # get_container should require allow_existing to return an existing vg vg.exists = True vg._complete = True self.assertEqual(factory.get_container(), None) self.assertEqual(factory.get_container(allow_existing=True), vg)
def test_get_container(self): for disk in self.b.disks: self.b.format_device(disk, get_format("lvmpv")) vg = self.b.new_vg(parents=self.b.disks, name="newvg") self.b.create_device(vg) self.assertEqual(self.b.vgs, [vg]) factory = devicefactory.get_device_factory(self.b, self.device_type, Size("500 MiB"), fstype="xfs") # get_container on lvm factory should return the lone non-existent vg self.assertEqual(factory.get_container(), vg) # get_container should require allow_existing to return an existing vg vg.exists = True vg._complete = True self.assertEqual(factory.get_container(), None) self.assertEqual(factory.get_container(allow_existing=True), vg)
def _destroy_device(storage, device): """Destroy the given device in the storage model. :param storage: an instance of Blivet :param device: an instance of a device """ # Remove the device. if device.is_disk and device.partitioned and not device.format.supported: storage.recursive_remove(device) elif device.direct and not device.isleaf: # We shouldn't call this method for with non-leaf devices # except for those which are also directly accessible like # lvm snapshot origins and btrfs subvolumes that contain # other subvolumes. storage.recursive_remove(device) else: storage.destroy_device(device) # Initialize the disk. if device.is_disk: storage.initialize_disk(device) # Remove empty extended partitions. if getattr(device, "is_logical", False): storage.remove_empty_extended_partitions() # If we've just removed the last partition and the disk label # is preexisting, reinitialize the disk. if device.type == "partition" and device.exists and device.disk.format.exists: config = DiskInitializationConfig() if config.can_initialize(storage, device.disk): storage.initialize_disk(device.disk) # Get the device container. if hasattr(device, "vg"): container = device.vg device_type = devicefactory.get_device_type(device) elif hasattr(device, "volume"): container = device.volume device_type = devicefactory.DEVICE_TYPE_BTRFS else: container = None device_type = None # Adjust container to size of remaining devices, if auto-sized. if (container and not container.exists and container.children and container.size_policy == devicefactory.SIZE_POLICY_AUTO): # Create the device factory. factory = devicefactory.get_device_factory( storage, device_type=device_type, size=Size(0), disks=container.disks, container_name=container.name, container_encrypted=container.encrypted, container_raid_level=get_device_raid_level(container), container_size=container.size_policy, ) # Configure the factory's devices. factory.configure() # Finally, remove empty parents of the device. for parent in device.parents: if not parent.children and not parent.is_disk: destroy_device(storage, parent)
def _factory_device(self, *args, **kwargs): """ Run the device factory and return the device it produces. """ factory = devicefactory.get_device_factory(self.b, *args, **kwargs) factory.configure() return factory.device
def test_default_factory_type(self): factory = devicefactory.get_device_factory(self.b) self.assertIsInstance(factory, devicefactory.LVMFactory)