I have nothing to say other than what's in the commits themselves.
--- MANIFEST.in | 1 + examples/list_devices.py | 32 ++++++++++++++++++++++++++++++++ python-blivet.spec | 2 +- 3 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 examples/list_devices.py
diff --git a/MANIFEST.in b/MANIFEST.in index 6ae6640..36972ba 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,2 +1,3 @@ include COPYING ChangeLog Makefile python-blivet.spec recursive-include po *.po *.pot Makefile +recursive-include examples *.py diff --git a/examples/list_devices.py b/examples/list_devices.py new file mode 100644 index 0000000..8539ea1 --- /dev/null +++ b/examples/list_devices.py @@ -0,0 +1,32 @@ +import logging +import sys + +blivet_log = logging.getLogger("blivet") + +def set_up_logging(): + """ Configure the blivet logger to use /tmp/blivet.log as its log file. """ + blivet_log.setLevel(logging.DEBUG) + program_log = logging.getLogger("program") + program_log.setLevel(logging.DEBUG) + handler = logging.FileHandler("/tmp/blivet.log") + handler.setLevel(logging.DEBUG) + formatter = logging.Formatter("%(asctime)s,%(msecs)03d %(levelname)s %(name)s: %(message)s") + handler.setFormatter(formatter) + blivet_log.addHandler(handler) + program_log.addHandler(handler) + + +# doing this before importing blivet gets the logging from format class +# registrations and other stuff triggered by the import +set_up_logging() + +import blivet + +blivet_log.info(sys.argv[0]) + +storage = blivet.Blivet() # create an instance of Blivet +storage.reset() # detect system storage configuration + +for device in sorted(storage.devices, key=lambda d: len(d.ancestors)): + print device # this is a blivet.devices.StorageDevice instance + diff --git a/python-blivet.spec b/python-blivet.spec index fe905dd..cce0e8d 100644 --- a/python-blivet.spec +++ b/python-blivet.spec @@ -70,7 +70,7 @@ make DESTDIR=%{buildroot} install
%files -f %{realname}.lang %defattr(-,root,root,-) -%doc README ChangeLog COPYING +%doc README ChangeLog COPYING examples %{python_sitelib}/*
%changelog
Also adds support for representing the system's nodev filesystem mounts.
The include_nodev flag must be set to True prior to calling Blivet.getActiveMounts, which is called from within Blivet.reset (if flags.installer_mode is False).
There can be multiple mounts of any given nodev filesystem type, which presents a problem in terms of looking up devices by name. The chosen solution is to add a unique identifier to each NoDevice instance's name. --- blivet/__init__.py | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++- blivet/devices.py | 5 +++-- blivet/devicetree.py | 2 ++ blivet/flags.py | 4 ++++ blivet/formats/fs.py | 30 +++++++++++++++++++++------- 5 files changed, 86 insertions(+), 10 deletions(-)
diff --git a/blivet/__init__.py b/blivet/__init__.py index 7958eb1..6456311 100644 --- a/blivet/__init__.py +++ b/blivet/__init__.py @@ -55,6 +55,7 @@ from deviceaction import * from formats import getFormat from formats import get_device_format_class from formats import get_default_filesystem_type +from formats.fs import nodev_filesystems import devicefactory from devicelibs.dm import name_from_dm_node from devicelibs.crypto import generateBackupPassphrase @@ -406,6 +407,9 @@ class Blivet(object): if flags.installer_mode: self.roots = findExistingInstallations(self.devicetree)
+ if not flags.installer_mode: + self.getActiveMounts() + self.dumpState("initial")
self.updateBootLoaderDiskList() @@ -1870,6 +1874,56 @@ class Blivet(object):
return new
+ def getActiveMounts(self): + """ Reflect active mounts in the appropriate devices' formats. """ + log.info("collecting information about active mounts") + for _line in open("/proc/mounts").readlines(): + (line, pound, comment) = _line.partition("#") + try: + (devspec, mountpoint, fstype, options, rest) = line.split(None, 4) + except IndexError: + blivet_log.error("failed to parse /proc/mounts line: %s" % _line) + continue + + if fstype == "btrfs": + # get the subvol name from /proc/self/mountinfo + for line in open("/proc/self/mountinfo").readlines(): + fields = line.split() + _subvol = fields[3] + _mountpoint = fields[4] + _devspec = fields[9] + if _mountpoint == mountpoint and _devspec == devspec: + log.debug("subvol %s" % _subvol) + options += ",subvol=%s" % _subvol[1:] + + if fstype in nodev_filesystems: + if not flags.include_nodev: + continue + + log.info("found nodev %s filesystem mounted at %s" + % (fstype, mountpoint)) + # nodev filesystems require some special handling. + # For now, a lot of this is based on the idea that it's a losing + # battle to require the presence of an FS class for every type + # of nodev filesystem. Based on that idea, we just instantiate + # NoDevFS directly and then hack in the fstype as the device + # attribute. + fmt = getFormat("nodev") + fmt.device = fstype + + # NoDevice also needs some special works since they don't have + # per-instance names in the kernel. + device = NoDevice(format=fmt) + n = len([d for d in self.devices if d.format.type == fstype]) + device._name += ".%d" % n + self.devicetree._addDevice(device) + devspec = device.name + + device = self.devicetree.resolveDevice(devspec, options=options) + if device is not None: + device.format.mountpoint = mountpoint # for future mounts + device.format._mountpoint = mountpoint # active mountpoint +
def mountExistingSystem(fsset, rootDevice, allowDirty=None, dirtyCB=None, @@ -2656,7 +2710,6 @@ class FSSet(object):
return fstab
- def getReleaseString(): relName = None relVer = None diff --git a/blivet/devices.py b/blivet/devices.py index 791084a..19885bf 100644 --- a/blivet/devices.py +++ b/blivet/devices.py @@ -3415,7 +3415,7 @@ class NoDevice(StorageDevice): format -- a DeviceFormat instance """ if format: - name = format.type + name = format.device else: name = "none"
@@ -3424,7 +3424,8 @@ class NoDevice(StorageDevice): @property def path(self): """ Device node representing this device. """ - return self.name + # the name may have a '.%d' suffix to make it unique + return self.name.split(".")[0]
def setup(self, orig=False): """ Open, or set up, a device. """ diff --git a/blivet/devicetree.py b/blivet/devicetree.py index 88ba130..026dda6 100644 --- a/blivet/devicetree.py +++ b/blivet/devicetree.py @@ -2142,6 +2142,8 @@ class DeviceTree(object): if edd_number == spec: device = self.getDeviceByName(edd_name) break + elif options and "nodev" in options.split(","): + device = self.getDeviceByName(devspec) else: if not devspec.startswith("/dev/"): device = self.getDeviceByName(devspec) diff --git a/blivet/flags.py b/blivet/flags.py index ed0e5dc..e892b74 100644 --- a/blivet/flags.py +++ b/blivet/flags.py @@ -54,6 +54,10 @@ class Flags(object):
self.gpt = False
+ # whether to include nodev filesystems in the devicetree (only + # meaningful when flags.installer_mode is False) + self.include_nodev = False + self.boot_cmdline = {}
self.update_from_boot_cmdline() diff --git a/blivet/formats/fs.py b/blivet/formats/fs.py index de94ff4..840adb3 100644 --- a/blivet/formats/fs.py +++ b/blivet/formats/fs.py @@ -57,14 +57,19 @@ mib = 1024 * 1024.0
fs_configs = {}
-def get_kernel_filesystems(): - fs_list = [] +kernel_filesystems = [] +nodev_filesystems = [] + +def update_kernel_filesystems(): + global kernel_filesystems + global nodev_filesystems for line in open("/proc/filesystems").readlines(): - fs_list.append(line.split()[-1]) - return fs_list + fields = line.split() + kernel_filesystems.append(fields[-1]) + if fields[0] == "nodev": + nodev_filesystems.append(fields[-1])
-global kernel_filesystems -kernel_filesystems = get_kernel_filesystems() +update_kernel_filesystems()
def fsConfigFromFile(config_file): """ Generate a set of attribute name/value pairs with which a @@ -485,7 +490,7 @@ class FS(DeviceFormat):
# If we successfully loaded a kernel module, for this filesystem, we # also need to update the list of supported filesystems. - kernel_filesystems = get_kernel_filesystems() + update_kernel_filesystems()
def testMount(self, options=None): """ Try to mount the fs and return True if successful. """ @@ -1370,6 +1375,17 @@ class NoDevFS(FS): def _setDevice(self, devspec): self._device = devspec
+ @property + def type(self): + if self.device != self._type: + return self.device + else: + return self._type + + @property + def mountType(self): + return self.device # this is probably set to the real/specific fstype + def _getExistingSize(self): pass
On Fri, Mar 01, 2013 at 04:13:20PM -0600, David Lehman wrote:
for _line in open("/proc/mounts").readlines():
(line, pound, comment) = _line.partition("#")
How would comments get into /proc/mounts?
On Fri, 2013-03-01 at 18:11 -0800, Brian C. Lane wrote:
On Fri, Mar 01, 2013 at 04:13:20PM -0600, David Lehman wrote:
for _line in open("/proc/mounts").readlines():
(line, pound, comment) = _line.partition("#")
How would comments get into /proc/mounts?
A fine question. That could be a relic from copy/paste of fstab-related code or maybe just a thinko. I'll remove it.
anaconda-patches mailing list anaconda-patches@lists.fedorahosted.org https://lists.fedorahosted.org/mailman/listinfo/anaconda-patches
--- blivet/devicetree.py | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/blivet/devicetree.py b/blivet/devicetree.py index 026dda6..834d6fe 100644 --- a/blivet/devicetree.py +++ b/blivet/devicetree.py @@ -2159,6 +2159,11 @@ class DeviceTree(object): if dm_name: devspec = "/dev/mapper/" + dm_name
+ if re.match(r'/dev/md\d+(p\d+)?$', devspec): + md_name = devicelibs.mdraid.name_from_md_node(devspec[5:]) + if md_name: + devspec = "/dev/md/" + md_name + # device path device = self.getDeviceByPath(devspec)
--- blivet/devicetree.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/blivet/devicetree.py b/blivet/devicetree.py index 834d6fe..b432adc 100644 --- a/blivet/devicetree.py +++ b/blivet/devicetree.py @@ -2214,7 +2214,10 @@ class DeviceTree(object): device = self.getDeviceByName(lv)
# check mount options for btrfs volumes in case it's a subvol - if device and device.type == "btrfs volume" and options: + if device and device.type.startswith("btrfs") and options: + # start with the volume -- not a subvolume + device = getattr(device, "volume", device) + attr = None if "subvol=" in options: attr = "name"
--- blivet/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/blivet/__init__.py b/blivet/__init__.py index 6456311..89c632e 100644 --- a/blivet/__init__.py +++ b/blivet/__init__.py @@ -348,7 +348,8 @@ class Blivet(object): dev.disk.setup() dev.disk.format.commitToDisk()
- self.dumpState("final") + if flags.installer_mode: + self.dumpState("final")
@property def nextID(self): @@ -406,12 +407,11 @@ class Blivet(object):
if flags.installer_mode: self.roots = findExistingInstallations(self.devicetree) + self.dumpState("initial")
if not flags.installer_mode: self.getActiveMounts()
- self.dumpState("initial") - self.updateBootLoaderDiskList()
@property
--- blivet/devicefactory.py | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-)
diff --git a/blivet/devicefactory.py b/blivet/devicefactory.py index 6a1f9d5..3982570 100644 --- a/blivet/devicefactory.py +++ b/blivet/devicefactory.py @@ -674,21 +674,27 @@ class PartitionFactory(DeviceFactory): def set_device_size(self, container, device=None): size = self.size if device: - if size != device.size: + if isinstance(device, LUKSDevice): + use_dev = device.slave + else: + use_dev = device + + if size != use_dev.size: log.info("adjusting device size from %.2f to %.2f" - % (device.size, size)) + % (use_dev.size, size))
+ # use device here since the leaf format is what we're concerned with base_size = max(PartitionFactory.default_size, device.format.minSize) size = max(base_size, size) - device.req_base_size = base_size - device.req_size = base_size - device.req_max_size = size - device.req_grow = size > base_size + use_dev.req_base_size = base_size + use_dev.req_size = base_size + use_dev.req_max_size = size + use_dev.req_grow = size > base_size
# this probably belongs somewhere else but this is our chance to # update the disk set - device.req_disks = self.disks[:] + use_dev.req_disks = self.disks[:]
return size
@@ -769,7 +775,12 @@ class LVMFactory(DeviceFactory): size = self.size free = container.freeSpace if device: - free += device.size + if isinstance(device, LUKSDevice): + use_dev = device.slave + else: + use_dev = device + + free += use_dev.size
if free < size: log.info("adjusting device size from %.2f to %.2f so it fits " @@ -777,11 +788,11 @@ class LVMFactory(DeviceFactory): size = free
if device: - if size != device.size: + if size != use_dev.size: log.info("adjusting device size from %.2f to %.2f" - % (device.size, size)) + % (use_dev.size, size))
- device.size = size + use_dev.size = size
return size
--- blivet/__init__.py | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-)
diff --git a/blivet/__init__.py b/blivet/__init__.py index 89c632e..1c61c6e 100644 --- a/blivet/__init__.py +++ b/blivet/__init__.py @@ -272,6 +272,7 @@ class Blivet(object):
self.__luksDevs = {} self.size_sets = [] + self.setDefaultFSType(get_default_filesystem_type())
self.iscsi = iscsi.iscsi() self.fcoe = fcoe.fcoe() @@ -279,7 +280,6 @@ class Blivet(object): self.dasd = dasd.DASD()
self._nextID = 0 - self.defaultFSType = get_default_filesystem_type() self._dumpFile = "/tmp/storage.state"
# these will both be empty until our reset method gets called @@ -1702,6 +1702,27 @@ class Blivet(object): return fstype
@property + def defaultFSType(self): + return self._defaultFSType + + def setDefaultFSType(self, newtype): + """ Set the default fstype for this instance. + + Raise ValueError on invalid input. + """ + log.debug("trying to set new default fstype to '%s'" % newtype) + fmt = getFormat(newtype) + if fmt.type is None: + raise ValueError("unrecognized value for new default fs type") + + if (not fmt.mountable or not fmt.formattable or not fmt.supported or + not fmt.linuxNative): + log.debug("invalid default fstype: %r" % fmt) + raise ValueError("new value is not valid as a default fs type") + + self._defaultFSType = newtype + + @property def mountpoints(self): return self.fsset.mountpoints
Related: rhbz#906906 Related: rhbz#906908 --- blivet/devicefactory.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+)
diff --git a/blivet/devicefactory.py b/blivet/devicefactory.py index 3982570..466fec3 100644 --- a/blivet/devicefactory.py +++ b/blivet/devicefactory.py @@ -150,6 +150,18 @@ class DeviceFactory(object):
return size
+ def handle_no_size(self, device=None, container=None): + """ Set device size so that it grows to the largest size possible. """ + if self.size is not None: + return + + free_info = self.storage.getFreeSpace(disks=self.disks) + free = sum(d[0] for d in free_info.values()) + self.size = int(free.convertTo(spec="mb")) + + if device: + self.size += device.size + @property def device_size(self): """ The total disk space required for this device. """ @@ -451,6 +463,9 @@ class DeviceFactory(object):
container = self.get_container(device=device, name=container_name)
+ # handle special size value of None, which means to grow unbounded + self.handle_no_size(device=device, container=container) + # TODO: striping, mirroring, &c # TODO: non-partition members (pv-on-md)
@@ -753,6 +768,20 @@ class LVMFactory(DeviceFactory): encrypt_members = True encrypt_leaves = False
+ def handle_no_size(self, device=None, container=None): + """ Set device size so that it grows to the largest size possible. """ + if self.size is not None: + return + + if container and container.exists: + self.size = container.freeSpace + + if device: + self.size += device.size + else: + super(LVMFactory, self).handle_no_size(device=device, + container=container) + @property def device_size(self): size_func_kwargs = {}
This fixes breakage caused by commit 912306651fc433. --- blivet/devicelibs/mdraid.py | 8 +++----- blivet/devicetree.py | 26 +++++++++----------------- 2 files changed, 12 insertions(+), 22 deletions(-)
diff --git a/blivet/devicelibs/mdraid.py b/blivet/devicelibs/mdraid.py index 0a3fdf7..fee83f1 100644 --- a/blivet/devicelibs/mdraid.py +++ b/blivet/devicelibs/mdraid.py @@ -240,17 +240,15 @@ def mdexamine(device):
info = {} if len(_bvars) > 1 and _bvars[1].startswith("/dev/md"): - info["device"] = _bvars[1] - _vars = _vars[2:] - elif len(_vars) > 1: - _vars = _vars[1:] + info["DEVICE"] = _bvars[1] + _bvars = _bvars[2:]
for var in _vars: (name, equals, value) = var.partition("=") if not equals: continue
- info[name] = value.strip() + info[name.upper()] = value.strip()
if "MD_METADATA" not in info: for var in _bvars: diff --git a/blivet/devicetree.py b/blivet/devicetree.py index b432adc..f969bab 100644 --- a/blivet/devicetree.py +++ b/blivet/devicetree.py @@ -1132,21 +1132,10 @@ class DeviceTree(object): ret = False vg_name = vg_device.name
- if not flags.installer_mode: - info = devicelibs.lvm.lvs(vg_name) - try: - lv_names = udev_device_get_lv_names(info) - lv_uuids = udev_device_get_lv_uuids(info) - lv_sizes = udev_device_get_lv_sizes(info) - lv_attr = udev_device_get_lv_attr(info) - except KeyError as e: - log.warning("invalid data for %s: %s" % (vg_name, e)) - return - else: - lv_names = vg_device.lv_names - lv_uuids = vg_device.lv_uuids - lv_sizes = vg_device.lv_sizes - lv_attr = vg_device.lv_attr + lv_names = vg_device.lv_names + lv_uuids = vg_device.lv_uuids + lv_sizes = vg_device.lv_sizes + lv_attr = vg_device.lv_attr
if not vg_device.complete: log.warning("Skipping LVs for incomplete VG %s" % vg_name) @@ -1295,6 +1284,9 @@ class DeviceTree(object): exists=True) self._addDevice(vg_device)
+ if not flags.installer_mode: + info.update(lvm.lvs(vg_name)) + # Now we add any lv info found in this pv to the vg_device, we # do this for all pvs as pvs only contain lv info for lvs which they # contain themselves @@ -1376,10 +1368,10 @@ class DeviceTree(object): break
if not md_metadata: - md_metadata = md_info.get("metadata", "0.90") + md_metadata = info.get("METADATA", "0.90")
if not md_name: - md_path = md_info.get("device", "") + md_path = info.get("DEVICE", "") if md_path: md_name = devicePathToName(md_path) if re.match(r'md\d+$', md_name):
This is caused by an error in commit e3ceb9b553fb0b69. --- blivet/devicefactory.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/blivet/devicefactory.py b/blivet/devicefactory.py index 466fec3..f548cc5 100644 --- a/blivet/devicefactory.py +++ b/blivet/devicefactory.py @@ -606,7 +606,7 @@ class DeviceFactory(object): self.size = 0 self.disks = container.disks try: - self.set_container_members(container, factory) + self.set_container_members(container) except StorageError as e: log.error("failed to revert container: %s" % e) raise ErrorRecoveryFailure("failed to revert container")
--- blivet/size.py | 1 + 1 file changed, 1 insertion(+)
diff --git a/blivet/size.py b/blivet/size.py index 34f75b5..5f83d5f 100644 --- a/blivet/size.py +++ b/blivet/size.py @@ -66,6 +66,7 @@ def _makeSpecs(prefix, abbr):
if abbr: specs.append(abbr.lower() + _("b")) + specs.append(abbr.lower())
return specs
It will still be a DeviceFormat instance, but it will have a type that is not None and will reflect what was requested. --- blivet/formats/__init__.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/blivet/formats/__init__.py b/blivet/formats/__init__.py index c8ddc0b..4a6c416 100644 --- a/blivet/formats/__init__.py +++ b/blivet/formats/__init__.py @@ -91,6 +91,14 @@ def getFormat(fmt_type, *args, **kwargs): className = fmt.__class__.__name__ except AttributeError: className = None + + # this allows us to store the given type for formats we implement as + # DeviceFormat. + if fmt_type and fmt.type is None: + # this should add/set an instance attribute + fmt._type = fmt_type + fmt._name = None + log.debug("getFormat('%s') returning %s instance" % (fmt_type, className)) return fmt
@@ -137,7 +145,7 @@ def get_device_format_class(fmt_type): class DeviceFormat(object): """ Generic device format. """ _type = None - _name = "Unknown" + _name = _("Unknown") _udevTypes = [] partedFlag = None partedSystem = None
--- blivet/deviceaction.py | 1 + blivet/devices.py | 2 ++ blivet/devicetree.py | 1 + blivet/udev.py | 10 ++++++---- 4 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/blivet/deviceaction.py b/blivet/deviceaction.py index e615536..7f4d9b6 100644 --- a/blivet/deviceaction.py +++ b/blivet/deviceaction.py @@ -441,6 +441,7 @@ class ActionCreateFormat(DeviceAction): self.device.updateSysfsPath() info = udev_get_block_device(self.device.sysfsPath) self.device.format.uuid = udev_device_get_uuid(info) + self.device.deviceLinks = udev_device_get_symlinks(info)
def cancel(self): self.device.format = self.origFormat diff --git a/blivet/devices.py b/blivet/devices.py index 19885bf..f091378 100644 --- a/blivet/devices.py +++ b/blivet/devices.py @@ -494,6 +494,8 @@ class StorageDevice(Device):
self._partedDevice = None
+ self.deviceLinks = [] + if self.exists and flags.testing and not self._size: def read_int_from_sys(path): return int(open(path).readline().strip()) diff --git a/blivet/devicetree.py b/blivet/devicetree.py index f969bab..1ea6f3b 100644 --- a/blivet/devicetree.py +++ b/blivet/devicetree.py @@ -1026,6 +1026,7 @@ class DeviceTree(object): if device.format.type: log.info("got format: %r" % device.format) device.originalFormat = copy.copy(device.format) + device.deviceLinks = udev_device_get_symlinks(info)
def handleUdevDiskLabelFormat(self, info, device): disklabel_type = info.get("ID_PART_TABLE_TYPE") diff --git a/blivet/udev.py b/blivet/udev.py index ec1dcaa..b944cb2 100644 --- a/blivet/udev.py +++ b/blivet/udev.py @@ -352,11 +352,13 @@ def udev_device_get_bus(udev_info): def udev_device_get_path(info): return info["ID_PATH"]
+def udev_device_get_symlinks(info): + return info.get("symlinks", []) + def udev_device_get_by_path(info): - if info.has_key('symlinks'): - for link in info['symlinks']: - if link.startswith('/dev/disk/by-path/'): - return link + for link in udev_device_get_symlinks(info): + if link.startswith('/dev/disk/by-path/'): + return link
return udev_device_get_name(info)
Looks good other than the one question about patch #2
anaconda-patches@lists.fedorahosted.org