From 912306651fc433c19e7f71b357ce0e69e5001d5b Mon Sep 17 00:00:00 2001
From: David Lehman <dlehman@redhat.com>
Date: Fri, 1 Feb 2013 11:34:55 -0600
Subject: [PATCH 1/5] Add ability to grab 70-anaconda.rules udev data directly.

This means blivet can run with or without 70-anaconda.rules.
---
 blivet/devicelibs/lvm.py    | 71 +++++++++++++++++++--------------------
 blivet/devicelibs/mdraid.py | 17 ++++++++--
 blivet/devicetree.py        | 82 ++++++++++++++++++++++++++++++++++++---------
 3 files changed, 114 insertions(+), 56 deletions(-)

diff --git a/blivet/devicelibs/lvm.py b/blivet/devicelibs/lvm.py
index 7691993..4ab0c36 100644
--- a/blivet/devicelibs/lvm.py
+++ b/blivet/devicelibs/lvm.py
@@ -205,28 +205,27 @@ def pvinfo(device):
         pvs -o pv_name,pv_mda_count,vg_name,vg_uuid --config \
             'devices { scan = "/dev" filter = ["a/loop0/", "r/.*/"] }'
     """
-    #cfg = "'devices { scan = \"/dev\" filter = [\"a/%s/\", \"r/.*/\"] }'" 
-    args = ["pvs", "--noheadings"] + \
-            ["--units", "m"] + \
-            ["-o", "pv_name,pv_mda_count,vg_name,vg_uuid"] + \
+    args = ["pvs",
+            "--unit=k", "--nosuffix", "--nameprefixes", "--rows",
+            "--unquoted", "--noheadings",
+            "-opv_uuid,pe_start,vg_name,vg_uuid,vg_size,vg_free,vg_extent_size,vg_extent_count,vg_free_count,pv_count"] + \
             config_args + \
             [device]
 
     rc = util.capture_output(["lvm"] + args)
-    vals = rc.split()
-    if not vals:
-        raise LVMError("pvinfo failed for %s" % device)
+    _vars = rc.split()
+    info = {}
+    for var in _vars:
+        (name, equals, value) = var.partition("=")
+        if not equals:
+            continue
 
-    # don't raise an exception if pv is not a part of any vg
-    pv_name = vals[0]
-    try:
-        vg_name, vg_uuid = vals[2], vals[3]
-    except IndexError:
-        vg_name, vg_uuid = "", ""
-    
-    info = {'pv_name': pv_name,
-            'vg_name': vg_name,
-            'vg_uuid': vg_uuid}
+        if "," in value:
+            val = value.strip().split(",")
+        else:
+            val = value.strip()
+
+        info[name] = val
 
     return info
 
@@ -304,34 +303,32 @@ def vginfo(vg_name):
     if len(info) != 7:
         raise LVMError(_("vginfo failed for %s" % vg_name))
 
-    d = {}
-    (d['uuid'],d['size'],d['free'],d['pe_size'],
-     d['pe_count'],d['pe_free'],d['pv_count']) = info
-    return d
+    return info
 
 def lvs(vg_name):
-    args = ["lvs", "--noheadings", "--nosuffix"] + \
-            ["--units", "m"] + \
-            ["-o", "lv_name,lv_uuid,lv_size,lv_attr"] + \
+    args = ["lvs",
+            "--unit", "m", "--nosuffix", "--nameprefixes", "--rows",
+            "--unquoted", "--noheadings",
+            "-olv_name,lv_uuid,lv_size,lv_attr"] + \
             config_args + \
             [vg_name]
 
-    buf = util.capture_output(["lvm"] + args)
-
-    lvs = {}
-    for line in buf.splitlines():
-        line = line.strip()
-        if not line:
+    rc = util.capture_output(["lvm"] + args)
+    _vars = rc.split()
+    info = {}
+    for var in _vars:
+        (name, equals, value) = var.partition("=")
+        if not equals:
             continue
-        (name, uuid, size, attr) = line.split()
-        lvs[name] = {"size": size,
-                     "uuid": uuid,
-                     "attr": attr}
 
-    if not lvs:
-        raise LVMError(_("lvs failed for %s" % vg_name))
+        val = value.strip()
 
-    return lvs
+        if name not in info:
+            info[name] = []
+
+        info[name].append(val)
+
+    return info
 
 def lvorigin(vg_name, lv_name):
     args = ["lvs", "--noheadings", "-o", "origin"] + \
diff --git a/blivet/devicelibs/mdraid.py b/blivet/devicelibs/mdraid.py
index ab18641..0c26056 100644
--- a/blivet/devicelibs/mdraid.py
+++ b/blivet/devicelibs/mdraid.py
@@ -234,11 +234,13 @@ def mddeactivate(device):
 
 def mdexamine(device):
     _vars = util.capture_output(["mdadm",
+                                 "--examine", "--export", device]).split()
+    _bvars = util.capture_output(["mdadm",
                                  "--examine", "--brief", device]).split()
 
     info = {}
-    if len(_vars) > 1 and _vars[1].startswith("/dev/md"):
-        info["device"] = _vars[1]
+    if len(_bvars) > 1 and _bvars[1].startswith("/dev/md"):
+        info["device"] = _bvars[1]
         _vars = _vars[2:]
     elif len(_vars) > 1:
         _vars = _vars[1:]
@@ -248,7 +250,16 @@ def mdexamine(device):
         if not equals:
             continue
 
-        info[name.lower()] = value.strip()
+        info[name] = value.strip()
+
+    if "MD_METADATA" not in info:
+        for var in _bvars:
+            (name, equals, value) = var.partition("=")
+            if not equals:
+                continue
+
+            if name == "metadata":
+                info["MD_METADATA"] = value
 
     return info
 
diff --git a/blivet/devicetree.py b/blivet/devicetree.py
index 5bb4459..70c8bfc 100644
--- a/blivet/devicetree.py
+++ b/blivet/devicetree.py
@@ -549,13 +549,20 @@ class DeviceTree(object):
         uuid = udev_device_get_uuid(info)
         sysfs_path = udev_device_get_sysfs_path(info)
 
-        # initiate detection of all PVs and hope that it leads to us having
-        # the VG and LVs in the tree
-        for pv_name in os.listdir("/sys" + sysfs_path + "/slaves"):
-            link = os.readlink("/sys" + sysfs_path + "/slaves/" + pv_name)
-            pv_sysfs_path = os.path.normpath(sysfs_path + '/slaves/' + link)
-            pv_info = udev_get_block_device(pv_sysfs_path)
-            self.addUdevDevice(pv_info)
+        vg_name = udev_device_get_lv_vg_name(info)
+        device = self.getDeviceByName(vg_name)
+        if device and not isinstance(device, LVMVolumeGroupDevice):
+            log.warning("found non-vg device with name %s" % vg_name)
+            device = None
+
+        if not device:
+            # initiate detection of all PVs and hope that it leads to us having
+            # the VG and LVs in the tree
+            for pv_name in os.listdir("/sys" + sysfs_path + "/slaves"):
+                link = os.readlink("/sys" + sysfs_path + "/slaves/" + pv_name)
+                pv_sysfs_path = os.path.normpath(sysfs_path + '/slaves/' + link)
+                pv_info = udev_get_block_device(pv_sysfs_path)
+                self.addUdevDevice(pv_info)
 
         vg_name = udev_device_get_lv_vg_name(info)
         device = self.getDeviceByName(vg_name)
@@ -973,6 +980,11 @@ class DeviceTree(object):
 
         log.info("scanning %s (%s)..." % (name, sysfs_path))
         device = self.getDeviceByName(name)
+        if device is None and udev_device_is_md(info):
+            device = self.getDeviceByName(udev_device_get_md_name(info))
+            if device and not isinstance(device, MDRaidArrayDevice):
+                # make sure any device we found is an md device
+                device = None
 
         #
         # The first step is to either look up or create the device
@@ -1150,10 +1162,22 @@ class DeviceTree(object):
         """
         ret = False
         vg_name = vg_device.name
-        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 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
 
         if not vg_device.complete:
             log.warning("Skipping LVs for incomplete VG %s" % vg_name)
@@ -1230,8 +1254,8 @@ class DeviceTree(object):
 
                 mirrors[name]["log"] = lv_sizes[index]
 
-            lv_dev = self.getDeviceByName(name)
-            if lv_dev is None and flags.installer_mode:
+            lv_dev = self.getDeviceByUuid(lv_uuids[index])
+            if lv_dev is None:
                 lv_uuid = lv_uuids[index]
                 lv_size = lv_sizes[index]
                 lv_device = LVMLogicalVolumeDevice(lv_name,
@@ -1240,7 +1264,19 @@ class DeviceTree(object):
                                                    size=lv_size,
                                                    exists=True)
                 self._addDevice(lv_device)
-                lv_device.setup()
+                if flags.installer_mode:
+                    lv_device.setup()
+
+                if lv_device.status:
+                    lv_device.updateSysfsPath()
+                    lv_info = udev_get_block_device(lv_device.sysfsPath)
+                    if not lv_info:
+                        log.error("failed to get udev data for lv %s" % lv_device.name)
+                        continue
+
+                    # do format handling now
+                    self.addUdevDevice(lv_info)
+
                 ret = True
 
         for name, mirror in mirrors.items():
@@ -1336,8 +1372,8 @@ class DeviceTree(object):
                 log.warning("invalid data for %s: %s" % (name, e))
                 return
 
+            md_metadata = info.get("MD_METADATA")
             md_name = None
-            md_metadata = None
 
             # check the list of devices udev knows about to see if the array
             # this device belongs to is already active
@@ -1357,9 +1393,17 @@ class DeviceTree(object):
                 if dev_uuid == md_uuid and dev_level == md_level:
                     md_name = udev_device_get_md_name(dev)
                     md_metadata = dev.get("MD_METADATA")
+                    if not md_name:
+                        # containers don't typically have names and they also
+                        # don't have a symlink in /dev/md
+                        md_name = udev_device_get_name(dev)
+                        if md_level != "container" and \
+                           re.match(r'md\d+$', md_name):
+                            # md0 -> 0
+                            md_name = md_name[2:]
+
                     break
 
-            md_info = devicelibs.mdraid.mdexamine(device.path)
             if not md_metadata:
                 md_metadata = md_info.get("metadata", "0.90")
 
@@ -1552,6 +1596,9 @@ class DeviceTree(object):
             # luks/dmcrypt
             kwargs["name"] = "luks-%s" % uuid
         elif format_type in formats.mdraid.MDRaidMember._udevTypes:
+            if not flags.installer_mode:
+                info.update(devicelibs.mdraid.mdexamine(device.path))
+
             # mdraid
             try:
                 kwargs["mdUuid"] = udev_device_get_md_uuid(info)
@@ -1560,6 +1607,9 @@ class DeviceTree(object):
             kwargs["biosraid"] = udev_device_is_biosraid_member(info)
         elif format_type == "LVM2_member":
             # lvm
+            if not flags.installer_mode:
+                info.update(devicelibs.lvm.pvinfo(device.path))
+
             try:
                 kwargs["vgName"] = udev_device_get_vg_name(info)
             except KeyError as e:
-- 
1.8.1

