---
blivet/__init__.py | 330 +++++++++++++++---
blivet/dasd.py | 3 -
blivet/devices.py | 833 ++++++++++++++++++++++++--------------------
blivet/devicetree.py | 248 +++++++++++--
blivet/formats/__init__.py | 107 ++++--
blivet/formats/biosboot.py | 12 +-
blivet/formats/disklabel.py | 72 ++--
blivet/formats/dmraid.py | 16 +-
blivet/formats/fs.py | 146 +++++---
blivet/formats/luks.py | 74 +++-
blivet/formats/lvmpv.py | 47 ++-
blivet/formats/mdraid.py | 20 +-
blivet/formats/multipath.py | 15 +-
blivet/formats/prepboot.py | 29 +-
blivet/formats/swap.py | 60 +++-
blivet/iscsi.py | 3 -
blivet/partitioning.py | 447 ++++++++++++++++--------
17 files changed, 1645 insertions(+), 817 deletions(-)
diff --git a/blivet/__init__.py b/blivet/__init__.py
index d5904e5..20bed1c 100644
--- a/blivet/__init__.py
+++ b/blivet/__init__.py
@@ -1,5 +1,4 @@
# __init__.py
-# Entry point for anaconda's storage configuration module.
#
# Copyright (C) 2009, 2010, 2011, 2012, 2013 Red Hat, Inc.
#
@@ -95,6 +94,7 @@ import logging
log = logging.getLogger("blivet")
def enable_installer_mode():
+ """ Configure the module for use by anaconda (OS installer).
"""
global isys
global ROOT_PATH
global shortProductName
@@ -238,13 +238,17 @@ class StorageDiscoveryConfig(object):
self.initializeDisks = False
self.protectedDevSpecs = []
self.diskImages = {}
- self.mpathFriendlyNames = True
# Whether clearPartitions removes scheduled/non-existent devices and
# disklabels depends on this flag.
self.clearNonExistent = False
def update(self, ksdata):
+ """ Update configuration from ksdata source.
+
+ :param ksdata: kickstart data used as data source
+ :type ksdata: :class:`pykickstart.Handler`
+ """
self.ignoredDisks = ksdata.ignoredisk.ignoredisk[:]
self.exclusiveDisks = ksdata.ignoredisk.onlyuse[:]
self.clearPartType = ksdata.clearpart.type
@@ -256,11 +260,9 @@ class StorageDiscoveryConfig(object):
class Blivet(object):
""" Top-level class for managing storage configuration.
"""
def __init__(self, ksdata=None):
- """ Create a Blivet instance.
-
- Keyword Arguments:
-
- ksdata - a pykickstart Handler instance
+ """
+ :keyword ksdata: kickstart data store
+ :type ksdata: :class:`pykickstart.Handler`
"""
self.ksdata = ksdata
self._bootloader = None
@@ -304,6 +306,7 @@ class Blivet(object):
self.services = set()
def doIt(self):
+ """ Commit queued changes to disk. """
self.devicetree.processActions()
if not flags.installer_mode:
return
@@ -368,11 +371,13 @@ class Blivet(object):
@property
def nextID(self):
+ """ Used for creating unique placeholder names.
"""
id = self._nextID
self._nextID += 1
return id
def shutdown(self):
+ """ Deactivate all devices (installer_mode only).
"""
try:
self.devicetree.teardownAll()
except Exception as e:
@@ -381,9 +386,14 @@ class Blivet(object):
def reset(self, cleanupOnly=False):
""" Reset storage configuration to reflect actual system state.
- This should rescan from scratch but not clobber user-obtained
- information like passphrases, iscsi config, &c
+ This will cancel any queued actions and rescan from scratch but not
+ clobber user-obtained information like passphrases, iscsi config, &c
+ :keyword cleanupOnly: prepare the tree only to deactivate devices
+ :type cleanupOnly: bool
+
+ See :meth:`devicetree.Devicetree.populate` for more information
+ about the cleanupOnly keyword argument.
"""
log.info("resetting Blivet (version %s) instance %s" % (__version__,
self))
if flags.installer_mode:
@@ -470,7 +480,7 @@ class Blivet(object):
def disks(self):
""" A list of the disks in the device tree.
- Ignored disks are not included, as are disks with no media present.
+ Ignored disks are excluded, as are disks with no media present.
This is based on the current state of the device tree and
does not necessarily reflect the actual on-disk state of the
@@ -551,12 +561,24 @@ class Blivet(object):
@property
def thinlvs(self):
+ """ A list of the LVM Thin Logical Volumes in the device tree.
+
+ This is based on the current state of the device tree and
+ does not necessarily reflect the actual on-disk state of the
+ system's disks.
+ """
thin = self.devicetree.getDevicesByType("lvmthinlv")
thin.sort(key=lambda d: d.name)
return thin
@property
def thinpools(self):
+ """ A list of the LVM Thin Pool Logical Volumes in the device
tree.
+
+ This is based on the current state of the device tree and
+ does not necessarily reflect the actual on-disk state of the
+ system's disks.
+ """
pools = self.devicetree.getDevicesByType("lvmthinpool")
pools.sort(key=lambda d: d.name)
return pools
@@ -608,6 +630,12 @@ class Blivet(object):
@property
def btrfsVolumes(self):
+ """ A list of the BTRFS volumes in the device tree.
+
+ This is based on the current state of the device tree and
+ does not necessarily reflect the actual on-disk state of the
+ system's disks.
+ """
return sorted(self.devicetree.getDevicesByType("btrfs volume"),
key=lambda d: d.name)
@@ -625,6 +653,21 @@ class Blivet(object):
return swaps
def shouldClear(self, device, **kwargs):
+ """ Return True if a clearpart settings say a device should be
cleared.
+
+ :param device: the device (required)
+ :type device: :class:`~.devices.StorageDevice`
+ :keyword clearPartType: overrides :attr:`self.config.clearPartType`
+ :type clearPartType: int
+ :keyword clearPartDisks: overrides
+ :attr:`self.config.clearPartDisks`
+ :type clearPartDisks: list
+ :keyword clearPartDevices: overrides
+ :attr:`self.config.clearPartDevices`
+ :type clearPartDevices: list
+ :returns: whether or not clearPartitions should remove this device
+ :rtype: bool
+ """
clearPartType = kwargs.get("clearPartType", self.config.clearPartType)
clearPartDisks = kwargs.get("clearPartDisks",
self.config.clearPartDisks)
@@ -704,6 +747,14 @@ class Blivet(object):
return True
def recursiveRemove(self, device):
+ """ Remove a device after removing its dependent devices.
+
+ If the device is not a leaf, all of its dependents are removed
+ recursively until it is a leaf device. At that point the device is
+ removed, unless it is a disk. If the device is a disk, its
+ formatting is removed by no attempt is made to actually remove the
+ disk device.
+ """
log.debug("removing %s" % device.name)
devices = self.deviceDeps(device)
@@ -727,17 +778,7 @@ class Blivet(object):
self.destroyDevice(device)
def clearPartitions(self):
- """ Clear partitions and dependent devices from disks.
-
- Arguments:
-
- None
-
- NOTES:
-
- - Needs some error handling
-
- """
+ """ Clear partitions and dependent devices from disks.
"""
# Sort partitions by descending partition number to minimize confusing
# things like multiple "destroy sda5" actions due to parted
renumbering
# partitions. This can still happen through the UI but it makes sense to
@@ -771,7 +812,14 @@ class Blivet(object):
""" (Re)initialize a disk by creating a disklabel on it.
The disk should not contain any partitions except perhaps for a
- magic partitions on mac and sun disklabels.
+ magic partitions on mac and sun disklabels. If the disk does contain
+ partitions other than the disklabel-type-specific "magic"
partitions
+ ValueError will be raised.
+
+ :param disk: the disk to initialize
+ :type disk: :class:`~.devices.StorageDevice`
+ :returns None:
+ :raises: ValueError
"""
# first, remove magic mac/sun partitions from the parted Disk
if disk.partitioned:
@@ -825,6 +873,18 @@ class Blivet(object):
disks and clearPartType allow specifying a set of disks other than
self.disks and a clearPartType value other than
self.config.clearPartType.
+
+ :keyword disks: overrides :attr:`disks`
+ :type disks: list
+ :keyword clearPartType: overrides :attr:`self.config.clearPartType`
+ :type clearPartType: int
+ :returns: dict with disk name keys and tuple (disk, fs) free values
+ :rtype: dict
+
+ .. note::
+
+ The free space values are :class:`~.size.Size` instances.
+
"""
from size import Size
if disks is None:
@@ -868,13 +928,32 @@ class Blivet(object):
@property
def names(self):
+ """ A list of all of the known in-use device names.
"""
return self.devicetree.names
def deviceDeps(self, device):
+ """ Return a list of the devices that depend on the specified
device.
+
+ :param device: the subtree root device
+ :type device: :class:`~.devices.StorageDevice`
+ :returns: list of dependent devices
+ :rtype: list
+ """
return self.devicetree.getDependentDevices(device)
def newPartition(self, *args, **kwargs):
- """ Return a new PartitionDevice instance for configuring.
"""
+ """ Return a new (unallocated) PartitionDevice instance.
+
+ :keyword fmt_type: format type
+ :type fmt_type: str
+ :keyword fmt_args: arguments for format constructor
+ :type fmt_args: dict
+ :keyword mountpoint: mountpoint for format (filesystem)
+ :type mountpoint: str
+
+ All other arguments are passed on to the
+ :class:`~.devices.PartitionDevice` constructor.
+ """
if kwargs.has_key("fmt_type"):
kwargs["format"] = getFormat(kwargs.pop("fmt_type"),
mountpoint=kwargs.pop("mountpoint",
@@ -898,7 +977,23 @@ class Blivet(object):
return PartitionDevice(name, *args, **kwargs)
def newMDArray(self, *args, **kwargs):
- """ Return a new MDRaidArrayDevice instance for configuring.
"""
+ """ Return a new MDRaidArrayDevice instance.
+
+ :keyword fmt_type: format type
+ :type fmt_type: str
+ :keyword fmt_args: arguments for format constructor
+ :type fmt_args: dict
+ :keyword mountpoint: mountpoint for format (filesystem)
+ :type mountpoint: str
+ :returns: the new md array device
+ :rtype: :class:`~.devices.MDRaidArrayDevice`
+
+ All other arguments are passed on to the
+ :class:`~.devices.MDRaidArrayDevice` constructor.
+
+ If a name is not specified, one will be generated based on the
+ format type, mountpoint, hostname, and/or product name.
+ """
if kwargs.has_key("fmt_type"):
kwargs["format"] = getFormat(kwargs.pop("fmt_type"),
mountpoint=kwargs.pop("mountpoint",
@@ -922,7 +1017,17 @@ class Blivet(object):
return MDRaidArrayDevice(name, *args, **kwargs)
def newVG(self, *args, **kwargs):
- """ Return a new LVMVolumeGroupDevice instance.
"""
+ """ Return a new LVMVolumeGroupDevice instance.
+
+ :returns: the new volume group device
+ :rtype: :class:`~.devices.LVMVolumeGroupDevice`
+
+ All arguments are passed on to the
+ :class:`~.devices.LVMVolumeGroupDevice` constructor.
+
+ If a name is not specified, one will be generated based on the
+ hostname, and/or product name.
+ """
pvs = kwargs.pop("parents", [])
for pv in pvs:
if pv not in self.devices:
@@ -948,7 +1053,32 @@ class Blivet(object):
return LVMVolumeGroupDevice(name, pvs, *args, **kwargs)
def newLV(self, *args, **kwargs):
- """ Return a new LVMLogicalVolumeDevice instance.
"""
+ """ Return a new LVMLogicalVolumeDevice instance.
+
+ :keyword fmt_type: format type
+ :type fmt_type: str
+ :keyword fmt_args: arguments for format constructor
+ :type fmt_args: dict
+ :keyword mountpoint: mountpoint for format (filesystem)
+ :type mountpoint: str
+ :keyword thin_pool: whether to create a thin pool
+ :type thin_pool: bool
+ :keyword thin_volume: whether to create a thin volume
+ :type thin_volume: bool
+ :returns: the new device
+ :rtype: :class:`~.devices.LVMLogicalVolumeDevice`
+
+ All other arguments are passed on to the appropriate
+ :class:`~.devices.LVMLogicalVolumeDevice` constructor.
+
+ If a name is not specified, one will be generated based on the
+ format type and/or mountpoint.
+
+ .. note::
+
+ If you are creating a thin volume, the parents kwarg should
+ contain the pool -- not the vg.
+ """
thin_volume = kwargs.pop("thin_volume", False)
thin_pool = kwargs.pop("thin_pool", False)
vg = kwargs.get("parents", [None])[0]
@@ -1001,7 +1131,30 @@ class Blivet(object):
return device_class(name, *args, **kwargs)
def newBTRFS(self, *args, **kwargs):
- """ Return a new BTRFSVolumeDevice or BRFSSubVolumeDevice.
"""
+ """ Return a new BTRFSVolumeDevice or BRFSSubVolumeDevice.
+
+ :keyword fmt_args: arguments for format constructor
+ :type fmt_args: dict
+ :keyword mountpoint: mountpoint for format (filesystem)
+ :type mountpoint: str
+ :keyword subvol: whether this is a subvol (as opposed to a volume)
+ :type subvol: bool
+ :returns: the new device
+ :rtype: :class:`~.devices.BTRFSDevice`
+
+ All other arguments are passed on to the appropriate
+ :class:`~.devices.BTRFSDevice` constructor.
+
+ For volumes, the label is the same as the name. If a name/label is
+ not specified, one will be generated based on the hostname and/or
+ product name.
+
+ .. note::
+
+ If you are creating a subvolume, the parents kwarg should
+ contain the volume you want to contain the subvolume.
+
+ """
log.debug("newBTRFS: args = %s ; kwargs = %s" % (args, kwargs))
name = kwargs.pop("name", None)
if args:
@@ -1049,6 +1202,24 @@ class Blivet(object):
return device
def newBTRFSSubVolume(self, *args, **kwargs):
+ """ Return a new BRFSSubVolumeDevice.
+
+ :keyword fmt_args: arguments for format constructor
+ :type fmt_args: dict
+ :keyword mountpoint: mountpoint for format (filesystem)
+ :type mountpoint: str
+ :returns: the new device
+ :rtype: :class:`~.devices.BTRFSSubVolumeDevice`
+
+ All other arguments are passed on to the
+ :class:`~.devices.BTRFSSubVolumeDevice` constructor.
+
+ .. note::
+
+ Since you are creating a subvolume, the parents kwarg should
+ contain the volume you want to contain the subvolume.
+
+ """
kwargs["subvol"] = True
return self.newBTRFS(*args, **kwargs)
@@ -1059,15 +1230,21 @@ class Blivet(object):
def createDevice(self, device):
""" Schedule creation of a device.
- TODO: We could do some things here like assign the next
- available raid minor if one isn't already set.
+ :param device: the device to schedule creation of
+ :type device: :class:`~.devices.StorageDevice`
+ :rtype: None
"""
self.devicetree.registerAction(ActionCreateDevice(device))
if device.format.type:
self.devicetree.registerAction(ActionCreateFormat(device))
def destroyDevice(self, device):
- """ Schedule destruction of a device. """
+ """ Schedule destruction of a device.
+
+ :param device: the device to schedule destruction of
+ :type device: :class:`~.devices.StorageDevice`
+ :rtype: None
+ """
if device.format.exists and device.format.type:
# schedule destruction of any formatting while we're at it
self.devicetree.registerAction(ActionDestroyFormat(device))
@@ -1076,12 +1253,29 @@ class Blivet(object):
self.devicetree.registerAction(action)
def formatDevice(self, device, format):
- """ Schedule formatting of a device. """
+ """ Schedule formatting of a device.
+
+ :param device: the device to create the formatting on
+ :type device: :class:`~.devices.StorageDevice`
+ :param format: the format to create on the device
+ :type format: :class:`~.formats.DeviceFormat`
+ :rtype: None
+
+ A format destroy action will be scheduled first, so it is not
+ necessary to create and schedule an
+ :class:`~.deviceaction.ActionDestroyFormat` prior to calling this
+ method.
+ """
self.devicetree.registerAction(ActionDestroyFormat(device))
self.devicetree.registerAction(ActionCreateFormat(device, format))
def resetDevice(self, device):
- """ Cancel all scheduled actions and reset formatting.
"""
+ """ Cancel all scheduled actions and reset formatting.
+
+ :param device: the device to reset
+ :type device: :class:`~.devices.StorageDevice`
+ :rtype: None
+ """
actions = self.devicetree.findActions(device=device)
for action in reversed(actions):
self.devicetree.cancelAction(action)
@@ -1090,6 +1284,17 @@ class Blivet(object):
device.format = copy.copy(device.originalFormat)
def resizeDevice(self, device, new_size):
+ """ Schedule a resize of a device and its formatting, if any.
+
+ :param device: the device to resize
+ :type device: :class:`~.devices.StorageDevice`
+ :param new_size: the new target size for the device
+ :type new_size: :class:`~.size.Size`
+ :rtype: None
+
+ If the device has formatting that is recognized as being resizable
+ an action will be scheduled to resize it as well.
+ """
classes = []
if device.resizable:
classes.append(ActionResizeDevice)
@@ -1165,7 +1370,13 @@ class Blivet(object):
return tmp
def suggestContainerName(self, hostname=None, prefix=""):
- """ Return a reasonable, unused device name. """
+ """ Return a reasonable, unused device name.
+
+ :keyword hostname: the system's hostname
+ :keyword prefix: a prefix for the container name
+ :returns: the suggested name
+ :rtype: str
+ """
if not prefix:
prefix = shortProductName
@@ -1198,7 +1409,19 @@ class Blivet(object):
def suggestDeviceName(self, parent=None, swap=None,
mountpoint=None, prefix=""):
- """ Return a suitable, unused name for a new logical volume.
"""
+ """ Return a suitable, unused name for a new device.
+
+ :keyword parent: the parent device
+ :type parent: :class:`~.devices.StorageDevice`
+ :keyword swap: will this be a swap device
+ :type swap: bool
+ :keyword mountpoint: the device's mountpoint
+ :type mountpoint: str
+ :keyword prefix: device name prefix
+ :type prefix: str
+ :returns: the suggested name
+ :rtype: str
+ """
body = ""
if mountpoint:
if mountpoint == "/":
@@ -1253,6 +1476,7 @@ class Blivet(object):
@property
def fileSystemFreeSpace(self):
+ """ Combined free space in / and /usr as :class:`~.size.Size`.
"""
mountpoints = ["/", "/usr"]
free = 0
btrfs_volumes = []
@@ -1279,6 +1503,8 @@ class Blivet(object):
def sanityCheck(self):
""" Run a series of tests to verify the storage configuration.
+ This is installer-specific.
+
This function is called at the end of partitioning so that
we can make sure you don't have anything silly (like no /,
a really small /, etc). Returns (errors, warnings) where
@@ -1482,6 +1708,7 @@ class Blivet(object):
return list(pkgs)
def write(self):
+ """ Write out all storage-related configuration files.
"""
if not os.path.isdir("%s/etc" % ROOT_PATH):
os.mkdir("%s/etc" % ROOT_PATH)
@@ -1702,26 +1929,14 @@ class Blivet(object):
def factoryDevice(self, device_type, size, **kwargs):
""" Schedule creation of a device based on a top-down
specification.
- Arguments:
-
- device_type an AUTOPART_TYPE constant (lvm|btrfs|plain)
- size device's requested size
-
- Keyword arguments:
-
- mountpoint the device's mountpoint
- fstype the device's filesystem type, or swap
- label filesystem label
- disks the set of disks we can allocate from
- encrypted boolean
+ :param device_type: device type constant
+ :type device_type: int (:const:`~.devicefactory.DEVICE_TYPE_*`)
+ :param size: requested size
+ :type size: :class:`~.size.Size`
+ :returns: the newly configured device
+ :rtype: :class:`~.devices.StorageDevice`
- raid_level (btrfs/md/lvm only) RAID level (string)
-
- name name for new device
- container_name name of requested container
-
- device an already-defined but non-existent device
- to adjust instead of creating a new device
+ See :class:`~.devicefactory.DeviceFactory` for possible kwargs.
"""
log_method_call(self, device_type, size, **kwargs)
@@ -2826,7 +3041,16 @@ def findExistingInstallations(devicetree):
return roots
class Root(object):
+ """ A Root represents an existing OS installation. """
def __init__(self, mounts=None, swaps=None, name=None):
+ """
+ :keyword mounts: mountpoint dict
+ :type mounts: dict (mountpoint keys and :class:`~.devices.StorageDevice`
values)
+ :keyword swaps: swap device list
+ :type swaps: list of :class:`~.devices.StorageDevice`
+ :keyword name: name for this installed OS
+ :type name: str
+ """
# mountpoint key, StorageDevice value
if not mounts:
self.mounts = {}
diff --git a/blivet/dasd.py b/blivet/dasd.py
index 12cfaa7..24e7703 100644
--- a/blivet/dasd.py
+++ b/blivet/dasd.py
@@ -213,7 +213,4 @@ class DASD:
self._completedCylinders += 1.0
callback_data.set(self._completedCylinders / self.totalCylinders)
-# Create DASD singleton
-DASD = DASD()
-
# vim:tw=78:ts=4:et:sw=4
diff --git a/blivet/devices.py b/blivet/devices.py
index c7b0811..d4e5d5b 100644
--- a/blivet/devices.py
+++ b/blivet/devices.py
@@ -20,79 +20,6 @@
# Red Hat Author(s): Dave Lehman <dlehman(a)redhat.com>
#
-
-"""
- Device classes for use by anaconda.
-
- This is the hierarchy of device objects that anaconda will use for
- managing storage devices in the system. These classes will
- individually make use of external support modules as needed to
- perform operations specific to the type of device they represent.
-
- TODO:
- - see how to do network devices (NetworkManager may help)
- - perhaps just a wrapper here
- - document return values of all methods/functions
- - find out what other kinds of wild and crazy devices we need to
- represent here (iseries? xen? more mainframe? mac? ps?)
- - PReP
- - this is a prime candidate for a PseudoDevice
- - DASD
- - ZFCP
- - XEN
-
- What specifications do we allow? new existing
- partitions
- usage + +
- filesystem, partition type are implicit
- mountpoint + +
- size
- exact + -
- range + -
- resize - +
- format - +
- encryption + +
-
- disk
- exact + -
- set + -
- how will we specify this?
- partition w/ multiple parents cannot otherwise occur
- primary + -
-
- mdraid sets
- filesystem (*) + +
- mountpoint + +
- size?
- format - +
- encryption + +
-
- level + ?
- device minor + ?
- member devices + ?
- spares + ?
- name?
- bitmap? (boolean) + -
-
- volume groups
- name + -
- member pvs + +
- pesize + ?
-
- logical volumes
- filesystem + +
- mountpoint + +
- size
- exact + ?
- format - +
- encryption + +
-
- name + ?
- vgname + ?
-
-
-"""
-
import os
import math
import copy
@@ -138,6 +65,13 @@ device_majors = get_device_majors()
def devicePathToName(devicePath):
+ """ Return a name based on the given path to a device node.
+
+ :param devicePath: the path to a device node
+ :type devicePath: str
+ :returns: the name
+ :rtype: str
+ """
if devicePath.startswith("/dev/"):
name = devicePath[5:]
else:
@@ -153,6 +87,13 @@ def devicePathToName(devicePath):
def deviceNameToDiskByPath(deviceName=None):
+ """ Return a /dev/disk/by-path/ symlink path for the given device
name.
+
+ :param deviceName: the device name
+ :type deviceName: str
+ :returns: the full path to a /dev/disk/by-path/ symlink, or None
+ :rtype: str or NoneType
+ """
if not deviceName:
return ""
@@ -208,16 +149,11 @@ class Device(object):
_services = []
def __init__(self, name, parents=None):
- """ Create a Device instance.
-
- Arguments:
-
- name -- the device name (generally a device node's basename)
-
- Keyword Arguments:
-
- parents -- a list of required Device instances
-
+ """
+ :param name: the device name (generally a device node's basename)
+ :type name: str
+ :keyword parents: a list of parent devices
+ :type parents: list of :class:`Device` instances
"""
self._name = name
if parents is None:
@@ -276,10 +212,12 @@ class Device(object):
return d
def removeChild(self):
+ """ Decrement the child counter for this device.
"""
log_method_call(self, name=self.name, kids=self.kids)
self.kids -= 1
def addChild(self):
+ """ Increment the child counter for this device.
"""
log_method_call(self, name=self.name, kids=self.kids)
self.kids += 1
@@ -300,18 +238,36 @@ class Device(object):
raise NotImplementedError("destroy method not defined for Device")
def setupParents(self, orig=False):
- """ Run setup method of all parent devices. """
+ """ Run setup method of all parent devices.
+
+ :keyword orig: set up original format instead of current format
+ :type orig: bool
+ """
log_method_call(self, name=self.name, orig=orig, kids=self.kids)
for parent in self.parents:
parent.setup(orig=orig)
def teardownParents(self, recursive=None):
- """ Run teardown method of all parent devices. """
+ """ Run teardown method of all parent devices.
+
+ :keyword recursive: tear down all ancestor devices recursively
+ :type recursive: bool
+ """
for parent in self.parents:
parent.teardown(recursive=recursive)
def dependsOn(self, dep):
- """ Return True if this device depends on dep. """
+ """ Return True if this device depends on dep.
+
+ This device depends on another device if the other device is an
+ ancestor of this device. For example, a PartitionDevice depends on
+ the DiskDevice on which it resides.
+
+ :param dep: the other device
+ :type dep: :class:`Device`
+ :returns: whether this device depends on 'dep'
+ :rtype: bool
+ """
# XXX does a device depend on itself?
if dep in self.parents:
return True
@@ -327,12 +283,7 @@ class Device(object):
@property
def status(self):
- """ This device's status.
-
- For now, this should return a boolean:
- True the device is open and ready for use
- False the device is not open
- """
+ """ Is this device currently active and ready for use?
"""
return False
@property
@@ -357,6 +308,7 @@ class Device(object):
@property
def ancestors(self):
+ """ A list of all of this device's ancestors, including
itself. """
l = set([self])
for p in [d for d in self.parents if d not in l]:
l.update(set(p.ancestors))
@@ -392,6 +344,7 @@ class Device(object):
@property
def mediaPresent(self):
+ """ True if this device contains usable media. """
return True
@@ -399,9 +352,8 @@ class NetworkStorageDevice(object):
""" Virtual base class for network backed storage devices
"""
def __init__(self, host_address=None, nic=None):
- """ Create a NetworkStorage Device instance. Note this class is
only
- to be used as a baseclass and then only with multiple inheritance.
- The only correct use is:
+ """ Note this class is only to be used as a baseclass and then
only with
+ multiple inheritance. The only correct use is:
class MyStorageDevice(StorageDevice, NetworkStorageDevice):
The sole purpose of this class is to:
@@ -410,10 +362,10 @@ class NetworkStorageDevice(object):
2) To be able to get the host address of the host (server) backing
the storage *or* the NIC through which the storage is connected
- Arguments:
-
- host_address -- host address of the backing server
- nic -- nic to which the storage is bound
+ :keyword host_address: host address of the backing server
+ :type host_address: str
+ :keyword nic: NIC to which the block device is bound
+ :type nic: str
"""
self.host_address = host_address
self.nic = nic
@@ -426,10 +378,6 @@ class StorageDevice(Device):
path attribute, although it is not guaranteed to be useful, or
even present, unless the StorageDevice's setup method has been
run.
-
- StorageDevice instances can optionally contain a filesystem,
- represented by an FS instance. A StorageDevice's create method
- should create a filesystem if one has been specified.
"""
_type = "blivet"
_devDir = "/dev"
@@ -442,25 +390,33 @@ class StorageDevice(Device):
size=None, major=None, minor=None,
sysfsPath='', parents=None, exists=False, serial=None,
vendor="", model="", bus=""):
- """ Create a StorageDevice instance.
-
- Arguments:
-
- name -- the device name (generally a device node's basename)
-
- Keyword Arguments:
-
- size -- the device's size (units/format TBD)
- major -- the device major
- minor -- the device minor
- sysfsPath -- sysfs device path
- format -- a DeviceFormat instance
- uuid -- universally unique identifier
- parents -- a list of required Device instances
- serial -- the ID_SERIAL_SHORT for this device
- vendor -- the manufacturer of this Device
- model -- manufacturer's device model string
- bus -- the interconnect this device uses
+ """
+ :param name: the device name (generally a device node's basename)
+ :type name: str
+ :keyword exists: does this device exist?
+ :type exists: bool
+ :keyword size: the device's size in MB
+ :type size: int or float
+ :keyword parents: a list of parent devices
+ :type parents: list of :class:`StorageDevice`
+ :keyword format: this device's formatting
+ :type format: :class:`~.formats.DeviceFormat` or a subclass of it
+ :keyword uuid: universally unique identifier (device -- not fs)
+ :type uuid: str
+ :keyword sysfsPath: sysfs device path
+ :type sysfsPath: str
+ :keyword major: the device major
+ :type major: int
+ :keyword minor: the device minor
+ :type minor: int
+ :keyword serial: the ID_SERIAL_SHORT for this device
+ :type serial: str
+ :keyword vendor: the manufacturer of this Device
+ :type vendor: str
+ :keyword model: manufacturer's device model string
+ :type model: str
+ :keyword bus: the interconnect this device uses
+ :type bus: str
"""
# allow specification of individual parents
@@ -1014,7 +970,12 @@ class StorageDevice(Device):
data.mountpoint += str(self.id)
class DiskDevice(StorageDevice):
- """ A disk """
+ """ A local/generic disk.
+
+ This is not the only kind of device that is treated as a disk. More
+ useful than checking isinstance(device, DiskDevice) is checking
+ device.isDisk.
+ """
_type = "disk"
_partitionable = True
_isDisk = True
@@ -1023,26 +984,29 @@ class DiskDevice(StorageDevice):
size=None, major=None, minor=None, sysfsPath='',
parents=None, serial=None, vendor="", model="",
bus="",
exists=True):
- """ Create a DiskDevice instance.
-
- Arguments:
-
- name -- the device name (generally a device node's basename)
-
- Keyword Arguments:
-
- size -- the device's size (units/format TBD)
- major -- the device major
- minor -- the device minor
- sysfsPath -- sysfs device path
- format -- a DeviceFormat instance
- parents -- a list of required Device instances
- removable -- whether or not this is a removable device
- serial -- the ID_SERIAL_SHORT for this device
- vendor -- the manufacturer of this Device
- model -- manufacturer's device model string
- bus -- the interconnect this device uses
-
+ """
+ :param name: the device name (generally a device node's basename)
+ :type name: str
+ :keyword size: the device's size in MB
+ :type size: int or float
+ :keyword parents: a list of parent devices
+ :type parents: list of :class:`StorageDevice`
+ :keyword format: this device's formatting
+ :type format: :class:`~.formats.DeviceFormat` or a subclass of it
+ :keyword uuid: universally unique identifier (device -- not fs)
+ :type uuid: str
+ :keyword sysfsPath: sysfs device path
+ :type sysfsPath: str
+ :keyword removable: whether or not this is a removable device
+ :type removable: bool
+ :keyword serial: the ID_SERIAL_SHORT for this device
+ :type serial: str
+ :keyword vendor: the manufacturer of this Device
+ :type vendor: str
+ :keyword model: manufacturer's device model string
+ :type model: str
+ :keyword bus: the interconnect this device uses
+ :type bus: str
DiskDevices always exist.
"""
@@ -1109,38 +1073,49 @@ class PartitionDevice(StorageDevice):
major=None, minor=None, bootable=None,
sysfsPath='', parents=None, exists=False,
partType=None, primary=False, weight=0):
- """ Create a PartitionDevice instance.
-
- Arguments:
-
- name -- the device name (generally a device node's basename)
-
- Keyword Arguments:
-
- exists -- indicates whether this is an existing device
- format -- the device's format (DeviceFormat instance)
-
- For existing partitions:
-
- parents -- the disk that contains this partition
- major -- the device major
- minor -- the device minor
- sysfsPath -- sysfs device path
-
- For new partitions:
-
- partType -- primary,extended,&c (as parted constant)
- grow -- whether or not to grow the partition
- maxsize -- max size for growable partitions (in MB)
- size -- the device's size (in MB)
- start -- start sector (see note, below)
- end -- end sector (see note, below)
- bootable -- whether the partition is bootable
- parents -- a list of potential containing disks
- weight -- an initial sorting weight to assign
-
- NOTE: If start/end sectors are specified they will not be adjusted
- for optimal alignment. It is up to the caller to do that.
+ """
+ :param name: the device name (generally a device node's basename)
+ :type name: str
+ :keyword exists: does this device exist?
+ :type exists: bool
+ :keyword size: the device's size in MB
+ :type size: int or float
+ :keyword parents: a list of parent devices
+ :type parents: list of :class:`StorageDevice`
+ :keyword format: this device's formatting
+ :type format: :class:`~.formats.DeviceFormat` or a subclass of it
+
+ For existing partitions only:
+
+ :keyword major: the device major
+ :type major: long
+ :keyword minor: the device minor
+ :type minor: long
+ :keyword sysfsPath: sysfs device path
+ :type sysfsPath: str
+
+ For non-existent partitions only:
+
+ :keyword partType: parted type constant, eg:
+ :const:`parted.PARTITION_NORMAL`
+ :type partType: parted partition type constant
+ :keyword grow: whether or not to grow the partition
+ :type grow: bool
+ :keyword maxsize: max size for growable partitions in MB
+ :type maxsize: int or float
+ :keyword start: start sector (see note, below)
+ :type start: long
+ :keyword end: end sector (see note, below)
+ :type end: long
+ :keyword bootable: whether the partition is bootable
+ :type bootable: bool
+ :keyword weight: an initial sorting weight to assign
+ :type weight: int
+
+ .. note::
+
+ If a start sector is specified the partition will not be
+ adjusted for optimal alignment. That is up to the caller.
"""
self.req_disks = []
self.req_partType = None
@@ -1794,21 +1769,23 @@ class DMDevice(StorageDevice):
def __init__(self, name, format=None, size=None, dmUuid=None,
target=None, exists=False, parents=None, sysfsPath=''):
- """ Create a DMDevice instance.
-
- Arguments:
-
- name -- the device name (generally a device node's basename)
-
- Keyword Arguments:
-
- target -- the device-mapper target type (string)
- size -- the device's size (units/format TBD)
- dmUuid -- the device's device-mapper UUID
- sysfsPath -- sysfs device path
- format -- a DeviceFormat instance
- parents -- a list of required Device instances
- exists -- indicates whether this is an existing device
+ """
+ :param name: the device name (generally a device node's basename)
+ :type name: str
+ :keyword exists: does this device exist?
+ :type exists: bool
+ :keyword size: the device's size in MB
+ :type size: int or float
+ :keyword parents: a list of parent devices
+ :type parents: list of :class:`StorageDevice`
+ :keyword format: this device's formatting
+ :type format: :class:`~.formats.DeviceFormat` or a subclass of it
+ :keyword sysfsPath: sysfs device path
+ :type sysfsPath: str
+ :keyword dmUuid: device-mapper UUID
+ :type dmUuid: str
+ :keyword target: device mapper table/target name (eg: "linear")
+ :type target: str
"""
StorageDevice.__init__(self, name, format=format, size=size,
exists=exists,
@@ -1911,20 +1888,21 @@ class DMLinearDevice(DMDevice):
def __init__(self, name, format=None, size=None, dmUuid=None,
exists=False, parents=None, sysfsPath=''):
- """ Create a DMLinearDevice instance.
-
- Arguments:
-
- name -- the device name (generally a device node's basename)
-
- Keyword Arguments:
-
- size -- the device's size (units/format TBD)
- dmUuid -- the device's device-mapper UUID
- sysfsPath -- sysfs device path
- format -- a DeviceFormat instance
- parents -- a list of required Device instances
- exists -- indicates whether this is an existing device
+ """
+ :param name: the device name (generally a device node's basename)
+ :type name: str
+ :keyword exists: does this device exist?
+ :type exists: bool
+ :keyword size: the device's size in MB
+ :type size: int or float
+ :keyword parents: a list of parent devices
+ :type parents: list of :class:`StorageDevice`
+ :keyword format: this device's formatting
+ :type format: :class:`~.formats.DeviceFormat` or a subclass of it
+ :keyword sysfsPath: sysfs device path
+ :type sysfsPath: str
+ :keyword dmUuid: device-mapper UUID
+ :type dmUuid: str
"""
if not parents:
raise ValueError("DMLinearDevice requires a backing block device")
@@ -1975,19 +1953,19 @@ class DMCryptDevice(DMDevice):
def __init__(self, name, format=None, size=None, uuid=None,
exists=False, sysfsPath='', parents=None):
- """ Create a DMCryptDevice instance.
-
- Arguments:
-
- name -- the device name (generally a device node's basename)
-
- Keyword Arguments:
-
- size -- the device's size (units/format TBD)
- sysfsPath -- sysfs device path
- format -- a DeviceFormat instance
- parents -- a list of required Device instances
- exists -- indicates whether this is an existing device
+ """
+ :param name: the device name (generally a device node's basename)
+ :type name: str
+ :keyword exists: does this device exist?
+ :type exists: bool
+ :keyword size: the device's size in MB
+ :type size: int or float
+ :keyword parents: a list of parent devices
+ :type parents: list of :class:`StorageDevice`
+ :keyword format: this device's formatting
+ :type format: :class:`~.formats.DeviceFormat` or a subclass of it
+ :keyword sysfsPath: sysfs device path
+ :type sysfsPath: str
"""
DMDevice.__init__(self, name, format=format, size=size,
parents=parents, sysfsPath=sysfsPath,
@@ -2000,20 +1978,21 @@ class LUKSDevice(DMCryptDevice):
def __init__(self, name, format=None, size=None, uuid=None,
exists=False, sysfsPath='', parents=None):
- """ Create a LUKSDevice instance.
-
- Arguments:
-
- name -- the device name
-
- Keyword Arguments:
-
- size -- the device's size in MB
- uuid -- the device's UUID
- sysfsPath -- sysfs device path
- format -- a DeviceFormat instance
- parents -- a list of required Device instances
- exists -- indicates whether this is an existing device
+ """
+ :param name: the device name (generally a device node's basename)
+ :type name: str
+ :keyword exists: does this device exist?
+ :type exists: bool
+ :keyword size: the device's size
+ :type size: int or float
+ :keyword parents: a list of parent devices
+ :type parents: list of :class:`StorageDevice`
+ :keyword format: this device's formatting
+ :type format: :class:`~.formats.DeviceFormat` or a subclass of it
+ :keyword sysfsPath: sysfs device path
+ :type sysfsPath: str
+ :keyword uuid: the device UUID
+ :type uuid: str
"""
DMCryptDevice.__init__(self, name, format=format, size=size,
parents=parents, sysfsPath=sysfsPath,
@@ -2059,28 +2038,32 @@ class LVMVolumeGroupDevice(DMDevice):
def __init__(self, name, parents=None, size=None, free=None,
peSize=None, peCount=None, peFree=None, pvCount=None,
uuid=None, exists=False, sysfsPath=''):
- """ Create a LVMVolumeGroupDevice instance.
-
- Arguments:
-
- name -- the device name (generally a device node's basename)
- parents -- a list of physical volumes (StorageDevice)
-
- Keyword Arguments:
-
- peSize -- physical extent size (in MB)
- exists -- indicates whether this is an existing device
- sysfsPath -- sysfs device path
-
- For existing VG's only:
-
- size -- the VG's size (in MB)
- free -- amount of free space in the VG
- peFree -- number of free extents
- peCount -- total number of extents
- pvCount -- number of PVs in this VG
- uuid -- the VG's UUID
-
+ """
+ :param name: the device name (generally a device node's basename)
+ :type name: str
+ :keyword exists: does this device exist?
+ :type exists: bool
+ :keyword parents: a list of parent devices
+ :type parents: list of :class:`StorageDevice`
+ :keyword sysfsPath: sysfs device path
+ :type sysfsPath: str
+ :keyword peSize: physical extent size
+ :type peSize: int or float
+
+ For existing VG's only:
+
+ :keyword size: the VG's size
+ :type size: int or float
+ :keyword free -- amount of free space in the VG
+ :type free: int or float
+ :keyword peFree: number of free extents
+ :type peFree: int
+ :keyword peCount -- total number of extents
+ :type peCount: int
+ :keyword pvCount: number of PVs in this VG
+ :type pvCount: int
+ :keyword uuid: the VG UUID
+ :type uuid: str
"""
self.pvClass = get_device_format_class("lvmpv")
if not self.pvClass:
@@ -2510,31 +2493,43 @@ class LVMLogicalVolumeDevice(DMDevice):
format=None, exists=False, sysfsPath='',
grow=None, maxsize=None, percent=None,
singlePV=False):
- """ Create a LVMLogicalVolumeDevice instance.
-
- Arguments:
-
- name -- the device name (generally a device node's basename)
- vgdev -- volume group (LVMVolumeGroupDevice instance)
-
- Keyword Arguments:
-
- size -- the device's size (in MB)
- uuid -- the device's UUID
- copies -- number of copies in the vg (>1 for mirrored lvs)
- logSize -- size of log volume (for mirrored lvs)
- snapshotSpace -- sum of sizes of snapshots of this lv
- sysfsPath -- sysfs device path
- format -- a DeviceFormat instance
- exists -- indicates whether this is an existing device
- singlePV -- if true, maps this lv to a single pv
- segType -- segment type (eg: "linear", "raid1")
-
- For new (non-existent) LVs only:
-
- grow -- whether to grow this LV
- maxsize -- maximum size for growable LV (in MB)
- percent -- percent of VG space to take
+ """
+ :param name: the device name (generally a device node's basename)
+ :type name: str
+ :keyword exists: does this device exist?
+ :type exists: bool
+ :keyword size: the device's size in MB
+ :type size: int or float
+ :keyword parents: a list of parent devices
+ :type parents: list of :class:`StorageDevice`
+ :keyword format: this device's formatting
+ :type format: :class:`~.formats.DeviceFormat` or a subclass of it
+ :keyword sysfsPath: sysfs device path
+ :type sysfsPath: str
+ :keyword uuid: the device UUID
+ :type uuid: str
+
+ For existing LVs only:
+
+ :keyword copies: number of copies in the vg (>1 for mirrored lvs)
+ :type copies: int
+ :keyword logSize: size of log volume (for mirrored lvs)
+ :type logSize: int or float
+ :keyword snapshotSpace: sum of sizes of snapshots of this lv
+ :type snapshotSpace: int or float
+ :keyword singlePV: if true, maps this lv to a single pv
+ :type singlePV: bool
+ :keyword segType: segment type (eg: "linear", "raid1")
+ :type segType: str
+
+ For non-existent LVs only:
+
+ :keyword grow: whether to grow this LV
+ :type grow: bool
+ :keyword maxsize: maximum size for growable LV
+ :type maxsize: int or float
+ :keyword percent -- percent of VG space to take
+ :type percent: int
"""
if self.__class__.__name__ == "LVMLogicalVolumeDevice":
@@ -2802,29 +2797,36 @@ class LVMThinPoolDevice(LVMLogicalVolumeDevice):
format=None, exists=False, sysfsPath='',
grow=None, maxsize=None, percent=None,
metadatasize=None, chunksize=None, segType=None):
- """ Create a LVMLogicalVolumeDevice instance.
-
- Arguments:
-
- name -- the device name (generally a device node's basename)
- parents -- vg (LVMVolumeGroupDevice instance)
-
- Keyword Arguments:
-
- size -- the device's size (in MB)
- uuid -- the device's UUID
- sysfsPath -- sysfs device path
- format -- a DeviceFormat instance
- exists -- indicates whether this is an existing device
-
- For new (non-existent) LVs only:
-
- grow -- whether to grow this LV
- maxsize -- maximum size for growable LV (in MB)
- percent -- percent of VG space to take
- metadatasize -- the size of the metadata LV (in MB)
- chunksize -- chunk size for the pool (in MB)
-
+ """
+ :param name: the device name (generally a device node's basename)
+ :type name: str
+ :keyword exists: does this device exist?
+ :type exists: bool
+ :keyword size: the device's size in MB
+ :type size: int or float
+ :keyword parents: a list of parent devices
+ :type parents: list of :class:`StorageDevice`
+ :keyword format: this device's formatting
+ :type format: :class:`~.formats.DeviceFormat` or a subclass of it
+ :keyword sysfsPath: sysfs device path
+ :type sysfsPath: str
+ :keyword uuid: the device UUID
+ :type uuid: str
+ :keyword segType: segment type
+ :type segType: str
+
+ For non-existent pools only:
+
+ :keyword grow: whether to grow this LV
+ :type grow: bool
+ :keyword maxsize: maximum size for growable LV
+ :type maxsize: int or float
+ :keyword percent: percent of VG space to take
+ :type percent: int
+ :keyword metadatasize: the size of the metadata LV
+ :type metadatasize: int or float
+ :keyword chunksize: chunk size for the pool
+ :type chunksize: int or float
"""
if metadatasize is not None and \
not lvm.is_valid_thin_pool_metadata_size(metadatasize):
@@ -2955,23 +2957,28 @@ class MDRaidArrayDevice(StorageDevice):
memberDevices=None, totalDevices=None,
uuid=None, format=None, exists=False, metadataVersion=None,
parents=None, sysfsPath=''):
- """ Create a MDRaidArrayDevice instance.
-
- Arguments:
-
- name -- the device name (generally a device node's basename)
-
- Keyword Arguments:
-
- level -- the device's RAID level (a string, eg: '1' or
'raid1')
- metadataVersion -- the version of the device's md metadata
- parents -- list of member devices (StorageDevice instances)
- size -- the device's size (units/format TBD)
- uuid -- the device's UUID
- minor -- the device minor
- sysfsPath -- sysfs device path
- format -- a DeviceFormat instance
- exists -- indicates whether this is an existing device
+ """
+ :param name: the device name (generally a device node's basename)
+ :type name: str
+ :keyword exists: does this device exist?
+ :type exists: bool
+ :keyword size: the device's size in MB
+ :type size: int or float
+ :keyword parents: a list of parent devices
+ :type parents: list of :class:`StorageDevice`
+ :keyword format: this device's formatting
+ :type format: :class:`~.formats.DeviceFormat` or a subclass of it
+ :keyword sysfsPath: sysfs device path
+ :type sysfsPath: str
+ :keyword uuid: the device UUID
+ :type uuid: str
+
+ :keyword level: the device's RAID level
+ :type level: str (eg: "raid1")
+ :keyword metadataVersion: the version of the device's md metadata
+ :type metadataVersion: str (eg: "0.90")
+ :keyword minor: the device minor (obsolete?)
+ :type minor: int
"""
StorageDevice.__init__(self, name, format=format, exists=exists,
major=major, minor=minor, size=size,
@@ -3488,19 +3495,22 @@ class DMRaidArrayDevice(DMDevice):
def __init__(self, name, raidSet=None, format=None,
size=None, parents=None, sysfsPath=''):
- """ Create a DMRaidArrayDevice instance.
-
- Arguments:
-
- name -- the dmraid name also the device node's basename
-
- Keyword Arguments:
-
- raidSet -- the RaidSet object from block
- parents -- a list of the member devices
- sysfsPath -- sysfs device path
- size -- the device's size
- format -- a DeviceFormat instance
+ """
+ :param name: the device name (generally a device node's basename)
+ :type name: str
+ :keyword size: the device's size in MB
+ :type size: int or float
+ :keyword parents: a list of parent devices
+ :type parents: list of :class:`StorageDevice`
+ :keyword format: this device's formatting
+ :type format: :class:`~.formats.DeviceFormat` or a subclass of it
+ :keyword sysfsPath: sysfs device path
+ :type sysfsPath: str
+ :keyword raidSet: the RaidSet object from block
+ :type raidSet: :class:`block.RaidSet`
+
+ DMRaidArrayDevices always exist. Blivet cannot create or destroy
+ them.
"""
if isinstance(parents, list):
for parent in parents:
@@ -3598,19 +3608,22 @@ class MultipathDevice(DMDevice):
def __init__(self, name, format=None, size=None, serial=None,
parents=None, sysfsPath=''):
- """ Create a MultipathDevice instance.
-
- Arguments:
-
- name -- the device name (generally a device node's basename)
-
- Keyword Arguments:
-
- sysfsPath -- sysfs device path
- size -- the device's size
- format -- a DeviceFormat instance
- parents -- a list of the backing devices (Device instances)
- serial -- the device's serial number
+ """
+ :param name: the device name (generally a device node's basename)
+ :type name: str
+ :keyword size: the device's size in MB
+ :type size: int or float
+ :keyword parents: a list of parent devices
+ :type parents: list of :class:`StorageDevice`
+ :keyword format: this device's formatting
+ :type format: :class:`~.formats.DeviceFormat` or a subclass of it
+ :keyword sysfsPath: sysfs device path
+ :type sysfsPath: str
+ :keyword serial: the device's serial number
+ :type serial: str
+
+ MultipathDevices always exist. Blivet cannot create or destroy
+ them.
"""
DMDevice.__init__(self, name, format=format, size=size,
@@ -3703,13 +3716,9 @@ class NoDevice(StorageDevice):
_type = "nodev"
def __init__(self, format=None):
- """ Create a NoDevice instance.
-
- Arguments:
-
- Keyword Arguments:
-
- format -- a DeviceFormat instance
+ """
+ :keyword format: the device's formatting
+ :type format: :class:`~.formats.DeviceFormat` or a subclass of it
"""
if format:
name = format.device
@@ -3783,18 +3792,17 @@ class FileDevice(StorageDevice):
def __init__(self, path, format=None, size=None,
exists=False, parents=None):
- """ Create a FileDevice instance.
-
- Arguments:
-
- path -- full path to the file
-
- Keyword Arguments:
-
- format -- a DeviceFormat instance
- size -- the file size (units TBD)
- parents -- a list of required devices (Device instances)
- exists -- indicates whether this is an existing device
+ """
+ :param path: full path to the file
+ :type path: str
+ :keyword exists: does this device exist?
+ :type exists: bool
+ :keyword size: the device's size in MB
+ :type size: int or float
+ :keyword parents: a list of parent devices
+ :type parents: list of :class:`StorageDevice`
+ :keyword format: this device's formatting
+ :type format: :class:`~.formats.DeviceFormat` or a subclass of it
"""
if not path.startswith("/"):
raise ValueError("FileDevice requires an absolute path")
@@ -3887,19 +3895,17 @@ class LoopDevice(StorageDevice):
def __init__(self, name=None, format=None, size=None, sysfsPath=None,
exists=False, parents=None):
- """ Create a LoopDevice instance.
-
- Arguments:
-
- name -- the device's name
-
- Keyword Arguments:
-
- format -- a DeviceFormat instance
- size -- the device's size in MB
- parents -- a list of required devices (Device instances)
- exists -- indicates whether this is an existing device
-
+ """
+ :param name: the device name (generally a device node's basename)
+ :type name: str
+ :keyword exists: does this device exist?
+ :type exists: bool
+ :keyword size: the device's size in MB
+ :type size: int or float
+ :keyword parents: a list of parent devices
+ :type parents: list of :class:`StorageDevice`
+ :keyword format: this device's formatting
+ :type format: :class:`~.formats.DeviceFormat` or a subclass of it
Loop devices always exist.
"""
@@ -3972,6 +3978,29 @@ class iScsiDiskDevice(DiskDevice, NetworkStorageDevice):
_packages = ["iscsi-initiator-utils", "dracut-network"]
def __init__(self, device, **kwargs):
+ """
+ :param name: the device name (generally a device node's basename)
+ :type name: str
+ :keyword exists: does this device exist?
+ :type exists: bool
+ :keyword size: the device's size in MB
+ :type size: int or float
+ :keyword parents: a list of parent devices
+ :type parents: list of :class:`StorageDevice`
+ :keyword format: this device's formatting
+ :type format: :class:`~.formats.DeviceFormat` or a subclass of it
+ :keyword node: ???
+ :type node: str
+ :keyword ibft: use iBFT
+ :type ibft: bool
+ :keyword nic: name of NIC to use
+ :type nic: str
+ :keyword initiator: initiator name
+ :type initiator: str
+ :keyword fw_name: qla4xxx partial offload
+ :keyword fw_address: qla4xxx partial offload
+ :keyword fw_port: qla4xxx partial offload
+ """
self.node = kwargs.pop("node")
self.ibft = kwargs.pop("ibft")
self.nic = kwargs.pop("nic")
@@ -4037,6 +4066,20 @@ class FcoeDiskDevice(DiskDevice, NetworkStorageDevice):
_packages = ["fcoe-utils", "dracut-network"]
def __init__(self, device, **kwargs):
+ """
+ :param name: the device name (generally a device node's basename)
+ :type name: str
+ :keyword exists: does this device exist?
+ :type exists: bool
+ :keyword size: the device's size in MB
+ :type size: int or float
+ :keyword parents: a list of parent devices
+ :type parents: list of :class:`StorageDevice`
+ :keyword format: this device's formatting
+ :type format: :class:`~.formats.DeviceFormat` or a subclass of it
+ :keyword nic: name of NIC to use
+ :keyword identifier: ???
+ """
self.nic = kwargs.pop("nic")
self.identifier = kwargs.pop("identifier")
DiskDevice.__init__(self, device, **kwargs)
@@ -4116,6 +4159,21 @@ class ZFCPDiskDevice(DiskDevice):
_type = "zfcp"
def __init__(self, device, **kwargs):
+ """
+ :param name: the device name (generally a device node's basename)
+ :type name: str
+ :keyword exists: does this device exist?
+ :type exists: bool
+ :keyword size: the device's size in MB
+ :type size: int or float
+ :keyword parents: a list of parent devices
+ :type parents: list of :class:`StorageDevice`
+ :keyword format: this device's formatting
+ :type format: :class:`~.formats.DeviceFormat` or a subclass of it
+ :keyword hba_id: ???
+ :keyword wwpn: ???
+ :keyword fcp_lun: ???
+ """
self.hba_id = kwargs.pop("hba_id")
self.wwpn = kwargs.pop("wwpn")
self.fcp_lun = kwargs.pop("fcp_lun")
@@ -4144,6 +4202,21 @@ class DASDDevice(DiskDevice):
_type = "dasd"
def __init__(self, device, **kwargs):
+ """
+ :param name: the device name (generally a device node's basename)
+ :type name: str
+ :keyword exists: does this device exist?
+ :type exists: bool
+ :keyword size: the device's size in MB
+ :type size: int or float
+ :keyword parents: a list of parent devices
+ :type parents: list of :class:`StorageDevice`
+ :keyword format: this device's formatting
+ :type format: :class:`~.formats.DeviceFormat` or a subclass of it
+ :keyword busid: bus ID
+ :keyword opts: options
+ :type opts: dict with option name keys and option value values
+ """
self.busid = kwargs.pop('busid')
self.opts = kwargs.pop('opts')
DiskDevice.__init__(self, device, **kwargs)
@@ -4209,6 +4282,14 @@ class NFSDevice(StorageDevice, NetworkStorageDevice):
_packages = ["dracut-network"]
def __init__(self, device, format=None, parents=None):
+ """
+ :param device: the device name (generally a device node's basename)
+ :type device: str
+ :keyword parents: a list of parent devices
+ :type parents: list of :class:`StorageDevice`
+ :keyword format: this device's formatting
+ :type format: :class:`~.formats.DeviceFormat` or a subclass of it
+ """
# we could make host/ip, path, &c but will anything use it?
StorageDevice.__init__(self, device, format=format, parents=parents)
NetworkStorageDevice.__init__(self, device.split(":")[0])
diff --git a/blivet/devicetree.py b/blivet/devicetree.py
index e72ce7c..80f52b6 100644
--- a/blivet/devicetree.py
+++ b/blivet/devicetree.py
@@ -57,29 +57,43 @@ log = logging.getLogger("blivet")
class DeviceTree(object):
""" A quasi-tree that represents the devices in the system.
- The tree contains a list of device instances, which does not
- necessarily reflect the actual state of the system's devices.
- DeviceActions are used to perform modifications to the tree,
- except when initially populating the tree.
+ The tree contains a list of :class:`~.devices.StorageDevice` instances,
+ which does not necessarily reflect the actual state of the system's
+ devices. :class:`~.deviceaction.DeviceAction` is used to perform
+ modifications to the tree, except when initially populating the tree.
- DeviceAction instances are registered, possibly causing the
- addition or removal of Device instances to/from the tree. The
- DeviceActions are all reversible up to the time their execute
- method has been called.
+ :class:`~.deviceaction.DeviceAction` instances are registered, possibly
+ causing the addition or removal of :class:`~.devices.StorageDevice`
+ instances to/from the tree. A :class:`~.deviceaction.DeviceAction`
+ is reversible up to the time its 'execute' method is called.
Only one action of any given type/object pair should exist for
any given device at any given time.
- DeviceAction instances can only be registered for leaf devices,
- except for resize actions.
+ :class:`~.deviceaction.DeviceAction` instances can only be registered
+ for leaf devices, except for resize actions.
"""
def __init__(self, conf=None, passphrase=None, luksDict=None,
iscsi=None, dasd=None):
+ """
+
+ :keyword conf: storage discovery configuration
+ :type conf: :class:`~.StorageDiscoveryConfig`
+ :keyword passphrase: default LUKS passphrase
+ :keyword luksDict: a dict with UUID keys and passphrase values
+ :type luksDict: dict
+ :keyword iscsi: ISCSI control object
+ :type iscsi: :class:`~.iscsi.iscsi`
+ :keyword dasd: DASD control object
+ :type dasd: :class:`~.dasd.DASD`
+
+ """
self.reset(conf, passphrase, luksDict, iscsi, dasd)
def reset(self, conf=None, passphrase=None, luksDict=None,
iscsi=None, dasd=None):
+ """ Reset the instance to its initial state. """
# internal data members
self._devices = []
self._actions = []
@@ -127,7 +141,17 @@ class DeviceTree(object):
self._cleanup = False
def setDiskImages(self, images):
- """ Set the disk images and reflect them in exclusiveDisks.
"""
+ """ Set the disk images and reflect them in exclusiveDisks.
+
+ :param images: dict with image name keys and filename values
+ :type images: dict
+
+ .. note::
+
+ Disk images are automatically exclusive. That means that, in the
+ presence of disk images, any local storage not associated with
+ the disk images is ignored.
+ """
self.diskImages = images
# disk image files are automatically exclusive
self.exclusiveDisks = self.diskImages.keys()
@@ -261,6 +285,9 @@ class DeviceTree(object):
def _addDevice(self, newdev):
""" Add a device to the tree.
+ :param newdev: the device to add
+ :type newdev: a subclass of :class:`~.devices.StorageDevice`
+
Raise ValueError if the device's identifier is already
in the list.
"""
@@ -288,7 +315,16 @@ class DeviceTree(object):
def _removeDevice(self, dev, force=None, moddisk=True):
""" Remove a device from the tree.
- Only leaves may be removed.
+ :param dev: the device to remove
+ :type dev: a subclass of :class:`~.devices.StorageDevice`
+ :keyword force: whether to force removal of a non-leaf device
+ :type force: bool
+ :keyword moddisk: update parent disk's format (partitions only)
+ :type moddisk: bool
+
+ .. note::
+
+ Only leaves may be removed.
"""
if dev not in self._devices:
raise ValueError("Device '%s' not in tree" % dev.name)
@@ -338,6 +374,9 @@ class DeviceTree(object):
def registerAction(self, action):
""" Register an action to be performed at a later time.
+ :param action: the action
+ :type action: :class:`~.deviceaction.DeviceAction`
+
Modifications to the Device instance are handled before we
get here.
"""
@@ -363,6 +402,9 @@ class DeviceTree(object):
def cancelAction(self, action):
""" Cancel a registered action.
+ :param action: the action
+ :type action: :class:`~.deviceaction.DeviceAction`
+
This will unregister the action and do any required
modifications to the device list.
@@ -383,12 +425,21 @@ class DeviceTree(object):
devid=None):
""" Find all actions that match all specified parameters.
- Keyword arguments:
-
- device -- device to match (Device, or None to match any)
- type -- action type to match (string, or None to match any)
- object -- operand type to match (string, or None to match any)
- path -- device path to match (string, or None to match any)
+ A value of None for any of the keyword arguments indicates that any
+ value is acceptable for that field.
+
+ :keyword device: device to match
+ :type device: :class:`~.devices.StorageDevice` or None
+ :keyword type: action type to match (eg: "create",
"destroy")
+ :type type: str or None
+ :keyword object: operand type to match (eg: "device" or
"format")
+ :type object: str or None
+ :keyword path: device path to match
+ :type path: str or None
+ :keyword devid: device id to match
+ :type devid: int or None
+ :returns: a list of matching actions
+ :rtype: list of :class:`~.deviceaction.DeviceAction`
"""
if device is None and type is None and object is None and \
@@ -424,6 +475,9 @@ class DeviceTree(object):
""" Return a list of devices that depend on dep.
The list includes both direct and indirect dependents.
+
+ :param dep: the device whose dependents we are looking for
+ :type dep: :class:`~.devices.StorageDevice`
"""
dependents = []
@@ -442,14 +496,10 @@ class DeviceTree(object):
def isIgnored(self, info):
""" Return True if info is a device we should ignore.
- Arguments:
-
- info -- a dict representing a udev db entry
-
- TODO:
-
- - filtering of SAN/FC devices
- - filtering by driver?
+ :param info: udevdb device entry
+ :type info: dict
+ :returns: whether the device will be ignored
+ :rtype: bool
"""
sysfs_path = udev_device_get_sysfs_path(info)
@@ -513,12 +563,20 @@ class DeviceTree(object):
# FIXME: check for virtual devices whose slaves are on the ignore list
def udevDeviceIsDisk(self, info):
- # We want exclusiveDisks to operate on anything that could be
- # considered a directly usable disk, ie: fwraid array, mpath, or disk.
- #
- # Unfortunately, since so many things are represented as disks by
- # udev/sysfs, we have to define what is a disk in terms of what is
- # not a disk.
+ """ Return True if the udev device looks like a disk.
+
+ :param info: udevdb device entry
+ :type info: dict
+ :returns: whether the device is a disk
+ :rtype: bool
+
+ We want exclusiveDisks to operate on anything that could be
+ considered a directly usable disk, ie: fwraid array, mpath, or disk.
+
+ Unfortunately, since so many things are represented as disks by
+ udev/sysfs, we have to define what is a disk in terms of what is
+ not a disk.
+ """
return (udev_device_is_disk(info) and
not (udev_device_is_cdrom(info) or
udev_device_is_partition(info) or
@@ -1764,6 +1822,20 @@ class DeviceTree(object):
devicelibs.lvm.lvm_cc_addFilterRejectRegexp(pv.name)
def hide(self, device):
+ """ Hide the specified device.
+
+ :param device: the device to hide
+ :type device: :class:`~.devices.StorageDevice`
+
+ If the device is not a leaf device, all devices that depend on it
+ will be hidden leaves-first until the device is a leaf device.
+
+ .. note::
+
+ Hiding a device will cancel any actions scheduled on that device
+ or any device that depends on it.
+
+ """
if device in self._hidden:
return
@@ -1805,6 +1877,18 @@ class DeviceTree(object):
self.dasd.removeDASD(device)
def unhide(self, device):
+ """ Restore a device's visibility.
+
+ :param device: the device to restore/unhide
+ :type device: :class:`~.devices.StorageDevice`
+
+ .. note::
+
+ Actions canceled while hiding the device are not rescheduled
+ automatically.
+
+ """
+
# the hidden list should be in leaves-first order
for hidden in reversed(self._hidden):
if hidden == device or hidden.dependsOn(device):
@@ -1900,7 +1984,15 @@ class DeviceTree(object):
self.backupConfigs(restore=True)
def populate(self, cleanupOnly=False):
- """ Locate all storage devices. """
+ """ Locate all storage devices.
+
+ Everything should already be active. We just go through and gather
+ details as needed and set up the relations between various devices.
+
+ Devices excluded via disk filtering (or because of disk images) are
+ scanned just the rest, but then they are hidden at the end of this
+ process.
+ """
self.backupConfigs()
if cleanupOnly:
self._cleanup = True
@@ -2017,6 +2109,15 @@ class DeviceTree(object):
log.error("setup of %s failed: %s" % (device.name, msg))
def getDeviceBySysfsPath(self, path, incomplete=False, hidden=False):
+ """ Return a list of devices with a matching sysfs path.
+
+ :param path: the sysfs path to match
+ :type path: str
+ :keyword incomplete: include incomplete devices in results
+ :type incomplete: bool
+ :keyword hidden: include hidden devices in results
+ :type hidden: bool
+ """
if not path:
return None
@@ -2037,6 +2138,15 @@ class DeviceTree(object):
return found
def getDeviceByUuid(self, uuid, incomplete=False, hidden=False):
+ """ Return a list of devices with a matching UUID.
+
+ :param uuid: the UUID to match
+ :type uuid: str
+ :keyword incomplete: include incomplete devices in results
+ :type incomplete: bool
+ :keyword hidden: include hidden devices in results
+ :type hidden: bool
+ """
if not uuid:
return None
@@ -2060,6 +2170,15 @@ class DeviceTree(object):
return found
def getDevicesBySerial(self, serial, incomplete=False, hidden=False):
+ """ Return a list of devices with a matching serial.
+
+ :param serial: the serial to match
+ :type serial: str
+ :keyword incomplete: include incomplete devices in results
+ :type incomplete: bool
+ :keyword hidden: include hidden devices in results
+ :type hidden: bool
+ """
devices = self._devices[:]
if hidden:
devices += self._hidden
@@ -2079,6 +2198,15 @@ class DeviceTree(object):
return retval
def getDeviceByLabel(self, label, incomplete=False, hidden=False):
+ """ Return a device with a matching filesystem label.
+
+ :param label: the filesystem label to match
+ :type label: str
+ :keyword incomplete: search incomplete devices
+ :type incomplete: bool
+ :keyword hidden: search hidden devices
+ :type hidden: bool
+ """
if not label:
return None
@@ -2103,6 +2231,15 @@ class DeviceTree(object):
return found
def getDeviceByName(self, name, incomplete=False, hidden=False):
+ """ Return a device with a matching name.
+
+ :param name: the name to look for
+ :type name: str
+ :keyword incomplete: search incomplete devices
+ :type incomplete: bool
+ :keyword hidden: search hidden devices
+ :type hidden: bool
+ """
log_method_call(self, name=name)
if not name:
log_method_return(self, None)
@@ -2129,6 +2266,15 @@ class DeviceTree(object):
return found
def getDeviceByPath(self, path, preferLeaves=True, incomplete=False, hidden=False):
+ """ Return a device with a matching path.
+
+ :param path: the path to match
+ :type path: str
+ :keyword incomplete: include incomplete devices in results
+ :type incomplete: bool
+ :keyword hidden: include hidden devices in results
+ :type hidden: bool
+ """
log_method_call(self, path=path)
if not path:
log_method_return(self, None)
@@ -2166,20 +2312,35 @@ class DeviceTree(object):
return found
def getDevicesByType(self, device_type):
+ """ Return a list of devices with a matching device type.
+
+ :param device_type: the type to match
+ :type device_type: str
+ """
# TODO: expand this to catch device format types
return [d for d in self._devices if d.type == device_type]
def getDevicesByInstance(self, device_class):
+ """ Return a list of devices with a matching device class.
+
+ :param path: the device class to match
+ :type path: class
+ """
return [d for d in self._devices if isinstance(d, device_class)]
def getDeviceByID(self, id_num):
+ """ Return a device with specified device id.
+
+ :param id_num: the id to look for
+ :type id_num: int
+ """
for device in self._devices:
if device.id == id_num:
return device
@property
def devices(self):
- """ List of device instances """
+ """ List of devices currently in the tree """
devices = []
for device in self._devices:
if not getattr(device, "complete", True):
@@ -2206,7 +2367,7 @@ class DeviceTree(object):
@property
def uuids(self):
- """ Dict with uuid keys and Device values. """
+ """ Dict with uuid keys and :class:`~.devices.Device` values.
"""
uuids = {}
for dev in self._devices:
try:
@@ -2253,6 +2414,23 @@ class DeviceTree(object):
return [c for c in self._devices if device in c.parents]
def resolveDevice(self, devspec, blkidTab=None, cryptTab=None, options=None):
+ """ Return the device matching the provided device specification.
+
+ The spec can be anything from a device name (eg: 'sda3') to a device
+ node path (eg: '/dev/mapper/fedora-root' or '/dev/dm-2') to
+ something like 'UUID=xyz-tuv-qrs' or 'LABEL=rootfs'.
+
+ :param devspec: a string describing a block device
+ :type devspec: str
+ :keyword blkidTab: blkid info
+ :type blkidTab: :class:`~.BlkidTab`
+ :keyword cryptTab: crypto info
+ :type cryptTab: :class:`~.CryptTab`
+ :keyword options: mount options
+ :type options: str
+ :returns: the device
+ :rtype: :class:`~.devices.StorageDevice` or None
+ """
# find device in the tree
device = None
if devspec.startswith("UUID="):
diff --git a/blivet/formats/__init__.py b/blivet/formats/__init__.py
index a7416f1..5e0ea32 100644
--- a/blivet/formats/__init__.py
+++ b/blivet/formats/__init__.py
@@ -60,26 +60,19 @@ def get_default_filesystem_type():
raise DeviceFormatError("None of %s is supported by your kernel" %
",".join(default_fstypes))
def getFormat(fmt_type, *args, **kwargs):
- """ Return a DeviceFormat instance based on fmt_type and args.
-
- Given a device format type and a set of constructor arguments,
- return a DeviceFormat instance.
-
- Return None if no suitable format class is found.
-
- Arguments:
-
- fmt_type -- the name of the format type (eg: 'ext3', 'swap')
-
- Keyword Arguments:
-
- The keyword arguments may vary according to the format type,
- but here is the common set:
-
- device -- path to the device on which the format resides
- uuid -- the UUID of the (preexisting) formatted device
- exists -- whether or not the format exists on the device
-
+ """ Return an instance of the appropriate DeviceFormat class.
+
+ :param fmt_type: The name of the formatting type
+ :type fmt_type: str.
+ :return: the format instance
+ :rtype: :class:`DeviceFormat`
+ :raises: ValueError
+
+ .. note::
+
+ Any additional arguments will be passed on to the constructor for
+ the format class. See the various :class:`DeviceFormat` subclasses
+ for an exhaustive list of the arguments that can be passed.
"""
fmt_class = get_device_format_class(fmt_type)
fmt = None
@@ -103,8 +96,10 @@ def getFormat(fmt_type, *args, **kwargs):
def collect_device_format_classes():
""" Pick up all device format classes from this directory.
- Note: Modules must call register_device_format(FormatClass) in
- order for the format class to be picked up.
+ .. note::
+
+ Modules must call :func:`register_device_format` to make format
+ classes available to :func:`getFormat`.
"""
dir = os.path.dirname(__file__)
for module_file in os.listdir(dir):
@@ -120,7 +115,13 @@ def collect_device_format_classes():
log.debug(format_exc())
def get_device_format_class(fmt_type):
- """ Return an appropriate format class based on fmt_type.
"""
+ """ Return an appropriate format class.
+
+ :param fmt_type: The name of the format type.
+ :type fmt_type: str.
+ :returns: The chosen DeviceFormat class
+ :rtype: class.
+ """
if not device_formats:
collect_device_format_classes()
@@ -141,7 +142,12 @@ def get_device_format_class(fmt_type):
return fmt
class DeviceFormat(object):
- """ Generic device format. """
+ """ Generic device format.
+
+ This represents the absence of recognized formatting. That could mean a
+ device is uninitialized, has had zeros written to it, or contains some
+ valid formatting that this module does not support.
+ """
_type = None
_name = N_("Unknown")
_udevTypes = []
@@ -161,14 +167,21 @@ class DeviceFormat(object):
_ksMountpoint = None
def __init__(self, *args, **kwargs):
- """ Create a DeviceFormat instance.
-
- Keyword Arguments:
-
- device -- path to the underlying device
- uuid -- this format's UUID
- exists -- indicates whether this is an existing format
-
+ """
+ :keyword device: The path to the device node.
+ :type device: str
+ :keyword uuid: the formatting's UUID.
+ :type uuid: str
+ :keyword exists: Whether the formatting exists. (default: False)
+ :raises: ValueError
+
+ .. note::
+
+ The 'device' kwarg is required for existing formats. For non-
+ existent formats, it is only necessary that the :attr:`device`
+ attribute be set before the :meth:`create` method runs. Note
+ that you can specify the device at the last moment by specifying
+ it via the 'device' kwarg to the :meth:`create` method.
"""
self.device = kwargs.get("device")
self.uuid = kwargs.get("uuid")
@@ -298,6 +311,18 @@ class DeviceFormat(object):
return self._majorminor
def create(self, *args, **kwargs):
+ """ Write the formatting to the specified block device.
+
+ :keyword device: path to device node
+ :type device: str.
+ :raises: FormatCreateError
+ :returns: None.
+
+ .. :note::
+
+ If a device node path is passed to this method it will overwrite
+ any previously set value of this instance's "device"
attribute.
+ """
log_method_call(self, device=self.device,
type=self.type, status=self.status)
# allow late specification of device path
@@ -309,6 +334,11 @@ class DeviceFormat(object):
raise FormatCreateError("invalid device specification",
self.device)
def destroy(self, *args, **kwargs):
+ """ Remove the formatting from the associated block device.
+
+ :raises: FormatDestroyError
+ :returns: None.
+ """
log_method_call(self, device=self.device,
type=self.type, status=self.status)
try:
@@ -327,6 +357,18 @@ class DeviceFormat(object):
self.exists = False
def setup(self, *args, **kwargs):
+ """ Activate the formatting.
+
+ :keyword device: device node path
+ :type device: str.
+ :raises: FormatSetupError.
+ :returns: None.
+
+ .. :note::
+
+ If a device node path is passed to this method it will overwrite
+ any previously set value of this instance's "device"
attribute.
+ """
log_method_call(self, device=self.device,
type=self.type, status=self.status)
@@ -345,6 +387,7 @@ class DeviceFormat(object):
raise FormatSetupError("invalid device specification")
def teardown(self, *args, **kwargs):
+ """ Deactivate the formatting. """
log_method_call(self, device=self.device,
type=self.type, status=self.status)
diff --git a/blivet/formats/biosboot.py b/blivet/formats/biosboot.py
index 73b980e..5ed0305 100644
--- a/blivet/formats/biosboot.py
+++ b/blivet/formats/biosboot.py
@@ -39,13 +39,15 @@ class BIOSBoot(DeviceFormat):
_minSize = 0.5 # minimum size in MB
def __init__(self, *args, **kwargs):
- """ Create a BIOSBoot instance.
-
- Keyword Arguments:
+ """
+ :keyword device: path to the block device node
+ :type device: str
+ :keyword exists: whether the formatting exists
+ :type exists: bool
- device -- path to the underlying device
- exists -- indicates whether this is an existing format
+ .. note::
+ The 'device' kwarg is required for existing formats.
"""
DeviceFormat.__init__(self, *args, **kwargs)
diff --git a/blivet/formats/disklabel.py b/blivet/formats/disklabel.py
index bfb707a..323b36b 100644
--- a/blivet/formats/disklabel.py
+++ b/blivet/formats/disklabel.py
@@ -45,18 +45,20 @@ class DiskLabel(DeviceFormat):
_supported = False # is supported
def __init__(self, *args, **kwargs):
- """ Create a DiskLabel instance.
-
- Keyword Arguments:
-
- labelType -- type of disklabel to create
- device -- path to the underlying device
- exists -- indicates whether this is an existing format
-
+ """
+ :keyword device: full path to the block device node (required)
+ :type device: str
+ :keyword labelType: type of disklabel to create
+ :type labelType: str
+ :keyword exists: whether the formatting exists
+ :type exists: bool
"""
log_method_call(self, *args, **kwargs)
DeviceFormat.__init__(self, *args, **kwargs)
+ if not self.device:
+ raise ValueError("DiskLabel requires a valid device path")
+
if not self.exists:
self._labelType = kwargs.get("labelType", "msdos")
else:
@@ -231,25 +233,6 @@ class DiskLabel(DeviceFormat):
""" Device status. """
return False
- def setup(self, *args, **kwargs):
- """ Open, or set up, a device. """
- log_method_call(self, device=self.device,
- type=self.type, status=self.status)
- if not self.exists:
- raise DeviceFormatError("format has not been created")
-
- if self.status:
- return
-
- DeviceFormat.setup(self, *args, **kwargs)
-
- def teardown(self, *args, **kwargs):
- """ Close, or tear down, a device. """
- log_method_call(self, device=self.device,
- type=self.type, status=self.status)
- if not self.exists:
- raise DeviceFormatError("format has not been created")
-
def create(self, *args, **kwargs):
""" Create the device. """
log_method_call(self, device=self.device,
@@ -305,15 +288,23 @@ class DiskLabel(DeviceFormat):
else:
self.updateOrigPartedDisk()
- def addPartition(self, *args, **kwargs):
- partition = kwargs.get("partition", None)
- if not partition:
- partition = args[0]
+ def addPartition(self, partition, constraint=None):
+ """ Add a partition to the disklabel.
+
+ :param partition: partition from which to get geom, type (required)
+ :type partition: parted.Partition.
+ :keyword constraint: constraint to use
+ :type constraint: parted.Constraint.
+
+ .. note::
+
+ This does not add the :class:`parted.Partition` instance you
+ pass in. The geometry and type are taken from that instance and
+ used to create a new :class:`parted.Partition` to add to the
+ disklabel.
+ """
geometry = partition.geometry
- constraint = kwargs.get("constraint", None)
- if not constraint and len(args) > 1:
- constraint = args[1]
- elif not constraint:
+ if not constraint:
constraint = parted.Constraint(exactGeom=geometry)
new_partition = parted.Partition(disk=self.partedDisk,
@@ -323,6 +314,17 @@ class DiskLabel(DeviceFormat):
constraint=constraint)
def removePartition(self, partition):
+ """ Remove a partition from the disklabel.
+
+ :param partition: the partition to remove
+ :type partition: parted.Partition.
+
+ .. note::
+
+ Unlike :meth:`addPartition`, the actual partition instance
+ passed is what will be removed from the disklabel.
+
+ """
self.partedDisk.removePartition(partition)
@property
diff --git a/blivet/formats/dmraid.py b/blivet/formats/dmraid.py
index b42c90a..875a4ce 100644
--- a/blivet/formats/dmraid.py
+++ b/blivet/formats/dmraid.py
@@ -58,15 +58,13 @@ class DMRaidMember(DeviceFormat):
_hidden = True # hide devices with this formatting?
def __init__(self, *args, **kwargs):
- """ Create a DeviceFormat instance.
-
- Keyword Arguments:
-
- device -- path to the underlying device
- uuid -- this format's UUID
- exists -- indicates whether this is an existing format
-
- On initialization this format is like DeviceFormat
+ """
+ :keyword device: path to the underlying device (required)
+ :type device: str
+ :keyword uuid: this format's UUID
+ :type uuid: str
+ :keyword exists: whether this is an existing format
+ :type exists: bool
"""
log_method_call(self, *args, **kwargs)
diff --git a/blivet/formats/fs.py b/blivet/formats/fs.py
index 5a05569..cf54c31 100644
--- a/blivet/formats/fs.py
+++ b/blivet/formats/fs.py
@@ -109,7 +109,7 @@ def fsConfigFromFile(config_file):
fs_configs[fs_attrs['type']] = fs_attrs
class FS(DeviceFormat):
- """ Filesystem class. """
+ """ Filesystem base class. """
_type = "Abstract Filesystem Class" # fs type name
_mountType = None # like _type but for passing to mount
_name = None
@@ -129,18 +129,25 @@ class FS(DeviceFormat):
_fsProfileSpecifier = None # mkfs option specifying fsprofile
def __init__(self, *args, **kwargs):
- """ Create a FS instance.
-
- Keyword Args:
-
- device -- path to the device containing the filesystem
- mountpoint -- the filesystem's mountpoint
- label -- the filesystem label
- uuid -- the filesystem UUID
- mountopts -- mount options for the filesystem
- size -- the filesystem's size in MiB
- exists -- indicates whether this is an existing filesystem
+ """
+ :keyword device: path to the block device node (required for
+ existing filesystems)
+ :keyword mountpoint: the filesystem's planned mountpoint
+ :keyword label: the filesystem label
+ :keyword uuid: the filesystem UUID
+ :keyword mountopts: mount options for the filesystem
+ :type mountopts: str
+ :keyword size: the filesystem's size in MiB
+ :keyword exists: indicates whether this is an existing filesystem
+ :type exists: bool
+ .. note::
+
+ The 'device' kwarg is required for existing formats. For non-
+ existent formats, it is only necessary that the :attr:`device`
+ attribute be set before the :meth:`create` method runs. Note
+ that you can specify the device at the last moment by specifying
+ it via the 'device' kwarg to the :meth:`create` method.
"""
if self.__class__ is FS:
raise TypeError("FS is an abstract class.")
@@ -247,9 +254,10 @@ class FS(DeviceFormat):
return buf
def _getExistingSize(self, info=None):
- """ Determine the size of this filesystem. Filesystem must
- exist. Each filesystem varies, but the general procedure
- is to run the filesystem dump or info utility and read
+ """ Determine the size of this filesystem.
+
+ Filesystem must exist. Each filesystem varies, but the general
+ procedure is to run the filesystem dump or info utility and read
the block size and number of blocks for the filesystem
and compute megabytes from that.
@@ -278,6 +286,11 @@ class FS(DeviceFormat):
are looking for, the command to run and arguments, or
something else. If you catch an exception from this method,
assume the filesystem cannot be resized.
+
+ :keyword info: filesystem info buffer
+ :type info: str (output of :attr:`infofsProg`)
+ :returns: size of existing fs in MiB.
+ :rtype: float.
"""
size = self._size
@@ -356,14 +369,9 @@ class FS(DeviceFormat):
def doFormat(self, *args, **kwargs):
""" Create the filesystem.
- Arguments:
-
- None
-
- Keyword Arguments:
-
- options -- list of options to pass to mkfs
-
+ :keyword options: options to pass to mkfs
+ :type options: list of strings
+ :raises: FormatCreateError, FSError
"""
log_method_call(self, type=self.mountType, device=self.device,
mountpoint=self.mountpoint)
@@ -407,13 +415,10 @@ class FS(DeviceFormat):
return argv
def doResize(self, *args, **kwargs):
- """ Resize this filesystem to new size @newsize.
+ """ Resize this filesystem based on this instance's targetSize
attr.
- Arguments:
-
- None
+ :raises: FSResizeError, FSError
"""
-
if not self.exists:
raise FSResizeError("filesystem does not exist", self.device)
@@ -468,6 +473,10 @@ class FS(DeviceFormat):
return _("Unknown return code: %d.") % (rc,)
def doCheck(self):
+ """ Run a filesystem check.
+
+ :raises: FSError
+ """
if not self.exists:
raise FSError("filesystem has not been created")
@@ -509,7 +518,7 @@ class FS(DeviceFormat):
self._supported = False
return
- # If we successfully loaded a kernel module, for this filesystem, we
+ # If we successfully loaded a kernel module for this filesystem, we
# also need to update the list of supported filesystems.
update_kernel_filesystems()
@@ -518,7 +527,7 @@ class FS(DeviceFormat):
ret = False
if self.status:
- raise RuntimeError("filesystem is already mounted")
+ return True
# create a temp dir
prefix = "%s.%s" % (os.path.basename(self.device), self.type)
@@ -540,15 +549,11 @@ class FS(DeviceFormat):
def mount(self, *args, **kwargs):
""" Mount this filesystem.
- Arguments:
-
- None
-
- Keyword Arguments:
-
- options -- mount options (overrides all other option strings)
- chroot -- prefix to apply to mountpoint
- mountpoint -- mountpoint (overrides self.mountpoint)
+ :keyword options: mount options (overrides all other option strings)
+ :type options: str.
+ :keyword chroot: prefix to apply to mountpoint
+ :keyword mountpoint: mountpoint (overrides self.mountpoint)
+ :raises: FSError
"""
options = kwargs.get("options", "")
chroot = kwargs.get("chroot", "/")
@@ -634,7 +639,11 @@ class FS(DeviceFormat):
return argv
def writeLabel(self, label):
- """ Create a label for this filesystem. """
+ """ Create a label for this filesystem.
+
+ :param label: the label text
+ :raises: FSError
+ """
if not self.exists:
raise FSError("filesystem has not been created")
@@ -773,6 +782,18 @@ class FS(DeviceFormat):
# generically named methods so filesystems and formatted devices
# like swap and LVM physical volumes can have a common API.
def create(self, *args, **kwargs):
+ """ Create the filesystem on the specified block device.
+
+ :keyword device: path to device node
+ :type device: str.
+ :raises: FormatCreateError, FSError
+ :returns: None.
+
+ .. :note::
+
+ If a device node path is passed to this method it will overwrite
+ any previously set value of this instance's "device"
attribute.
+ """
if self.exists:
raise FSError("filesystem already exists")
@@ -784,7 +805,19 @@ class FS(DeviceFormat):
""" Mount the filesystem.
The filesystem will be mounted at the directory indicated by
- self.mountpoint.
+ self.mountpoint unless overridden via the 'mountpoint' kwarg.
+
+ :keyword device: device node path
+ :type device: str.
+ :keyword mountpoint: mountpoint (overrides self.mountpoint)
+ :type mountpoint: str.
+ :raises: FormatSetupError.
+ :returns: None.
+
+ .. :note::
+
+ If a device node path is passed to this method it will overwrite
+ any previously set value of this instance's "device"
attribute.
"""
return self.mount(**kwargs)
@@ -880,7 +913,12 @@ class Ext2FS(FS):
raise FSError("failed to set UUID for %s: %s" % (self.device,
err))
def _getMinSize(self, info=None):
- """ Minimum size for this filesystem in MB. """
+ """ Set the minimum size for this filesystem in MiB.
+
+ :keyword info: filesystem info buffer
+ :type info: str (output of :attr:`infofsProg`)
+ :rtype: None.
+ """
size = self._minSize
blockSize = None
@@ -1050,6 +1088,23 @@ class BTRFS(FS):
pass
def setup(self, *args, **kwargs):
+ """ Mount the filesystem.
+
+ The filesystem will be mounted at the directory indicated by
+ self.mountpoint unless overridden via the 'mountpoint' kwarg.
+
+ :keyword device: device node path
+ :type device: str.
+ :keyword mountpoint: mountpoint (overrides self.mountpoint)
+ :type mountpoint: str.
+ :raises: FormatSetupError.
+ :returns: None.
+
+ .. :note::
+
+ If a device node path is passed to this method it will overwrite
+ any previously set value of this instance's "device"
attribute.
+ """
log_method_call(self, type=self.mountType, device=self.device,
mountpoint=self.mountpoint)
if not self.mountpoint and "mountpoint" not in kwargs:
@@ -1306,7 +1361,12 @@ class NTFS(FS):
return False
def _getMinSize(self, info=None):
- # try to determine the minimum size.
+ """ Set the minimum size for this filesystem in MiB.
+
+ :keyword info: filesystem info buffer
+ :type info: str (output of :attr:`infofsProg`)
+ :rtype: None
+ """
size = self._minSize
if self.exists and os.path.exists(self.device) and \
util.find_program_in_path(self.resizefsProg):
diff --git a/blivet/formats/luks.py b/blivet/formats/luks.py
index fac1bf8..685725f 100644
--- a/blivet/formats/luks.py
+++ b/blivet/formats/luks.py
@@ -41,7 +41,7 @@ log = logging.getLogger("blivet")
class LUKS(DeviceFormat):
- """ A LUKS device. """
+ """ LUKS """
_type = "luks"
_name = N_("LUKS")
_lockedName = N_("Encrypted")
@@ -52,20 +52,32 @@ class LUKS(DeviceFormat):
_packages = ["cryptsetup"] # required packages
def __init__(self, *args, **kwargs):
- """ Create a LUKS instance.
-
- Keyword Arguments:
-
- device -- the path to the underlying device
- name -- the name of the mapped device
- uuid -- this device's UUID
- passphrase -- device passphrase (string)
- key_file -- path to a file containing a key (string)
- cipher -- cipher mode string
- key_size -- key size in bits
- exists -- indicates whether this is an existing format
- escrow_cert -- certificate to use for key escrow
- add_backup_passphrase -- generate a backup passphrase?
+ """
+ :keyword device: the path to the underlying device
+ :keyword uuid: the LUKS UUID
+ :keyword exists: indicates whether this is an existing format
+ :type exists: bool
+ :keyword name: the name of the mapped device
+ :keyword passphrase: device passphrase
+ :type passphrase: str
+ :keyword key_file: path to a file containing a key
+ :type key_file: str
+ :keyword cipher: cipher mode
+ :type cipher: str
+ :keyword key_size: key size in bits
+ :type key_size: int
+ :keyword escrow_cert: certificate (contents) to use for key escrow
+ :type escrow_cert: str
+ :keyword add_backup_passphrase: generate a backup passphrase?
+ :type add_backup_passphrase: bool.
+
+ .. note::
+
+ The 'device' kwarg is required for existing formats. For non-
+ existent formats, it is only necessary that the :attr:`device`
+ attribute be set before the :meth:`create` method runs. Note
+ that you can specify the device at the last moment by specifying
+ it via the 'device' kwarg to the :meth:`create` method.
"""
log_method_call(self, *args, **kwargs)
DeviceFormat.__init__(self, *args, **kwargs)
@@ -154,7 +166,18 @@ class LUKS(DeviceFormat):
raise NotImplementedError("probe method not defined for LUKS")
def setup(self, *args, **kwargs):
- """ Open, or set up, the format. """
+ """ Open the encrypted block device.
+
+ :keyword device: device node path
+ :type device: str.
+ :raises: FormatSetupError.
+ :returns: None.
+
+ .. :note::
+
+ If a device node path is passed to this method it will overwrite
+ any previously set value of this instance's "device"
attribute.
+ """
log_method_call(self, device=self.device, mapName=self.mapName,
type=self.type, status=self.status)
if not self.configured:
@@ -180,7 +203,18 @@ class LUKS(DeviceFormat):
crypto.luks_close(self.mapName)
def create(self, *args, **kwargs):
- """ Create the format. """
+ """ Write the formatting to the specified block device.
+
+ :keyword device: path to device node
+ :type device: str.
+ :raises: FormatCreateError
+ :returns: None.
+
+ .. :note::
+
+ If a device node path is passed to this method it will overwrite
+ any previously set value of this instance's "device"
attribute.
+ """
log_method_call(self, device=self.device,
type=self.type, status=self.status)
if not self.hasKey:
@@ -204,7 +238,11 @@ class LUKS(DeviceFormat):
self.notifyKernel()
def destroy(self, *args, **kwargs):
- """ Create the format. """
+ """ Remove the formatting from the associated block device.
+
+ :raises: FormatDestroyError
+ :returns: None.
+ """
log_method_call(self, device=self.device,
type=self.type, status=self.status)
self.teardown()
diff --git a/blivet/formats/lvmpv.py b/blivet/formats/lvmpv.py
index 554f238..034825e 100644
--- a/blivet/formats/lvmpv.py
+++ b/blivet/formats/lvmpv.py
@@ -47,17 +47,23 @@ class LVMPhysicalVolume(DeviceFormat):
_ksMountpoint = "pv."
def __init__(self, *args, **kwargs):
- """ Create an LVMPhysicalVolume instance.
-
- Keyword Arguments:
-
- device -- path to the underlying device
- uuid -- this PV's uuid (not the VG uuid)
- vgName -- the name of the VG this PV belongs to
- vgUuid -- the UUID of the VG this PV belongs to
- peStart -- offset of first physical extent
- exists -- indicates whether this is an existing format
-
+ """
+ :keyword device: path to the block device node
+ :keyword uuid: this PV's uuid (not the VG uuid)
+ :keyword exists: indicates whether this is an existing format
+ :type exists: bool
+ :keyword vgName: the name of the VG this PV belongs to
+ :keyword vgUuid: the UUID of the VG this PV belongs to
+ :keyword peStart: offset of first physical extent
+ :type peStart: float
+
+ .. note::
+
+ The 'device' kwarg is required for existing formats. For non-
+ existent formats, it is only necessary that the :attr:`device`
+ attribute be set before the :meth:`create` method runs. Note
+ that you can specify the device at the last moment by specifying
+ it via the 'device' kwarg to the :meth:`create` method.
"""
log_method_call(self, *args, **kwargs)
DeviceFormat.__init__(self, *args, **kwargs)
@@ -96,7 +102,18 @@ class LVMPhysicalVolume(DeviceFormat):
#self.vgUuid = info['vg_uuid']
def create(self, *args, **kwargs):
- """ Create the format. """
+ """ Write the formatting to the specified block device.
+
+ :keyword device: path to device node
+ :type device: str
+ :raises: FormatCreateError
+ :returns: None.
+
+ .. :note::
+
+ If a device node path is passed to this method it will overwrite
+ any previously set value of this instance's "device"
attribute.
+ """
log_method_call(self, device=self.device,
type=self.type, status=self.status)
@@ -119,7 +136,11 @@ class LVMPhysicalVolume(DeviceFormat):
self.notifyKernel()
def destroy(self, *args, **kwargs):
- """ Destroy the format. """
+ """ Remove the formatting from the associated block device.
+
+ :raises: FormatDestroyError
+ :returns: None.
+ """
log_method_call(self, device=self.device,
type=self.type, status=self.status)
if not self.exists:
diff --git a/blivet/formats/mdraid.py b/blivet/formats/mdraid.py
index 7fbf6bb..8050b24 100644
--- a/blivet/formats/mdraid.py
+++ b/blivet/formats/mdraid.py
@@ -47,15 +47,16 @@ class MDRaidMember(DeviceFormat):
_ksMountpoint = "raid."
def __init__(self, *args, **kwargs):
- """ Create a MDRaidMember instance.
-
- Keyword Arguments:
+ """
+ :keyword device: path to block device node
+ :keyword uuid: this member device's uuid
+ :keyword exists: whether this is an existing format
+ :type exists: bool
+ :keyword mdUuid: the uuid of the array this device belongs to
- device -- path to underlying device
- uuid -- this member device's uuid
- mdUuid -- the uuid of the array this device belongs to
- exists -- indicates whether this is an existing format
+ .. note::
+ The 'device' kwarg is required for existing formats.
"""
log_method_call(self, *args, **kwargs)
DeviceFormat.__init__(self, *args, **kwargs)
@@ -91,6 +92,11 @@ class MDRaidMember(DeviceFormat):
self.raidMinor = info['mdMinor']
def destroy(self, *args, **kwargs):
+ """ Remove the formatting from the associated block device.
+
+ :raises: FormatDestroyError
+ :returns: None.
+ """
if not self.exists:
raise MDMemberError("format does not exist")
diff --git a/blivet/formats/multipath.py b/blivet/formats/multipath.py
index 67c32e4..b7e7076 100644
--- a/blivet/formats/multipath.py
+++ b/blivet/formats/multipath.py
@@ -47,16 +47,11 @@ class MultipathMember(DeviceFormat):
_hidden = True # hide devices with this formatting?
def __init__(self, *args, **kwargs):
- """ Create a DeviceFormat instance.
-
- Keyword Arguments:
-
- device -- path to the underlying device
- uuid -- this format's UUID
- exists -- indicates whether this is an existing format
-
- On initialization this format is like DeviceFormat
-
+ """
+ :keyword device: path to the underlying device (required)
+ :keyword uuid: this format's UUID
+ :keyword exists: whether this is an existing format
+ :type exists: bool
"""
log_method_call(self, *args, **kwargs)
DeviceFormat.__init__(self, *args, **kwargs)
diff --git a/blivet/formats/prepboot.py b/blivet/formats/prepboot.py
index 4d20f0f..605486f 100644
--- a/blivet/formats/prepboot.py
+++ b/blivet/formats/prepboot.py
@@ -41,19 +41,36 @@ class PPCPRePBoot(DeviceFormat):
_minSize = 4 # minimum size in MB
def __init__(self, *args, **kwargs):
- """ Create a PRePBoot instance.
-
- Keyword Arguments:
+ """
+ :keyword device: path to block device node
+ :keyword exists: whether this is an existing format
+ :type exists: bool
- device -- path to the underlying device
- exists -- indicates whether this is an existing format
+ .. note::
+ The 'device' kwarg is required for existing formats. For non-
+ existent formats, it is only necessary that the :attr:`device`
+ attribute be set before the :meth:`create` method runs. Note
+ that you can specify the device at the last moment by specifying
+ it via the 'device' kwarg to the :meth:`create` method.
"""
DeviceFormat.__init__(self, *args, **kwargs)
def create(self, *args, **kwargs):
+ """ Write the formatting to the specified block device.
+
+ :keyword device: path to device node
+ :type device: str
+ :raises: FormatCreateError
+ :returns: None.
+
+ .. :note::
+
+ If a device node path is passed to this method it will overwrite
+ any previously set value of this instance's "device"
attribute.
+ """
if self.exists:
- raise FSError("PReP Boot format already exists")
+ raise FormatCreateError("PReP Boot format already exists")
DeviceFormat.create(self, *args, **kwargs)
diff --git a/blivet/formats/swap.py b/blivet/formats/swap.py
index 72ca84f..f0c1fd4 100644
--- a/blivet/formats/swap.py
+++ b/blivet/formats/swap.py
@@ -46,16 +46,22 @@ class SwapSpace(DeviceFormat):
_maxSize = 128 * 1024
def __init__(self, *args, **kwargs):
- """ Create a SwapSpace instance.
-
- Keyword Arguments:
-
- device -- path to the underlying device
- uuid -- this swap space's uuid
- label -- this swap space's label
- priority -- this swap space's priority
- exists -- indicates whether this is an existing format
-
+ """
+ :keyword device: path to the block device node
+ :keyword uuid: this swap space's uuid
+ :keyword exists: whether this is an existing format
+ :type exists: bool
+ :keyword label: this swap space's label
+ :keyword priority: this swap space's priority
+ :type priority: int
+
+ .. note::
+
+ The 'device' kwarg is required for existing formats. For non-
+ existent formats, it is only necessary that the 'device'
+ attribute be set before the :meth:`~.SwapSpace.create` method
+ runs. You can specify the device at the last moment by via the
+ 'device' kwarg to the :meth:`~.SwapSpace.create` method.
"""
log_method_call(self, *args, **kwargs)
DeviceFormat.__init__(self, *args, **kwargs)
@@ -120,7 +126,18 @@ class SwapSpace(DeviceFormat):
return self.exists and swap.swapstatus(self.device)
def setup(self, *args, **kwargs):
- """ Open, or set up, a device. """
+ """ Activate the formatting.
+
+ :keyword device: device node path
+ :type device: str.
+ :raises: FormatSetupError.
+ :returns: None.
+
+ .. :note::
+
+ If a device node path is passed to this method it will overwrite
+ any previously set value of this instance's "device"
attribute.
+ """
log_method_call(self, device=self.device,
type=self.type, status=self.status)
if not self.exists:
@@ -143,18 +160,23 @@ class SwapSpace(DeviceFormat):
swap.swapoff(self.device)
def create(self, *args, **kwargs):
- """ Create the device. """
+ """ Write the formatting to the specified block device.
+
+ :keyword device: path to device node
+ :type device: str.
+ :raises: FormatCreateError
+ :returns: None.
+
+ .. :note::
+
+ If a device node path is passed to this method it will overwrite
+ any previously set value of this instance's "device"
attribute.
+ """
log_method_call(self, device=self.device,
type=self.type, status=self.status)
- force = kwargs.get("force")
- if not force and self.exists:
+ if self.exists:
raise SwapSpaceError("format already exists")
- if force:
- self.teardown()
- elif self.status:
- raise SwapSpaceError("device exists and is active")
-
try:
DeviceFormat.create(self, *args, **kwargs)
swap.mkswap(self.device, label=self.label)
diff --git a/blivet/iscsi.py b/blivet/iscsi.py
index 45a0ac8..f30a861 100644
--- a/blivet/iscsi.py
+++ b/blivet/iscsi.py
@@ -405,7 +405,4 @@ class iscsi(object):
return nodeDisks
-# Create iscsi singleton
-iscsi = iscsi()
-
# vim:tw=78:ts=4:et:sw=4
diff --git a/blivet/partitioning.py b/blivet/partitioning.py
index 4216be2..c88c90d 100644
--- a/blivet/partitioning.py
+++ b/blivet/partitioning.py
@@ -39,7 +39,17 @@ import logging
log = logging.getLogger("blivet")
def _getCandidateDisks(storage):
- """ Return a list of disks with space for a default-sized partition.
"""
+ """ Return a list of disks to be used for autopart.
+
+ Disks must be partitioned and have a single free region large enough
+ for a default-sized (500MB) partition. They must also be in
+ :attr:`StorageDiscoveryConfig.clearPartDisks` if it is non-empty.
+
+ :param storage: a Blivet instance
+ :type storage: :class:`~.Blivet`
+ :returns: a list of partitioned disks with at least 500MB of free space
+ :rtype: list of :class:`~.devices.StorageDevice`
+ """
disks = []
for disk in storage.partitioned:
if storage.config.clearPartDisks and \
@@ -61,7 +71,18 @@ def _getCandidateDisks(storage):
return disks
def _scheduleImplicitPartitions(storage, disks):
- """ Schedule creation of a lvm/btrfs partition on each disk in disks.
"""
+ """ Schedule creation of a lvm/btrfs member partitions for autopart.
+
+ We create one such partition on each disk. They are not allocated until
+ later (in :func:`doPartitioning`).
+
+ :param storage: a :class:`~.Blivet` instance
+ :type storage: :class:`~.Blivet`
+ :param disks: list of partitioned disks with free space
+ :type disks: list of :class:`~.devices.StorageDevice`
+ :returns: list of newly created (unallocated) partitions
+ :rtype: list of :class:`~.devices.PartitionDevice`
+ """
# create a separate pv or btrfs partition for each disk with free space
devs = []
@@ -92,7 +113,17 @@ def _scheduleImplicitPartitions(storage, disks):
return devs
def _schedulePartitions(storage, disks):
- """ Schedule creation of autopart partitions. """
+ """ Schedule creation of autopart partitions.
+
+ This only schedules the requests for actual partitions.
+
+ :param storage: a :class:`~.Blivet` instance
+ :type storage: :class:`~.Blivet`
+ :param disks: list of partitioned disks with free space
+ :type disks: list of :class:`~.devices.StorageDevice`
+ :returns: None
+ :rtype: None
+ """
# basis for requests with requiredSpace is the sum of the sizes of the
# two largest free regions
all_free = getFreeRegions(disks)
@@ -197,7 +228,23 @@ def _schedulePartitions(storage, disks):
return
def _scheduleVolumes(storage, devs):
- """ Schedule creation of autopart lvm/btrfs volumes.
"""
+ """ Schedule creation of autopart lvm/btrfs volumes.
+
+ Schedules encryption of member devices if requested, schedules creation
+ of the container (:class:`~.devices.LVMVolumeGroupDevice` or
+ :class:`~.devices.BTRFSVolumeDevice`) then schedules creation of the
+ autopart volume requests.
+
+ :param storage: a :class:`~.Blivet` instance
+ :type storage: :class:`~.Blivet`
+ :param devs: list of member partitions
+ :type devs: list of :class:`~.devices.PartitionDevice`
+ :returns: None
+ :rtype: None
+
+ If an appropriate bootloader stage1 device exists on the boot drive, any
+ autopart request to create another one will be skipped/discarded.
+ """
if not devs:
return
@@ -283,6 +330,24 @@ def _scheduleVolumes(storage, devs):
storage.createDevice(dev)
def doAutoPartition(storage, data):
+ """ Perform automatic partitioning.
+
+ :param storage: a :class:`~.Blivet` instance
+ :type storage: :class:`~.Blivet`
+ :param data: kickstart data
+ :type data: :class:`pykickstart.BaseHandler`
+
+ :attr:`Blivet.doAutoPart` controls whether this method creates the
+ automatic partitioning layout. :attr:`Blivet.autoPartType` controls
+ which variant of autopart used. It uses one of the pykickstart
+ AUTOPART_TYPE_* constants. The set of eligible disks is defined in
+ :attr:`StorageDiscoveryConfig.clearPartDisks`.
+
+ .. note::
+
+ Clearing of partitions is handled separately, in
+ :meth:`~.Blivet.clearPartitions`.
+ """
log.debug("doAutoPart: %s" % storage.doAutoPart)
log.debug("encryptedAutoPart: %s" % storage.encryptedAutoPart)
log.debug("autoPartType: %s" % storage.autoPartType)
@@ -342,6 +407,13 @@ def partitionCompare(part1, part2):
< 1 => x < y
0 => x == y
1 => x > y
+
+ :param part1: the first partition
+ :type part1: :class:`devices.PartitionDevice`
+ :param part2: the other partition
+ :type part2: :class:`devices.PartitionDevice`
+ :return: see above
+ :rtype: int
"""
ret = 0
@@ -401,7 +473,7 @@ def partitionCompare(part1, part2):
return ret
def getNextPartitionType(disk, no_primary=None):
- """ Find the type of partition to create next on a disk.
+ """ Return the type of partition to create next on a disk.
Return a parted partition type value representing the type of the
next partition we will create on this disk.
@@ -413,15 +485,11 @@ def getNextPartitionType(disk, no_primary=None):
recommend creating a primary partition. This can be overridden
with the keyword argument no_primary.
- Arguments:
-
- disk -- a parted.Disk instance representing the disk
-
- Keyword arguments:
-
- no_primary -- given a choice between primary and logical
- partitions, prefer logical
-
+ :param disk: the disk from which a partition may be allocated
+ :type disk: :class:`parted.Disk`
+ :keyword no_primary: refuse to return :const:`parted.PARTITION_NORMAL`
+ :returns: the chosen partition type
+ :rtype: a parted PARTITION_* constant
"""
part_type = None
extended = disk.getExtendedPartition()
@@ -474,20 +542,20 @@ def getBestFreeSpaceRegion(disk, part_type, req_size, start=None,
free region with which to compare the best from this disk. The
overall best region is returned.
- Arguments:
-
- disk -- the disk (a parted.Disk instance)
- part_type -- the type of partition we want to allocate
- (one of parted's partition type constants)
- req_size -- the requested size of the partition (in MB)
-
- Keyword arguments:
-
- boot -- indicates whether this will be a bootable partition
- (boolean)
- best_free -- current best free region for this partition
- grow -- indicates whether this is a growable request
- start -- requested start sector for the partition
+ :param disk: the disk
+ :type disk: :class:`parted.Disk`
+ :param part_type: the type of partition we want to allocate
+ :type part_type: one of parted's PARTITION_* constants
+ :param req_size: the requested size of the partition in MB
+ :type req_size: int or float
+ :keyword start: requested start sector for the partition
+ :type start: int
+ :keyword boot: whether this will be a bootable partition
+ :type boot: bool
+ :keyword best_free: current best free region for this partition
+ :type best_free: :class:`parted.Geometry`
+ :keyword grow: indicates whether this is a growable request
+ :type grow: bool
"""
log.debug("getBestFreeSpaceRegion: disk=%s part_type=%d req_size=%dMB "
@@ -550,31 +618,38 @@ def getBestFreeSpaceRegion(disk, part_type, req_size, start=None,
def sectorsToSize(sectors, sectorSize):
""" Convert length in sectors to size in MB.
- Arguments:
-
- sectors - sector count
- sectorSize - sector size for the device, in bytes
+ :param sectors: sector count
+ :type sectors: int
+ :param sectorSize: sector size
+ :type sectorSize: int
+ :returns: the size
+ :rtype: float
"""
return (sectors * sectorSize) / (1024.0 * 1024.0)
def sizeToSectors(size, sectorSize):
""" Convert size in MB to length in sectors.
- Arguments:
-
- size - size in MB
- sectorSize - sector size for the device, in bytes
+ :param size: size in MB
+ :type size: int or float
+ :param sectorSize: sector size
+ :type sectorSize: int
+ :returns: sector count
+ :rtype: int
"""
return (size * 1024.0 * 1024.0) / sectorSize
def removeNewPartitions(disks, partitions):
- """ Remove newly added input partitions from input disks.
-
- Arguments:
+ """ Remove newly added partitions from disks.
- disks -- list of StorageDevice instances with DiskLabel format
- partitions -- list of PartitionDevice instances
+ Remove all non-existent partitions from the disks in blivet's model.
+ :param: disks: list of partitioned disks
+ :type disks: list of :class:`~.devices.StorageDevice`
+ :param partitions: list of partitions
+ :type partitions: list of :class:`~.devices.PartitionDevice`
+ :returns: None
+ :rtype: NoneType
"""
log.debug("removing all non-preexisting partitions %s from disk(s) %s"
% (["%s(id %d)" % (p.name, p.id) for p in partitions
@@ -605,18 +680,28 @@ def removeNewPartitions(disks, partitions):
disk.format.partedDisk.removePartition(extended)
def addPartition(disklabel, free, part_type, size, start=None, end=None):
- """ Return new partition after adding it to the specified disk.
-
- Arguments:
-
- disklabel -- disklabel instance to add partition to
- free -- where to add the partition (parted.Geometry instance)
- part_type -- partition type (parted.PARTITION_* constant)
- size -- size (in MB) of the new partition
-
- The new partition will be aligned unless start/end sectors are provided.
-
- Return value is a parted.Partition instance.
+ """ Add a new partition to a disk.
+
+ :param disklabel: the disklabel to add the partition to
+ :type disklabel: :class:`~.formats.DiskLabel`
+ :param free: the free region in which to place the new partition
+ :type free: :class:`parted.Geometry`
+ :param part_type: the partition type
+ :type part_type: a parted.PARTITION_* constant
+ :param size: size of the new partition in MB
+ :type size: int or float
+ :keyword start: starting sector for the partition
+ :type start: int
+ :keyword end: ending sector for the partition
+ :type end: int
+ :raises: :class:`~.errors.PartitioningError`
+ :returns: the newly added partitions
+ :rtype: :class:`parted.Partition`
+
+ .. note::
+
+ The new partition will be aligned using the kernel-provided optimal
+ alignment unless a start sector is provided.
"""
if start is not None:
@@ -673,12 +758,10 @@ def addPartition(disklabel, free, part_type, size, start=None,
end=None):
def getFreeRegions(disks):
""" Return a list of free regions on the specified disks.
- Arguments:
-
- disks -- list of parted.Disk instances
-
- Return value is a list of unaligned parted.Geometry instances.
-
+ :param disks: list of disks
+ :type disks: list of :class:`~.devices.Disks`
+ :returns: list of free regions
+ :rtype: list of :class:`parted.Geometry`
"""
free = []
for disk in disks:
@@ -689,6 +772,15 @@ def getFreeRegions(disks):
return free
def updateExtendedPartitions(storage, disks):
+ """ Reconcile extended partition changes with the DeviceTree.
+
+ :param storage: the Blivet instance
+ :type storage: :class:`~.Blivet`
+ :param disks: list of disks
+ :type disks: list of :class:`~.devices.StorageDevice`
+ :returns: :const:`None`
+ :rtype: NoneType
+ """
# XXX hack -- if we created any extended partitions we need to add
# them to the tree now
for disk in disks:
@@ -742,14 +834,10 @@ def doPartitioning(storage):
appropriate parted.Partition instance from their containing
disk. All req_xxxx attributes must be unchanged.
- Arguments:
-
- storage - Main anaconda Storage instance
-
- Keyword/Optional Arguments:
-
- None
-
+ :param storage: Blivet instance
+ :type storage: :class:`~.Blivet`
+ :raises: :class:`~.errors.PartitioningError`
+ :returns: :const:`None`
"""
disks = storage.partitioned
for disk in disks:
@@ -824,16 +912,26 @@ def doPartitioning(storage):
def allocatePartitions(storage, disks, partitions, freespace):
""" Allocate partitions based on requested features.
+ :param storage: a Blivet instance
+ :type storage: :class:`~.Blivet`
+ :param disks: list of usable disks
+ :type disks: list of :class:`~.devices.StorageDevice`
+ :param partitions: list of partitions
+ :type partitions: list of :class:`~.devices.PartitionDevice`
+ :param freespace: list of free regions on disks
+ :type freespace: list of :class:`parted.Geometry`
+ :raises: :class:`~.errors.PartitioningError`
+ :returns: :const:`None`
+
Non-existing partitions are sorted according to their requested
attributes, and then allocated.
The basic approach to sorting is that the more specifically-
defined a request is, the earlier it will be allocated. See
- the function partitionCompare for details on the sorting
- criteria.
+ :func:`partitionCompare` for details of the sorting criteria.
- The PartitionDevice instances will have their name and parents
- attributes set once they have been allocated.
+ The :class:`~.devices.PartitionDevice` instances will have their name
+ and parents attributes set once they have been allocated.
"""
log.debug("allocatePartitions: disks=%s ; partitions=%s" %
([d.name for d in disks],
@@ -1114,10 +1212,9 @@ class Request(object):
partitions.
"""
def __init__(self, device):
- """ Create a Request instance.
-
- Arguments:
-
+ """
+ :param device: the device being requested
+ :type device: :class:`~.devices.StorageDevice`
"""
self.device = device
self.growth = 0 # growth in sectors
@@ -1150,12 +1247,9 @@ class Request(object):
class PartitionRequest(Request):
def __init__(self, partition):
- """ Create a PartitionRequest instance.
-
- Arguments:
-
- partition -- a PartitionDevice instance
-
+ """
+ :param partition: the partition being requested
+ :type partition: :class:`~.devices.PartitionDevice`
"""
super(PartitionRequest, self).__init__(partition)
self.base = partition.partedPartition.geometry.length # base sectors
@@ -1178,12 +1272,9 @@ class PartitionRequest(Request):
class LVRequest(Request):
def __init__(self, lv):
- """ Create a LVRequest instance.
-
- Arguments:
-
- lv -- an LVMLogicalVolumeDevice instance
-
+ """
+ :param lv: the logical volume being requested
+ :type lv: :class:`~.devices.LVMLogicalVolumeDevice`
"""
super(LVRequest, self).__init__(lv)
@@ -1207,17 +1298,11 @@ class LVRequest(Request):
class Chunk(object):
""" A free region from which devices will be allocated
"""
def __init__(self, length, requests=None):
- """ Create a Chunk instance.
-
- Arguments:
-
- length -- the length of the chunk in allocation units
-
-
- Keyword Arguments:
-
- requests -- list of Request instances allocated from this chunk
-
+ """
+ :param length: the length of the chunk (units vary with subclass)
+ :type length: int
+ :keyword requests: list of requests to add
+ :type requests: list of :class:`Request`
"""
if not hasattr(self, "path"):
self.path = None
@@ -1247,7 +1332,11 @@ class Chunk(object):
return s
def addRequest(self, req):
- """ Add a Request to this chunk. """
+ """ Add a request to this chunk.
+
+ :param req: the request to add
+ :type req: :class:`Request`
+ """
log.debug("adding request %d to chunk %s" % (req.device.id, self))
self.requests.append(req)
@@ -1257,7 +1346,15 @@ class Chunk(object):
self.base += req.base
def reclaim(self, request, amount):
- """ Reclaim units from a request and return them to the pool.
"""
+ """ Reclaim units from a request and return them to the pool.
+
+ :param request: the request to reclaim units from
+ :type request: :class:`Request`
+ :param amount: number of units to reclaim from the request
+ :type amount: int
+ :raises: ValueError
+ :returns: None
+ """
log.debug("reclaim: %s %d (%d MB)" % (request, amount,
self.lengthToSize(amount)))
if request.growth < amount:
log.error("tried to reclaim %d from request with %d of growth"
@@ -1305,7 +1402,15 @@ class Chunk(object):
return size
def trimOverGrownRequest(self, req, base=None):
- """ Enforce max growth and return extra units to the pool.
"""
+ """ Enforce max growth and return extra units to the pool.
+
+ :param req: the request to trim
+ :type req: :class:`Request`
+ :keyword base: base unit count to adjust if req is done growing
+ :type base: int
+ :returns: the new base or None if no base was given
+ :rtype: int or None
+ """
max_growth = self.maxGrowth(req)
if max_growth and req.growth >= max_growth:
if req.growth > max_growth:
@@ -1330,7 +1435,19 @@ class Chunk(object):
pass
def growRequests(self, uniform=False):
- """ Calculate growth amounts for requests in this chunk.
"""
+ """ Calculate growth amounts for requests in this chunk.
+
+ :keyword uniform: grow requests uniformly instead of proportionally
+ :type uniform: bool
+
+ The default mode of growth is as follows: given a total number of
+ available units, requests receive an allotment proportional to their
+ base sizes. That means a request with base size 1000 will grow four
+ times as fast as a request with base size 250.
+
+ Under uniform growth, all requests receive an equal portion of the
+ free units.
+ """
log.debug("Chunk.growRequests: %r" % self)
self.sortRequests()
@@ -1404,17 +1521,11 @@ class Chunk(object):
class DiskChunk(Chunk):
""" A free region on disk from which partitions will be allocated
"""
def __init__(self, geometry, requests=None):
- """ Create a Chunk instance.
-
- Arguments:
-
- geometry -- parted.Geometry instance describing the free space
-
-
- Keyword Arguments:
-
- requests -- list of Request instances allocated from this chunk
-
+ """
+ :param geometry: the free region this chunk represents
+ :type geometry: :class:`parted.Geometry`
+ :keyword requests: list of requests to add initially
+ :type requests: list of :class:`PartitionRequest`
Note: We will limit partition growth based on disklabel
limitations for partition end sector, so a 10TB disk with an
@@ -1440,7 +1551,11 @@ class DiskChunk(Chunk):
return s
def addRequest(self, req):
- """ Add a Request to this chunk. """
+ """ Add a request to this chunk.
+
+ :param req: the request to add
+ :type req: :class:`PartitionRequest`
+ """
if not isinstance(req, PartitionRequest):
raise ValueError(_("DiskChunk requests must be of type "
"PartitionRequest"))
@@ -1467,6 +1582,11 @@ class DiskChunk(Chunk):
super(DiskChunk, self).addRequest(req)
def maxGrowth(self, req):
+ """ Return the maximum possible growth for a request.
+
+ :param req: the request
+ :type req: :class:`PartitionRequest`
+ """
req_end = req.device.partedPartition.geometry.end
req_start = req.device.partedPartition.geometry.start
@@ -1515,17 +1635,11 @@ class DiskChunk(Chunk):
class VGChunk(Chunk):
""" A free region in an LVM VG from which LVs will be allocated
"""
def __init__(self, vg, requests=None):
- """ Create a VGChunk instance.
-
- Arguments:
-
- vg -- an LVMVolumeGroupDevice within which this chunk resides
-
-
- Keyword Arguments:
-
- requests -- list of Request instances allocated from this chunk
-
+ """
+ :param vg: the volume group whose free space this chunk represents
+ :type vg: :class:`~.devices.LVMVolumeGroupDevice`
+ :keyword requests: list of requests to add initially
+ :type requests: list of :class:`LVRequest`
"""
self.vg = vg
self.path = vg.path
@@ -1533,7 +1647,11 @@ class VGChunk(Chunk):
super(VGChunk, self).__init__(usable_extents, requests=requests)
def addRequest(self, req):
- """ Add a Request to this chunk. """
+ """ Add a request to this chunk.
+
+ :param req: the request to add
+ :type req: :class:`LVRequest`
+ """
if not isinstance(req, LVRequest):
raise ValueError(_("VGChunk requests must be of type "
"LVRequest"))
@@ -1550,7 +1668,20 @@ class VGChunk(Chunk):
# sort the partitions by start sector
self.requests.sort(key=lambda r: r.device, cmp=lvCompare)
- def growRequests(self):
+ def growRequests(self, uniform=False):
+ """ Calculate growth amounts for requests in this chunk.
+
+ :keyword uniform: grow requests uniformly instead of proportionally
+ :type uniform: bool
+
+ The default mode of growth is as follows: given a total number of
+ available units, requests receive an allotment proportional to their
+ base sizes. That means a request with base size 1000 will grow four
+ times as fast as a request with base size 250.
+
+ Under uniform growth, all requests receive an equal portion of the
+ free units.
+ """
self.sortRequests()
# grow the percentage-based requests
@@ -1578,23 +1709,17 @@ class VGChunk(Chunk):
self.base -= req.base
req.done = True
- super(VGChunk, self).growRequests()
+ super(VGChunk, self).growRequests(uniform=uniform)
class ThinPoolChunk(VGChunk):
""" A free region in an LVM thin pool from which LVs will be allocated
"""
def __init__(self, pool, requests=None):
- """ Create a ThinPoolChunk instance.
-
- Arguments:
-
- pool -- an LVMThinPoolDevice within which this chunk resides
-
-
- Keyword Arguments:
-
- requests -- list of Request instances allocated from this chunk
-
+ """
+ :param pool: the thin pool whose free space this chunk represents
+ :type pool: :class:`~.devices.LVMThinPoolDevice`
+ :keyword requests: list of requests to add initially
+ :type requests: list of :class:`LVRequest`
"""
self.vg = pool.vg # only used for align, &c
self.path = pool.path
@@ -1605,14 +1730,16 @@ class ThinPoolChunk(VGChunk):
def getDiskChunks(disk, partitions, free):
""" Return a list of Chunk instances representing a disk.
- Arguments:
-
- disk -- a StorageDevice with a DiskLabel format
- partitions -- list of PartitionDevice instances
- free -- list of parted.Geometry instances representing free space
+ :param disk: the disk
+ :type disk: :class:`~.devices.StorageDevice`
+ :param partitions: list of partitions
+ :type partitions: list of :class:`~.devices.PartitionDevice`
+ :param free: list of free regions
+ :type free: list of :class:`parted.Geometry`
+ :returns: list of chunks representing the disk
+ :rtype: list of :class:`DiskChunk`
Partitions and free regions not on the specified disk are ignored.
-
"""
# list of all new partitions on this disk
disk_parts = [p for p in partitions if p.disk == disk and not p.exists]
@@ -1641,6 +1768,12 @@ class TotalSizeSet(object):
size has been achieved.
"""
def __init__(self, devices, size):
+ """
+ :param devices: the set of devices
+ :type devices: list of :class:`~.devices.PartitionDevice`
+ :param size: the target combined size in MB
+ :type size: int or float
+ """
self.devices = []
for device in devices:
if isinstance(device, LUKSDevice):
@@ -1674,6 +1807,16 @@ class TotalSizeSet(object):
class SameSizeSet(object):
""" Set of device requests with a common target size.
"""
def __init__(self, devices, size, grow=False, max_size=None):
+ """
+ :param devices: the set of devices
+ :type devices: list of :class:`~.devices.PartitionDevice`
+ :param size: target size for each device/request in MB
+ :type size: int or float
+ :keyword grow: whether the devices can be grown
+ :type grow: bool
+ :keyword max_size: the maximum size for growable devices in MB
+ :type max_size: int or float
+ """
self.devices = []
for device in devices:
if isinstance(device, LUKSDevice):
@@ -1784,11 +1927,15 @@ def growPartitions(disks, partitions, free, size_sets=None):
the ratio of that partition's base size to the sum of the base sizes
of all growable partitions allocated from the chunk.
- Arguments:
-
- disks -- a list of all usable disks (DiskDevice instances)
- partitions -- a list of all partitions (PartitionDevice instances)
- free -- a list of all free regions (parted.Geometry instances)
+ :param disks: all usable disks
+ :type disks: list of :class:`~.devices.StorageDevice`
+ :param partitions: all partitions
+ :type partitions: list of :class:`~.devices.PartitionDevice`
+ :param free: all free regions on disks
+ :type free: list of :class:`parted.Geometry`
+ :keyword size_sets: list of size-related partition sets
+ :type size_sets: list of :class:`TotalSizeSet` or :class:`SameSizeSet`
+ :returns: :const:`None`
"""
log.debug("growPartitions: disks=%s, partitions=%s" %
([d.name for d in disks],
--
1.8.1.4