diff --git a/lib/block/drbd.py b/lib/block/drbd.py
index 5f1d47b673f2156df1d510ed1bdf1ff55cbcbeff..76f58b4dc4308ec0da092c5591b9c58782217be2 100644
--- a/lib/block/drbd.py
+++ b/lib/block/drbd.py
@@ -265,6 +265,116 @@ class DRBD8Info(object):
     return DRBD8Info.CreateFromLines(lines)
 
 
+class DRBD8ShowInfo(object):
+  """Helper class which parses the output of drbdsetup show
+
+  """
+  _PARSE_SHOW = None
+
+  @classmethod
+  def _GetShowParser(cls):
+    """Return a parser for `drbd show` output.
+
+    This will either create or return an already-created parser for the
+    output of the command `drbd show`.
+
+    """
+    if cls._PARSE_SHOW is not None:
+      return cls._PARSE_SHOW
+
+    # pyparsing setup
+    lbrace = pyp.Literal("{").suppress()
+    rbrace = pyp.Literal("}").suppress()
+    lbracket = pyp.Literal("[").suppress()
+    rbracket = pyp.Literal("]").suppress()
+    semi = pyp.Literal(";").suppress()
+    colon = pyp.Literal(":").suppress()
+    # this also converts the value to an int
+    number = pyp.Word(pyp.nums).setParseAction(lambda s, l, t: int(t[0]))
+
+    comment = pyp.Literal("#") + pyp.Optional(pyp.restOfLine)
+    defa = pyp.Literal("_is_default").suppress()
+    dbl_quote = pyp.Literal('"').suppress()
+
+    keyword = pyp.Word(pyp.alphanums + "-")
+
+    # value types
+    value = pyp.Word(pyp.alphanums + "_-/.:")
+    quoted = dbl_quote + pyp.CharsNotIn('"') + dbl_quote
+    ipv4_addr = (pyp.Optional(pyp.Literal("ipv4")).suppress() +
+                 pyp.Word(pyp.nums + ".") + colon + number)
+    ipv6_addr = (pyp.Optional(pyp.Literal("ipv6")).suppress() +
+                 pyp.Optional(lbracket) + pyp.Word(pyp.hexnums + ":") +
+                 pyp.Optional(rbracket) + colon + number)
+    # meta device, extended syntax
+    meta_value = ((value ^ quoted) + lbracket + number + rbracket)
+    # device name, extended syntax
+    device_value = pyp.Literal("minor").suppress() + number
+
+    # a statement
+    stmt = (~rbrace + keyword + ~lbrace +
+            pyp.Optional(ipv4_addr ^ ipv6_addr ^ value ^ quoted ^ meta_value ^
+                         device_value) +
+            pyp.Optional(defa) + semi +
+            pyp.Optional(pyp.restOfLine).suppress())
+
+    # an entire section
+    section_name = pyp.Word(pyp.alphas + "_")
+    section = section_name + lbrace + pyp.ZeroOrMore(pyp.Group(stmt)) + rbrace
+
+    bnf = pyp.ZeroOrMore(pyp.Group(section ^ stmt))
+    bnf.ignore(comment)
+
+    cls._PARSE_SHOW = bnf
+
+    return bnf
+
+  @classmethod
+  def GetDevInfo(cls, show_data):
+    """Parse details about a given DRBD minor.
+
+    This returns, if available, the local backing device (as a path)
+    and the local and remote (ip, port) information from a string
+    containing the output of the `drbdsetup show` command as returned
+    by DRBD8._GetShowData.
+
+    This will return a dict with keys:
+      - local_dev
+      - meta_dev
+      - meta_index
+      - local_addr
+      - remote_addr
+
+    """
+    retval = {}
+    if not show_data:
+      return retval
+
+    try:
+      # run pyparse
+      results = (cls._GetShowParser()).parseString(show_data)
+    except pyp.ParseException, err:
+      base.ThrowError("Can't parse drbdsetup show output: %s", str(err))
+
+    # and massage the results into our desired format
+    for section in results:
+      sname = section[0]
+      if sname == "_this_host":
+        for lst in section[1:]:
+          if lst[0] == "disk":
+            retval["local_dev"] = lst[1]
+          elif lst[0] == "meta-disk":
+            retval["meta_dev"] = lst[1]
+            retval["meta_index"] = lst[2]
+          elif lst[0] == "address":
+            retval["local_addr"] = tuple(lst[1:])
+      elif sname == "_remote_host":
+        for lst in section[1:]:
+          if lst[0] == "address":
+            retval["remote_addr"] = tuple(lst[1:])
+    return retval
+
+
 class DRBD8(base.BlockDev):
   """DRBD v8.x block device.
 
@@ -283,7 +393,6 @@ class DRBD8(base.BlockDev):
   _USERMODE_HELPER_FILE = "/sys/module/drbd/parameters/usermode_helper"
 
   _MAX_MINORS = 255
-  _PARSE_SHOW = None
 
   # timeout constants
   _NET_RECONFIG_TIMEOUT = 60
@@ -449,64 +558,6 @@ class DRBD8(base.BlockDev):
 
     return highest + 1
 
-  @classmethod
-  def _GetShowParser(cls):
-    """Return a parser for `drbd show` output.
-
-    This will either create or return an already-created parser for the
-    output of the command `drbd show`.
-
-    """
-    if cls._PARSE_SHOW is not None:
-      return cls._PARSE_SHOW
-
-    # pyparsing setup
-    lbrace = pyp.Literal("{").suppress()
-    rbrace = pyp.Literal("}").suppress()
-    lbracket = pyp.Literal("[").suppress()
-    rbracket = pyp.Literal("]").suppress()
-    semi = pyp.Literal(";").suppress()
-    colon = pyp.Literal(":").suppress()
-    # this also converts the value to an int
-    number = pyp.Word(pyp.nums).setParseAction(lambda s, l, t: int(t[0]))
-
-    comment = pyp.Literal("#") + pyp.Optional(pyp.restOfLine)
-    defa = pyp.Literal("_is_default").suppress()
-    dbl_quote = pyp.Literal('"').suppress()
-
-    keyword = pyp.Word(pyp.alphanums + "-")
-
-    # value types
-    value = pyp.Word(pyp.alphanums + "_-/.:")
-    quoted = dbl_quote + pyp.CharsNotIn('"') + dbl_quote
-    ipv4_addr = (pyp.Optional(pyp.Literal("ipv4")).suppress() +
-                 pyp.Word(pyp.nums + ".") + colon + number)
-    ipv6_addr = (pyp.Optional(pyp.Literal("ipv6")).suppress() +
-                 pyp.Optional(lbracket) + pyp.Word(pyp.hexnums + ":") +
-                 pyp.Optional(rbracket) + colon + number)
-    # meta device, extended syntax
-    meta_value = ((value ^ quoted) + lbracket + number + rbracket)
-    # device name, extended syntax
-    device_value = pyp.Literal("minor").suppress() + number
-
-    # a statement
-    stmt = (~rbrace + keyword + ~lbrace +
-            pyp.Optional(ipv4_addr ^ ipv6_addr ^ value ^ quoted ^ meta_value ^
-                         device_value) +
-            pyp.Optional(defa) + semi +
-            pyp.Optional(pyp.restOfLine).suppress())
-
-    # an entire section
-    section_name = pyp.Word(pyp.alphas + "_")
-    section = section_name + lbrace + pyp.ZeroOrMore(pyp.Group(stmt)) + rbrace
-
-    bnf = pyp.ZeroOrMore(pyp.Group(section ^ stmt))
-    bnf.ignore(comment)
-
-    cls._PARSE_SHOW = bnf
-
-    return bnf
-
   @classmethod
   def _GetShowData(cls, minor):
     """Return the `drbdsetup show` data for a minor.
@@ -519,46 +570,6 @@ class DRBD8(base.BlockDev):
       return None
     return result.stdout
 
-  @classmethod
-  def _GetDevInfo(cls, out):
-    """Parse details about a given DRBD minor.
-
-    This return, if available, the local backing device (as a path)
-    and the local and remote (ip, port) information from a string
-    containing the output of the `drbdsetup show` command as returned
-    by _GetShowData.
-
-    """
-    data = {}
-    if not out:
-      return data
-
-    bnf = cls._GetShowParser()
-    # run pyparse
-
-    try:
-      results = bnf.parseString(out)
-    except pyp.ParseException, err:
-      base.ThrowError("Can't parse drbdsetup show output: %s", str(err))
-
-    # and massage the results into our desired format
-    for section in results:
-      sname = section[0]
-      if sname == "_this_host":
-        for lst in section[1:]:
-          if lst[0] == "disk":
-            data["local_dev"] = lst[1]
-          elif lst[0] == "meta-disk":
-            data["meta_dev"] = lst[1]
-            data["meta_index"] = lst[2]
-          elif lst[0] == "address":
-            data["local_addr"] = tuple(lst[1:])
-      elif sname == "_remote_host":
-        for lst in section[1:]:
-          if lst[0] == "address":
-            data["remote_addr"] = tuple(lst[1:])
-    return data
-
   def _MatchesLocal(self, info):
     """Test if our local config matches with an existing device.
 
@@ -775,7 +786,7 @@ class DRBD8(base.BlockDev):
                       minor, result.fail_reason, result.output)
 
     def _CheckNetworkConfig():
-      info = self._GetDevInfo(self._GetShowData(minor))
+      info = DRBD8ShowInfo.GetDevInfo(self._GetShowData(minor))
       if not "local_addr" in info or not "remote_addr" in info:
         raise utils.RetryAgain()
 
@@ -797,7 +808,7 @@ class DRBD8(base.BlockDev):
                       self._aminor)
     if len(devices) != 2:
       base.ThrowError("drbd%d: need two devices for AddChildren", self.minor)
-    info = self._GetDevInfo(self._GetShowData(self.minor))
+    info = DRBD8ShowInfo.GetDevInfo(self._GetShowData(self.minor))
     if "local_dev" in info:
       base.ThrowError("drbd%d: already attached to a local disk", self.minor)
     backend, meta = devices
@@ -820,7 +831,7 @@ class DRBD8(base.BlockDev):
       base.ThrowError("drbd%d: can't attach to drbd8 during RemoveChildren",
                       self._aminor)
     # early return if we don't actually have backing storage
-    info = self._GetDevInfo(self._GetShowData(self.minor))
+    info = DRBD8ShowInfo.GetDevInfo(self._GetShowData(self.minor))
     if "local_dev" not in info:
       return
     if len(self._children) != 2:
@@ -1172,7 +1183,7 @@ class DRBD8(base.BlockDev):
     # pylint: disable=W0631
     net_data = (self._lhost, self._lport, self._rhost, self._rport)
     for minor in (self._aminor,):
-      info = self._GetDevInfo(self._GetShowData(minor))
+      info = DRBD8ShowInfo.GetDevInfo(self._GetShowData(minor))
       match_l = self._MatchesLocal(info)
       match_r = self._MatchesNet(info)
 
@@ -1184,7 +1195,7 @@ class DRBD8(base.BlockDev):
         # disk matches, but not attached to network, attach and recheck
         self._AssembleNet(minor, net_data, constants.DRBD_NET_PROTOCOL,
                           hmac=constants.DRBD_HMAC_ALG, secret=self._secret)
-        if self._MatchesNet(self._GetDevInfo(self._GetShowData(minor))):
+        if self._MatchesNet(DRBD8ShowInfo.GetDevInfo(self._GetShowData(minor))):
           break
         else:
           base.ThrowError("drbd%d: network attach successful, but 'drbdsetup"
@@ -1194,7 +1205,7 @@ class DRBD8(base.BlockDev):
         # no local disk, but network attached and it matches
         self._AssembleLocal(minor, self._children[0].dev_path,
                             self._children[1].dev_path, self.size)
-        if self._MatchesNet(self._GetDevInfo(self._GetShowData(minor))):
+        if self._MatchesNet(DRBD8ShowInfo.GetDevInfo(self._GetShowData(minor))):
           break
         else:
           base.ThrowError("drbd%d: disk attach successful, but 'drbdsetup"
@@ -1221,7 +1232,7 @@ class DRBD8(base.BlockDev):
         # None)
         self._AssembleNet(minor, net_data, constants.DRBD_NET_PROTOCOL,
                           hmac=constants.DRBD_HMAC_ALG, secret=self._secret)
-        if self._MatchesNet(self._GetDevInfo(self._GetShowData(minor))):
+        if self._MatchesNet(DRBD8ShowInfo.GetDevInfo(self._GetShowData(minor))):
           break
         else:
           base.ThrowError("drbd%d: network attach successful, but 'drbdsetup"
diff --git a/test/py/ganeti.block.bdev_unittest.py b/test/py/ganeti.block.bdev_unittest.py
index 58dcbac04ae3cccf8a7c411dd5900d3761776a02..bb6d8a82ff6e4dfca27dd197187509249bec4125 100755
--- a/test/py/ganeti.block.bdev_unittest.py
+++ b/test/py/ganeti.block.bdev_unittest.py
@@ -104,12 +104,12 @@ class TestDRBD8Runner(testutils.GanetiTestCase):
 
   def testParserCreation(self):
     """Test drbdsetup show parser creation"""
-    drbd.DRBD8._GetShowParser()
+    drbd.DRBD8ShowInfo._GetShowParser()
 
   def testParser80(self):
     """Test drbdsetup show parser for disk and network version 8.0"""
     data = testutils.ReadTestData("bdev-drbd-8.0.txt")
-    result = drbd.DRBD8._GetDevInfo(data)
+    result = drbd.DRBD8ShowInfo.GetDevInfo(data)
     self.failUnless(self._has_disk(result, "/dev/xenvg/test.data",
                                    "/dev/xenvg/test.meta"),
                     "Wrong local disk info")
@@ -120,7 +120,7 @@ class TestDRBD8Runner(testutils.GanetiTestCase):
   def testParser83(self):
     """Test drbdsetup show parser for disk and network version 8.3"""
     data = testutils.ReadTestData("bdev-drbd-8.3.txt")
-    result = drbd.DRBD8._GetDevInfo(data)
+    result = drbd.DRBD8ShowInfo.GetDevInfo(data)
     self.failUnless(self._has_disk(result, "/dev/xenvg/test.data",
                                    "/dev/xenvg/test.meta"),
                     "Wrong local disk info")
@@ -131,7 +131,7 @@ class TestDRBD8Runner(testutils.GanetiTestCase):
   def testParserNetIP4(self):
     """Test drbdsetup show parser for IPv4 network"""
     data = testutils.ReadTestData("bdev-drbd-net-ip4.txt")
-    result = drbd.DRBD8._GetDevInfo(data)
+    result = drbd.DRBD8ShowInfo.GetDevInfo(data)
     self.failUnless(("local_dev" not in result and
                      "meta_dev" not in result and
                      "meta_index" not in result),
@@ -143,7 +143,7 @@ class TestDRBD8Runner(testutils.GanetiTestCase):
   def testParserNetIP6(self):
     """Test drbdsetup show parser for IPv6 network"""
     data = testutils.ReadTestData("bdev-drbd-net-ip6.txt")
-    result = drbd.DRBD8._GetDevInfo(data)
+    result = drbd.DRBD8ShowInfo.GetDevInfo(data)
     self.failUnless(("local_dev" not in result and
                      "meta_dev" not in result and
                      "meta_index" not in result),
@@ -155,7 +155,7 @@ class TestDRBD8Runner(testutils.GanetiTestCase):
   def testParserDisk(self):
     """Test drbdsetup show parser for disk"""
     data = testutils.ReadTestData("bdev-drbd-disk.txt")
-    result = drbd.DRBD8._GetDevInfo(data)
+    result = drbd.DRBD8ShowInfo.GetDevInfo(data)
     self.failUnless(self._has_disk(result, "/dev/xenvg/test.data",
                                    "/dev/xenvg/test.meta"),
                     "Wrong local disk info")