Statistics
| Branch: | Tag: | Revision:

root / lib / ssh.py @ 82122173

History | View | Annotate | Download (4.1 kB)

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
from ganeti import constants
33

    
34

    
35
__all__ = ["SSHCall", "CopyFileToNode", "VerifyNodeHostname",
36
           "KNOWN_HOSTS_OPTS", "BATCH_MODE_OPTS", "ASK_KEY_OPTS"]
37

    
38

    
39
KNOWN_HOSTS_OPTS = [
40
  "-oGlobalKnownHostsFile=%s" % constants.SSH_KNOWN_HOSTS_FILE,
41
  "-oUserKnownHostsFile=/dev/null",
42
  ]
43

    
44
# Note: BATCH_MODE conflicts with ASK_KEY
45
BATCH_MODE_OPTS = [
46
  "-oEscapeChar=none",
47
  "-oBatchMode=yes",
48
  "-oStrictHostKeyChecking=yes",
49
  ]
50

    
51
ASK_KEY_OPTS = [
52
  "-oStrictHostKeyChecking=ask",
53
  "-oEscapeChar=none",
54
  "-oHashKnownHosts=no",
55
  ]
56

    
57

    
58
def SSHCall(hostname, user, command, batch=True, ask_key=False):
59
  """Execute a command on a remote node.
60

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

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

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

75
  """
76
  argv = ["ssh", "-q"]
77
  argv.extend(KNOWN_HOSTS_OPTS)
78
  if batch:
79
    # if we are in batch mode, we can't ask the key
80
    if ask_key:
81
      raise errors.ProgrammerError("SSH call requested conflicting options")
82
    argv.extend(BATCH_MODE_OPTS)
83
  elif ask_key:
84
    argv.extend(ASK_KEY_OPTS)
85
  argv.extend(["%s@%s" % (user, hostname), command])
86
  return utils.RunCmd(argv)
87

    
88

    
89
def CopyFileToNode(node, filename):
90
  """Copy a file to another node with scp.
91

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

96
  Returns:
97
    success: True/False
98

99
  """
100
  if not os.path.isfile(filename):
101
    logger.Error("file %s does not exist" % (filename))
102
    return False
103

    
104
  if not os.path.isabs(filename):
105
    logger.Error("file %s must be an absolute path" % (filename))
106
    return False
107

    
108
  command = ["scp", "-q", "-p"]
109
  command.extend(KNOWN_HOSTS_OPTS)
110
  command.extend(BATCH_MODE_OPTS)
111
  command.append(filename)
112
  command.append("%s:%s" % (node, filename))
113

    
114
  result = utils.RunCmd(command)
115

    
116
  if result.failed:
117
    logger.Error("copy to node %s failed (%s) error %s,"
118
                 " command was %s" %
119
                 (node, result.fail_reason, result.output, result.cmd))
120

    
121
  return not result.failed
122

    
123

    
124
def VerifyNodeHostname(node):
125
  """Verify hostname consistency via SSH.
126

127

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

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

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

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

145
  """
146
  retval = SSHCall(node, 'root', 'hostname')
147

    
148
  if retval.failed:
149
    msg = "ssh problem"
150
    output = retval.output
151
    if output:
152
      msg += ": %s" % output
153
    return False, msg
154

    
155
  remotehostname = retval.stdout.strip()
156

    
157
  if not remotehostname or remotehostname != node:
158
    return False, "hostname mismatch, got %s" % remotehostname
159

    
160
  return True, "host matches"