Revision d3b18b8e
b/tools/setup-ssh | ||
---|---|---|
38 | 38 |
from ganeti import constants |
39 | 39 |
from ganeti import errors |
40 | 40 |
from ganeti import netutils |
41 |
from ganeti import ssconf |
|
41 | 42 |
from ganeti import ssh |
42 | 43 |
from ganeti import utils |
43 | 44 |
|
... | ... | |
48 | 49 |
""" |
49 | 50 |
|
50 | 51 |
|
52 |
class JoinCheckError(errors.GenericError): |
|
53 |
"""Exception raised if join check fails. |
|
54 |
|
|
55 |
""" |
|
56 |
|
|
57 |
|
|
58 |
def _CheckJoin(transport): |
|
59 |
"""Checks if a join is safe or dangerous. |
|
60 |
|
|
61 |
Note: This function relies on the fact, that all |
|
62 |
hosts have the same configuration at compile time of |
|
63 |
Ganeti. So that the constants do not mismatch. |
|
64 |
|
|
65 |
@param transport: The paramiko transport instance |
|
66 |
@return: True if the join is safe; False otherwise |
|
67 |
|
|
68 |
""" |
|
69 |
sftp = transport.open_sftp_client() |
|
70 |
ss = ssconf.SimpleStore() |
|
71 |
ss_cluster_name_path = ss.KeyToFilename(constants.SS_CLUSTER_NAME) |
|
72 |
|
|
73 |
cluster_files = { |
|
74 |
ss_cluster_name_path: utils.ReadFile(ss_cluster_name_path), |
|
75 |
constants.NODED_CERT_FILE: utils.ReadFile(constants.NODED_CERT_FILE), |
|
76 |
} |
|
77 |
|
|
78 |
try: |
|
79 |
remote_noded_file = _ReadSftpFile(sftp, constants.NODED_CERT_FILE) |
|
80 |
except IOError: |
|
81 |
# We can just assume that the file doesn't exist as such error reporting |
|
82 |
# is lacking from paramiko |
|
83 |
# |
|
84 |
# We don't have the noded certificate. As without the cert, the |
|
85 |
# noded is not running, we are on the safe bet to say that this |
|
86 |
# node doesn't belong to a cluster |
|
87 |
return True |
|
88 |
|
|
89 |
try: |
|
90 |
remote_cluster_name = _ReadSftpFile(sftp, ss_cluster_name_path) |
|
91 |
except IOError: |
|
92 |
# This can indicate that a previous join was not successful |
|
93 |
# So if the noded cert was found and matches we are fine |
|
94 |
return cluster_files[constants.NODED_CERT_FILE] == remote_noded_file |
|
95 |
|
|
96 |
return (cluster_files[constants.NODED_CERT_FILE] == remote_noded_file and |
|
97 |
cluster_files[ss_cluster_name_path] == remote_cluster_name) |
|
98 |
|
|
99 |
|
|
51 | 100 |
def _RunRemoteCommand(transport, command): |
52 | 101 |
"""Invokes and wait for the command over SSH. |
53 | 102 |
|
... | ... | |
84 | 133 |
_RunRemoteCommand(transport, "%s %s" % (constants.DAEMON_UTIL, command)) |
85 | 134 |
|
86 | 135 |
|
136 |
def _ReadSftpFile(sftp, filename): |
|
137 |
"""Reads a file over sftp. |
|
138 |
|
|
139 |
@param sftp: An open paramiko SFTP client |
|
140 |
@param filename: The filename of the file to read |
|
141 |
@return: The content of the file |
|
142 |
|
|
143 |
""" |
|
144 |
remote_file = sftp.open(filename, "r") |
|
145 |
try: |
|
146 |
return remote_file.read() |
|
147 |
finally: |
|
148 |
remote_file.close() |
|
149 |
|
|
150 |
|
|
87 | 151 |
def _WriteSftpFile(sftp, name, perm, data): |
88 | 152 |
"""SFTPs data to a remote file. |
89 | 153 |
|
... | ... | |
159 | 223 |
""" |
160 | 224 |
program = os.path.basename(sys.argv[0]) |
161 | 225 |
|
162 |
parser = optparse.OptionParser(usage=("%prog [--debug|--verbose] <node>"
|
|
163 |
" <node...>"), prog=program) |
|
226 |
parser = optparse.OptionParser(usage=("%prog [--debug|--verbose] [--force]"
|
|
227 |
" <node> <node...>"), prog=program)
|
|
164 | 228 |
parser.add_option(cli.DEBUG_OPT) |
165 | 229 |
parser.add_option(cli.VERBOSE_OPT) |
166 | 230 |
parser.add_option(cli.NOSSH_KEYCHECK_OPT) |
... | ... | |
172 | 236 |
parser.add_option(optparse.Option("--key-type", dest="key_type", |
173 | 237 |
choices=("rsa", "dsa"), default="dsa", |
174 | 238 |
help="The private key type (rsa or dsa)")) |
239 |
parser.add_option(optparse.Option("-j", "--force-join", dest="force_join", |
|
240 |
action="store_true", default=False, |
|
241 |
help="Force the join of the host")) |
|
175 | 242 |
|
176 | 243 |
(options, args) = parser.parse_args() |
177 | 244 |
|
... | ... | |
368 | 435 |
continue |
369 | 436 |
try: |
370 | 437 |
try: |
438 |
if not _CheckJoin(transport): |
|
439 |
if options.force_join: |
|
440 |
logging.warning("Host %s failed join check, forced to continue", |
|
441 |
host) |
|
442 |
else: |
|
443 |
raise JoinCheckError("Host %s failed join check" % host) |
|
371 | 444 |
SetupSSH(transport) |
372 | 445 |
except errors.GenericError, err: |
373 | 446 |
logging.error("While doing setup on host %s an error occured: %s", |
Also available in: Unified diff