From 72d1a517e2e20fad24d77ce2602a5cd41a7b37dc Mon Sep 17 00:00:00 2001
From: Joe Julian <me@joejulian.name>
Date: Thu, 4 Feb 2016 11:58:10 -0800
Subject: [PATCH 62/62] Add realpath to lvm.pvdisplay and use it in vg_present

Any sort of symlink could be used for inclusion into an lvm vg but lvm's
pvdisplay may show a real device name, or a mapper device name which is
a symlink.

Since we're interested in finding out if the actual device is part of
our volgroup, we test the realpath of both the device requested and the
device returned by pvdisplay to ensure they're the same device.

Fixes #26867 and #30882
---
 salt/modules/linux_lvm.py            | 18 ++++++++++++++++--
 salt/states/lvm.py                   |  6 +++---
 tests/unit/modules/linux_lvm_test.py | 16 ++++++++++++++++
 3 files changed, 35 insertions(+), 5 deletions(-)

diff --git a/salt/modules/linux_lvm.py b/salt/modules/linux_lvm.py
index 7009481..1aac2ef 100644
--- a/salt/modules/linux_lvm.py
+++ b/salt/modules/linux_lvm.py
@@ -60,10 +60,18 @@ def fullversion():
     return ret
 
 
-def pvdisplay(pvname=''):
+def pvdisplay(pvname='', real=False):
     '''
     Return information about the physical volume(s)
 
+    pvname
+        physical device name
+    real
+        dereference any symlinks and report the real device
+
+        .. versionadded:: 2015.8.7
+
+
     CLI Examples:
 
     .. code-block:: bash
@@ -84,7 +92,11 @@ def pvdisplay(pvname=''):
     for line in out:
         if 'is a new physical volume' not in line:
             comps = line.strip().split(':')
-            ret[comps[0]] = {
+            if real:
+                device = os.path.realpath(comps[0])
+            else:
+                device = comps[0]
+            ret[device] = {
                 'Physical Volume Device': comps[0],
                 'Volume Group Name': comps[1],
                 'Physical Volume Size (kB)': comps[2],
@@ -97,6 +109,8 @@ def pvdisplay(pvname=''):
                 'Free Physical Extents': comps[9],
                 'Allocated Physical Extents': comps[10],
                 }
+            if real:
+                ret[device]['Real Physical Volume Device'] = device
     return ret
 
 
diff --git a/salt/states/lvm.py b/salt/states/lvm.py
index fa746f4..a4541cb 100644
--- a/salt/states/lvm.py
+++ b/salt/states/lvm.py
@@ -126,15 +126,15 @@ def vg_present(name, devices=None, **kwargs):
         ret['comment'] = 'Volume Group {0} already present'.format(name)
         for device in devices.split(','):
             realdev = os.path.realpath(device)
-            pvs = __salt__['lvm.pvdisplay'](realdev)
+            pvs = __salt__['lvm.pvdisplay'](realdev, real=True)
             if pvs and pvs.get(realdev, None):
                 if pvs[realdev]['Volume Group Name'] == name:
                     ret['comment'] = '{0}\n{1}'.format(
                         ret['comment'],
                         '{0} is part of Volume Group'.format(device))
                 elif pvs[realdev]['Volume Group Name'] == '#orphans_lvm2':
-                    __salt__['lvm.vgextend'](name, realdev)
-                    pvs = __salt__['lvm.pvdisplay'](realdev)
+                    __salt__['lvm.vgextend'](name, device)
+                    pvs = __salt__['lvm.pvdisplay'](realdev, real=True)
                     if pvs[realdev]['Volume Group Name'] == name:
                         ret['changes'].update(
                             {device: 'added to {0}'.format(name)})
diff --git a/tests/unit/modules/linux_lvm_test.py b/tests/unit/modules/linux_lvm_test.py
index b4567dd..d4674fa 100644
--- a/tests/unit/modules/linux_lvm_test.py
+++ b/tests/unit/modules/linux_lvm_test.py
@@ -71,6 +71,22 @@ class LinuxLVMTestCase(TestCase):
                                         'Total Physical Extents': 'I',
                                         'Volume Group Name': 'B'}})
 
+            mockpath = MagicMock(return_value='Z')
+            with patch.object(os.path, 'realpath', mockpath):
+                self.assertDictEqual(linux_lvm.pvdisplay(real=True),
+                                     {'Z': {'Allocated Physical Extents': 'K',
+                                            'Current Logical Volumes Here': 'G',
+                                            'Free Physical Extents': 'J',
+                                            'Internal Physical Volume Number': 'D',
+                                            'Physical Extent Size (kB)': 'H',
+                                            'Physical Volume (not) Allocatable': 'F',
+                                            'Physical Volume Device': 'A',
+                                            'Physical Volume Size (kB)': 'C',
+                                            'Physical Volume Status': 'E',
+                                            'Real Physical Volume Device': 'Z',
+                                            'Total Physical Extents': 'I',
+                                            'Volume Group Name': 'B'}})
+
     def test_vgdisplay(self):
         '''
         Tests information about the volume group(s)
-- 
2.8.2

