Fix compatibility with DRBD 8.3
authorIustin Pop <iustin@google.com>
Tue, 5 May 2009 10:48:50 +0000 (12:48 +0200)
committerIustin Pop <iustin@google.com>
Tue, 5 May 2009 13:19:44 +0000 (15:19 +0200)
DRBD 8.3 changes two more things compared to 8.2:
  - /proc/drbd format changed in multiple ways; the part we're
    interested is the ‘st:’ to ‘ro:‘ change (in the changelog named as
    “Renamed 'state' to 'role'”
  - “drbdsetup /dev/drbdN show” changed the ‘device’ stanza from:
      device "/dev/drbd0";
    to:
      device                  minor 0;

This patch fixes these both and adds data files and unittests for DRBD
8.3.1.

Signed-off-by: Iustin Pop <iustin@google.com>

lib/bdev.py
test/data/bdev-8.3-both.txt [new file with mode: 0644]
test/data/proc_drbd83.txt [new file with mode: 0644]
test/ganeti.bdev_unittest.py

index 94e8ab8..9d3f08b 100644 (file)
@@ -563,7 +563,7 @@ class DRBD8Status(object):
 
   """
   UNCONF_RE = re.compile(r"\s*[0-9]+:\s*cs:Unconfigured$")
-  LINE_RE = re.compile(r"\s*[0-9]+:\s*cs:(\S+)\s+st:([^/]+)/(\S+)"
+  LINE_RE = re.compile(r"\s*[0-9]+:\s*cs:(\S+)\s+(?:st|ro):([^/]+)/(\S+)"
                        "\s+ds:([^/]+)/(\S+)\s+.*$")
   SYNC_RE = re.compile(r"^.*\ssync'ed:\s*([0-9.]+)%.*"
                        "\sfinish: ([0-9]+):([0-9]+):([0-9]+)\s.*$")
@@ -903,10 +903,13 @@ class DRBD8(BaseDRBD):
     # meta device, extended syntax
     meta_value = ((value ^ quoted) + pyp.Literal('[').suppress() +
                   number + pyp.Word(']').suppress())
+    # device name, extended syntax
+    device_value = pyp.Literal("minor").suppress() + number
 
     # a statement
     stmt = (~rbrace + keyword + ~lbrace +
-            pyp.Optional(addr_port ^ value ^ quoted ^ meta_value) +
+            pyp.Optional(addr_port ^ value ^ quoted ^ meta_value ^
+                         device_value) +
             pyp.Optional(defa) + semi +
             pyp.Optional(pyp.restOfLine).suppress())
 
diff --git a/test/data/bdev-8.3-both.txt b/test/data/bdev-8.3-both.txt
new file mode 100644 (file)
index 0000000..bc6e741
--- /dev/null
@@ -0,0 +1,36 @@
+disk {
+       size                    0s _is_default; # bytes
+       on-io-error             detach;
+       fencing                 dont-care _is_default;
+       max-bio-bvecs           0 _is_default;
+}
+net {
+       timeout                 60 _is_default; # 1/10 seconds
+       max-epoch-size          2048 _is_default;
+       max-buffers             2048 _is_default;
+       unplug-watermark        128 _is_default;
+       connect-int             10 _is_default; # seconds
+       ping-int                10 _is_default; # seconds
+       sndbuf-size             131070 _is_default; # bytes
+       ko-count                0 _is_default;
+       after-sb-0pri           discard-zero-changes;
+       after-sb-1pri           consensus;
+       after-sb-2pri           disconnect _is_default;
+       rr-conflict             disconnect _is_default;
+       ping-timeout            5 _is_default; # 1/10 seconds
+}
+syncer {
+       rate                    61440k; # bytes/second
+       after                   -1 _is_default;
+       al-extents              257;
+}
+protocol C;
+_this_host {
+       device                  minor 0;
+       disk                    "/dev/xenvg/test.data";
+       meta-disk               "/dev/xenvg/test.meta" [ 0 ];
+       address                 ipv4 192.168.1.1:11000;
+}
+_remote_host {
+       address                 ipv4 192.168.1.2:11000;
+}
diff --git a/test/data/proc_drbd83.txt b/test/data/proc_drbd83.txt
new file mode 100644 (file)
index 0000000..114944c
Binary files /dev/null and b/test/data/proc_drbd83.txt differ
index 2db785c..b2299b1 100755 (executable)
@@ -61,7 +61,7 @@ class TestDRBD8Runner(testutils.GanetiTestCase):
     """Test drbdsetup show parser creation"""
     bdev.DRBD8._GetShowParser()
 
-  def testParserBoth(self):
+  def testParserBoth80(self):
     """Test drbdsetup show parser for disk and network"""
     data = self._ReadTestData("bdev-both.txt")
     result = bdev.DRBD8._GetDevInfo(data)
@@ -70,7 +70,18 @@ class TestDRBD8Runner(testutils.GanetiTestCase):
                     "Wrong local disk info")
     self.failUnless(self._has_net(result, ("192.168.1.1", 11000),
                                   ("192.168.1.2", 11000)),
-                    "Wrong network info")
+                    "Wrong network info (8.0.x)")
+
+  def testParserBoth83(self):
+    """Test drbdsetup show parser for disk and network"""
+    data = self._ReadTestData("bdev-8.3-both.txt")
+    result = bdev.DRBD8._GetDevInfo(data)
+    self.failUnless(self._has_disk(result, "/dev/xenvg/test.data",
+                                   "/dev/xenvg/test.meta"),
+                    "Wrong local disk info")
+    self.failUnless(self._has_net(result, ("192.168.1.1", 11000),
+                                  ("192.168.1.2", 11000)),
+                    "Wrong network info (8.2.x)")
 
   def testParserNet(self):
     """Test drbdsetup show parser for disk and network"""
@@ -103,8 +114,11 @@ class TestDRBD8Status(testutils.GanetiTestCase):
     """Read in txt data"""
     testutils.GanetiTestCase.setUp(self)
     proc_data = self._TestDataFilename("proc_drbd8.txt")
+    proc83_data = self._TestDataFilename("proc_drbd83.txt")
     self.proc_data = bdev.DRBD8._GetProcData(filename=proc_data)
+    self.proc83_data = bdev.DRBD8._GetProcData(filename=proc83_data)
     self.mass_data = bdev.DRBD8._MassageProcData(self.proc_data)
+    self.mass83_data = bdev.DRBD8._MassageProcData(self.proc83_data)
 
   def testIOErrors(self):
     """Test handling of errors while reading the proc file."""
@@ -116,6 +130,7 @@ class TestDRBD8Status(testutils.GanetiTestCase):
   def testMinorNotFound(self):
     """Test not-found-minor in /proc"""
     self.failUnless(9 not in self.mass_data)
+    self.failUnless(9 not in self.mass83_data)
 
   def testLineNotMatch(self):
     """Test wrong line passed to DRBD8Status"""
@@ -123,45 +138,51 @@ class TestDRBD8Status(testutils.GanetiTestCase):
 
   def testMinor0(self):
     """Test connected, primary device"""
-    stats = bdev.DRBD8Status(self.mass_data[0])
-    self.failUnless(stats.is_in_use)
-    self.failUnless(stats.is_connected and stats.is_primary and
-                    stats.peer_secondary and stats.is_disk_uptodate)
+    for data in [self.mass_data, self.mass83_data]:
+      stats = bdev.DRBD8Status(data[0])
+      self.failUnless(stats.is_in_use)
+      self.failUnless(stats.is_connected and stats.is_primary and
+                      stats.peer_secondary and stats.is_disk_uptodate)
 
   def testMinor1(self):
     """Test connected, secondary device"""
-    stats = bdev.DRBD8Status(self.mass_data[1])
-    self.failUnless(stats.is_in_use)
-    self.failUnless(stats.is_connected and stats.is_secondary and
-                    stats.peer_primary and stats.is_disk_uptodate)
+    for data in [self.mass_data, self.mass83_data]:
+      stats = bdev.DRBD8Status(data[1])
+      self.failUnless(stats.is_in_use)
+      self.failUnless(stats.is_connected and stats.is_secondary and
+                      stats.peer_primary and stats.is_disk_uptodate)
 
   def testMinor2(self):
     """Test unconfigured device"""
-    stats = bdev.DRBD8Status(self.mass_data[2])
-    self.failIf(stats.is_in_use)
+    for data in [self.mass_data, self.mass83_data]:
+      stats = bdev.DRBD8Status(data[2])
+      self.failIf(stats.is_in_use)
 
   def testMinor4(self):
     """Test WFconn device"""
-    stats = bdev.DRBD8Status(self.mass_data[4])
-    self.failUnless(stats.is_in_use)
-    self.failUnless(stats.is_wfconn and stats.is_primary and
-                    stats.rrole == 'Unknown' and
-                    stats.is_disk_uptodate)
+    for data in [self.mass_data, self.mass83_data]:
+      stats = bdev.DRBD8Status(data[4])
+      self.failUnless(stats.is_in_use)
+      self.failUnless(stats.is_wfconn and stats.is_primary and
+                      stats.rrole == 'Unknown' and
+                      stats.is_disk_uptodate)
 
   def testMinor6(self):
     """Test diskless device"""
-    stats = bdev.DRBD8Status(self.mass_data[6])
-    self.failUnless(stats.is_in_use)
-    self.failUnless(stats.is_connected and stats.is_secondary and
-                    stats.peer_primary and stats.is_diskless)
+    for data in [self.mass_data, self.mass83_data]:
+      stats = bdev.DRBD8Status(data[6])
+      self.failUnless(stats.is_in_use)
+      self.failUnless(stats.is_connected and stats.is_secondary and
+                      stats.peer_primary and stats.is_diskless)
 
   def testMinor8(self):
     """Test standalone device"""
-    stats = bdev.DRBD8Status(self.mass_data[8])
-    self.failUnless(stats.is_in_use)
-    self.failUnless(stats.is_standalone and
-                    stats.rrole == 'Unknown' and
-                    stats.is_disk_uptodate)
+    for data in [self.mass_data, self.mass83_data]:
+      stats = bdev.DRBD8Status(data[8])
+      self.failUnless(stats.is_in_use)
+      self.failUnless(stats.is_standalone and
+                      stats.rrole == 'Unknown' and
+                      stats.is_disk_uptodate)
 
 if __name__ == '__main__':
   unittest.main()