Commit c92b310a authored by Michael Hanselmann's avatar Michael Hanselmann
Browse files

Move SSH functions into a class

This renames some functions and does some minor codestyle cleanup.

Reviewed-by: ultrotter
parent 75a5f456
......@@ -42,6 +42,10 @@ from ganeti import objects
from ganeti import ssconf
def _GetSshRunner():
return ssh.SshRunner()
def StartMaster():
"""Activate local node as master node.
......@@ -197,7 +201,7 @@ def VerifyNode(what):
if 'nodelist' in what:
result['nodelist'] = {}
for node in what['nodelist']:
success, message = ssh.VerifyNodeHostname(node)
success, message = _GetSshRunner().VerifyNodeHostname(node)
if not success:
result['nodelist'][node] = message
return result
......@@ -1188,9 +1192,8 @@ def ExportSnapshot(disk, dest_node, instance):
destcmd = utils.BuildShellCmd("mkdir -p %s && cat > %s/%s",
destdir, destdir, destfile)
remotecmd = ssh.BuildSSHCmd(dest_node, constants.GANETI_RUNAS, destcmd)
remotecmd = _GetSshRunner().BuildCmd(dest_node, constants.GANETI_RUNAS,
# all commands have been checked, so we're safe to combine them
command = '|'.join([expcmd, comprcmd, utils.ShellQuoteArgs(remotecmd)])
......@@ -1331,7 +1334,8 @@ def ImportOSIntoInstance(instance, os_disk, swap_disk, src_node, src_image):
os.mkdir(constants.LOG_OS_DIR, 0750)
destcmd = utils.BuildShellCmd('cat %s', src_image)
remotecmd = ssh.BuildSSHCmd(src_node, constants.GANETI_RUNAS, destcmd)
remotecmd = _GetSshRunner().BuildCmd(src_node, constants.GANETI_RUNAS,
comprcmd = "gunzip"
impcmd = utils.BuildShellCmd("(cd %s; %s -i %s -b %s -s %s &>%s)",
......@@ -74,6 +74,8 @@ class LogicalUnit(object):
self.op = op
self.cfg = cfg
self.sstore = sstore
self.__ssh = None
for attr_name in self._OP_REQP:
attr_val = getattr(op, attr_name, None)
if attr_val is None:
......@@ -89,6 +91,16 @@ class LogicalUnit(object):
raise errors.OpPrereqError("Commands must be run on the master"
" node %s" % master)
def __GetSSH(self):
"""Returns the SshRunner object
if not self.__ssh:
self.__ssh = ssh.SshRunner()
return self.__ssh
ssh = property(fget=__GetSSH)
def CheckPrereq(self):
"""Check prerequisites for this LU.
......@@ -1229,7 +1241,7 @@ class LURemoveNode(LogicalUnit):
ssh.SSHCall(, 'root', "%s stop" % constants.NODE_INITD_SCRIPT)
self.ssh.Run(, 'root', "%s stop" % constants.NODE_INITD_SCRIPT)
logger.Info("Removing node %s from config" %
......@@ -1539,7 +1551,7 @@ class LUAddNode(LogicalUnit):
constants.SSL_CERT_FILE, gntpem,
result = ssh.SSHCall(node, 'root', mycommand, batch=False, ask_key=True)
result = self.ssh.Run(node, 'root', mycommand, batch=False, ask_key=True)
if result.failed:
raise errors.OpExecError("Remote command on node %s, error: %s,"
" output: %s" %
......@@ -1597,7 +1609,7 @@ class LUAddNode(LogicalUnit):
" you gave (%s). Please fix and re-run this"
" command." % new_node.secondary_ip)
success, msg = ssh.VerifyNodeHostname(node)
success, msg = self.ssh.VerifyNodeHostname(node)
if not success:
raise errors.OpExecError("Node '%s' claims it has a different hostname"
" than the one the resolver gives: %s."
......@@ -1623,7 +1635,7 @@ class LUAddNode(LogicalUnit):
if self.sstore.GetHypervisorType() == constants.HT_XEN_HVM31:
for fname in to_copy:
if not ssh.CopyFileToNode(node, fname):
if not self.ssh.CopyFileToNode(node, fname):
logger.Error("could not copy file %s to node %s" % (fname, node))
logger.Info("adding node %s to cluster.conf" % node)
......@@ -1767,7 +1779,7 @@ class LUClusterCopyFile(NoHooksLU):
for node in self.nodes:
if node == myname:
if not ssh.CopyFileToNode(node, filename):
if not self.ssh.CopyFileToNode(node, filename):
logger.Error("Copy of file %s to node %s failed" % (filename, node))
......@@ -1810,7 +1822,7 @@ class LURunClusterCommand(NoHooksLU):
data = []
for node in self.nodes:
result = ssh.SSHCall(node, "root", self.op.command)
result = self.ssh.Run(node, "root", self.op.command)
data.append((node, result.output, result.exit_code))
return data
......@@ -32,10 +32,6 @@ from ganeti import errors
from ganeti import constants
__all__ = ["SSHCall", "CopyFileToNode", "VerifyNodeHostname",
"-oGlobalKnownHostsFile=%s" % constants.SSH_KNOWN_HOSTS_FILE,
......@@ -90,8 +86,12 @@ def GetUserFiles(user, mkdir=False):
for base in ["id_dsa", "", "authorized_keys"]]
def BuildSSHCmd(hostname, user, command, batch=True, ask_key=False):
"""Build an ssh string to execute a command on a remote node.
class SshRunner:
"""Wrapper for SSH commands.
def BuildCmd(self, hostname, user, command, batch=True, ask_key=False):
"""Build an ssh command to execute a command on a remote node.
hostname: the target host, string
......@@ -117,9 +117,8 @@ def BuildSSHCmd(hostname, user, command, batch=True, ask_key=False):
argv.extend(["%s@%s" % (user, hostname), command])
return argv
def SSHCall(hostname, user, command, batch=True, ask_key=False):
"""Execute a command on a remote node.
def Run(self, hostname, user, command, batch=True, ask_key=False):
"""Runs a command on a remote node.
This method has the same return value as `utils.RunCmd()`, which it
uses to launch ssh.
......@@ -133,14 +132,13 @@ def SSHCall(hostname, user, command, batch=True, ask_key=False):
we can connect to an unknown host (not valid in batch mode)
`utils.RunResult` as for `utils.RunCmd()`
`utils.RunResult` like `utils.RunCmd()`
return utils.RunCmd(BuildSSHCmd(hostname, user, command,
batch=batch, ask_key=ask_key))
return utils.RunCmd(self.BuildCmd(hostname, user, command, batch=batch,
def CopyFileToNode(node, filename):
def CopyFileToNode(self, node, filename):
"""Copy a file to another node with scp.
......@@ -174,11 +172,9 @@ def CopyFileToNode(node, filename):
return not result.failed
def VerifyNodeHostname(node):
def VerifyNodeHostname(self, node):
"""Verify hostname consistency via SSH.
This functions connects via ssh to a node and compares the hostname
reported by the node to the name with have (the one that we
connected to).
......@@ -197,7 +193,7 @@ def VerifyNodeHostname(node):
detail: String with details
retval = SSHCall(node, 'root', 'hostname')
retval = self.Run(node, 'root', 'hostname')
if retval.failed:
msg = "ssh problem"
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment