Welcome to Blivet’s documentation!¶
Contents:
Introduction to Blivet¶
Blivet is a python module for system storage configuration.
The main thing that blivet offers is the ability to model a series of changes
without necessarily commiting any of the changes to disk. You can schedule an
arbitrarily large series of changes (called ‘actions’), seeing the effects of
each (within the DeviceTree instance) as it is scheduled.
Nothing is written to disk, however, until you execute the actions.
Building Blocks¶
Individual block devices are represented by the various subclasses of
StorageDevice, while the formatting of the data they contain
is represented by the various subclasses of DeviceFormat.
The hierarchy of devices is represented by DeviceTree.
DiskDevice, PartitionDevice,
LVMLogicalVolumeDevice, and
MDRaidArrayDevice are some of the most important examples of
StorageDevice subclasses.
Some examples of DeviceFormat subclasses include
SwapSpace, DiskLabel,
and subclasses of FS such as Ext4FS
and XFS.
Every StorageDevice instance has a format that contains an instance of some DeviceFormat
subclass – even if it is “blank” or “unformatted” (in which case it is an instance of DeviceFormat itself).
Every DeviceFormat has a
device attribute that is a string representing
the path to the device node for the block device containing the formatting.
StorageDevice and DeviceFormat can
represent either existent or non-existent devices and formatting.
StorageDevice and DeviceFormat share a similar API, which consists of methods to control existing devices/formats
(setup(),
teardown()), methods to create or modify
devices/formats (create(),
destroy(), resize())
, and attributes to store critical data
(status, exists)
. Some useful attributes of StorageDevice that are not found
in DeviceFormat include
parents, isleaf,
ancestors, and disks.
DeviceTree provides
devices which is a list of
StorageDevice instances representing the current state of the
system as configured within blivet. It also provides some methods for looking up
devices (get_device_by_name()) and for listing devices
that build upon a device (get_dependent_devices()).
Getting Started¶
First Steps¶
First, create an instance of the Blivet class:
import blivet
b = blivet.Blivet()
Next, scan the system’s storage configuration and store it in the tree:
b.reset()
Now, you can do some simple things like listing the devices:
for device in b.devices:
print(device)
To make changes to the configuration you’ll schedule actions, but
Blivet provides some convenience methods to hide the details. Here’s an example of removing partition ‘/dev/sda3’:
sda3 = b.devicetree.get_device_by_name("sda3")
b.destroy_device(sda3) # schedules actions to destroy format and device
At this point, the StorageDevice representing sda3 is no longer in the tree. That means you could allocate a new partition from the newly free space if you wanted to (via blivet, that is, since there is not actually any free space on the physical disk yet – you haven’t commited the changes). If you now ran the following line:
sda3 = b.devicetree.get_device_by_name("sda3")
sda3 would be None since that device has been removed from the tree.
When you are ready to commit your changes to disk, here’s how:
b.do_it()
That’s it. Now you have actually removed /dev/sda3 from the disk.
Here’s an alternative approach that uses the lower-level
DeviceTree class directly:
import blivet
dt = blivet.devicetree.DeviceTree()
dt.populate()
sda3 = dt.get_device_by_name("sda3")
action1 = ActionDestroyFormat(sda3)
action2 = ActionDestroyDevice(sda3)
dt.actions.add(action1)
dt.actions.add(action2)
dt.actions.process()
Here’s the Blivet approach again for comparison:
import blivet
b = blivet.Blivet() # contains a DeviceTree instance
b.reset() # calls DeviceTree.populate()
sda3 = b.devicetree.get_device_by_name("sda3")
b.destroy_device(sda3) # schedules actions to destroy format and device
b.do_it() # calls DeviceTree.actions.process()
Scheduling a Series of Actions¶
Start out as before:
import blivet
from blivet.size import Size
b = blivet.Blivet()
b.reset()
sda3 = b.devicetree.get_device_by_name("sda3")
Now we’re going to wipe the existing formatting from sda3:
b.destroy_format(sda3)
Now let’s assume sda3 is larger than 10GiB and resize it to that size:
b.resize_device(sda3, Size("10 GiB"))
And then let’s create a new ext4 filesystem there:
new_fmt = blivet.formats.get_format("ext4", device=sda3.path)
b.format_device(sda3, new_fmt)
If you want to commit the whole set of changes in one shot, it’s easy:
b.do_it()
Now you can mount the new filesystem at the directory “/mnt/test”:
sda3.format.setup(mountpoint="/mnt/test")
Once you’re finished, unmount it as follows:
sda3.format.teardown()
Disk Partitions¶
Disk partitions are a little bit tricky in that they require an extra step to actually allocate the partitions from free space on the disk(s). What that means is deciding exactly which sectors on which disk the new partition will occupy. Blivet offers some powerful means for deciding for you where to place the partitions, but it also allows you to specify an exact start and end sector on a specific disk if that’s how you want to do it. Here’s an example of letting Blivet handle the details of creating a partition of minimum size 10GiB on either sdb or sdc that is also growable to a maximum size of 20GiB:
sdb = b.devicetree.get_device_by_name("sdb")
sdc = b.devicetree.get_device_by_name("sdc")
new_part = b.new_partition(size=Size("10 GiB"), grow=True,
maxsize=Size("20 GiB"),
parents=[sdb, sdc])
b.create_device(new_part)
blivet.partitioning.do_partitioning(b)
Now you could see where it ended up:
print("partition %s of size %s on disk %s" % (new_part.name,
new_part.size,
new_part.disk.name))
From here, everything is the same as it was in the first examples. All that’s left is to execute the scheduled action:
b.do_it() # or b.devicetree.process_actions()
Backing up, let’s see how it looks if you want to specify the start and end sectors. If you specify a start sector you have to also specify a single disk from which to allocate the partition:
new_part = b.new_partition(start=2048, end=204802048, parents=[sdb])
All the rest is the same as the previous partitioning example.
Public API¶
API Specification¶
This should be considered an exhaustive listing of blivet’s public API. Anything not listed should be considered unstable and subject to change between minor releases.
blivet¶
devices¶
btrfsBTRFSSubVolumeDevice(see inherited public API)vol_idvolume
BTRFSVolumeDevice(see inherited public API)data_leveldefault_subvolumemembersmetadata_level
diskDiskDevice(see inherited public API)modelvendor
fileDirectoryDevice(see inherited public API)FileDevice(see inherited public API)SparseFileDevice(see inherited public API)
loopLoopDevice(see inherited public API)
luksLUKSDevice(see inherited public API)map_name
lvmLVMCachebacking_device_namecache_device_nameexistsmd_sizemodesizestats
LVMCacheRequestfast_devspv_space_requestsmode
LVMLogicalVolumeDevice(see inherited public API)cachecachedis_internal_lvis_raid_lvis_snapshot_lvis_thin_lvis_thin_poolmap_namemetadata_sizevg
LVMVolumeGroupDevice(see inherited public API)cached_lvscompleteextentsfree_extentsfree_spacelvspv_free_infothinlvsthinpools
mdMDRaidArrayDevice(see inherited public API)completedegradedlevelmember_devicesmember_status()memberssparestotal_devices
MDBiosRaidArrayDevice(see inherited public API)
nfsNFSDevice(see inherited public API)
opticalOpticalDevice(see inherited public API)
partitionPartitionDevice(see inherited public API)bootableis_extendedis_logicalis_primary
storageStorageDevicealign_target_size()ancestorschildrencurrent_sizedepends_on()directdisksencryptedexistsformatformat_immutablefstab_specis_diskis_leafmax_sizemin_sizenameparentspartitionablepartitionedpathprotectedraw_deviceread_onlyresizableresize()setup()sizestatussysfs_pathtarget_sizeteardown()uuid
events¶
managerevent_managerdisable()enable()enablederror_cbnotify_cb
formats¶
get_format()
DeviceFormatcontrollablecurrent_sizedestroyabledevicedo_resize()existsformattablehiddennamelabellabel_format_oklabelinglinux_nativemax_sizemin_sizemountableoptionspackagesresizablesetup()sizetarget_sizeteardown()statussupportedtypeupdate_size_infouuid
biosbootBIOSBoot(see inherited public API)
disklabelDiskLabel(see inherited public API)label_typesector_size
dmraidDMRaidMember(see inherited public API)
fsFS(see inherited public API)do_check()mountpointsystem_mountpointwrite_label()
AppleBootstrapFS(see inherited public API)BindFS(see inherited public API)BTRFS(see inherited public API)container_uuid
DevPtsFS(see inherited public API)EFIFS(see inherited public API)EFIVarFS(see inherited public API)Ext2FS(see inherited public API)Ext3FS(see inherited public API)Ext4FS(see inherited public API)FATFS(see inherited public API)GFS2(see inherited public API)HFS(see inherited public API)HFSPlus(see inherited public API)Iso9660FS(see inherited public API)JFS(see inherited public API)MacEFIFS(see inherited public API)NFS(see inherited public API)NFSv4(see inherited public API)NoDevFS(see inherited public API)NTFS(see inherited public API)ProcFS(see inherited public API)ReiserFS(see inherited public API)SELinuxFS(see inherited public API)SysFS(see inherited public API)TmpFS(see inherited public API)USBFS(see inherited public API)XFS(see inherited public API)
luksLUKS(see inherited public API)add_passphrase()configuredhas_keymap_name()remove_passphrase()
lvmpvLVMPhysicalVolume(see inherited public API)container_uuid
mdraidMDRaidMember(see inherited public API)container_uuid
multipathMultipathMember(see inherited public API)
prepbootPPCPRePBoot(see inherited public API)
swapSwapSpace(see inherited public API)
blivet.actionlist- See ‘actions’ attribute in DeviceTree.
blivet.autopartdo_autopart()do_reqpart()swap_suggestion()
blivet.blivetBlivetbtrfs_volumesclear_partitions()configcopy()create_device()default_fstype()destroy_device()devicesdevicetreedisksdo_it()factory_device()file_system_free_space()format_device()get_free_space()get_fstype()initialize_disk()lvsmdarraysmdcontainersmdmembersmountpointsnamesnew_btrfs()new_btrfs_sub_volume()new_lv()new_mdarray()new_partition()new_tmp_fs()new_vg()partitionedpartitionspvsreset()reset_device()resize_device()root_devicesafe_device_name()save_passphrase()set_default_fstype()shutdown()suggest_container_name()suggest_device_name()swapsthinlvsthinpoolsupdate_ksdata()vgs
blivet.deviceactionActionAddMemberActionRemoveMemberActionCreateDeviceActionCreateFormatActionDestroyDeviceActionDestroyFormatActionResizeDeviceActionResizeFormat
blivet.devicefactoryconfigure()DEVICE_TYPE_MDDEVICE_TYPE_PARTITIONDEVICE_TYPE_BTRFSDEVICE_TYPE_DISKDEVICE_TYPE_LVM_THINPis_supported_device_type()get_device_factory()get_device_type()SIZE_POLICY_AUTOSIZE_POLICY_MAX
blivet.devicetreeDeviceTreeactionsadd()find()prune()remove()sort()
cancel_disk_actions()devicesfilesystemsget_dependent_devices()get_device_by_id()get_device_by_label()get_device_by_name()get_device_by_path()get_device_by_sysfs_path()get_device_by_uuid()get_disk_actions()get_related_disks()handle_device()handle_format()hide()labelsleavespopulate()recursive_remove()resolve_device()setup_all()teardown_all()unhide()uuids
blivet.errorsAlignmentErrorAvailabilityErrorBTRFSErrorBTRFSValueErrorCorruptGPTErrorDependencyErrorDeviceActionErrorDeviceCreateErrorDeviceDestroyErrorDeviceErrorDeviceFactoryErrorDeviceFormatErrorDeviceNotFoundErrorDeviceResizeErrorDeviceSetupErrorDeviceTeardownErrorDeviceTreeErrorDeviceUserDeniedFormatErrorDiskLabelCommitErrorDiskLabelErrorDiskLabelScanErrorDMErrorDMRaidMemberErrorDuplicateVGErrorEventHandlingErrorEventManagerErrorEventParamErrorFormatCreateErrorFormatDestroyErrorFormatResizeErrorFormatSetupErrorFormatTeardownErrorFSErrorFSReadLabelErrorFSResizeErrorFSTabTypeMismatchErrorFSWriteLabelErrorInvalidDiskLabelErrorLUKSErrorMDMemberErrorMPathErrorMultipathMemberErrorNotEnoughFreeSpaceErrorNoDisksErrorPhysicalVolumeErrorPartitioningErrorRaidErrorSinglePhysicalVolumeErrorSizePlacesErrorStorageErrorSwapSpaceErrorThreadErrorUdevErrorUnknownSourceDeviceErrorUnrecognizedFSTabEntryErrorUnusableConfigurationError
blivet.fcoefcoeadd_san()startup()
has_fcoe()
blivet.flagsflags
blivet.iscsiiscsiavailable()create_interfaces()delete_interfaces()discover()ifacesinitiatorinitiator_setlog_into_node()modeshutdown()startup()
blivet.partitioningdo_partitioning()grow_lvm()
blivet.populator- See ‘populate’, ‘handle_device’, and ‘handle_format’ methods in DeviceTree.
blivet.sizeBEBEiBGBGiBKBKiBMBMiBPBPiBROUND_DOWNROUND_UPROUND_DEFAULTSizeconvert_to()human_readable()round_to_nearest()
TBTiBYBYiBZBZiB
blivet.utilset_up_logging()
blivet.zfcpzfcpadd_fcp()shutdown()startup()
Explanation¶
In general, anything listed is public and anything not listed is not public. There are a couple of strange situations that deserve explanation:
blivet.devicetreeDeviceTreeactionsadd()find()prune()remove()sort()
cancel_disk_actions()
- The class DeviceTree itself is listed, which means the constructor interface is considered to be stable.
- DeviceTree has an ‘actions’ attribute that is an instance of class ActionList. ActionList’s constructor isn’t public, but the methods and attributes listed under the ‘actions’ attribute are.
- DeviceTree has a ‘cancel_disk_actions’ method which is public.
blivet.iscsiiscsiavailable()create_interfaces()
- The module blivet.iscsi contains a module-level ‘iscsi’ attribute, which is public.
- The class iSCSI is not public. You shouldn’t create instances of it. Instead, you should use the existing instance at blivet.iscsi.iscsi.
- The ‘available’ and ‘create_interfaces’ methods of the iSCSI class are public. The above example is incomplete, but if it were complete it would mean that the only public members of the iSCSI class are the ‘available’ and ‘create_interfaces’ methods.
Testing Blivet¶
Note: The test suite documented here is available only from the git repository not as part of any installable packages.
In order to execute blivet’s test suite from inside the source directory execute the command:
make test
Tests descending from ImageBackedTestCase or
LoopBackedTestCase require root access on the
system and will be skipped if you’re running as non-root user.
Tests descending from ImageBackedTestCase will
also be skipped if the environment variable JENKINS_HOME is not defined. If
you’d like to execute them use the following commands (as root):
# export JENKINS_HOME=`pwd`
# make test
To execute the Pylint code analysis tool run:
make check
Running Pylint doesn’t require root privileges but requires Python3 due to usage of pocket-lint.
It is also possible to generate test coverage reports using the Python coverage tool. To do that execute:
make coverage
It is also possible to check all external links in the documentation for integrity. To do this:
cd doc/
make linkcheck
Test Suite Architecture¶
Blivet’s test suite relies on several base classes listed below. All test cases inherit from them.
unittest.TestCase- the standard unit test class in Python. Used for tests which don’t touch disk space;StorageTestCase- intended as a base class for higher-level tests. Most of what it does is stub out operations that touch disks. Currently it is only used inDeviceActionTestCase;LoopBackedTestCaseandImageBackedTestCase- both classes represent actual storage space.ImageBackedTestCaseuses the same stacks as anaconda disk image installations. These mimic normal disks more closely than using loop devices directly. UsuallyLoopBackedTestCaseis used for stacks of limited depth (eg: md array with two loop members) andImageBackedTestCasefor stacks of greater or arbitrary depth.
In order to get a high level view of how test classes inherit from each other you can generate an inheritance diagram:
PYTHONPATH=.:tests/ python3-pyreverse -p "Blivet_Tests" -o svg -SkAmy tests/