Statistics
| Branch: | Tag: | Revision:

root / lib / ssh.py @ 2ec08468

History | View | Annotate | Download (4.1 kB)

1 a8083063 Iustin Pop
#!/usr/bin/python
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 a8083063 Iustin Pop
# Copyright (C) 2006, 2007 Google Inc.
5 a8083063 Iustin Pop
#
6 a8083063 Iustin Pop
# This program is free software; you can redistribute it and/or modify
7 a8083063 Iustin Pop
# it under the terms of the GNU General Public License as published by
8 a8083063 Iustin Pop
# the Free Software Foundation; either version 2 of the License, or
9 a8083063 Iustin Pop
# (at your option) any later version.
10 a8083063 Iustin Pop
#
11 a8083063 Iustin Pop
# This program is distributed in the hope that it will be useful, but
12 a8083063 Iustin Pop
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 a8083063 Iustin Pop
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 a8083063 Iustin Pop
# General Public License for more details.
15 a8083063 Iustin Pop
#
16 a8083063 Iustin Pop
# You should have received a copy of the GNU General Public License
17 a8083063 Iustin Pop
# along with this program; if not, write to the Free Software
18 a8083063 Iustin Pop
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 a8083063 Iustin Pop
# 02110-1301, USA.
20 a8083063 Iustin Pop
21 a8083063 Iustin Pop
22 a8083063 Iustin Pop
"""Module encapsulating ssh functionality.
23 a8083063 Iustin Pop

24 a8083063 Iustin Pop
"""
25 a8083063 Iustin Pop
26 a8083063 Iustin Pop
27 a8083063 Iustin Pop
import os
28 a8083063 Iustin Pop
29 a8083063 Iustin Pop
from ganeti import logger
30 a8083063 Iustin Pop
from ganeti import utils
31 a8083063 Iustin Pop
from ganeti import errors
32 82122173 Iustin Pop
from ganeti import constants
33 82122173 Iustin Pop
34 82122173 Iustin Pop
35 82122173 Iustin Pop
__all__ = ["SSHCall", "CopyFileToNode", "VerifyNodeHostname",
36 82122173 Iustin Pop
           "KNOWN_HOSTS_OPTS", "BATCH_MODE_OPTS", "ASK_KEY_OPTS"]
37 82122173 Iustin Pop
38 82122173 Iustin Pop
39 82122173 Iustin Pop
KNOWN_HOSTS_OPTS = [
40 82122173 Iustin Pop
  "-oGlobalKnownHostsFile=%s" % constants.SSH_KNOWN_HOSTS_FILE,
41 82122173 Iustin Pop
  "-oUserKnownHostsFile=/dev/null",
42 82122173 Iustin Pop
  ]
43 82122173 Iustin Pop
44 82122173 Iustin Pop
# Note: BATCH_MODE conflicts with ASK_KEY
45 82122173 Iustin Pop
BATCH_MODE_OPTS = [
46 82122173 Iustin Pop
  "-oEscapeChar=none",
47 82122173 Iustin Pop
  "-oBatchMode=yes",
48 82122173 Iustin Pop
  "-oStrictHostKeyChecking=yes",
49 82122173 Iustin Pop
  ]
50 82122173 Iustin Pop
51 82122173 Iustin Pop
ASK_KEY_OPTS = [
52 82122173 Iustin Pop
  "-oStrictHostKeyChecking=ask",
53 82122173 Iustin Pop
  "-oEscapeChar=none",
54 82122173 Iustin Pop
  "-oHashKnownHosts=no",
55 82122173 Iustin Pop
  ]
56 82122173 Iustin Pop
57 a8083063 Iustin Pop
58 a8083063 Iustin Pop
def SSHCall(hostname, user, command, batch=True, ask_key=False):
59 a8083063 Iustin Pop
  """Execute a command on a remote node.
60 a8083063 Iustin Pop

61 a8083063 Iustin Pop
  This method has the same return value as `utils.RunCmd()`, which it
62 a8083063 Iustin Pop
  uses to launch ssh.
63 a8083063 Iustin Pop

64 a8083063 Iustin Pop
  Args:
65 a8083063 Iustin Pop
    hostname: the target host, string
66 a8083063 Iustin Pop
    user: user to auth as
67 a8083063 Iustin Pop
    command: the command
68 82122173 Iustin Pop
    batch: if true, ssh will run in batch mode with no prompting
69 82122173 Iustin Pop
    ask_key: if true, ssh will run with StrictHostKeyChecking=ask, so that
70 82122173 Iustin Pop
             we can connect to an unknown host (not valid in batch mode)
71 a8083063 Iustin Pop

72 a8083063 Iustin Pop
  Returns:
73 a8083063 Iustin Pop
    `utils.RunResult` as for `utils.RunCmd()`
74 a8083063 Iustin Pop

75 a8083063 Iustin Pop
  """
76 82122173 Iustin Pop
  argv = ["ssh", "-q"]
77 82122173 Iustin Pop
  argv.extend(KNOWN_HOSTS_OPTS)
78 a8083063 Iustin Pop
  if batch:
79 a8083063 Iustin Pop
    # if we are in batch mode, we can't ask the key
80 a8083063 Iustin Pop
    if ask_key:
81 3ecf6786 Iustin Pop
      raise errors.ProgrammerError("SSH call requested conflicting options")
82 82122173 Iustin Pop
    argv.extend(BATCH_MODE_OPTS)
83 82122173 Iustin Pop
  elif ask_key:
84 82122173 Iustin Pop
    argv.extend(ASK_KEY_OPTS)
85 a8083063 Iustin Pop
  argv.extend(["%s@%s" % (user, hostname), command])
86 a8083063 Iustin Pop
  return utils.RunCmd(argv)
87 a8083063 Iustin Pop
88 a8083063 Iustin Pop
89 a8083063 Iustin Pop
def CopyFileToNode(node, filename):
90 a8083063 Iustin Pop
  """Copy a file to another node with scp.
91 a8083063 Iustin Pop

92 a8083063 Iustin Pop
  Args:
93 a8083063 Iustin Pop
    node: node in the cluster
94 a8083063 Iustin Pop
    filename: absolute pathname of a local file
95 a8083063 Iustin Pop

96 a8083063 Iustin Pop
  Returns:
97 a8083063 Iustin Pop
    success: True/False
98 a8083063 Iustin Pop

99 a8083063 Iustin Pop
  """
100 a8083063 Iustin Pop
  if not os.path.isfile(filename):
101 a8083063 Iustin Pop
    logger.Error("file %s does not exist" % (filename))
102 a8083063 Iustin Pop
    return False
103 a8083063 Iustin Pop
104 a8083063 Iustin Pop
  if not os.path.isabs(filename):
105 a8083063 Iustin Pop
    logger.Error("file %s must be an absolute path" % (filename))
106 a8083063 Iustin Pop
    return False
107 a8083063 Iustin Pop
108 82122173 Iustin Pop
  command = ["scp", "-q", "-p"]
109 82122173 Iustin Pop
  command.extend(KNOWN_HOSTS_OPTS)
110 82122173 Iustin Pop
  command.extend(BATCH_MODE_OPTS)
111 82122173 Iustin Pop
  command.append(filename)
112 82122173 Iustin Pop
  command.append("%s:%s" % (node, filename))
113 a8083063 Iustin Pop
114 a8083063 Iustin Pop
  result = utils.RunCmd(command)
115 a8083063 Iustin Pop
116 a8083063 Iustin Pop
  if result.failed:
117 a8083063 Iustin Pop
    logger.Error("copy to node %s failed (%s) error %s,"
118 a8083063 Iustin Pop
                 " command was %s" %
119 a8083063 Iustin Pop
                 (node, result.fail_reason, result.output, result.cmd))
120 a8083063 Iustin Pop
121 a8083063 Iustin Pop
  return not result.failed
122 a8083063 Iustin Pop
123 a8083063 Iustin Pop
124 a8083063 Iustin Pop
def VerifyNodeHostname(node):
125 a8083063 Iustin Pop
  """Verify hostname consistency via SSH.
126 a8083063 Iustin Pop

127 a8083063 Iustin Pop

128 a8083063 Iustin Pop
  This functions connects via ssh to a node and compares the hostname
129 a8083063 Iustin Pop
  reported by the node to the name with have (the one that we
130 a8083063 Iustin Pop
  connected to).
131 a8083063 Iustin Pop

132 a8083063 Iustin Pop
  This is used to detect problems in ssh known_hosts files
133 a8083063 Iustin Pop
  (conflicting known hosts) and incosistencies between dns/hosts
134 a8083063 Iustin Pop
  entries and local machine names
135 a8083063 Iustin Pop

136 a8083063 Iustin Pop
  Args:
137 a8083063 Iustin Pop
    node: nodename of a host to check. can be short or full qualified hostname
138 a8083063 Iustin Pop

139 a8083063 Iustin Pop
  Returns:
140 a8083063 Iustin Pop
    (success, detail)
141 a8083063 Iustin Pop
    where
142 a8083063 Iustin Pop
      success: True/False
143 a8083063 Iustin Pop
      detail: String with details
144 a8083063 Iustin Pop

145 a8083063 Iustin Pop
  """
146 a8083063 Iustin Pop
  retval = SSHCall(node, 'root', 'hostname')
147 a8083063 Iustin Pop
148 a8083063 Iustin Pop
  if retval.failed:
149 a8083063 Iustin Pop
    msg = "ssh problem"
150 a8083063 Iustin Pop
    output = retval.output
151 a8083063 Iustin Pop
    if output:
152 a8083063 Iustin Pop
      msg += ": %s" % output
153 a8083063 Iustin Pop
    return False, msg
154 a8083063 Iustin Pop
155 a8083063 Iustin Pop
  remotehostname = retval.stdout.strip()
156 a8083063 Iustin Pop
157 a8083063 Iustin Pop
  if not remotehostname or remotehostname != node:
158 a8083063 Iustin Pop
    return False, "hostname mismatch, got %s" % remotehostname
159 a8083063 Iustin Pop
160 a8083063 Iustin Pop
  return True, "host matches"