X-Git-Url: https://code.grnet.gr/git/ganeti-local/blobdiff_plain/74a50c4689c8f1f160f5f0a6fb6b4275ed922996..a08e181fe8847215f960db8661d31f32a9639da7:/test/py/ganeti.hypervisor.hv_xen_unittest.py diff --git a/test/py/ganeti.hypervisor.hv_xen_unittest.py b/test/py/ganeti.hypervisor.hv_xen_unittest.py index d226d10..057ac76 100755 --- a/test/py/ganeti.hypervisor.hv_xen_unittest.py +++ b/test/py/ganeti.hypervisor.hv_xen_unittest.py @@ -26,6 +26,7 @@ import unittest import tempfile import shutil import random +import os from ganeti import constants from ganeti import objects @@ -365,6 +366,356 @@ class _TestXenHypervisor(object): "", "This command failed", None, NotImplemented, NotImplemented) + def _FakeTcpPing(self, expected, result, target, port, **kwargs): + self.assertEqual((target, port), expected) + return result + + def testReadingNonExistentConfigFile(self): + hv = self._GetHv() + + try: + hv._ReadConfigFile("inst15780.example.com") + except errors.HypervisorError, err: + self.assertTrue(str(err).startswith("Failed to load Xen config file:")) + else: + self.fail("Exception was not raised") + + def testRemovingAutoConfigFile(self): + name = "inst8206.example.com" + cfgfile = utils.PathJoin(self.tmpdir, name) + autodir = utils.PathJoin(self.tmpdir, "auto") + autocfgfile = utils.PathJoin(autodir, name) + + os.mkdir(autodir) + + utils.WriteFile(autocfgfile, data="") + + hv = self._GetHv() + + self.assertTrue(os.path.isfile(autocfgfile)) + hv._WriteConfigFile(name, "content") + self.assertFalse(os.path.exists(autocfgfile)) + self.assertEqual(utils.ReadFile(cfgfile), "content") + + def _XenList(self, cmd): + self.assertEqual(cmd, [self.CMD, "list"]) + + # TODO: Use actual data from "xl" command + output = testutils.ReadTestData("xen-xm-list-4.0.1-four-instances.txt") + + return self._SuccessCommand(output, cmd) + + def testGetInstanceInfo(self): + hv = self._GetHv(run_cmd=self._XenList) + + (name, instid, memory, vcpus, state, runtime) = \ + hv.GetInstanceInfo("server01.example.com") + + self.assertEqual(name, "server01.example.com") + self.assertEqual(instid, 1) + self.assertEqual(memory, 1024) + self.assertEqual(vcpus, 1) + self.assertEqual(state, "-b----") + self.assertAlmostEqual(runtime, 167643.2) + + def testGetInstanceInfoDom0(self): + hv = self._GetHv(run_cmd=self._XenList) + + # TODO: Not sure if this is actually used anywhere (can't find it), but the + # code supports querying for Dom0 + (name, instid, memory, vcpus, state, runtime) = \ + hv.GetInstanceInfo(hv_xen._DOM0_NAME) + + self.assertEqual(name, "Domain-0") + self.assertEqual(instid, 0) + self.assertEqual(memory, 1023) + self.assertEqual(vcpus, 1) + self.assertEqual(state, "r-----") + self.assertAlmostEqual(runtime, 154706.1) + + def testGetInstanceInfoUnknown(self): + hv = self._GetHv(run_cmd=self._XenList) + + result = hv.GetInstanceInfo("unknown.example.com") + self.assertTrue(result is None) + + def testGetAllInstancesInfo(self): + hv = self._GetHv(run_cmd=self._XenList) + + result = hv.GetAllInstancesInfo() + + self.assertEqual(map(compat.fst, result), [ + "server01.example.com", + "web3106215069.example.com", + "testinstance.example.com", + ]) + + def testListInstances(self): + hv = self._GetHv(run_cmd=self._XenList) + + self.assertEqual(hv.ListInstances(), [ + "server01.example.com", + "web3106215069.example.com", + "testinstance.example.com", + ]) + + def testVerify(self): + output = testutils.ReadTestData("xen-xm-info-4.0.1.txt") + hv = self._GetHv(run_cmd=compat.partial(self._SuccessCommand, + output)) + self.assertTrue(hv.Verify() is None) + + def testVerifyFailing(self): + hv = self._GetHv(run_cmd=self._FailingCommand) + self.assertTrue("failed:" in hv.Verify()) + + def _StartInstanceCommand(self, inst, paused, failcreate, cmd): + if cmd == [self.CMD, "info"]: + output = testutils.ReadTestData("xen-xm-info-4.0.1.txt") + elif cmd == [self.CMD, "list"]: + output = testutils.ReadTestData("xen-xm-list-4.0.1-dom0-only.txt") + elif cmd[:2] == [self.CMD, "create"]: + args = cmd[2:] + cfgfile = utils.PathJoin(self.tmpdir, inst.name) + + if paused: + self.assertEqual(args, ["-p", cfgfile]) + else: + self.assertEqual(args, [cfgfile]) + + if failcreate: + return self._FailingCommand(cmd) + + output = "" + else: + self.fail("Unhandled command: %s" % (cmd, )) + + return self._SuccessCommand(output, cmd) + #return self._FailingCommand(cmd) + + def _MakeInstance(self): + # Copy default parameters + bep = objects.FillDict(constants.BEC_DEFAULTS, {}) + hvp = objects.FillDict(constants.HVC_DEFAULTS[self.HVNAME], {}) + + # Override default VNC password file path + if constants.HV_VNC_PASSWORD_FILE in hvp: + hvp[constants.HV_VNC_PASSWORD_FILE] = self.vncpw_path + + disks = [ + (objects.Disk(dev_type=constants.LD_LV, mode=constants.DISK_RDWR), + utils.PathJoin(self.tmpdir, "disk0")), + (objects.Disk(dev_type=constants.LD_LV, mode=constants.DISK_RDONLY), + utils.PathJoin(self.tmpdir, "disk1")), + ] + + inst = objects.Instance(name="server01.example.com", + hvparams=hvp, beparams=bep, + osparams={}, nics=[], os="deb1", + disks=map(compat.fst, disks)) + inst.UpgradeConfig() + + return (inst, disks) + + def testStartInstance(self): + (inst, disks) = self._MakeInstance() + + for failcreate in [False, True]: + for paused in [False, True]: + run_cmd = compat.partial(self._StartInstanceCommand, + inst, paused, failcreate) + + hv = self._GetHv(run_cmd=run_cmd) + + # Ensure instance is not listed + self.assertTrue(inst.name not in hv.ListInstances()) + + # Remove configuration + cfgfile = utils.PathJoin(self.tmpdir, inst.name) + utils.RemoveFile(cfgfile) + + if failcreate: + self.assertRaises(errors.HypervisorError, hv.StartInstance, + inst, disks, paused) + else: + hv.StartInstance(inst, disks, paused) + + # Check if configuration was updated + lines = utils.ReadFile(cfgfile).splitlines() + + if constants.HV_VNC_PASSWORD_FILE in inst.hvparams: + self.assertTrue(("vncpasswd = '%s'" % self.vncpw) in lines) + else: + extra = inst.hvparams[constants.HV_KERNEL_ARGS] + self.assertTrue(("extra = '%s'" % extra) in lines) + + def _StopInstanceCommand(self, instance_name, force, fail, cmd): + if ((force and cmd[:2] == [self.CMD, "destroy"]) or + (not force and cmd[:2] == [self.CMD, "shutdown"])): + self.assertEqual(cmd[2:], [instance_name]) + output = "" + else: + self.fail("Unhandled command: %s" % (cmd, )) + + if fail: + # Simulate a failing command + return self._FailingCommand(cmd) + else: + return self._SuccessCommand(output, cmd) + + def testStopInstance(self): + name = "inst4284.example.com" + cfgfile = utils.PathJoin(self.tmpdir, name) + cfgdata = "config file content\n" + + for force in [False, True]: + for fail in [False, True]: + utils.WriteFile(cfgfile, data=cfgdata) + + run_cmd = compat.partial(self._StopInstanceCommand, name, force, fail) + + hv = self._GetHv(run_cmd=run_cmd) + + self.assertTrue(os.path.isfile(cfgfile)) + + if fail: + try: + hv._StopInstance(name, force) + except errors.HypervisorError, err: + self.assertTrue(str(err).startswith("Failed to stop instance")) + else: + self.fail("Exception was not raised") + self.assertEqual(utils.ReadFile(cfgfile), cfgdata, + msg=("Configuration was removed when stopping" + " instance failed")) + else: + hv._StopInstance(name, force) + self.assertFalse(os.path.exists(cfgfile)) + + def _MigrateNonRunningInstCmd(self, cmd): + if cmd == [self.CMD, "list"]: + output = testutils.ReadTestData("xen-xm-list-4.0.1-dom0-only.txt") + else: + self.fail("Unhandled command: %s" % (cmd, )) + + return self._SuccessCommand(output, cmd) + + def testMigrateInstanceNotRunning(self): + name = "nonexistinginstance.example.com" + target = constants.IP4_ADDRESS_LOCALHOST + port = 14618 + + hv = self._GetHv(run_cmd=self._MigrateNonRunningInstCmd) + + for live in [False, True]: + try: + hv._MigrateInstance(NotImplemented, name, target, port, live, + _ping_fn=NotImplemented) + except errors.HypervisorError, err: + self.assertEqual(str(err), "Instance not running, cannot migrate") + else: + self.fail("Exception was not raised") + + def _MigrateInstTargetUnreachCmd(self, cmd): + if cmd == [self.CMD, "list"]: + output = testutils.ReadTestData("xen-xm-list-4.0.1-four-instances.txt") + else: + self.fail("Unhandled command: %s" % (cmd, )) + + return self._SuccessCommand(output, cmd) + + def testMigrateTargetUnreachable(self): + name = "server01.example.com" + target = constants.IP4_ADDRESS_LOCALHOST + port = 28349 + + hv = self._GetHv(run_cmd=self._MigrateInstTargetUnreachCmd) + + for live in [False, True]: + if self.CMD == constants.XEN_CMD_XL: + # TODO: Detect unreachable targets + pass + else: + try: + hv._MigrateInstance(NotImplemented, name, target, port, live, + _ping_fn=compat.partial(self._FakeTcpPing, + (target, port), False)) + except errors.HypervisorError, err: + wanted = "Remote host %s not" % target + self.assertTrue(str(err).startswith(wanted)) + else: + self.fail("Exception was not raised") + + def _MigrateInstanceCmd(self, cluster_name, instance_name, target, port, + live, fail, cmd): + if cmd == [self.CMD, "list"]: + output = testutils.ReadTestData("xen-xm-list-4.0.1-four-instances.txt") + elif cmd[:2] == [self.CMD, "migrate"]: + if self.CMD == constants.XEN_CMD_XM: + args = ["-p", str(port)] + + if live: + args.append("-l") + + elif self.CMD == constants.XEN_CMD_XL: + args = [ + "-s", constants.XL_SSH_CMD % cluster_name, + "-C", utils.PathJoin(self.tmpdir, instance_name), + ] + + else: + self.fail("Unknown Xen command '%s'" % self.CMD) + + args.extend([instance_name, target]) + self.assertEqual(cmd[2:], args) + + if fail: + return self._FailingCommand(cmd) + + output = "" + else: + self.fail("Unhandled command: %s" % (cmd, )) + + return self._SuccessCommand(output, cmd) + + def testMigrateInstance(self): + clustername = "cluster.example.com" + instname = "server01.example.com" + target = constants.IP4_ADDRESS_LOCALHOST + port = 22364 + + for live in [False, True]: + for fail in [False, True]: + ping_fn = \ + testutils.CallCounter(compat.partial(self._FakeTcpPing, + (target, port), True)) + + run_cmd = \ + compat.partial(self._MigrateInstanceCmd, + clustername, instname, target, port, live, + fail) + + hv = self._GetHv(run_cmd=run_cmd) + + if fail: + try: + hv._MigrateInstance(clustername, instname, target, port, live, + _ping_fn=ping_fn) + except errors.HypervisorError, err: + self.assertTrue(str(err).startswith("Failed to migrate instance")) + else: + self.fail("Exception was not raised") + else: + hv._MigrateInstance(clustername, instname, target, port, live, + _ping_fn=ping_fn) + + if self.CMD == constants.XEN_CMD_XM: + expected_pings = 1 + else: + expected_pings = 0 + + self.assertEqual(ping_fn.Count(), expected_pings) + def _MakeTestClass(cls, cmd): """Makes a class for testing.