From 5bb0a1cb04229dd160a880442b736ff570139a72 Mon Sep 17 00:00:00 2001
From: Thomas Thrainer <thomasth@google.com>
Date: Thu, 25 Apr 2013 08:39:44 +0200
Subject: [PATCH] Make DRBD version queryable from noded

gnt-cluster verify should issue a warning if there are multiple DRBD
versions present in a node group. In order to do so, the DRBD version
has to be queryable from noded.

Signed-off-by: Thomas Thrainer <thomasth@google.com>
Reviewed-by: Helga Velroyen <helgav@google.com>
---
 lib/backend.py                        |  9 +++++++++
 lib/block/drbd_info.py                | 29 ++++++++++++++++++++++-----
 lib/constants.py                      |  1 +
 test/py/ganeti.block.drbd_unittest.py | 18 +++++++++++++----
 4 files changed, 48 insertions(+), 9 deletions(-)

diff --git a/lib/backend.py b/lib/backend.py
index 509e5e4c5..a4f1e71d0 100644
--- a/lib/backend.py
+++ b/lib/backend.py
@@ -66,6 +66,7 @@ from ganeti import pathutils
 from ganeti import vcluster
 from ganeti import ht
 from ganeti.block.base import BlockDev
+from ganeti.block.drbd_info import DRBD8Info
 from ganeti import hooksmaster
 
 
@@ -830,6 +831,14 @@ def VerifyNode(what, cluster_name):
     hyper = hypervisor.GetHypervisor(what[constants.NV_HVINFO])
     result[constants.NV_HVINFO] = hyper.GetNodeInfo()
 
+  if constants.NV_DRBDVERSION in what and vm_capable:
+    try:
+      drbd_version = DRBD8Info.CreateFromFile().GetVersionString()
+    except errors.BlockDeviceError, err:
+      logging.warning("Can't get DRBD version", exc_info=True)
+      drbd_version = str(err)
+    result[constants.NV_DRBDVERSION] = drbd_version
+
   if constants.NV_DRBDLIST in what and vm_capable:
     try:
       used_minors = drbd.DRBD8.GetUsedDevs()
diff --git a/lib/block/drbd_info.py b/lib/block/drbd_info.py
index 991494cd6..ef6eda237 100644
--- a/lib/block/drbd_info.py
+++ b/lib/block/drbd_info.py
@@ -149,7 +149,7 @@ class DRBD8Info(object):
 
   """
 
-  _VERSION_RE = re.compile(r"^version: (\d+)\.(\d+)\.(\d+)(?:\.\d+)?"
+  _VERSION_RE = re.compile(r"^version: (\d+)\.(\d+)\.(\d+)(?:\.(\d+))?"
                            r" \(api:(\d+)/proto:(\d+)(?:-(\d+))?\)")
   _VALID_LINE_RE = re.compile("^ *([0-9]+): cs:([^ ]+).*$")
 
@@ -164,6 +164,7 @@ class DRBD8Info(object):
       - k_major
       - k_minor
       - k_point
+      - k_fix (only on some drbd versions)
       - api
       - proto
       - proto2 (only on drbd > 8.2.X)
@@ -171,6 +172,22 @@ class DRBD8Info(object):
     """
     return self._version
 
+  def GetVersionString(self):
+    """Return the DRBD version as a single string.
+
+    """
+    version = self.GetVersion()
+    retval = "%d.%d.%d" % \
+             (version["k_major"], version["k_minor"], version["k_point"])
+    if "k_fix" in version:
+      retval += ".%s" % version["k_fix"]
+
+    retval += " (api:%d/proto:%d" % (version["api"], version["proto"])
+    if "proto2" in version:
+      retval += "-%s" % version["proto2"]
+    retval += ")"
+    return retval
+
   def GetMinors(self):
     """Return a list of minor for which information is available.
 
@@ -198,11 +215,13 @@ class DRBD8Info(object):
       "k_major": int(values[0]),
       "k_minor": int(values[1]),
       "k_point": int(values[2]),
-      "api": int(values[3]),
-      "proto": int(values[4]),
+      "api": int(values[4]),
+      "proto": int(values[5]),
       }
-    if values[5] is not None:
-      retval["proto2"] = values[5]
+    if values[3] is not None:
+      retval["k_fix"] = values[3]
+    if values[6] is not None:
+      retval["proto2"] = values[6]
 
     return retval
 
diff --git a/lib/constants.py b/lib/constants.py
index bbd5930b0..573d8bf76 100644
--- a/lib/constants.py
+++ b/lib/constants.py
@@ -1669,6 +1669,7 @@ CV_ALL_ECODES_STRINGS = \
 # Node verify constants
 NV_BRIDGES = "bridges"
 NV_DRBDHELPER = "drbd-helper"
+NV_DRBDVERSION = "drbd-version"
 NV_DRBDLIST = "drbd-list"
 NV_EXCLUSIVEPVS = "exclusive-pvs"
 NV_FILELIST = "filelist"
diff --git a/test/py/ganeti.block.drbd_unittest.py b/test/py/ganeti.block.drbd_unittest.py
index 112f5b101..757a286e4 100755
--- a/test/py/ganeti.block.drbd_unittest.py
+++ b/test/py/ganeti.block.drbd_unittest.py
@@ -36,11 +36,19 @@ import testutils
 class TestDRBD8(testutils.GanetiTestCase):
   def testGetVersion(self):
     data = [
-      ["version: 8.0.12 (api:76/proto:86-91)"],
-      ["version: 8.2.7 (api:88/proto:0-100)"],
-      ["version: 8.3.7.49 (api:188/proto:13-191)"],
+      "version: 8.0.0 (api:76/proto:80)",
+      "version: 8.0.12 (api:76/proto:86-91)",
+      "version: 8.2.7 (api:88/proto:0-100)",
+      "version: 8.3.7.49 (api:188/proto:13-191)",
     ]
     result = [
+      {
+        "k_major": 8,
+        "k_minor": 0,
+        "k_point": 0,
+        "api": 76,
+        "proto": 80,
+      },
       {
         "k_major": 8,
         "k_minor": 0,
@@ -61,14 +69,16 @@ class TestDRBD8(testutils.GanetiTestCase):
         "k_major": 8,
         "k_minor": 3,
         "k_point": 7,
+        "k_fix": "49",
         "api": 188,
         "proto": 13,
         "proto2": "191",
       }
     ]
     for d, r in zip(data, result):
-      info = drbd.DRBD8Info.CreateFromLines(d)
+      info = drbd.DRBD8Info.CreateFromLines([d])
       self.assertEqual(info.GetVersion(), r)
+      self.assertEqual(info.GetVersionString(), d.replace("version: ", ""))
 
 
 class TestDRBD8Runner(testutils.GanetiTestCase):
-- 
GitLab