4 # Copyright (C) 2011, 2013 Google Inc.
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 # General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 """Script for testing ganeti.hypervisor.hv_xen"""
24 import string # pylint: disable=W0402
32 from ganeti import constants
33 from ganeti import objects
34 from ganeti import pathutils
35 from ganeti import hypervisor
36 from ganeti import utils
37 from ganeti import errors
38 from ganeti import compat
40 from ganeti.hypervisor import hv_xen
45 # Map from hypervisor class to hypervisor name
46 HVCLASS_TO_HVNAME = utils.InvertDict(hypervisor._HYPERVISOR_MAP)
49 class TestConsole(unittest.TestCase):
51 for cls in [hv_xen.XenPvmHypervisor, hv_xen.XenHvmHypervisor]:
52 instance = objects.Instance(name="xen.example.com",
53 primary_node="node24828")
54 cons = cls.GetInstanceConsole(instance, {}, {})
55 self.assertTrue(cons.Validate())
56 self.assertEqual(cons.kind, constants.CONS_SSH)
57 self.assertEqual(cons.host, instance.primary_node)
58 self.assertEqual(cons.command[-1], instance.name)
61 class TestCreateConfigCpus(unittest.TestCase):
63 for cpu_mask in [None, ""]:
64 self.assertEqual(hv_xen._CreateConfigCpus(cpu_mask),
68 self.assertEqual(hv_xen._CreateConfigCpus(constants.CPU_PINNING_ALL),
72 self.assertEqual(hv_xen._CreateConfigCpus("9"), "cpu = \"9\"")
74 def testMultiple(self):
75 self.assertEqual(hv_xen._CreateConfigCpus("0-2,4,5-5:3:all"),
76 ("cpus = [ \"0,1,2,4,5\", \"3\", \"%s\" ]" %
77 constants.CPU_PINNING_ALL_XEN))
80 class TestGetCommand(testutils.GanetiTestCase):
81 def testDefault(self):
83 hv = hv_xen.XenHypervisor()
84 self.assertEqual(hv._GetCommand(), expected_cmd)
86 def testCommandExplicit(self):
87 """Test the case when the command is given as class parameter explicitly.
91 hv = hv_xen.XenHypervisor(_cmd=constants.XEN_CMD_XL)
92 self.assertEqual(hv._GetCommand(), expected_cmd)
94 def testCommandInvalid(self):
95 """Test the case an invalid command is given as class parameter explicitly.
98 hv = hv_xen.XenHypervisor(_cmd="invalidcommand")
99 self.assertRaises(errors.ProgrammerError, hv._GetCommand, None)
101 def testCommandHvparams(self):
103 test_hvparams = {constants.HV_XEN_CMD: constants.XEN_CMD_XL}
104 hv = hv_xen.XenHypervisor()
105 self.assertEqual(hv._GetCommand(hvparams=test_hvparams), expected_cmd)
107 def testCommandHvparamsInvalid(self):
109 hv = hv_xen.XenHypervisor()
110 self.assertRaises(KeyError, hv._GetCommand, test_hvparams)
112 def testCommandHvparamsCmdInvalid(self):
113 test_hvparams = {constants.HV_XEN_CMD: "invalidcommand"}
114 hv = hv_xen.XenHypervisor()
115 self.assertRaises(errors.ProgrammerError, hv._GetCommand, test_hvparams)
118 class TestParseXmList(testutils.GanetiTestCase):
120 data = testutils.ReadTestData("xen-xm-list-4.0.1-dom0-only.txt")
123 self.assertEqual(hv_xen._ParseXmList(data.splitlines(), False), [])
126 result = hv_xen._ParseXmList(data.splitlines(), True)
127 self.assertEqual(len(result), 1)
128 self.assertEqual(len(result[0]), 6)
131 self.assertEqual(result[0][0], hv_xen._DOM0_NAME)
134 self.assertEqual(result[0][1], 0)
137 self.assertEqual(result[0][2], 1023)
140 self.assertEqual(result[0][3], 1)
143 self.assertEqual(result[0][4], "r-----")
146 self.assertAlmostEqual(result[0][5], 121152.6)
148 def testWrongLineFormat(self):
150 ["three fields only"],
151 ["name InvalidID 128 1 r----- 12345"],
156 hv_xen._ParseXmList(["Header would be here"] + lines, False)
157 except errors.HypervisorError, err:
158 self.assertTrue("Can't parse output of xm list" in str(err))
160 self.fail("Exception was not raised")
163 class TestGetInstanceList(testutils.GanetiTestCase):
165 return utils.RunResult(constants.EXIT_FAILURE, None,
166 "stdout", "stderr", None,
167 NotImplemented, NotImplemented)
169 def testTimeout(self):
170 fn = testutils.CallCounter(self._Fail)
172 hv_xen._GetInstanceList(fn, False, _timeout=0.1)
173 except errors.HypervisorError, err:
174 self.assertTrue("timeout exceeded" in str(err))
176 self.fail("Exception was not raised")
178 self.assertTrue(fn.Count() < 10,
179 msg="'xm list' was called too many times")
181 def _Success(self, stdout):
182 return utils.RunResult(constants.EXIT_SUCCESS, None, stdout, "", None,
183 NotImplemented, NotImplemented)
185 def testSuccess(self):
186 data = testutils.ReadTestData("xen-xm-list-4.0.1-four-instances.txt")
188 fn = testutils.CallCounter(compat.partial(self._Success, data))
190 result = hv_xen._GetInstanceList(fn, True, _timeout=0.1)
192 self.assertEqual(len(result), 4)
194 self.assertEqual(map(compat.fst, result), [
196 "server01.example.com",
197 "web3106215069.example.com",
198 "testinstance.example.com",
201 self.assertEqual(fn.Count(), 1)
204 class TestParseNodeInfo(testutils.GanetiTestCase):
206 self.assertEqual(hv_xen._ParseNodeInfo(""), {})
208 def testUnknownInput(self):
211 "something else goes",
214 self.assertEqual(hv_xen._ParseNodeInfo(data), {})
216 def testBasicInfo(self):
217 data = testutils.ReadTestData("xen-xm-info-4.0.1.txt")
218 result = hv_xen._ParseNodeInfo(data)
219 self.assertEqual(result, {
223 "hv_version": (4, 0),
225 "memory_total": 16378,
229 class TestMergeInstanceInfo(testutils.GanetiTestCase):
231 self.assertEqual(hv_xen._MergeInstanceInfo({}, lambda _: []), {})
233 def _FakeXmList(self, include_node):
234 self.assertTrue(include_node)
236 (hv_xen._DOM0_NAME, NotImplemented, 4096, 7, NotImplemented,
238 ("inst1.example.com", NotImplemented, 2048, 4, NotImplemented,
242 def testMissingNodeInfo(self):
243 result = hv_xen._MergeInstanceInfo({}, self._FakeXmList)
244 self.assertEqual(result, {
249 def testWithNodeInfo(self):
250 info = testutils.ReadTestData("xen-xm-info-4.0.1.txt")
251 result = hv_xen._GetNodeInfo(info, self._FakeXmList)
252 self.assertEqual(result, {
257 "hv_version": (4, 0),
261 "memory_total": 16378,
265 class TestGetConfigFileDiskData(unittest.TestCase):
266 def testLetterCount(self):
267 self.assertEqual(len(hv_xen._DISK_LETTERS), 26)
269 def testNoDisks(self):
270 self.assertEqual(hv_xen._GetConfigFileDiskData([], "hd"), [])
272 def testManyDisks(self):
273 for offset in [0, 1, 10]:
274 disks = [(objects.Disk(dev_type=constants.LD_LV), "/tmp/disk/%s" % idx)
275 for idx in range(len(hv_xen._DISK_LETTERS) + offset)]
278 result = hv_xen._GetConfigFileDiskData(disks, "hd")
279 self.assertEqual(result, [
280 "'phy:/tmp/disk/%s,hd%s,r'" % (idx, string.ascii_lowercase[idx])
281 for idx in range(len(hv_xen._DISK_LETTERS) + offset)
285 hv_xen._GetConfigFileDiskData(disks, "hd")
286 except errors.HypervisorError, err:
287 self.assertEqual(str(err), "Too many disks")
289 self.fail("Exception was not raised")
291 def testTwoLvDisksWithMode(self):
293 (objects.Disk(dev_type=constants.LD_LV, mode=constants.DISK_RDWR),
295 (objects.Disk(dev_type=constants.LD_LV, mode=constants.DISK_RDONLY),
299 result = hv_xen._GetConfigFileDiskData(disks, "hd")
300 self.assertEqual(result, [
301 "'phy:/tmp/diskFirst,hda,w'",
302 "'phy:/tmp/diskLast,hdb,r'",
305 def testFileDisks(self):
307 (objects.Disk(dev_type=constants.LD_FILE, mode=constants.DISK_RDWR,
308 physical_id=[constants.FD_LOOP]),
310 (objects.Disk(dev_type=constants.LD_FILE, mode=constants.DISK_RDONLY,
311 physical_id=[constants.FD_BLKTAP]),
313 (objects.Disk(dev_type=constants.LD_FILE, mode=constants.DISK_RDWR,
314 physical_id=[constants.FD_LOOP]),
316 (objects.Disk(dev_type=constants.LD_FILE, mode=constants.DISK_RDWR,
317 physical_id=[constants.FD_BLKTAP]),
321 result = hv_xen._GetConfigFileDiskData(disks, "sd")
322 self.assertEqual(result, [
323 "'file:/tmp/diskFirst,sda,w'",
324 "'tap:aio:/tmp/diskTwo,sdb,r'",
325 "'file:/tmp/diskThree,sdc,w'",
326 "'tap:aio:/tmp/diskLast,sdd,w'",
329 def testInvalidFileDisk(self):
331 (objects.Disk(dev_type=constants.LD_FILE, mode=constants.DISK_RDWR,
332 physical_id=["#unknown#"]),
336 self.assertRaises(KeyError, hv_xen._GetConfigFileDiskData, disks, "sd")
339 class TestXenHypervisorRunXen(unittest.TestCase):
343 def testCommandUnknown(self):
344 cmd = "#unknown command#"
345 self.assertFalse(cmd in constants.KNOWN_XEN_COMMANDS)
346 hv = hv_xen.XenHypervisor(_cfgdir=NotImplemented,
347 _run_cmd_fn=NotImplemented,
349 self.assertRaises(errors.ProgrammerError, hv._RunXen, [])
351 def testCommandValid(self):
353 mock_run_cmd = mock.Mock()
354 hv = hv_xen.XenHypervisor(_cfgdir=NotImplemented,
355 _run_cmd_fn=mock_run_cmd)
356 hv._RunXen([self.XEN_SUB_CMD])
357 mock_run_cmd.assert_called_with([xen_cmd, self.XEN_SUB_CMD])
359 def testCommandFromHvparams(self):
360 expected_xen_cmd = "xl"
361 hvparams = {constants.HV_XEN_CMD: constants.XEN_CMD_XL}
362 mock_run_cmd = mock.Mock()
363 hv = hv_xen.XenHypervisor(_cfgdir=NotImplemented,
364 _run_cmd_fn=mock_run_cmd)
365 hv._RunXen([self.XEN_SUB_CMD], hvparams=hvparams)
366 mock_run_cmd.assert_called_with([expected_xen_cmd, self.XEN_SUB_CMD])
369 class TestXenHypervisorGetInstanceList(unittest.TestCase):
371 RESULT_OK = utils.RunResult(0, None, "", "", "", None, None)
375 expected_xen_cmd = "xm"
376 mock_run_cmd = mock.Mock( return_value=self.RESULT_OK )
377 hv = hv_xen.XenHypervisor(_cfgdir=NotImplemented,
378 _run_cmd_fn=mock_run_cmd)
379 hv._GetInstanceList(True)
380 mock_run_cmd.assert_called_with([expected_xen_cmd, self.XEN_LIST])
382 def testFromHvparams(self):
383 expected_xen_cmd = "xl"
384 hvparams = {constants.HV_XEN_CMD: constants.XEN_CMD_XL}
385 mock_run_cmd = mock.Mock( return_value=self.RESULT_OK )
386 hv = hv_xen.XenHypervisor(_cfgdir=NotImplemented,
387 _run_cmd_fn=mock_run_cmd)
388 hv._GetInstanceList(True, hvparams=hvparams)
389 mock_run_cmd.assert_called_with([expected_xen_cmd, self.XEN_LIST])
392 class TestXenHypervisorListInstances(unittest.TestCase):
394 RESULT_OK = utils.RunResult(0, None, "", "", "", None, None)
397 def testDefaultXm(self):
398 expected_xen_cmd = "xm"
399 mock_run_cmd = mock.Mock( return_value=self.RESULT_OK )
400 hv = hv_xen.XenHypervisor(_cfgdir=NotImplemented,
401 _run_cmd_fn=mock_run_cmd)
403 mock_run_cmd.assert_called_with([expected_xen_cmd, self.XEN_LIST])
405 def testHvparamsXl(self):
406 expected_xen_cmd = "xl"
407 hvparams = {constants.HV_XEN_CMD: constants.XEN_CMD_XL}
408 mock_run_cmd = mock.Mock( return_value=self.RESULT_OK )
409 hv = hv_xen.XenHypervisor(_cfgdir=NotImplemented,
410 _run_cmd_fn=mock_run_cmd)
411 hv.ListInstances(hvparams=hvparams)
412 mock_run_cmd.assert_called_with([expected_xen_cmd, self.XEN_LIST])
415 class TestXenHypervisorWriteConfigFile(unittest.TestCase):
417 self.tmpdir = tempfile.mkdtemp()
420 shutil.rmtree(self.tmpdir)
422 def testWriteError(self):
423 cfgdir = utils.PathJoin(self.tmpdir, "foobar")
425 hv = hv_xen.XenHypervisor(_cfgdir=cfgdir,
426 _run_cmd_fn=NotImplemented,
429 self.assertFalse(os.path.exists(cfgdir))
432 hv._WriteConfigFile("name", "data")
433 except errors.HypervisorError, err:
434 self.assertTrue(str(err).startswith("Cannot write Xen instance"))
436 self.fail("Exception was not raised")
439 class _TestXenHypervisor(object):
440 TARGET = NotImplemented
442 HVNAME = NotImplemented
445 super(_TestXenHypervisor, self).setUp()
447 self.tmpdir = tempfile.mkdtemp()
449 self.vncpw = "".join(random.sample(string.ascii_letters, 10))
451 self.vncpw_path = utils.PathJoin(self.tmpdir, "vncpw")
452 utils.WriteFile(self.vncpw_path, data=self.vncpw)
455 super(_TestXenHypervisor, self).tearDown()
457 shutil.rmtree(self.tmpdir)
459 def _GetHv(self, run_cmd=NotImplemented):
460 return self.TARGET(_cfgdir=self.tmpdir, _run_cmd_fn=run_cmd, _cmd=self.CMD)
462 def _SuccessCommand(self, stdout, cmd):
463 self.assertEqual(cmd[0], self.CMD)
465 return utils.RunResult(constants.EXIT_SUCCESS, None, stdout, "", None,
466 NotImplemented, NotImplemented)
468 def _FailingCommand(self, cmd):
469 self.assertEqual(cmd[0], self.CMD)
471 return utils.RunResult(constants.EXIT_FAILURE, None,
472 "", "This command failed", None,
473 NotImplemented, NotImplemented)
475 def _FakeTcpPing(self, expected, result, target, port, **kwargs):
476 self.assertEqual((target, port), expected)
479 def testReadingNonExistentConfigFile(self):
483 hv._ReadConfigFile("inst15780.example.com")
484 except errors.HypervisorError, err:
485 self.assertTrue(str(err).startswith("Failed to load Xen config file:"))
487 self.fail("Exception was not raised")
489 def testRemovingAutoConfigFile(self):
490 name = "inst8206.example.com"
491 cfgfile = utils.PathJoin(self.tmpdir, name)
492 autodir = utils.PathJoin(self.tmpdir, "auto")
493 autocfgfile = utils.PathJoin(autodir, name)
497 utils.WriteFile(autocfgfile, data="")
501 self.assertTrue(os.path.isfile(autocfgfile))
502 hv._WriteConfigFile(name, "content")
503 self.assertFalse(os.path.exists(autocfgfile))
504 self.assertEqual(utils.ReadFile(cfgfile), "content")
506 def _XenList(self, cmd):
507 self.assertEqual(cmd, [self.CMD, "list"])
509 # TODO: Use actual data from "xl" command
510 output = testutils.ReadTestData("xen-xm-list-4.0.1-four-instances.txt")
512 return self._SuccessCommand(output, cmd)
514 def testGetInstanceInfo(self):
515 hv = self._GetHv(run_cmd=self._XenList)
517 (name, instid, memory, vcpus, state, runtime) = \
518 hv.GetInstanceInfo("server01.example.com")
520 self.assertEqual(name, "server01.example.com")
521 self.assertEqual(instid, 1)
522 self.assertEqual(memory, 1024)
523 self.assertEqual(vcpus, 1)
524 self.assertEqual(state, "-b----")
525 self.assertAlmostEqual(runtime, 167643.2)
527 def testGetInstanceInfoDom0(self):
528 hv = self._GetHv(run_cmd=self._XenList)
530 # TODO: Not sure if this is actually used anywhere (can't find it), but the
531 # code supports querying for Dom0
532 (name, instid, memory, vcpus, state, runtime) = \
533 hv.GetInstanceInfo(hv_xen._DOM0_NAME)
535 self.assertEqual(name, "Domain-0")
536 self.assertEqual(instid, 0)
537 self.assertEqual(memory, 1023)
538 self.assertEqual(vcpus, 1)
539 self.assertEqual(state, "r-----")
540 self.assertAlmostEqual(runtime, 154706.1)
542 def testGetInstanceInfoUnknown(self):
543 hv = self._GetHv(run_cmd=self._XenList)
545 result = hv.GetInstanceInfo("unknown.example.com")
546 self.assertTrue(result is None)
548 def testGetAllInstancesInfo(self):
549 hv = self._GetHv(run_cmd=self._XenList)
551 result = hv.GetAllInstancesInfo()
553 self.assertEqual(map(compat.fst, result), [
554 "server01.example.com",
555 "web3106215069.example.com",
556 "testinstance.example.com",
559 def testListInstances(self):
560 hv = self._GetHv(run_cmd=self._XenList)
562 self.assertEqual(hv.ListInstances(), [
563 "server01.example.com",
564 "web3106215069.example.com",
565 "testinstance.example.com",
568 def testVerify(self):
569 output = testutils.ReadTestData("xen-xm-info-4.0.1.txt")
570 hv = self._GetHv(run_cmd=compat.partial(self._SuccessCommand,
572 self.assertTrue(hv.Verify() is None)
574 def testVerifyFailing(self):
575 hv = self._GetHv(run_cmd=self._FailingCommand)
576 self.assertTrue("failed:" in hv.Verify())
578 def _StartInstanceCommand(self, inst, paused, failcreate, cmd):
579 if cmd == [self.CMD, "info"]:
580 output = testutils.ReadTestData("xen-xm-info-4.0.1.txt")
581 elif cmd == [self.CMD, "list"]:
582 output = testutils.ReadTestData("xen-xm-list-4.0.1-dom0-only.txt")
583 elif cmd[:2] == [self.CMD, "create"]:
585 cfgfile = utils.PathJoin(self.tmpdir, inst.name)
588 self.assertEqual(args, ["-p", cfgfile])
590 self.assertEqual(args, [cfgfile])
593 return self._FailingCommand(cmd)
597 self.fail("Unhandled command: %s" % (cmd, ))
599 return self._SuccessCommand(output, cmd)
601 def _MakeInstance(self):
602 # Copy default parameters
603 bep = objects.FillDict(constants.BEC_DEFAULTS, {})
604 hvp = objects.FillDict(constants.HVC_DEFAULTS[self.HVNAME], {})
606 # Override default VNC password file path
607 if constants.HV_VNC_PASSWORD_FILE in hvp:
608 hvp[constants.HV_VNC_PASSWORD_FILE] = self.vncpw_path
611 (objects.Disk(dev_type=constants.LD_LV, mode=constants.DISK_RDWR),
612 utils.PathJoin(self.tmpdir, "disk0")),
613 (objects.Disk(dev_type=constants.LD_LV, mode=constants.DISK_RDONLY),
614 utils.PathJoin(self.tmpdir, "disk1")),
617 inst = objects.Instance(name="server01.example.com",
618 hvparams=hvp, beparams=bep,
619 osparams={}, nics=[], os="deb1",
620 disks=map(compat.fst, disks))
625 def testStartInstance(self):
626 (inst, disks) = self._MakeInstance()
627 pathutils.LOG_XEN_DIR = self.tmpdir
629 for failcreate in [False, True]:
630 for paused in [False, True]:
631 run_cmd = compat.partial(self._StartInstanceCommand,
632 inst, paused, failcreate)
634 hv = self._GetHv(run_cmd=run_cmd)
636 # Ensure instance is not listed
637 self.assertTrue(inst.name not in hv.ListInstances())
639 # Remove configuration
640 cfgfile = utils.PathJoin(self.tmpdir, inst.name)
641 utils.RemoveFile(cfgfile)
644 self.assertRaises(errors.HypervisorError, hv.StartInstance,
646 # Check whether a stale config file is left behind
647 self.assertFalse(os.path.exists(cfgfile))
649 hv.StartInstance(inst, disks, paused)
650 # Check if configuration was updated
651 lines = utils.ReadFile(cfgfile).splitlines()
653 if constants.HV_VNC_PASSWORD_FILE in inst.hvparams:
654 self.assertTrue(("vncpasswd = '%s'" % self.vncpw) in lines)
656 extra = inst.hvparams[constants.HV_KERNEL_ARGS]
657 self.assertTrue(("extra = '%s'" % extra) in lines)
659 def _StopInstanceCommand(self, instance_name, force, fail, cmd):
660 if ((force and cmd[:2] == [self.CMD, "destroy"]) or
661 (not force and cmd[:2] == [self.CMD, "shutdown"])):
662 self.assertEqual(cmd[2:], [instance_name])
665 self.fail("Unhandled command: %s" % (cmd, ))
668 # Simulate a failing command
669 return self._FailingCommand(cmd)
671 return self._SuccessCommand(output, cmd)
673 def testStopInstance(self):
674 name = "inst4284.example.com"
675 cfgfile = utils.PathJoin(self.tmpdir, name)
676 cfgdata = "config file content\n"
678 for force in [False, True]:
679 for fail in [False, True]:
680 utils.WriteFile(cfgfile, data=cfgdata)
682 run_cmd = compat.partial(self._StopInstanceCommand, name, force, fail)
684 hv = self._GetHv(run_cmd=run_cmd)
686 self.assertTrue(os.path.isfile(cfgfile))
690 hv._StopInstance(name, force, None)
691 except errors.HypervisorError, err:
692 self.assertTrue(str(err).startswith("Failed to stop instance"))
694 self.fail("Exception was not raised")
695 self.assertEqual(utils.ReadFile(cfgfile), cfgdata,
696 msg=("Configuration was removed when stopping"
699 hv._StopInstance(name, force, None)
700 self.assertFalse(os.path.exists(cfgfile))
702 def _MigrateNonRunningInstCmd(self, cmd):
703 if cmd == [self.CMD, "list"]:
704 output = testutils.ReadTestData("xen-xm-list-4.0.1-dom0-only.txt")
706 self.fail("Unhandled command: %s" % (cmd, ))
708 return self._SuccessCommand(output, cmd)
710 def testMigrateInstanceNotRunning(self):
711 name = "nonexistinginstance.example.com"
712 target = constants.IP4_ADDRESS_LOCALHOST
715 hv = self._GetHv(run_cmd=self._MigrateNonRunningInstCmd)
717 for live in [False, True]:
719 hv._MigrateInstance(NotImplemented, name, target, port, live,
720 _ping_fn=NotImplemented)
721 except errors.HypervisorError, err:
722 self.assertEqual(str(err), "Instance not running, cannot migrate")
724 self.fail("Exception was not raised")
726 def _MigrateInstTargetUnreachCmd(self, cmd):
727 if cmd == [self.CMD, "list"]:
728 output = testutils.ReadTestData("xen-xm-list-4.0.1-four-instances.txt")
730 self.fail("Unhandled command: %s" % (cmd, ))
732 return self._SuccessCommand(output, cmd)
734 def testMigrateTargetUnreachable(self):
735 name = "server01.example.com"
736 target = constants.IP4_ADDRESS_LOCALHOST
739 hv = self._GetHv(run_cmd=self._MigrateInstTargetUnreachCmd)
741 for live in [False, True]:
742 if self.CMD == constants.XEN_CMD_XL:
743 # TODO: Detect unreachable targets
747 hv._MigrateInstance(NotImplemented, name, target, port, live,
748 _ping_fn=compat.partial(self._FakeTcpPing,
749 (target, port), False))
750 except errors.HypervisorError, err:
751 wanted = "Remote host %s not" % target
752 self.assertTrue(str(err).startswith(wanted))
754 self.fail("Exception was not raised")
756 def _MigrateInstanceCmd(self, cluster_name, instance_name, target, port,
758 if cmd == [self.CMD, "list"]:
759 output = testutils.ReadTestData("xen-xm-list-4.0.1-four-instances.txt")
760 elif cmd[:2] == [self.CMD, "migrate"]:
761 if self.CMD == constants.XEN_CMD_XM:
762 args = ["-p", str(port)]
767 elif self.CMD == constants.XEN_CMD_XL:
769 "-s", constants.XL_SSH_CMD % cluster_name,
770 "-C", utils.PathJoin(self.tmpdir, instance_name),
774 self.fail("Unknown Xen command '%s'" % self.CMD)
776 args.extend([instance_name, target])
777 self.assertEqual(cmd[2:], args)
780 return self._FailingCommand(cmd)
784 self.fail("Unhandled command: %s" % (cmd, ))
786 return self._SuccessCommand(output, cmd)
788 def testMigrateInstance(self):
789 clustername = "cluster.example.com"
790 instname = "server01.example.com"
791 target = constants.IP4_ADDRESS_LOCALHOST
794 for live in [False, True]:
795 for fail in [False, True]:
797 testutils.CallCounter(compat.partial(self._FakeTcpPing,
798 (target, port), True))
801 compat.partial(self._MigrateInstanceCmd,
802 clustername, instname, target, port, live,
805 hv = self._GetHv(run_cmd=run_cmd)
809 hv._MigrateInstance(clustername, instname, target, port, live,
811 except errors.HypervisorError, err:
812 self.assertTrue(str(err).startswith("Failed to migrate instance"))
814 self.fail("Exception was not raised")
816 hv._MigrateInstance(clustername, instname, target, port, live,
819 if self.CMD == constants.XEN_CMD_XM:
824 self.assertEqual(ping_fn.Count(), expected_pings)
826 def _GetNodeInfoCmd(self, fail, cmd):
827 if cmd == [self.CMD, "info"]:
829 return self._FailingCommand(cmd)
831 output = testutils.ReadTestData("xen-xm-info-4.0.1.txt")
832 elif cmd == [self.CMD, "list"]:
834 self.fail("'xm list' shouldn't be called when 'xm info' failed")
836 output = testutils.ReadTestData("xen-xm-list-4.0.1-four-instances.txt")
838 self.fail("Unhandled command: %s" % (cmd, ))
840 return self._SuccessCommand(output, cmd)
842 def testGetNodeInfo(self):
843 run_cmd = compat.partial(self._GetNodeInfoCmd, False)
844 hv = self._GetHv(run_cmd=run_cmd)
845 result = hv.GetNodeInfo()
847 self.assertEqual(result["hv_version"], (4, 0))
848 self.assertEqual(result["memory_free"], 8004)
850 def testGetNodeInfoFailing(self):
851 run_cmd = compat.partial(self._GetNodeInfoCmd, True)
852 hv = self._GetHv(run_cmd=run_cmd)
853 self.assertTrue(hv.GetNodeInfo() is None)
856 def _MakeTestClass(cls, cmd):
857 """Makes a class for testing.
859 The returned class has structure as shown in the following pseudo code:
861 class Test{cls.__name__}{cmd}(_TestXenHypervisor, unittest.TestCase):
864 HVNAME = {Hypervisor name retrieved using class}
867 @param cls: Hypervisor class to be tested
869 @param cmd: Hypervisor command
871 @return: Class name and class object (not instance)
874 name = "Test%sCmd%s" % (cls.__name__, cmd.title())
875 bases = (_TestXenHypervisor, unittest.TestCase)
876 hvname = HVCLASS_TO_HVNAME[cls]
878 return (name, type(name, bases, dict(TARGET=cls, CMD=cmd, HVNAME=hvname)))
881 # Create test classes programmatically instead of manually to reduce the risk
882 # of forgetting some combinations
883 for cls in [hv_xen.XenPvmHypervisor, hv_xen.XenHvmHypervisor]:
884 for cmd in constants.KNOWN_XEN_COMMANDS:
885 (name, testcls) = _MakeTestClass(cls, cmd)
887 assert name not in locals()
889 locals()[name] = testcls
892 if __name__ == "__main__":
893 testutils.GanetiTestProgram()