Convert IOErrors for /proc/drbd into our errors
authorIustin Pop <iustin@google.com>
Mon, 16 Feb 2009 12:17:18 +0000 (12:17 +0000)
committerIustin Pop <iustin@google.com>
Mon, 16 Feb 2009 12:17:18 +0000 (12:17 +0000)
If /proc/drbd can't be opened, this raises an IOError, but all the
error-handling behaviour in backend treats only BlockDeviceErrors. This
creates a plain failure in cluster verify and in other RPC calls.

This patch simply converts EnvironmentErrors into BlockDeviceErrors, and
also changes the RPC result for NV_DRBDLIST and its handling to be able
to show the error. The other RPC calls work by default now, due the
existing error handling.

Reviewed-by: ultrotter

lib/backend.py
lib/bdev.py
lib/cmdlib.py
test/ganeti.bdev_unittest.py

index b3e3f49..c172300 100644 (file)
@@ -437,9 +437,9 @@ def VerifyNode(what, cluster_name):
   if constants.NV_DRBDLIST in what:
     try:
       used_minors = bdev.DRBD8.GetUsedDevs().keys()
-    except errors.BlockDeviceError:
+    except errors.BlockDeviceError, err:
       logging.warning("Can't get used minors list", exc_info=True)
-      used_minors = []
+      used_minors = str(err)
     result[constants.NV_DRBDLIST] = used_minors
 
   return result
index d68f39e..545cc0b 100644 (file)
@@ -639,11 +639,18 @@ class BaseDRBD(BlockDev):
     """Return data from /proc/drbd.
 
     """
-    stat = open(filename, "r")
     try:
-      data = stat.read().splitlines()
-    finally:
-      stat.close()
+      stat = open(filename, "r")
+      try:
+        data = stat.read().splitlines()
+      finally:
+        stat.close()
+    except EnvironmentError, err:
+      if err.errno == errno.ENOENT:
+        _ThrowError("The file %s cannot be opened, check if the module"
+                    " is loaded (%s)", filename, str(err))
+      else:
+        _ThrowError("Can't read the DRBD proc file %s: %s", filename, str(err))
     if not data:
       _ThrowError("Can't read any data from %s", filename)
     return data
index 2bc0bae..8347140 100644 (file)
@@ -757,15 +757,19 @@ class LUVerifyCluster(LogicalUnit):
 
     # check used drbd list
     used_minors = node_result.get(constants.NV_DRBDLIST, [])
-    for minor, (iname, must_exist) in drbd_map.items():
-      if minor not in used_minors and must_exist:
-        feedback_fn("  - ERROR: drbd minor %d of instance %s is not active" %
-                    (minor, iname))
-        bad = True
-    for minor in used_minors:
-      if minor not in drbd_map:
-        feedback_fn("  - ERROR: unallocated drbd minor %d is in use" % minor)
-        bad = True
+    if not isinstance(used_minors, (tuple, list)):
+      feedback_fn("  - ERROR: cannot parse drbd status file: %s" %
+                  str(used_minors))
+    else:
+      for minor, (iname, must_exist) in drbd_map.items():
+        if minor not in used_minors and must_exist:
+          feedback_fn("  - ERROR: drbd minor %d of instance %s is not active" %
+                      (minor, iname))
+          bad = True
+      for minor in used_minors:
+        if minor not in drbd_map:
+          feedback_fn("  - ERROR: unallocated drbd minor %d is in use" % minor)
+          bad = True
 
     return bad
 
index 6b71768..2db785c 100755 (executable)
@@ -106,6 +106,13 @@ class TestDRBD8Status(testutils.GanetiTestCase):
     self.proc_data = bdev.DRBD8._GetProcData(filename=proc_data)
     self.mass_data = bdev.DRBD8._MassageProcData(self.proc_data)
 
+  def testIOErrors(self):
+    """Test handling of errors while reading the proc file."""
+    temp_file = self._CreateTempFile()
+    os.unlink(temp_file)
+    self.failUnlessRaises(errors.BlockDeviceError,
+                          bdev.DRBD8._GetProcData, filename=temp_file)
+
   def testMinorNotFound(self):
     """Test not-found-minor in /proc"""
     self.failUnless(9 not in self.mass_data)