Merge branch 'devel-2.6'
[ganeti-local] / test / ganeti.cmdlib_unittest.py
index fe57980..3cb0c40 100755 (executable)
@@ -42,6 +42,7 @@ from ganeti import ht
 from ganeti import objects
 from ganeti import compat
 from ganeti import rpc
+from ganeti import locking
 from ganeti import pathutils
 from ganeti.masterd import iallocator
 from ganeti.hypervisor import hv_xen
@@ -108,23 +109,26 @@ class TestIAllocatorChecks(testutils.GanetiTestCase):
     c_i = lambda: cmdlib._CheckIAllocatorOrNode(lu, "iallocator", "node")
 
     # Neither node nor iallocator given
-    op.iallocator = None
-    op.node = None
-    c_i()
-    self.assertEqual(lu.op.iallocator, default_iallocator)
-    self.assertEqual(lu.op.node, None)
+    for n in (None, []):
+      op.iallocator = None
+      op.node = n
+      c_i()
+      self.assertEqual(lu.op.iallocator, default_iallocator)
+      self.assertEqual(lu.op.node, n)
 
     # Both, iallocator and node given
-    op.iallocator = "test"
-    op.node = "test"
-    self.assertRaises(errors.OpPrereqError, c_i)
+    for a in ("test", constants.DEFAULT_IALLOCATOR_SHORTCUT):
+      op.iallocator = a
+      op.node = "test"
+      self.assertRaises(errors.OpPrereqError, c_i)
 
     # Only iallocator given
-    op.iallocator = other_iallocator
-    op.node = None
-    c_i()
-    self.assertEqual(lu.op.iallocator, other_iallocator)
-    self.assertEqual(lu.op.node, None)
+    for n in (None, []):
+      op.iallocator = other_iallocator
+      op.node = n
+      c_i()
+      self.assertEqual(lu.op.iallocator, other_iallocator)
+      self.assertEqual(lu.op.node, n)
 
     # Only node given
     op.iallocator = None
@@ -133,6 +137,13 @@ class TestIAllocatorChecks(testutils.GanetiTestCase):
     self.assertEqual(lu.op.iallocator, None)
     self.assertEqual(lu.op.node, "node")
 
+    # Asked for default iallocator, no node given
+    op.iallocator = constants.DEFAULT_IALLOCATOR_SHORTCUT
+    op.node = None
+    c_i()
+    self.assertEqual(lu.op.iallocator, default_iallocator)
+    self.assertEqual(lu.op.node, None)
+
     # No node, iallocator or default iallocator
     op.iallocator = None
     op.node = None
@@ -1241,22 +1252,26 @@ class TestGenerateDiskTemplate(unittest.TestCase):
 
 
 class _ConfigForDiskWipe:
+  def __init__(self, exp_node):
+    self._exp_node = exp_node
+
   def SetDiskID(self, device, node):
     assert isinstance(device, objects.Disk)
-    assert node == "node1.example.com"
+    assert node == self._exp_node
 
 
 class _RpcForDiskWipe:
-  def __init__(self, pause_cb, wipe_cb):
+  def __init__(self, exp_node, pause_cb, wipe_cb):
+    self._exp_node = exp_node
     self._pause_cb = pause_cb
     self._wipe_cb = wipe_cb
 
   def call_blockdev_pause_resume_sync(self, node, disks, pause):
-    assert node == "node1.example.com"
+    assert node == self._exp_node
     return rpc.RpcResult(data=self._pause_cb(disks, pause))
 
   def call_blockdev_wipe(self, node, bdev, offset, size):
-    assert node == "node1.example.com"
+    assert node == self._exp_node
     return rpc.RpcResult(data=self._wipe_cb(bdev, offset, size))
 
 
@@ -1273,15 +1288,50 @@ class _DiskPauseTracker:
     return (True, [True] * len(disks))
 
 
+class _DiskWipeProgressTracker:
+  def __init__(self, start_offset):
+    self._start_offset = start_offset
+    self.progress = {}
+
+  def __call__(self, (disk, _), offset, size):
+    assert isinstance(offset, (long, int))
+    assert isinstance(size, (long, int))
+
+    max_chunk_size = (disk.size / 100.0 * constants.MIN_WIPE_CHUNK_PERCENT)
+
+    assert offset >= self._start_offset
+    assert (offset + size) <= disk.size
+
+    assert size > 0
+    assert size <= constants.MAX_WIPE_CHUNK
+    assert size <= max_chunk_size
+
+    assert offset == self._start_offset or disk.logical_id in self.progress
+
+    # Keep track of progress
+    cur_progress = self.progress.setdefault(disk.logical_id, self._start_offset)
+
+    assert cur_progress == offset
+
+    # Record progress
+    self.progress[disk.logical_id] += size
+
+    return (True, None)
+
+
 class TestWipeDisks(unittest.TestCase):
+  def _FailingPauseCb(self, (disks, _), pause):
+    self.assertEqual(len(disks), 3)
+    self.assertTrue(pause)
+    # Simulate an RPC error
+    return (False, "error")
+
   def testPauseFailure(self):
-    def _FailPause((disks, _), pause):
-      self.assertEqual(len(disks), 3)
-      self.assertTrue(pause)
-      return (False, "error")
+    node_name = "node1372.example.com"
 
-    lu = _FakeLU(rpc=_RpcForDiskWipe(_FailPause, NotImplemented),
-                 cfg=_ConfigForDiskWipe())
+    lu = _FakeLU(rpc=_RpcForDiskWipe(node_name, self._FailingPauseCb,
+                                     NotImplemented),
+                 cfg=_ConfigForDiskWipe(node_name))
 
     disks = [
       objects.Disk(dev_type=constants.LD_LV),
@@ -1290,21 +1340,23 @@ class TestWipeDisks(unittest.TestCase):
       ]
 
     instance = objects.Instance(name="inst21201",
-                                primary_node="node1.example.com",
+                                primary_node=node_name,
                                 disk_template=constants.DT_PLAIN,
                                 disks=disks)
 
     self.assertRaises(errors.OpExecError, cmdlib._WipeDisks, lu, instance)
 
+  def _FailingWipeCb(self, (disk, _), offset, size):
+    # This should only ever be called for the first disk
+    self.assertEqual(disk.logical_id, "disk0")
+    return (False, None)
+
   def testFailingWipe(self):
+    node_name = "node13445.example.com"
     pt = _DiskPauseTracker()
 
-    def _WipeCb((disk, _), offset, size):
-      assert disk.logical_id == "disk0"
-      return (False, None)
-
-    lu = _FakeLU(rpc=_RpcForDiskWipe(pt, _WipeCb),
-                 cfg=_ConfigForDiskWipe())
+    lu = _FakeLU(rpc=_RpcForDiskWipe(node_name, pt, self._FailingWipeCb),
+                 cfg=_ConfigForDiskWipe(node_name))
 
     disks = [
       objects.Disk(dev_type=constants.LD_LV, logical_id="disk0",
@@ -1315,7 +1367,7 @@ class TestWipeDisks(unittest.TestCase):
       ]
 
     instance = objects.Instance(name="inst562",
-                                primary_node="node1.example.com",
+                                primary_node=node_name,
                                 disk_template=constants.DT_PLAIN,
                                 disks=disks)
 
@@ -1326,6 +1378,7 @@ class TestWipeDisks(unittest.TestCase):
     else:
       self.fail("Did not raise exception")
 
+    # Check if all disks were paused and resumed
     self.assertEqual(pt.history, [
       ("disk0", 100 * 1024, True),
       ("disk1", 500 * 1024, True),
@@ -1335,87 +1388,74 @@ class TestWipeDisks(unittest.TestCase):
       ("disk2", 256, False),
       ])
 
-  def testNormalWipe(self):
-    for start_offset in [0, 280, 8895, 1563204]:
-      pt = _DiskPauseTracker()
-
-      progress = {}
+  def _PrepareWipeTest(self, start_offset, disks):
+    node_name = "node-with-offset%s.example.com" % start_offset
+    pauset = _DiskPauseTracker()
+    progresst = _DiskWipeProgressTracker(start_offset)
 
-      def _WipeCb((disk, _), offset, size):
-        assert isinstance(offset, (long, int))
-        assert isinstance(size, (long, int))
+    lu = _FakeLU(rpc=_RpcForDiskWipe(node_name, pauset, progresst),
+                 cfg=_ConfigForDiskWipe(node_name))
 
-        max_chunk_size = (disk.size / 100.0 * constants.MIN_WIPE_CHUNK_PERCENT)
+    instance = objects.Instance(name="inst3560",
+                                primary_node=node_name,
+                                disk_template=constants.DT_PLAIN,
+                                disks=disks)
 
-        self.assertTrue(offset >= start_offset)
-        self.assertTrue((offset + size) <= disk.size)
+    return (lu, instance, pauset, progresst)
 
-        self.assertTrue(size > 0)
-        self.assertTrue(size <= constants.MAX_WIPE_CHUNK)
-        self.assertTrue(size <= max_chunk_size)
+  def testNormalWipe(self):
+    disks = [
+      objects.Disk(dev_type=constants.LD_LV, logical_id="disk0", size=1024),
+      objects.Disk(dev_type=constants.LD_LV, logical_id="disk1",
+                   size=500 * 1024),
+      objects.Disk(dev_type=constants.LD_LV, logical_id="disk2", size=128),
+      objects.Disk(dev_type=constants.LD_LV, logical_id="disk3",
+                   size=constants.MAX_WIPE_CHUNK),
+      ]
 
-        self.assertTrue(offset == start_offset or disk.logical_id in progress)
+    (lu, instance, pauset, progresst) = self._PrepareWipeTest(0, disks)
 
-        # Keep track of progress
-        cur_progress = progress.setdefault(disk.logical_id, start_offset)
-        self.assertEqual(cur_progress, offset)
+    cmdlib._WipeDisks(lu, instance)
 
-        progress[disk.logical_id] += size
+    self.assertEqual(pauset.history, [
+      ("disk0", 1024, True),
+      ("disk1", 500 * 1024, True),
+      ("disk2", 128, True),
+      ("disk3", constants.MAX_WIPE_CHUNK, True),
+      ("disk0", 1024, False),
+      ("disk1", 500 * 1024, False),
+      ("disk2", 128, False),
+      ("disk3", constants.MAX_WIPE_CHUNK, False),
+      ])
 
-        return (True, None)
+    # Ensure the complete disk has been wiped
+    self.assertEqual(progresst.progress,
+                     dict((i.logical_id, i.size) for i in disks))
 
-      lu = _FakeLU(rpc=_RpcForDiskWipe(pt, _WipeCb),
-                   cfg=_ConfigForDiskWipe())
+  def testWipeWithStartOffset(self):
+    for start_offset in [0, 280, 8895, 1563204]:
+      disks = [
+        objects.Disk(dev_type=constants.LD_LV, logical_id="disk0",
+                     size=128),
+        objects.Disk(dev_type=constants.LD_LV, logical_id="disk1",
+                     size=start_offset + (100 * 1024)),
+        ]
 
-      if start_offset > 0:
-        disks = [
-          objects.Disk(dev_type=constants.LD_LV, logical_id="disk0",
-                       size=128),
-          objects.Disk(dev_type=constants.LD_LV, logical_id="disk1",
-                       size=start_offset + (100 * 1024)),
-          ]
-      else:
-        disks = [
-          objects.Disk(dev_type=constants.LD_LV, logical_id="disk0", size=1024),
-          objects.Disk(dev_type=constants.LD_LV, logical_id="disk1",
-                       size=500 * 1024),
-          objects.Disk(dev_type=constants.LD_LV, logical_id="disk2", size=128),
-          objects.Disk(dev_type=constants.LD_LV, logical_id="disk3",
-                       size=constants.MAX_WIPE_CHUNK),
-          ]
-
-      instance = objects.Instance(name="inst3560",
-                                  primary_node="node1.example.com",
-                                  disk_template=constants.DT_PLAIN,
-                                  disks=disks)
-
-      if start_offset > 0:
-        # Test start offset with only one disk
-        cmdlib._WipeDisks(lu, instance,
-                          disks=[(1, disks[1], start_offset)])
-        self.assertEqual(pt.history, [
-          ("disk1", start_offset + (100 * 1024), True),
-          ("disk1", start_offset + (100 * 1024), False),
-          ])
-        self.assertEqual(progress, {
-          "disk1": disks[1].size,
-          })
-      else:
-        cmdlib._WipeDisks(lu, instance)
+      (lu, instance, pauset, progresst) = \
+        self._PrepareWipeTest(start_offset, disks)
 
-        self.assertEqual(pt.history, [
-          ("disk0", 1024, True),
-          ("disk1", 500 * 1024, True),
-          ("disk2", 128, True),
-          ("disk3", constants.MAX_WIPE_CHUNK, True),
-          ("disk0", 1024, False),
-          ("disk1", 500 * 1024, False),
-          ("disk2", 128, False),
-          ("disk3", constants.MAX_WIPE_CHUNK, False),
-          ])
+      # Test start offset with only one disk
+      cmdlib._WipeDisks(lu, instance,
+                        disks=[(1, disks[1], start_offset)])
 
-        # Ensure the complete disk has been wiped
-        self.assertEqual(progress, dict((i.logical_id, i.size) for i in disks))
+      # Only the second disk may have been paused and wiped
+      self.assertEqual(pauset.history, [
+        ("disk1", start_offset + (100 * 1024), True),
+        ("disk1", start_offset + (100 * 1024), False),
+        ])
+      self.assertEqual(progresst.progress, {
+        "disk1": disks[1].size,
+        })
 
 
 class TestDiskSizeInBytesToMebibytes(unittest.TestCase):
@@ -1449,5 +1489,17 @@ class TestDiskSizeInBytesToMebibytes(unittest.TestCase):
         self.assertEqual(warnsize, (1024 * 1024) - j)
 
 
+class TestCopyLockList(unittest.TestCase):
+  def test(self):
+    self.assertEqual(cmdlib._CopyLockList([]), [])
+    self.assertEqual(cmdlib._CopyLockList(None), None)
+    self.assertEqual(cmdlib._CopyLockList(locking.ALL_SET), locking.ALL_SET)
+
+    names = ["foo", "bar"]
+    output = cmdlib._CopyLockList(names)
+    self.assertEqual(names, output)
+    self.assertNotEqual(id(names), id(output), msg="List was not copied")
+
+
 if __name__ == "__main__":
   testutils.GanetiTestProgram()