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¶
btrfs
BTRFSSubVolumeDevice
(see inherited public API)vol_id
volume
BTRFSVolumeDevice
(see inherited public API)data_level
default_subvolume
members
metadata_level
disk
DiskDevice
(see inherited public API)model
vendor
file
DirectoryDevice
(see inherited public API)FileDevice
(see inherited public API)SparseFileDevice
(see inherited public API)
loop
LoopDevice
(see inherited public API)
luks
LUKSDevice
(see inherited public API)map_name
lvm
LVMCache
backing_device_name
cache_device_name
exists
md_size
mode
size
stats
LVMCacheRequest
fast_devs
pv_space_requests
mode
LVMLogicalVolumeDevice
(see inherited public API)cache
cached
is_internal_lv
is_raid_lv
is_snapshot_lv
is_thin_lv
is_thin_pool
map_name
metadata_size
vg
LVMVolumeGroupDevice
(see inherited public API)cached_lvs
complete
extents
free_extents
free_space
lvs
pv_free_info
thinlvs
thinpools
md
MDRaidArrayDevice
(see inherited public API)complete
degraded
level
member_devices
member_status()
members
spares
total_devices
MDBiosRaidArrayDevice
(see inherited public API)
nfs
NFSDevice
(see inherited public API)
optical
OpticalDevice
(see inherited public API)
partition
PartitionDevice
(see inherited public API)bootable
is_extended
is_logical
is_primary
storage
StorageDevice
align_target_size()
ancestors
children
current_size
depends_on()
direct
disks
encrypted
exists
format
format_immutable
fstab_spec
is_disk
is_leaf
max_size
min_size
name
parents
partitionable
partitioned
path
protected
raw_device
read_only
resizable
resize()
setup()
size
status
sysfs_path
target_size
teardown()
uuid
events¶
manager
event_manager
disable()
enable()
enabled
error_cb
notify_cb
formats¶
get_format()
DeviceFormat
controllable
current_size
destroyable
device
do_resize()
exists
formattable
hidden
name
label
label_format_ok
labeling
linux_native
max_size
min_size
mountable
options
packages
resizable
setup()
size
target_size
teardown()
status
supported
type
update_size_info
uuid
biosboot
BIOSBoot
(see inherited public API)
disklabel
DiskLabel
(see inherited public API)label_type
sector_size
dmraid
DMRaidMember
(see inherited public API)
fs
FS
(see inherited public API)do_check()
mountpoint
system_mountpoint
write_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)
luks
LUKS
(see inherited public API)add_passphrase()
configured
has_key
map_name()
remove_passphrase()
lvmpv
LVMPhysicalVolume
(see inherited public API)container_uuid
mdraid
MDRaidMember
(see inherited public API)container_uuid
multipath
MultipathMember
(see inherited public API)
prepboot
PPCPRePBoot
(see inherited public API)
swap
SwapSpace
(see inherited public API)
blivet.actionlist
- See ‘actions’ attribute in DeviceTree.
blivet.autopart
do_autopart()
do_reqpart()
swap_suggestion()
blivet.blivet
Blivet
btrfs_volumes
clear_partitions()
config
copy()
create_device()
default_fstype()
destroy_device()
devices
devicetree
disks
do_it()
factory_device()
file_system_free_space()
format_device()
get_free_space()
get_fstype()
initialize_disk()
lvs
mdarrays
mdcontainers
mdmembers
mountpoints
names
new_btrfs()
new_btrfs_sub_volume()
new_lv()
new_mdarray()
new_partition()
new_tmp_fs()
new_vg()
partitioned
partitions
pvs
reset()
reset_device()
resize_device()
root_device
safe_device_name()
save_passphrase()
set_default_fstype()
shutdown()
suggest_container_name()
suggest_device_name()
swaps
thinlvs
thinpools
update_ksdata()
vgs
blivet.deviceaction
ActionAddMember
ActionRemoveMember
ActionCreateDevice
ActionCreateFormat
ActionDestroyDevice
ActionDestroyFormat
ActionResizeDevice
ActionResizeFormat
blivet.devicefactory
configure()
DEVICE_TYPE_MD
DEVICE_TYPE_PARTITION
DEVICE_TYPE_BTRFS
DEVICE_TYPE_DISK
DEVICE_TYPE_LVM_THINP
is_supported_device_type()
get_device_factory()
get_device_type()
SIZE_POLICY_AUTO
SIZE_POLICY_MAX
blivet.devicetree
DeviceTree
actions
add()
find()
prune()
remove()
sort()
cancel_disk_actions()
devices
filesystems
get_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()
labels
leaves
populate()
recursive_remove()
resolve_device()
setup_all()
teardown_all()
unhide()
uuids
blivet.errors
AlignmentError
AvailabilityError
BTRFSError
BTRFSValueError
CorruptGPTError
DependencyError
DeviceActionError
DeviceCreateError
DeviceDestroyError
DeviceError
DeviceFactoryError
DeviceFormatError
DeviceNotFoundError
DeviceResizeError
DeviceSetupError
DeviceTeardownError
DeviceTreeError
DeviceUserDeniedFormatError
DiskLabelCommitError
DiskLabelError
DiskLabelScanError
DMError
DMRaidMemberError
DuplicateVGError
EventHandlingError
EventManagerError
EventParamError
FormatCreateError
FormatDestroyError
FormatResizeError
FormatSetupError
FormatTeardownError
FSError
FSReadLabelError
FSResizeError
FSTabTypeMismatchError
FSWriteLabelError
InvalidDiskLabelError
LUKSError
MDMemberError
MPathError
MultipathMemberError
NotEnoughFreeSpaceError
NoDisksError
PhysicalVolumeError
PartitioningError
RaidError
SinglePhysicalVolumeError
SizePlacesError
StorageError
SwapSpaceError
ThreadError
UdevError
UnknownSourceDeviceError
UnrecognizedFSTabEntryError
UnusableConfigurationError
blivet.fcoe
fcoe
add_san()
startup()
has_fcoe()
blivet.flags
flags
blivet.iscsi
iscsi
available()
create_interfaces()
delete_interfaces()
discover()
ifaces
initiator
initiator_set
log_into_node()
mode
shutdown()
startup()
blivet.partitioning
do_partitioning()
grow_lvm()
blivet.populator
- See ‘populate’, ‘handle_device’, and ‘handle_format’ methods in DeviceTree.
blivet.size
B
EB
EiB
GB
GiB
KB
KiB
MB
MiB
PB
PiB
ROUND_DOWN
ROUND_UP
ROUND_DEFAULT
Size
convert_to()
human_readable()
round_to_nearest()
TB
TiB
YB
YiB
ZB
ZiB
blivet.util
set_up_logging()
blivet.zfcp
zfcp
add_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.devicetree
DeviceTree
actions
add()
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.iscsi
iscsi
available()
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
;LoopBackedTestCase
andImageBackedTestCase
- both classes represent actual storage space.ImageBackedTestCase
uses the same stacks as anaconda disk image installations. These mimic normal disks more closely than using loop devices directly. UsuallyLoopBackedTestCase
is used for stacks of limited depth (eg: md array with two loop members) andImageBackedTestCase
for 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/