class VMBackedTestCase(unittest.TestCase): """ A class to encapsulate testing of blivet using block devices. The basic idea is you create some scratch block devices and then run some test code on them. :attr:`~.ImageBackedTestCase.disks` defines the set of disk images. :meth:`~.ImageBackedTestCase._set_up_storage` is where you specify the initial layout of the disks. It will be written to the disk images in :meth:`~.ImageBackedTestCase.set_up_storage`. You then write test methods as usual that use the disk images, which will be cleaned up and removed when each test method finishes. """ initialize_disks = True # Whether or not to create a disklabel on the disks. def set_up_disks(self): """ Create disk image files to build the test's storage on. If you are actually creating the disk image files here don't forget to set the initialize_disks flag so they get a fresh disklabel when clear_partitions gets called from create_storage later. """ def _set_up_storage(self): """ Schedule creation of storage devices on the disk images. .. note:: The disk images should already be in a populated devicetree. """ def set_up_storage(self): """ Create a device stack on top of disk images for this test to run on. This will write the configuration to whatever disk images are defined in set_up_disks. """ udev.ignored_device_names = [r'^zram'] # # create disk images # self.set_up_disks() # # populate the devicetree # self.blivet.reset() if self.initialize_disks: for disk in self.blivet.disks: self.blivet.initialize_disk(disk) # # create the rest of the stack # self._set_up_storage() # # write configuration to disk images # self.blivet.do_it() def setUp(self): """ Do any setup required prior to running a test. """ self.blivet = Blivet() self.addCleanup(self._clean_up) self.set_up_storage() def _clean_up(self): """ Clean up any resources that may have been set up for a test. """ self.blivet.reset() # XXX The only reason for this may be lvmetad for disk in self.blivet.disks: self.blivet.recursive_remove(disk) try: self.blivet.do_it() except Exception: self.blivet.reset() raise
class DBusBlivet(DBusObject): """ This class provides the main entry point to the Blivet1 service. It provides methods for controlling the blivet service and querying its state. """ def __init__(self, manager): super().__init__(manager) self._blivet = Blivet() self._id = ObjectID().id self._manager.add_object(self) self._set_up_callbacks() def _set_up_callbacks(self): callbacks.device_added.add(self._device_added) callbacks.device_removed.add(self._device_removed) callbacks.format_added.add(self._format_added) callbacks.format_removed.add(self._format_removed) callbacks.action_added.add(self._action_added) callbacks.action_removed.add(self._action_removed) callbacks.action_executed.add(self._action_executed) @property def id(self): return self._id @property def object_path(self): return BLIVET_OBJECT_PATH @property def interface(self): return BLIVET_INTERFACE @property def properties(self): props = {"Devices": self.ListDevices()} return props def _device_removed(self, device, keep=True): """ Update ObjectManager interface after a device is removed. """ # Make sure the format gets removed in case the device was removed w/o # removing the format first. removed_fmt = self._manager.get_object_by_id(device.format.id) if removed_fmt and removed_fmt.present: self._format_removed(device, device.format, keep=keep) elif removed_fmt and not keep: self._format_removed(device, device.format, keep=False) removed = self._manager.get_object_by_id(device.id) self._manager.remove_object(removed) if keep: removed.present = False self._manager.add_object(removed) else: removed.remove_from_connection() def _device_added(self, device): """ Update ObjectManager interface after a device is added. """ added = self._manager.get_object_by_id(device.id) if added: # This device was previously removed. Restore it. added.present = True else: added = DBusDevice(device, self._manager) self._manager.add_object(added) def _format_removed(self, device, fmt, keep=True): # pylint: disable=unused-argument removed = self._manager.get_object_by_id(fmt.id) if removed is None: return # We have to remove the object either way since its path will change. self._manager.remove_object(removed) if keep: removed.present = False self._manager.add_object(removed) else: removed.remove_from_connection() def _format_added(self, device, fmt): # pylint: disable=unused-argument added = self._manager.get_object_by_id(fmt.id) if added: # This format was previously removed. Restore it. added.present = True else: added = DBusFormat(fmt, self._manager) self._manager.add_object(added) def _action_removed(self, action): removed = self._manager.get_object_by_id(action.id) self._manager.remove_object(removed) removed.remove_from_connection() def _action_added(self, action): added = DBusAction(action, self._manager) self._manager.add_object(added) def _action_executed(self, action): if action.is_destroy: if action.is_device: self._device_removed(action.device, keep=False) elif action.is_format: self._format_removed(action.device, action.format, keep=False) self._action_removed(action) def _list_dbus_devices(self, removed=False): dbus_devices = (d for d in self._manager.objects if isinstance(d, DBusDevice)) return [d for d in dbus_devices if removed or d.present] def _get_device_by_object_path(self, object_path, removed=False): """ Return the StorageDevice corresponding to an object path. """ dbus_device = self._manager.get_object_by_path(object_path) if dbus_device is None or not isinstance(dbus_device, DBusDevice): raise dbus.exceptions.DBusException('%s.DeviceNotFound' % BUS_NAME, 'No device found with object path "%s".' % object_path) if not dbus_device.present and not removed: raise dbus.exceptions.DBusException('%s.DeviceNotFound' % BUS_NAME, 'Device with object path "%s" has already been ' 'removed.' % object_path) return dbus_device._device @dbus.service.method(dbus_interface=BLIVET_INTERFACE) def Reset(self): """ Reset the Blivet instance and populate the device tree. """ old_devices = self._blivet.devices[:] for removed in old_devices: self._device_removed(device=removed, keep=False) self._blivet.reset() @dbus.service.method(dbus_interface=BLIVET_INTERFACE) def Exit(self): """ Stop the blivet service. """ sys.exit(0) @dbus.service.method(dbus_interface=BLIVET_INTERFACE, out_signature='ao') def ListDevices(self): """ Return a list of strings describing the devices in this system. """ object_paths = sorted_object_paths_from_list(self._list_dbus_devices()) return dbus.Array(object_paths, signature='o') @dbus.service.method(dbus_interface=BLIVET_INTERFACE, in_signature='s', out_signature='o') def ResolveDevice(self, spec): """ Return a string describing the device the given specifier resolves to. """ device = self._blivet.devicetree.resolve_device(spec) if device is None: raise dbus.exceptions.DBusException('%s.DeviceLookupFailed' % BUS_NAME, 'No device was found that matches the device ' 'descriptor "%s".' % spec) return self._manager.get_object_by_id(device.id).object_path @dbus.service.method(dbus_interface=BLIVET_INTERFACE, in_signature='o') def RemoveDevice(self, object_path): """ Remove a device and all devices built on it. """ device = self._get_device_by_object_path(object_path) self._blivet.devicetree.recursive_remove(device) @dbus.service.method(dbus_interface=BLIVET_INTERFACE, in_signature='o') def InitializeDisk(self, object_path): """ Clear a disk and create a disklabel on it. """ self.RemoveDevice(object_path) device = self._get_device_by_object_path(object_path) self._blivet.initialize_disk(device) @dbus.service.method(dbus_interface=BLIVET_INTERFACE) def Commit(self): """ Commit pending changes to disk. """ try: self._blivet.do_it() except StorageError as e: raise dbus.exceptions.DBusException('%s.%s' % (BUS_NAME, e.__class__.__name__), "An error occured while committing the " "changes to disk: %s" % str(e))
class VMBackedTestCase(unittest.TestCase): """ A class to encapsulate testing of blivet using block devices. The basic idea is you create some scratch block devices and then run some test code on them. :attr:`~.ImageBackedTestCase.disks` defines the set of disk images. :meth:`~.ImageBackedTestCase._set_up_storage` is where you specify the initial layout of the disks. It will be written to the disk images in :meth:`~.ImageBackedTestCase.set_up_storage`. You then write test methods as usual that use the disk images, which will be cleaned up and removed when each test method finishes. """ initialize_disks = True # Whether or not to create a disklabel on the disks. def set_up_disks(self): """ Create disk image files to build the test's storage on. If you are actually creating the disk image files here don't forget to set the initialize_disks flag so they get a fresh disklabel when clear_partitions gets called from create_storage later. """ def _set_up_storage(self): """ Schedule creation of storage devices on the disk images. .. note:: The disk images should already be in a populated devicetree. """ def set_up_storage(self): """ Create a device stack on top of disk images for this test to run on. This will write the configuration to whatever disk images are defined in set_up_disks. """ # # create disk images # self.set_up_disks() # # populate the devicetree # self.blivet.reset() if self.initialize_disks: for disk in self.blivet.disks: self.blivet.initialize_disk(disk) # # create the rest of the stack # self._set_up_storage() # # write configuration to disk images # self.blivet.do_it() def setUp(self): """ Do any setup required prior to running a test. """ self.blivet = Blivet() self.addCleanup(self._clean_up) self.set_up_storage() def _clean_up(self): """ Clean up any resources that may have been set up for a test. """ self.blivet.reset() # XXX The only reason for this may be lvmetad for disk in self.blivet.disks: self.blivet.recursive_remove(disk) try: self.blivet.do_it() except Exception: self.blivet.reset() raise
class DBusBlivet(DBusObject): """ This class provides the main entry point to the Blivet1 service. It provides methods for controlling the blivet service and querying its state. """ def __init__(self, manager): super().__init__(manager) self._blivet = Blivet() self._id = ObjectID().id self._manager.add_object(self) self._set_up_callbacks() def _set_up_callbacks(self): callbacks.device_added.add(self._device_added) callbacks.device_removed.add(self._device_removed) callbacks.format_added.add(self._format_added) callbacks.format_removed.add(self._format_removed) callbacks.action_added.add(self._action_added) callbacks.action_removed.add(self._action_removed) callbacks.action_executed.add(self._action_executed) @property def id(self): return self._id @property def object_path(self): return BLIVET_OBJECT_PATH @property def interface(self): return BLIVET_INTERFACE @property def properties(self): props = { "Devices": self.ListDevices(), "DEVICE_TYPE_LVM": DEVICE_TYPE_LVM, "DEVICE_TYPE_LVM_THINP": DEVICE_TYPE_LVM_THINP, "DEVICE_TYPE_PARTITION": DEVICE_TYPE_PARTITION, "DEVICE_TYPE_MD": DEVICE_TYPE_MD, "DEVICE_TYPE_BTRFS": DEVICE_TYPE_BTRFS } return props def _device_removed(self, device, keep=True): """ Update ObjectManager interface after a device is removed. """ # Make sure the format gets removed in case the device was removed w/o # removing the format first. removed_fmt = self._manager.get_object_by_id(device.format.id) if removed_fmt and removed_fmt.present: self._format_removed(device, device.format, keep=keep) elif removed_fmt and not keep: self._format_removed(device, device.format, keep=False) removed = self._manager.get_object_by_id(device.id) self._manager.remove_object(removed) if keep: removed.present = False self._manager.add_object(removed) def _device_added(self, device): """ Update ObjectManager interface after a device is added. """ added = self._manager.get_object_by_id(device.id) if added: # This device was previously removed. Restore it. added.present = True else: added = DBusDevice(device, self._manager) self._manager.add_object(added) def _format_removed(self, device, fmt, keep=True): # pylint: disable=unused-argument removed = self._manager.get_object_by_id(fmt.id) if removed is None: return # We have to remove the object either way since its path will change. self._manager.remove_object(removed) if keep: removed.present = False self._manager.add_object(removed) def _format_added(self, device, fmt): # pylint: disable=unused-argument added = self._manager.get_object_by_id(fmt.id) if added: # This format was previously removed. Restore it. added.present = True else: added = DBusFormat(fmt, self._manager) self._manager.add_object(added) def _action_removed(self, action): removed = self._manager.get_object_by_id(action.id) self._manager.remove_object(removed) def _action_added(self, action): added = DBusAction(action, self._manager) self._manager.add_object(added) def _action_executed(self, action): if action.is_destroy: if action.is_device: self._device_removed(action.device, keep=False) elif action.is_format: self._format_removed(action.device, action.format, keep=False) self._action_removed(action) def _list_dbus_devices(self, removed=False): dbus_devices = (d for d in self._manager.objects if isinstance(d, DBusDevice)) return [d for d in dbus_devices if removed or d.present] def _get_device_by_object_path(self, object_path, removed=False): """ Return the StorageDevice corresponding to an object path. """ dbus_device = self._manager.get_object_by_path(object_path) if dbus_device is None or not isinstance(dbus_device, DBusDevice): raise dbus.exceptions.DBusException( '%s.DeviceNotFound' % BUS_NAME, 'No device found with object path "%s".' % object_path) if not dbus_device.present and not removed: raise dbus.exceptions.DBusException( '%s.DeviceNotFound' % BUS_NAME, 'Device with object path "%s" has already been ' 'removed.' % object_path) return dbus_device._device @dbus.service.method(dbus_interface=BLIVET_INTERFACE) def Reset(self): """ Reset the Blivet instance and populate the device tree. """ old_devices = self._blivet.devices[:] for removed in old_devices: self._device_removed(device=removed, keep=False) for action in self._blivet.devicetree.actions: self._action_removed(action) self._blivet.reset() @dbus.service.method(dbus_interface=BLIVET_INTERFACE) def Exit(self): """ Stop the blivet service. """ sys.exit(0) @dbus.service.method(dbus_interface=BLIVET_INTERFACE, out_signature='ao') def ListDevices(self): """ Return a list of strings describing the devices in this system. """ object_paths = sorted_object_paths_from_list(self._list_dbus_devices()) return dbus.Array(object_paths, signature='o') @dbus.service.method(dbus_interface=BLIVET_INTERFACE, in_signature='s', out_signature='o') def ResolveDevice(self, spec): """ Return a string describing the device the given specifier resolves to. """ device = self._blivet.devicetree.resolve_device(spec) if device is None: raise dbus.exceptions.DBusException( '%s.DeviceLookupFailed' % BUS_NAME, 'No device was found that matches the device ' 'descriptor "%s".' % spec) return self._manager.get_object_by_id(device.id).object_path @dbus.service.method(dbus_interface=BLIVET_INTERFACE, in_signature='o') def RemoveDevice(self, object_path): """ Remove a device and all devices built on it. """ device = self._get_device_by_object_path(object_path) self._blivet.devicetree.recursive_remove(device) @dbus.service.method(dbus_interface=BLIVET_INTERFACE, in_signature='o') def InitializeDisk(self, object_path): """ Clear a disk and create a disklabel on it. """ self.RemoveDevice(object_path) device = self._get_device_by_object_path(object_path) self._blivet.initialize_disk(device) @dbus.service.method(dbus_interface=BLIVET_INTERFACE) def Commit(self): """ Commit pending changes to disk. """ try: self._blivet.do_it() except StorageError as e: raise dbus.exceptions.DBusException( '%s.%s' % (BUS_NAME, e.__class__.__name__), "An error occured while committing the " "changes to disk: %s" % str(e)) @dbus.service.method(dbus_interface=BLIVET_INTERFACE, in_signature='ita{sv}', out_signature='o') def Factory(self, device_type, size, kwargs): disks = [ self._get_device_by_object_path(p) for p in kwargs.pop("disks", []) ] kwargs["disks"] = disks dbus_device = kwargs.pop("device", None) if dbus_device: device = self._get_device_by_object_path(dbus_device) kwargs["device"] = device try: device = self._blivet.factory_device(device_type, Size(size), **kwargs) except StorageError as e: raise dbus.exceptions.DBusException( '%s.%s' % (BUS_NAME, e.__class__.__name__), "An error occured while configuring the " "device: %s" % str(e)) if device is None: object_path = '/' else: object_path = self._manager.get_object_by_id(device.id).object_path return object_path
class ImageBackedTestCase(unittest.TestCase): """ A class to encapsulate testing of blivet using block devices. The basic idea is you create some scratch block devices and then run some test code on them. :attr:`~.ImageBackedTestCase.disks` defines the set of disk images. :meth:`~.ImageBackedTestCase._set_up_storage` is where you specify the initial layout of the disks. It will be written to the disk images in :meth:`~.ImageBackedTestCase.set_up_storage`. You then write test methods as usual that use the disk images, which will be cleaned up and removed when each test method finishes. """ initialize_disks = True """ Whether or not to create a disklabel on the disks. """ disks = {"disk1": Size("2 GiB"), "disk2": Size("2 GiB")} """ The names and sizes of the disk images to create/use. """ def set_up_disks(self): """ Create disk image files to build the test's storage on. If you are actually creating the disk image files here don't forget to set the initialize_disks flag so they get a fresh disklabel when clear_partitions gets called from create_storage later. """ for (name, size) in iter(self.disks.items()): path = util.create_sparse_tempfile(name, size) self.blivet.disk_images[name] = path # # set up the disk images with a disklabel # self.blivet.config.initialize_disks = self.initialize_disks def _set_up_storage(self): """ Schedule creation of storage devices on the disk images. .. note:: The disk images should already be in a populated devicetree. """ pass def set_up_storage(self): """ Create a device stack on top of disk images for this test to run on. This will write the configuration to whatever disk images are defined in set_up_disks. """ # # create disk images # self.set_up_disks() # # populate the devicetree # self.blivet.reset() # # clear and/or initialize disks as specified in set_up_disks # self.blivet.clear_partitions() # # create the rest of the stack # self._set_up_storage() # # write configuration to disk images # self.blivet.do_it() def setUp(self): """ Do any setup required prior to running a test. """ flags.image_install = True self.blivet = Blivet() self.addCleanup(self._clean_up) self.set_up_storage() def _clean_up(self): """ Clean up any resources that may have been set up for a test. """ # XXX The only reason for this may be lvmetad for disk in self.blivet.disks: self.blivet.recursive_remove(disk) try: self.blivet.do_it() except Exception: self.blivet.reset() raise self.blivet.reset() self.blivet.devicetree.teardown_disk_images() for fn in self.blivet.disk_images.values(): if os.path.exists(fn): os.unlink(fn) flags.image_install = False
class ImageBackedTestCase(unittest.TestCase): """ A class to encapsulate testing of blivet using block devices. The basic idea is you create some scratch block devices and then run some test code on them. :attr:`~.ImageBackedTestCase.disks` defines the set of disk images. :meth:`~.ImageBackedTestCase._set_up_storage` is where you specify the initial layout of the disks. It will be written to the disk images in :meth:`~.ImageBackedTestCase.set_up_storage`. You then write test methods as usual that use the disk images, which will be cleaned up and removed when each test method finishes. """ initialize_disks = True """ Whether or not to create a disklabel on the disks. """ disks = {"disk1": Size("2 GiB"), "disk2": Size("2 GiB")} """ The names and sizes of the disk images to create/use. """ def set_up_disks(self): """ Create disk image files to build the test's storage on. If you are actually creating the disk image files here don't forget to set the initialize_disks flag so they get a fresh disklabel when clear_partitions gets called from create_storage later. """ for (name, size) in iter(self.disks.items()): path = util.create_sparse_tempfile(name, size) self.blivet.disk_images[name] = path # # set up the disk images with a disklabel # self.blivet.config.initialize_disks = self.initialize_disks def _set_up_storage(self): """ Schedule creation of storage devices on the disk images. .. note:: The disk images should already be in a populated devicetree. """ def set_up_storage(self): """ Create a device stack on top of disk images for this test to run on. This will write the configuration to whatever disk images are defined in set_up_disks. """ # # create disk images # self.set_up_disks() # # populate the devicetree # self.blivet.reset() # # clear and/or initialize disks as specified in set_up_disks # self.blivet.clear_partitions() # # create the rest of the stack # self._set_up_storage() # # write configuration to disk images # self.blivet.do_it() def setUp(self): """ Do any setup required prior to running a test. """ self.blivet = Blivet() self.addCleanup(self._clean_up) self.set_up_storage() def _clean_up(self): """ Clean up any resources that may have been set up for a test. """ # XXX The only reason for this may be lvmetad for disk in self.blivet.disks: self.blivet.recursive_remove(disk) try: self.blivet.do_it() except Exception: self.blivet.reset() raise self.blivet.reset() self.blivet.devicetree.teardown_disk_images() for fn in self.blivet.disk_images.values(): if os.path.exists(fn): os.unlink(fn)