From d5a690cb7825fe1fecc49b4c48c08060038bcc94 Mon Sep 17 00:00:00 2001
From: Bernardo Dal Seno <bdalseno@google.com>
Date: Sun, 13 Jan 2013 16:37:11 +0100
Subject: [PATCH] cluster-verify checks that PVs are not shared

When exclusive_storage is set, cluster-verify complains if PVs are shared
among unrelated LVs.

Signed-off-by: Bernardo Dal Seno <bdalseno@google.com>
Reviewed-by: Michael Hanselmann <hansmi@google.com>
---
 lib/backend.py   | 26 +++++++++++++++++++++++++-
 lib/cmdlib.py    |  7 +++++++
 lib/constants.py |  1 +
 3 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/lib/backend.py b/lib/backend.py
index 47a941f97..027f38617 100644
--- a/lib/backend.py
+++ b/lib/backend.py
@@ -610,6 +610,23 @@ def GetNodeInfo(vg_names, hv_names, excl_stor):
   return (bootid, vg_info, hv_info)
 
 
+def _CheckExclusivePvs(pvi_list):
+  """Check that PVs are not shared among LVs
+
+  @type pvi_list: list of L{objects.LvmPvInfo} objects
+  @param pvi_list: information about the PVs
+
+  @rtype: list of tuples (string, list of strings)
+  @return: offending volumes, as tuples: (pv_name, [lv1_name, lv2_name...])
+
+  """
+  res = []
+  for pvi in pvi_list:
+    if len(pvi.lv_list) > 1:
+      res.append((pvi.name, pvi.lv_list))
+  return res
+
+
 def VerifyNode(what, cluster_name):
   """Verify the status of the local node.
 
@@ -764,8 +781,15 @@ def VerifyNode(what, cluster_name):
     result[constants.NV_VGLIST] = utils.ListVolumeGroups()
 
   if constants.NV_PVLIST in what and vm_capable:
+    check_exclusive_pvs = constants.NV_EXCLUSIVEPVS in what
     val = bdev.LogicalVolume.GetPVInfo(what[constants.NV_PVLIST],
-                                       filter_allocatable=False)
+                                       filter_allocatable=False,
+                                       include_lvs=check_exclusive_pvs)
+    if check_exclusive_pvs:
+      result[constants.NV_EXCLUSIVEPVS] = _CheckExclusivePvs(val)
+      for pvi in val:
+        # Avoid sending useless data on the wire
+        pvi.lv_list = []
     result[constants.NV_PVLIST] = map(objects.LvmPvInfo.ToDict, val)
 
   if constants.NV_VERSION in what:
diff --git a/lib/cmdlib.py b/lib/cmdlib.py
index 2ac179803..77226800d 100644
--- a/lib/cmdlib.py
+++ b/lib/cmdlib.py
@@ -1141,6 +1141,12 @@ def _CheckNodePVs(nresult, exclusive_storage):
   if exclusive_storage:
     (errmsgs, es_pvinfo) = utils.LvmExclusiveCheckNodePvs(pvlist)
     errlist.extend(errmsgs)
+    shared_pvs = nresult.get(constants.NV_EXCLUSIVEPVS, None)
+    if shared_pvs:
+      for (pvname, lvlist) in shared_pvs:
+        # TODO: Check that LVs are really unrelated (snapshots, DRBD meta...)
+        errlist.append("PV %s is shared among unrelated LVs (%s)" %
+                       (pvname, utils.CommaJoin(lvlist)))
   return (errlist, es_pvinfo)
 
 
@@ -3486,6 +3492,7 @@ class LUClusterVerifyGroup(LogicalUnit, _VerifyErrors):
     # it's True for at least a node, we act as if it were set for all the nodes
     self._exclusive_storage = compat.any(es_flags.values())
     if self._exclusive_storage:
+      node_verify_param[constants.NV_EXCLUSIVEPVS] = True
       es_unset_nodes = [n for (n, es) in es_flags.items()
                         if not es]
 
diff --git a/lib/constants.py b/lib/constants.py
index 3232e46bf..2fc7ce9af 100644
--- a/lib/constants.py
+++ b/lib/constants.py
@@ -1560,6 +1560,7 @@ CV_ALL_ECODES_STRINGS = \
 NV_BRIDGES = "bridges"
 NV_DRBDHELPER = "drbd-helper"
 NV_DRBDLIST = "drbd-list"
+NV_EXCLUSIVEPVS = "exclusive-pvs"
 NV_FILELIST = "filelist"
 NV_FILE_STORAGE_PATHS = "file-storage-paths"
 NV_HVINFO = "hvinfo"
-- 
GitLab