Skip to content
Snippets Groups Projects
Commit 3840729d authored by Iustin Pop's avatar Iustin Pop
Browse files

Add unittest for DRBD8 drdbsetup show parser

This patch changes the bdev.DRBD8._GetDevInfo to take a string instead
of a minor, separates the `drbdsetup show` invocation into a new
separate method (bdev.DRBD8._GetShowData) and modifies the rest of the
DRBD8 class to make the appropriate calls.

It also adds a unittest script and data files for testing various cases
of device output.

Reviewed-by: imsnah
parent f3a55c90
No related branches found
No related tags found
No related merge requests found
......@@ -1737,19 +1737,27 @@ class DRBD8(BaseDRBD):
return bnf
@classmethod
def _GetDevInfo(cls, minor):
"""Get 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.
def _GetShowData(cls, minor):
"""Return the `drbdsetup show` data for a minor.
"""
data = {}
result = utils.RunCmd(["drbdsetup", cls._DevPath(minor), "show"])
if result.failed:
logger.Error("Can't display the drbd config: %s" % result.fail_reason)
return data
out = result.stdout
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
......@@ -1881,7 +1889,7 @@ class DRBD8(BaseDRBD):
timeout = time.time() + 10
ok = False
while time.time() < timeout:
info = cls._GetDevInfo(minor)
info = cls._GetDevInfo(cls._GetShowData(minor))
if not "local_addr" in info or not "remote_addr" in info:
time.sleep(1)
continue
......@@ -1904,7 +1912,7 @@ class DRBD8(BaseDRBD):
raise errors.BlockDeviceError("Can't attach to dbrd8 during AddChildren")
if len(devices) != 2:
raise errors.BlockDeviceError("Need two devices for AddChildren")
info = self._GetDevInfo(self.minor)
info = self._GetDevInfo(self._GetShowData(self.minor))
if "local_dev" in info:
raise errors.BlockDeviceError("DRBD8 already attached to a local disk")
backend, meta = devices
......@@ -1930,7 +1938,7 @@ class DRBD8(BaseDRBD):
raise errors.BlockDeviceError("Can't attach to drbd8 during"
" RemoveChildren")
# early return if we don't actually have backing storage
info = self._GetDevInfo(self.minor)
info = self._GetDevInfo(self._GetShowData(self.minor))
if "local_dev" not in info:
return
if len(self._children) != 2:
......@@ -2083,7 +2091,7 @@ class DRBD8(BaseDRBD):
"""
for minor in self._GetUsedDevs():
info = self._GetDevInfo(minor)
info = self._GetDevInfo(self._GetShowData(minor))
match_l = self._MatchesLocal(info)
match_r = self._MatchesNet(info)
if match_l and match_r:
......@@ -2093,8 +2101,9 @@ class DRBD8(BaseDRBD):
(self._lhost, self._lport,
self._rhost, self._rport),
"C")
if res_r and self._MatchesNet(self._GetDevInfo(minor)):
break
if res_r:
if self._MatchesNet(self._GetDevInfo(self._GetShowData(minor))):
break
# the weakest case: we find something that is only net attached
# even though we were passed some children at init time
if match_r and "local_dev" not in info:
......@@ -2114,7 +2123,7 @@ class DRBD8(BaseDRBD):
# None)
if (self._AssembleNet(minor, (self._lhost, self._lport,
self._rhost, self._rport), "C") and
self._MatchesNet(self._GetDevInfo(minor))):
self._MatchesNet(self._GetDevInfo(self._GetShowData(minor)))):
break
else:
......
TESTS = \
ganeti.config_unittest.py \
ganeti.hooks_unittest.py \
ganeti.utils_unittest.py
ganeti.utils_unittest.py \
ganeti.bdev_unittest.py
TESTS_ENVIRONMENT = PYTHONPATH=.:$(top_builddir)
check-am: do-pre-check
......
disk {
size 0s _is_default; # bytes
on-io-error detach;
fencing dont-care _is_default;
}
net {
timeout 60 _is_default; # 1/10 seconds
max-epoch-size 16384;
max-buffers 16384;
unplug-watermark 128 _is_default;
connect-int 10 _is_default; # seconds
ping-int 10 _is_default; # seconds
sndbuf-size 8388608; # bytes
ko-count 0 _is_default;
after-sb-0pri disconnect _is_default;
after-sb-1pri disconnect _is_default;
after-sb-2pri disconnect _is_default;
rr-conflict disconnect _is_default;
ping-timeout 5 _is_default; # 1/10 seconds
}
syncer {
rate 30720k; # bytes/second
after -1 _is_default;
al-extents 257;
}
protocol A;
_this_host {
device "/dev/drbd63";
disk "/dev/xenvg/test.data";
meta-disk "/dev/xenvg/test.meta" [ 0 ];
address 192.168.1.1:11000;
}
_remote_host {
address 192.168.1.2:11000;
}
disk {
size 0s _is_default; # bytes
on-io-error detach;
fencing dont-care _is_default;
}
syncer {
rate 250k _is_default; # bytes/second
after -1 _is_default;
al-extents 257;
}
_this_host {
device "/dev/drbd58";
disk "/dev/xenvg/test.data";
meta-disk "/dev/xenvg/test.meta" [ 0 ];
}
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 disconnect _is_default;
after-sb-1pri disconnect _is_default;
after-sb-2pri disconnect _is_default;
rr-conflict disconnect _is_default;
ping-timeout 5 _is_default; # 1/10 seconds
}
syncer {
rate 250k _is_default; # bytes/second
after -1 _is_default;
al-extents 127 _is_default;
}
protocol C;
_this_host {
device "/dev/drbd59";
address 192.168.1.1:11002;
}
_remote_host {
address 192.168.1.2:11002;
}
#!/usr/bin/python
#
# Copyright (C) 2006, 2007 Google Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.
"""Script for unittesting the bdev module"""
import unittest
from ganeti import bdev
class TestDRBD8Runner(unittest.TestCase):
"""Testing case for DRBD8"""
@staticmethod
def _has_disk(data, dname, mname):
"""Check local disk corectness"""
retval = (
"local_dev" in data and
data["local_dev"] == dname and
"meta_dev" in data and
data["meta_dev"] == mname and
"meta_index" in data and
data["meta_index"] == 0
)
return retval
@staticmethod
def _has_net(data, local, remote):
"""Check network connection parameters"""
retval = (
"local_addr" in data and
data["local_addr"] == local and
"remote_addr" in data and
data["remote_addr"] == remote
)
return retval
def testParserCreation(self):
"""Test drbdsetup show parser creation"""
bdev.DRBD8._GetShowParser()
def testParserBoth(self):
"""Test drbdsetup show parser for disk and network"""
data = open("data/bdev-both.txt").read()
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")
def testParserNet(self):
"""Test drbdsetup show parser for disk and network"""
data = open("data/bdev-net.txt").read()
result = bdev.DRBD8._GetDevInfo(data)
self.failUnless(("local_dev" not in result and
"meta_dev" not in result and
"meta_index" not in result),
"Should not find local disk info")
self.failUnless(self._has_net(result, ("192.168.1.1", 11002),
("192.168.1.2", 11002)),
"Wrong network info")
def testParserDisk(self):
"""Test drbdsetup show parser for disk and network"""
data = open("data/bdev-disk.txt").read()
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(("local_addr" not in result and
"remote_addr" not in result),
"Should not find network info")
if __name__ == '__main__':
unittest.main()
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment