#!/usr/bin/python
#
-# Copyright (C) 2006, 2007 Google Inc.
+# Copyright (C) 2006, 2007, 2010 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
"""Script for unittesting the bdev module"""
+import os
import unittest
from ganeti import bdev
+from ganeti import errors
+from ganeti import constants
+import testutils
-class TestDRBD8Runner(unittest.TestCase):
+
+class TestBaseDRBD(testutils.GanetiTestCase):
+ def testGetVersion(self):
+ data = [
+ ["version: 8.0.12 (api:76/proto:86-91)"],
+ ["version: 8.2.7 (api:88/proto:0-100)"],
+ ["version: 8.3.7.49 (api:188/proto:13-191)"],
+ ]
+ result = [
+ {
+ "k_major": 8,
+ "k_minor": 0,
+ "k_point": 12,
+ "api": 76,
+ "proto": 86,
+ "proto2": "91",
+ },
+ {
+ "k_major": 8,
+ "k_minor": 2,
+ "k_point": 7,
+ "api": 88,
+ "proto": 0,
+ "proto2": "100",
+ },
+ {
+ "k_major": 8,
+ "k_minor": 3,
+ "k_point": 7,
+ "api": 188,
+ "proto": 13,
+ "proto2": "191",
+ }
+ ]
+ for d,r in zip(data, result):
+ self.assertEqual(bdev.BaseDRBD._GetVersion(d), r)
+
+
+class TestDRBD8Runner(testutils.GanetiTestCase):
"""Testing case for DRBD8"""
@staticmethod
"""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()
+ def testParser80(self):
+ """Test drbdsetup show parser for disk and network version 8.0"""
+ data = self._ReadTestData("bdev-drbd-8.0.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.0.2.1", 11000),
+ ("192.0.2.2", 11000)),
+ "Wrong network info (8.0.x)")
+
+ def testParser83(self):
+ """Test drbdsetup show parser for disk and network version 8.3"""
+ data = self._ReadTestData("bdev-drbd-8.3.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")
+ self.failUnless(self._has_net(result, ("192.0.2.1", 11000),
+ ("192.0.2.2", 11000)),
+ "Wrong network info (8.0.x)")
+
+ def testParserNetIP4(self):
+ """Test drbdsetup show parser for IPv4 network"""
+ data = self._ReadTestData("bdev-drbd-net-ip4.txt")
+ 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.0.2.1", 11002),
+ ("192.0.2.2", 11002)),
+ "Wrong network info (IPv4)")
- def testParserNet(self):
- """Test drbdsetup show parser for disk and network"""
- data = open("data/bdev-net.txt").read()
+ def testParserNetIP6(self):
+ """Test drbdsetup show parser for IPv6 network"""
+ data = self._ReadTestData("bdev-drbd-net-ip6.txt")
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")
+ self.failUnless(self._has_net(result, ("2001:db8:65::1", 11048),
+ ("2001:db8:66::1", 11048)),
+ "Wrong network info (IPv6)")
def testParserDisk(self):
- """Test drbdsetup show parser for disk and network"""
- data = open("data/bdev-disk.txt").read()
+ """Test drbdsetup show parser for disk"""
+ data = self._ReadTestData("bdev-drbd-disk.txt")
result = bdev.DRBD8._GetDevInfo(data)
self.failUnless(self._has_disk(result, "/dev/xenvg/test.data",
"/dev/xenvg/test.meta"),
"remote_addr" not in result),
"Should not find network info")
+ def testBarriersOptions(self):
+ """Test class method that generates drbdsetup options for disk barriers"""
+ # Tests that should fail because of wrong version/options combinations
+ should_fail = [
+ (8, 0, 12, "bfd", True),
+ (8, 0, 12, "fd", False),
+ (8, 0, 12, "b", True),
+ (8, 2, 7, "bfd", True),
+ (8, 2, 7, "b", True)
+ ]
+
+ for vmaj, vmin, vrel, opts, meta in should_fail:
+ self.assertRaises(errors.BlockDeviceError,
+ bdev.DRBD8._ComputeDiskBarrierArgs,
+ vmaj, vmin, vrel, opts, meta)
+
+ # get the valid options from the frozenset(frozenset()) in constants.
+ valid_options = [list(x)[0] for x in constants.DRBD_VALID_BARRIER_OPT]
+
+ # Versions that do not support anything
+ for vmaj, vmin, vrel in ((8, 0, 0), (8, 0, 11), (8, 2, 6)):
+ for opts in valid_options:
+ self.assertRaises(errors.BlockDeviceError,
+ bdev.DRBD8._ComputeDiskBarrierArgs,
+ vmaj, vmin, vrel, opts, True)
+
+ # Versions with partial support (testing only options that are supported)
+ tests = [
+ (8, 0, 12, "n", False, []),
+ (8, 0, 12, "n", True, ["--no-md-flushes"]),
+ (8, 2, 7, "n", False, []),
+ (8, 2, 7, "fd", False, ["--no-disk-flushes", "--no-disk-drain"]),
+ (8, 0, 12, "n", True, ["--no-md-flushes"]),
+ ]
+
+ # Versions that support everything
+ for vmaj, vmin, vrel in ((8, 3, 0), (8, 3, 12)):
+ tests.append((vmaj, vmin, vrel, "bfd", True,
+ ["--no-disk-barrier", "--no-disk-drain",
+ "--no-disk-flushes", "--no-md-flushes"]))
+ tests.append((vmaj, vmin, vrel, "n", False, []))
+ tests.append((vmaj, vmin, vrel, "b", True,
+ ["--no-disk-barrier", "--no-md-flushes"]))
+ tests.append((vmaj, vmin, vrel, "fd", False,
+ ["--no-disk-flushes", "--no-disk-drain"]))
+ tests.append((vmaj, vmin, vrel, "n", True, ["--no-md-flushes"]))
+
+ # Test execution
+ for test in tests:
+ vmaj, vmin, vrel, disabled_barriers, disable_meta_flush, expected = test
+ args = \
+ bdev.DRBD8._ComputeDiskBarrierArgs(vmaj, vmin, vrel,
+ disabled_barriers,
+ disable_meta_flush)
+ self.failUnless(set(args) == set(expected),
+ "For test %s, got wrong results %s" % (test, args))
+
+ # Unsupported or invalid versions
+ for vmaj, vmin, vrel in ((0, 7, 25), (9, 0, 0), (7, 0, 0), (8, 4, 0)):
+ self.assertRaises(errors.BlockDeviceError,
+ bdev.DRBD8._ComputeDiskBarrierArgs,
+ vmaj, vmin, vrel, "n", True)
+
+ # Invalid options
+ for option in ("", "c", "whatever", "nbdfc", "nf"):
+ self.assertRaises(errors.BlockDeviceError,
+ bdev.DRBD8._ComputeDiskBarrierArgs,
+ 8, 3, 11, option, True)
+
+
+class TestDRBD8Status(testutils.GanetiTestCase):
+ """Testing case for DRBD8 /proc status"""
+
+ def setUp(self):
+ """Read in txt data"""
+ testutils.GanetiTestCase.setUp(self)
+ proc_data = self._TestDataFilename("proc_drbd8.txt")
+ proc80e_data = self._TestDataFilename("proc_drbd80-emptyline.txt")
+ proc83_data = self._TestDataFilename("proc_drbd83.txt")
+ proc83_sync_data = self._TestDataFilename("proc_drbd83_sync.txt")
+ proc83_sync_krnl_data = \
+ self._TestDataFilename("proc_drbd83_sync_krnl2.6.39.txt")
+ self.proc_data = bdev.DRBD8._GetProcData(filename=proc_data)
+ self.proc80e_data = bdev.DRBD8._GetProcData(filename=proc80e_data)
+ self.proc83_data = bdev.DRBD8._GetProcData(filename=proc83_data)
+ self.proc83_sync_data = bdev.DRBD8._GetProcData(filename=proc83_sync_data)
+ self.proc83_sync_krnl_data = \
+ bdev.DRBD8._GetProcData(filename=proc83_sync_krnl_data)
+ self.mass_data = bdev.DRBD8._MassageProcData(self.proc_data)
+ self.mass80e_data = bdev.DRBD8._MassageProcData(self.proc80e_data)
+ self.mass83_data = bdev.DRBD8._MassageProcData(self.proc83_data)
+ self.mass83_sync_data = bdev.DRBD8._MassageProcData(self.proc83_sync_data)
+ self.mass83_sync_krnl_data = \
+ bdev.DRBD8._MassageProcData(self.proc83_sync_krnl_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 testHelper(self):
+ """Test reading usermode_helper in /sys."""
+ sys_drbd_helper = self._TestDataFilename("sys_drbd_usermode_helper.txt")
+ drbd_helper = bdev.DRBD8.GetUsermodeHelper(filename=sys_drbd_helper)
+ self.failUnlessEqual(drbd_helper, "/bin/true")
+
+ def testHelperIOErrors(self):
+ """Test handling of errors while reading usermode_helper in /sys."""
+ temp_file = self._CreateTempFile()
+ os.unlink(temp_file)
+ self.failUnlessRaises(errors.BlockDeviceError,
+ bdev.DRBD8.GetUsermodeHelper, filename=temp_file)
+
+ 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)
+ self.failUnless(3 not in self.mass80e_data)
+
+ def testLineNotMatch(self):
+ """Test wrong line passed to DRBD8Status"""
+ self.assertRaises(errors.BlockDeviceError, bdev.DRBD8Status, "foo")
+
+ def testMinor0(self):
+ """Test connected, primary device"""
+ 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"""
+ 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"""
+ for data in [self.mass_data, self.mass83_data, self.mass80e_data]:
+ stats = bdev.DRBD8Status(data[2])
+ self.failIf(stats.is_in_use)
+
+ def testMinor4(self):
+ """Test WFconn device"""
+ 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"""
+ 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"""
+ 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)
+
+ def testDRBD83SyncFine(self):
+ stats = bdev.DRBD8Status(self.mass83_sync_data[3])
+ self.failUnless(stats.is_in_resync)
+ self.failUnless(stats.sync_percent is not None)
+
+ def testDRBD83SyncBroken(self):
+ stats = bdev.DRBD8Status(self.mass83_sync_krnl_data[3])
+ self.failUnless(stats.is_in_resync)
+ self.failUnless(stats.sync_percent is not None)
+
if __name__ == '__main__':
- unittest.main()
+ testutils.GanetiTestProgram()