Statistics
| Branch: | Tag: | Revision:

root / lib / ssh.py @ 3899870e

History | View | Annotate | Download (3.4 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

    
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"