for extra in DAEMONS_EXTRA_LOGBASE[daemon]))
for daemon in DAEMONS_EXTRA_LOGBASE)
-# When the Xen toolstack used is "xl", live migration requires the source host
-# to connect to the target host via ssh (xl runs this command). We need to pass
-# the command xl runs some extra info so that it can use Ganeti's key
-# verification and not fail. Note that this string is incomplete: it must be
-# filled with the cluster name before being used.
-XL_SSH_CMD = ("ssh -l %s -oGlobalKnownHostsFile=%s"
- " -oUserKnownHostsFile=/dev/null"
- " -oCheckHostIp=no -oStrictHostKeyChecking=yes"
- " -oHostKeyAlias=%%s") % (SSH_LOGIN_USER,
- pathutils.SSH_KNOWN_HOSTS_FILE)
-
IE_MAGIC_RE = re.compile(r"^[-_.a-zA-Z0-9]{5,100}$")
# External script validation mask
"""
return self._ReadConfigFile(instance.name)
+ def _UseMigrationDaemon(self, hvparams):
+ """Whether to start a socat daemon when accepting an instance.
+
+ @rtype: bool
+
+ """
+ return self._GetCommand(hvparams) == constants.XEN_CMD_XL
+
def AcceptInstance(self, instance, info, target):
"""Prepare to accept an instance.
@param target: target host (usually ip), on this node
"""
- pass
+ if self._UseMigrationDaemon(instance.hvparams):
+ port = instance.hvparams[constants.HV_MIGRATION_PORT]
+ utils.StartDaemon(["socat", "TCP-LISTEN:%d,bind=%s" % (port, target),
+ "SYSTEM:'xl migrate-receive'"])
def FinalizeMigrationDst(self, instance, info, success):
"""Finalize an instance migration.
if success:
self._WriteConfigFile(instance.name, info)
- def MigrateInstance(self, cluster_name, instance, target, live):
+ def MigrateInstance(self, _cluster_name, instance, target, live):
"""Migrate an instance to a target node.
The migration will not be attempted if the instance is not
"""
port = instance.hvparams[constants.HV_MIGRATION_PORT]
- return self._MigrateInstance(cluster_name, instance.name, target, port,
- live, instance.hvparams)
+ return self._MigrateInstance(instance.name, target, port, live,
+ instance.hvparams)
- def _MigrateInstance(self, cluster_name, instance_name, target, port, live,
- hvparams, _ping_fn=netutils.TcpPing):
+ def _MigrateInstance(self, instance_name, target, port, live, hvparams,
+ _ping_fn=netutils.TcpPing):
"""Migrate an instance to a target node.
@see: L{MigrateInstance} for details
cmd = self._GetCommand(hvparams)
- if (cmd == constants.XEN_CMD_XM and
- not _ping_fn(target, port, live_port_needed=True)):
- raise errors.HypervisorError("Remote host %s not listening on port"
- " %s, cannot migrate" % (target, port))
-
args = ["migrate"]
if cmd == constants.XEN_CMD_XM:
+ # Try and see if xm is listening on the specified port
+ if not _ping_fn(target, port, live_port_needed=True):
+ raise errors.HypervisorError("Remote host %s not listening on port"
+ " %s, cannot migrate" % (target, port))
+
args.extend(["-p", "%d" % port])
if live:
args.append("-l")
elif cmd == constants.XEN_CMD_XL:
+ # Rather than using SSH, use socat as Ganeti cannot guarantee the presence
+ # of usable SSH keys as of 2.13
args.extend([
- "-s", constants.XL_SSH_CMD % cluster_name,
+ "-s", constants.XL_SOCAT_CMD % (target, port),
"-C", self._ConfigFileName(instance_name),
])
else:
- raise errors.HypervisorError("Unsupported Xen command: %s" % self._cmd)
+ raise errors.HypervisorError("Unsupported Xen command: %s" % cmd)
args.extend([instance_name, target])
xenKernel :: String
xenKernel = AutoConf.xenKernel
+xlSocatCmd :: String
+xlSocatCmd = "socat - tcp:%s:%d #"
+
+xlPidfileSuffix :: String
+xlPidfileSuffix = ".pid"
+
-- FIXME: perhaps rename to 'validXenCommands' for consistency with
-- other constants
knownXenCommands :: FrozenSet String
for live in [False, True]:
try:
- hv._MigrateInstance(NotImplemented, name, target, port, live,
- self.VALID_HVPARAMS, _ping_fn=NotImplemented)
+ hv._MigrateInstance(name, target, port, live, self.VALID_HVPARAMS,
+ _ping_fn=NotImplemented)
except errors.HypervisorError, err:
self.assertEqual(str(err), "Instance not running, cannot migrate")
else:
pass
else:
try:
- hv._MigrateInstance(NotImplemented, name, target, port, live,
- hvparams,
+ hv._MigrateInstance(name, target, port, live, hvparams,
_ping_fn=compat.partial(self._FakeTcpPing,
(target, port), False))
except errors.HypervisorError, err:
else:
self.fail("Exception was not raised")
- def _MigrateInstanceCmd(self, cluster_name, instance_name, target, port,
+ def _MigrateInstanceCmd(self, 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 self.CMD == constants.XEN_CMD_XL:
args = [
- "-s", constants.XL_SSH_CMD % cluster_name,
+ "-s", constants.XL_SOCAT_CMD % (target, port),
"-C", utils.PathJoin(self.tmpdir, instance_name),
]
return self._SuccessCommand(output, cmd)
def testMigrateInstance(self):
- clustername = "cluster.example.com"
instname = "server01.example.com"
target = constants.IP4_ADDRESS_LOCALHOST
port = 22364
run_cmd = \
compat.partial(self._MigrateInstanceCmd,
- clustername, instname, target, port, live,
- fail)
+ instname, target, port, live, fail)
hv = self._GetHv(run_cmd=run_cmd)
if fail:
try:
- hv._MigrateInstance(clustername, instname, target, port, live,
- hvparams, _ping_fn=ping_fn)
+ hv._MigrateInstance(instname, target, port, live, hvparams,
+ _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,
+ hv._MigrateInstance(instname, target, port, live,
hvparams, _ping_fn=ping_fn)
if self.CMD == constants.XEN_CMD_XM: