Disable hashing of the ssh keys.
[ganeti-local] / lib / ssh.py
1 #!/usr/bin/python
2 #
3
4 # Copyright (C) 2006, 2007 Google Inc.
5 #
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 # General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 # 02110-1301, USA.
20
21
22 """Module encapsulating ssh functionality.
23
24 """
25
26
27 import os
28
29 from ganeti import logger
30 from ganeti import utils
31 from ganeti import errors
32
33 def SSHCall(hostname, user, command, batch=True, ask_key=False):
34   """Execute a command on a remote node.
35
36   This method has the same return value as `utils.RunCmd()`, which it
37   uses to launch ssh.
38
39   Args:
40     hostname: the target host, string
41     user: user to auth as
42     command: the command
43
44   Returns:
45     `utils.RunResult` as for `utils.RunCmd()`
46
47   """
48   argv = ["ssh", "-q", "-oEscapeChar=none"]
49   if batch:
50     argv.append("-oBatchMode=yes")
51     # if we are in batch mode, we can't ask the key
52     if ask_key:
53       raise errors.ProgrammerError("SSH call requested conflicting options")
54   if ask_key:
55     argv.append("-oStrictHostKeyChecking=ask")
56     argv.append("-oHashKnownHosts=no")
57   else:
58     argv.append("-oStrictHostKeyChecking=yes")
59   argv.extend(["%s@%s" % (user, hostname), command])
60   return utils.RunCmd(argv)
61
62
63 def CopyFileToNode(node, filename):
64   """Copy a file to another node with scp.
65
66   Args:
67     node: node in the cluster
68     filename: absolute pathname of a local file
69
70   Returns:
71     success: True/False
72
73   """
74   if not os.path.isfile(filename):
75     logger.Error("file %s does not exist" % (filename))
76     return False
77
78   if not os.path.isabs(filename):
79     logger.Error("file %s must be an absolute path" % (filename))
80     return False
81
82   command = ["scp", "-q", "-p", "-oStrictHostKeyChecking=yes",
83              "-oBatchMode=yes", filename, "%s:%s" % (node, filename)]
84
85   result = utils.RunCmd(command)
86
87   if result.failed:
88     logger.Error("copy to node %s failed (%s) error %s,"
89                  " command was %s" %
90                  (node, result.fail_reason, result.output, result.cmd))
91
92   return not result.failed
93
94
95 def VerifyNodeHostname(node):
96   """Verify hostname consistency via SSH.
97
98
99   This functions connects via ssh to a node and compares the hostname
100   reported by the node to the name with have (the one that we
101   connected to).
102
103   This is used to detect problems in ssh known_hosts files
104   (conflicting known hosts) and incosistencies between dns/hosts
105   entries and local machine names
106
107   Args:
108     node: nodename of a host to check. can be short or full qualified hostname
109
110   Returns:
111     (success, detail)
112     where
113       success: True/False
114       detail: String with details
115
116   """
117   retval = SSHCall(node, 'root', 'hostname')
118
119   if retval.failed:
120     msg = "ssh problem"
121     output = retval.output
122     if output:
123       msg += ": %s" % output
124     return False, msg
125
126   remotehostname = retval.stdout.strip()
127
128   if not remotehostname or remotehostname != node:
129     return False, "hostname mismatch, got %s" % remotehostname
130
131   return True, "host matches"