diff --git a/lib/hypervisor/hv_xen.py b/lib/hypervisor/hv_xen.py index 583cc52b0866b4ba6b7b1d6d260a7a48a7679110..1c05814abf836a5634efcef14e64f735fa4aed8c 100644 --- a/lib/hypervisor/hv_xen.py +++ b/lib/hypervisor/hv_xen.py @@ -320,7 +320,7 @@ class XenHypervisor(hv_base.BaseHypervisor): XL_CONFIG_FILE, ] - def __init__(self, _cfgdir=None): + def __init__(self, _cfgdir=None, _run_cmd_fn=None, _cmd=None): hv_base.BaseHypervisor.__init__(self) if _cfgdir is None: @@ -328,6 +328,36 @@ class XenHypervisor(hv_base.BaseHypervisor): else: self._cfgdir = _cfgdir + if _run_cmd_fn is None: + self._run_cmd_fn = utils.RunCmd + else: + self._run_cmd_fn = _run_cmd_fn + + self._cmd = _cmd + + def _GetCommand(self): + if self._cmd is None: + # TODO: Make command a hypervisor parameter + cmd = constants.XEN_CMD + else: + cmd = self._cmd + + if cmd not in constants.KNOWN_XEN_COMMANDS: + raise errors.ProgrammerError("Unknown Xen command '%s'" % cmd) + + return cmd + + def _RunXen(self, args): + """Wrapper around L{utils.RunCmd} to run Xen command. + + @see: L{utils.RunCmd} + + """ + cmd = [self._GetCommand()] + cmd.extend(args) + + return self._run_cmd_fn(cmd) + def _ConfigFileName(self, instance_name): """Get the config file name for an instance. @@ -381,14 +411,11 @@ class XenHypervisor(hv_base.BaseHypervisor): """ utils.RemoveFile(self._ConfigFileName(instance_name)) - @staticmethod - def _GetXmList(include_node): + def _GetXmList(self, include_node): """Wrapper around module level L{_GetXmList}. """ - # TODO: Abstract running Xen command for testing - return _GetXmList(lambda: utils.RunCmd([constants.XEN_CMD, "list"]), - include_node) + return _GetXmList(lambda: self._RunXen(["list"]), include_node) def ListInstances(self): """Get the list of running instances. @@ -445,12 +472,12 @@ class XenHypervisor(hv_base.BaseHypervisor): self._MakeConfigFile(instance, startup_memory, block_devices) - cmd = [constants.XEN_CMD, "create"] + cmd = ["create"] if startup_paused: - cmd.extend(["-p"]) - cmd.extend([self._ConfigFileName(instance.name)]) - result = utils.RunCmd(cmd) + cmd.append("-p") + cmd.append(self._ConfigFileName(instance.name)) + result = self._RunXen(cmd) if result.failed: raise errors.HypervisorError("Failed to start instance %s: %s (%s)" % (instance.name, result.fail_reason, @@ -464,11 +491,11 @@ class XenHypervisor(hv_base.BaseHypervisor): name = instance.name if force: - command = [constants.XEN_CMD, "destroy", name] + action = "destroy" else: - command = [constants.XEN_CMD, "shutdown", name] - result = utils.RunCmd(command) + action = "shutdown" + result = self._RunXen([action, name]) if result.failed: raise errors.HypervisorError("Failed to stop instance %s: %s, %s" % (name, result.fail_reason, result.output)) @@ -486,7 +513,7 @@ class XenHypervisor(hv_base.BaseHypervisor): raise errors.HypervisorError("Failed to reboot instance %s," " not running" % instance.name) - result = utils.RunCmd([constants.XEN_CMD, "reboot", instance.name]) + result = self._RunXen(["reboot", instance.name]) if result.failed: raise errors.HypervisorError("Failed to reboot instance %s: %s, %s" % (instance.name, result.fail_reason, @@ -519,14 +546,16 @@ class XenHypervisor(hv_base.BaseHypervisor): @param mem: actual memory size to use for instance runtime """ - cmd = [constants.XEN_CMD, "mem-set", instance.name, mem] - result = utils.RunCmd(cmd) + result = self._RunXen(["mem-set", instance.name, mem]) if result.failed: raise errors.HypervisorError("Failed to balloon instance %s: %s (%s)" % (instance.name, result.fail_reason, result.output)) + + # Update configuration file cmd = ["sed", "-ie", "s/^memory.*$/memory = %s/" % mem] cmd.append(self._ConfigFileName(instance.name)) + result = utils.RunCmd(cmd) if result.failed: raise errors.HypervisorError("Failed to update memory for %s: %s (%s)" % @@ -539,8 +568,7 @@ class XenHypervisor(hv_base.BaseHypervisor): @see: L{_GetNodeInfo} and L{_ParseNodeInfo} """ - # TODO: Abstract running Xen command for testing - result = utils.RunCmd([constants.XEN_CMD, "info"]) + result = self._RunXen(["info"]) if result.failed: logging.error("Can't run 'xm info' (%s): %s", result.fail_reason, result.output) @@ -568,7 +596,7 @@ class XenHypervisor(hv_base.BaseHypervisor): @return: Problem description if something is wrong, C{None} otherwise """ - result = utils.RunCmd([constants.XEN_CMD, "info"]) + result = self._RunXen(["info"]) if result.failed: return "'xm info' failed: %s, %s" % (result.fail_reason, result.output) @@ -634,26 +662,29 @@ class XenHypervisor(hv_base.BaseHypervisor): port = instance.hvparams[constants.HV_MIGRATION_PORT] - if (constants.XEN_CMD == constants.XEN_CMD_XM and + if (self._cmd == constants.XEN_CMD_XM and not netutils.TcpPing(target, port, live_port_needed=True)): raise errors.HypervisorError("Remote host %s not listening on port" " %s, cannot migrate" % (target, port)) - args = [constants.XEN_CMD, "migrate"] - if constants.XEN_CMD == constants.XEN_CMD_XM: + args = ["migrate"] + + if self._cmd == constants.XEN_CMD_XM: args.extend(["-p", "%d" % port]) if live: args.append("-l") - elif constants.XEN_CMD == constants.XEN_CMD_XL: + + elif self._cmd == constants.XEN_CMD_XL: cluster_name = ssconf.SimpleStore().GetClusterName() args.extend(["-s", constants.XL_SSH_CMD % cluster_name]) args.extend(["-C", self._ConfigFileName(instance.name)]) + else: - raise errors.HypervisorError("Unsupported xen command: %s" % - constants.XEN_CMD) + raise errors.HypervisorError("Unsupported xen command: %s" % self._cmd) args.extend([instance.name, target]) - result = utils.RunCmd(args) + + result = self._RunXen(args) if result.failed: raise errors.HypervisorError("Failed to migrate instance %s: %s" % (instance.name, result.output))