--- 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@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],