import tempfile
import shutil
import random
+import os
from ganeti import constants
from ganeti import objects
"", "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.