Commit 01e2ce3a authored by Iustin Pop's avatar Iustin Pop
Browse files

Fix compatibility with DRBD 8.3



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: default avatarIustin Pop <iustin@google.com>
parent 34e71fea
...@@ -563,7 +563,7 @@ class DRBD8Status(object): ...@@ -563,7 +563,7 @@ class DRBD8Status(object):
""" """
UNCONF_RE = re.compile(r"\s*[0-9]+:\s*cs:Unconfigured$") 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+.*$") "\s+ds:([^/]+)/(\S+)\s+.*$")
SYNC_RE = re.compile(r"^.*\ssync'ed:\s*([0-9.]+)%.*" SYNC_RE = re.compile(r"^.*\ssync'ed:\s*([0-9.]+)%.*"
"\sfinish: ([0-9]+):([0-9]+):([0-9]+)\s.*$") "\sfinish: ([0-9]+):([0-9]+):([0-9]+)\s.*$")
...@@ -903,10 +903,13 @@ class DRBD8(BaseDRBD): ...@@ -903,10 +903,13 @@ class DRBD8(BaseDRBD):
# meta device, extended syntax # meta device, extended syntax
meta_value = ((value ^ quoted) + pyp.Literal('[').suppress() + meta_value = ((value ^ quoted) + pyp.Literal('[').suppress() +
number + pyp.Word(']').suppress()) number + pyp.Word(']').suppress())
# device name, extended syntax
device_value = pyp.Literal("minor").suppress() + number
# a statement # a statement
stmt = (~rbrace + keyword + ~lbrace + 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(defa) + semi +
pyp.Optional(pyp.restOfLine).suppress()) pyp.Optional(pyp.restOfLine).suppress())
......
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;
}
...@@ -61,7 +61,7 @@ class TestDRBD8Runner(testutils.GanetiTestCase): ...@@ -61,7 +61,7 @@ class TestDRBD8Runner(testutils.GanetiTestCase):
"""Test drbdsetup show parser creation""" """Test drbdsetup show parser creation"""
bdev.DRBD8._GetShowParser() bdev.DRBD8._GetShowParser()
def testParserBoth(self): def testParserBoth80(self):
"""Test drbdsetup show parser for disk and network""" """Test drbdsetup show parser for disk and network"""
data = self._ReadTestData("bdev-both.txt") data = self._ReadTestData("bdev-both.txt")
result = bdev.DRBD8._GetDevInfo(data) result = bdev.DRBD8._GetDevInfo(data)
...@@ -70,7 +70,18 @@ class TestDRBD8Runner(testutils.GanetiTestCase): ...@@ -70,7 +70,18 @@ class TestDRBD8Runner(testutils.GanetiTestCase):
"Wrong local disk info") "Wrong local disk info")
self.failUnless(self._has_net(result, ("192.168.1.1", 11000), self.failUnless(self._has_net(result, ("192.168.1.1", 11000),
("192.168.1.2", 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): def testParserNet(self):
"""Test drbdsetup show parser for disk and network""" """Test drbdsetup show parser for disk and network"""
...@@ -103,8 +114,11 @@ class TestDRBD8Status(testutils.GanetiTestCase): ...@@ -103,8 +114,11 @@ class TestDRBD8Status(testutils.GanetiTestCase):
"""Read in txt data""" """Read in txt data"""
testutils.GanetiTestCase.setUp(self) testutils.GanetiTestCase.setUp(self)
proc_data = self._TestDataFilename("proc_drbd8.txt") proc_data = self._TestDataFilename("proc_drbd8.txt")
proc83_data = self._TestDataFilename("proc_drbd83.txt")
self.proc_data = bdev.DRBD8._GetProcData(filename=proc_data) 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.mass_data = bdev.DRBD8._MassageProcData(self.proc_data)
self.mass83_data = bdev.DRBD8._MassageProcData(self.proc83_data)
def testIOErrors(self): def testIOErrors(self):
"""Test handling of errors while reading the proc file.""" """Test handling of errors while reading the proc file."""
...@@ -116,6 +130,7 @@ class TestDRBD8Status(testutils.GanetiTestCase): ...@@ -116,6 +130,7 @@ class TestDRBD8Status(testutils.GanetiTestCase):
def testMinorNotFound(self): def testMinorNotFound(self):
"""Test not-found-minor in /proc""" """Test not-found-minor in /proc"""
self.failUnless(9 not in self.mass_data) self.failUnless(9 not in self.mass_data)
self.failUnless(9 not in self.mass83_data)
def testLineNotMatch(self): def testLineNotMatch(self):
"""Test wrong line passed to DRBD8Status""" """Test wrong line passed to DRBD8Status"""
...@@ -123,45 +138,51 @@ class TestDRBD8Status(testutils.GanetiTestCase): ...@@ -123,45 +138,51 @@ class TestDRBD8Status(testutils.GanetiTestCase):
def testMinor0(self): def testMinor0(self):
"""Test connected, primary device""" """Test connected, primary device"""
stats = bdev.DRBD8Status(self.mass_data[0]) for data in [self.mass_data, self.mass83_data]:
self.failUnless(stats.is_in_use) stats = bdev.DRBD8Status(data[0])
self.failUnless(stats.is_connected and stats.is_primary and self.failUnless(stats.is_in_use)
stats.peer_secondary and stats.is_disk_uptodate) self.failUnless(stats.is_connected and stats.is_primary and
stats.peer_secondary and stats.is_disk_uptodate)
def testMinor1(self): def testMinor1(self):
"""Test connected, secondary device""" """Test connected, secondary device"""
stats = bdev.DRBD8Status(self.mass_data[1]) for data in [self.mass_data, self.mass83_data]:
self.failUnless(stats.is_in_use) stats = bdev.DRBD8Status(data[1])
self.failUnless(stats.is_connected and stats.is_secondary and self.failUnless(stats.is_in_use)
stats.peer_primary and stats.is_disk_uptodate) self.failUnless(stats.is_connected and stats.is_secondary and
stats.peer_primary and stats.is_disk_uptodate)
def testMinor2(self): def testMinor2(self):
"""Test unconfigured device""" """Test unconfigured device"""
stats = bdev.DRBD8Status(self.mass_data[2]) for data in [self.mass_data, self.mass83_data]:
self.failIf(stats.is_in_use) stats = bdev.DRBD8Status(data[2])
self.failIf(stats.is_in_use)
def testMinor4(self): def testMinor4(self):
"""Test WFconn device""" """Test WFconn device"""
stats = bdev.DRBD8Status(self.mass_data[4]) for data in [self.mass_data, self.mass83_data]:
self.failUnless(stats.is_in_use) stats = bdev.DRBD8Status(data[4])
self.failUnless(stats.is_wfconn and stats.is_primary and self.failUnless(stats.is_in_use)
stats.rrole == 'Unknown' and self.failUnless(stats.is_wfconn and stats.is_primary and
stats.is_disk_uptodate) stats.rrole == 'Unknown' and
stats.is_disk_uptodate)
def testMinor6(self): def testMinor6(self):
"""Test diskless device""" """Test diskless device"""
stats = bdev.DRBD8Status(self.mass_data[6]) for data in [self.mass_data, self.mass83_data]:
self.failUnless(stats.is_in_use) stats = bdev.DRBD8Status(data[6])
self.failUnless(stats.is_connected and stats.is_secondary and self.failUnless(stats.is_in_use)
stats.peer_primary and stats.is_diskless) self.failUnless(stats.is_connected and stats.is_secondary and
stats.peer_primary and stats.is_diskless)
def testMinor8(self): def testMinor8(self):
"""Test standalone device""" """Test standalone device"""
stats = bdev.DRBD8Status(self.mass_data[8]) for data in [self.mass_data, self.mass83_data]:
self.failUnless(stats.is_in_use) stats = bdev.DRBD8Status(data[8])
self.failUnless(stats.is_standalone and self.failUnless(stats.is_in_use)
stats.rrole == 'Unknown' and self.failUnless(stats.is_standalone and
stats.is_disk_uptodate) stats.rrole == 'Unknown' and
stats.is_disk_uptodate)
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment