Example #1
0
    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())
Example #2
0
    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())
Example #3
0
    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]))
Example #4
0
    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)
Example #5
0
    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]))
Example #6
0
    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)
Example #7
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)
Example #8
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
Example #9
0
    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())
Example #10
0
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
Example #11
0
    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]))
Example #12
0
    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)
Example #13
0
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
Example #14
0
    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]))
Example #15
0
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
Example #16
0
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)
Example #17
0
    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)
Example #18
0
    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)
Example #19
0
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)
Example #20
0
 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
Example #21
0
 def test_default_factory_type(self):
     factory = devicefactory.get_device_factory(self.b)
     self.assertIsInstance(factory, devicefactory.LVMFactory)
Example #22
0
 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
Example #23
0
 def test_default_factory_type(self):
     factory = devicefactory.get_device_factory(self.b)
     self.assertIsInstance(factory, devicefactory.LVMFactory)