Revision f7e6f3c8
b/qa/ganeti-qa.py | ||
---|---|---|
1 | 1 |
#!/usr/bin/python -u |
2 | 2 |
# |
3 | 3 |
|
4 |
# Copyright (C) 2007, 2008, 2009, 2010 Google Inc. |
|
4 |
# Copyright (C) 2007, 2008, 2009, 2010, 2011 Google Inc.
|
|
5 | 5 |
# |
6 | 6 |
# This program is free software; you can redistribute it and/or modify |
7 | 7 |
# it under the terms of the GNU General Public License as published by |
... | ... | |
354 | 354 |
pnode, snode) |
355 | 355 |
|
356 | 356 |
|
357 |
@rapi.client.UsesRapiClient |
|
358 |
def main(): |
|
359 |
"""Main program. |
|
357 |
def RunQa(): |
|
358 |
"""Main QA body. |
|
360 | 359 |
|
361 | 360 |
""" |
362 |
parser = optparse.OptionParser(usage="%prog [options] <config-file>") |
|
363 |
parser.add_option('--yes-do-it', dest='yes_do_it', |
|
364 |
action="store_true", |
|
365 |
help="Really execute the tests") |
|
366 |
(qa_config.options, args) = parser.parse_args() |
|
367 |
|
|
368 |
if len(args) == 1: |
|
369 |
(config_file, ) = args |
|
370 |
else: |
|
371 |
parser.error("Wrong number of arguments.") |
|
372 |
|
|
373 |
if not qa_config.options.yes_do_it: |
|
374 |
print ("Executing this script irreversibly destroys any Ganeti\n" |
|
375 |
"configuration on all nodes involved. If you really want\n" |
|
376 |
"to start testing, supply the --yes-do-it option.") |
|
377 |
sys.exit(1) |
|
378 |
|
|
379 |
qa_config.Load(config_file) |
|
380 |
|
|
381 | 361 |
rapi_user = "ganeti-qa" |
382 | 362 |
rapi_secret = utils.GenerateSecret() |
383 | 363 |
|
... | ... | |
476 | 456 |
RunTestIf("cluster-destroy", qa_cluster.TestClusterDestroy) |
477 | 457 |
|
478 | 458 |
|
459 |
@rapi.client.UsesRapiClient |
|
460 |
def main(): |
|
461 |
"""Main program. |
|
462 |
|
|
463 |
""" |
|
464 |
parser = optparse.OptionParser(usage="%prog [options] <config-file>") |
|
465 |
parser.add_option('--yes-do-it', dest='yes_do_it', |
|
466 |
action="store_true", |
|
467 |
help="Really execute the tests") |
|
468 |
(qa_config.options, args) = parser.parse_args() |
|
469 |
|
|
470 |
if len(args) == 1: |
|
471 |
(config_file, ) = args |
|
472 |
else: |
|
473 |
parser.error("Wrong number of arguments.") |
|
474 |
|
|
475 |
if not qa_config.options.yes_do_it: |
|
476 |
print ("Executing this script irreversibly destroys any Ganeti\n" |
|
477 |
"configuration on all nodes involved. If you really want\n" |
|
478 |
"to start testing, supply the --yes-do-it option.") |
|
479 |
sys.exit(1) |
|
480 |
|
|
481 |
qa_config.Load(config_file) |
|
482 |
|
|
483 |
qa_utils.StartMultiplexer(qa_config.GetMasterNode()["primary"]) |
|
484 |
try: |
|
485 |
RunQa() |
|
486 |
finally: |
|
487 |
qa_utils.CloseMultiplexers() |
|
488 |
|
|
479 | 489 |
if __name__ == '__main__': |
480 | 490 |
main() |
b/qa/qa_utils.py | ||
---|---|---|
1 | 1 |
# |
2 | 2 |
# |
3 | 3 |
|
4 |
# Copyright (C) 2007 Google Inc. |
|
4 |
# Copyright (C) 2007, 2011 Google Inc.
|
|
5 | 5 |
# |
6 | 6 |
# This program is free software; you can redistribute it and/or modify |
7 | 7 |
# it under the terms of the GNU General Public License as published by |
... | ... | |
28 | 28 |
import sys |
29 | 29 |
import subprocess |
30 | 30 |
import random |
31 |
import tempfile |
|
31 | 32 |
|
32 | 33 |
from ganeti import utils |
33 | 34 |
from ganeti import compat |
... | ... | |
42 | 43 |
_ERROR_SEQ = None |
43 | 44 |
_RESET_SEQ = None |
44 | 45 |
|
46 |
_MULTIPLEXERS = {} |
|
47 |
|
|
45 | 48 |
|
46 | 49 |
def _SetupColours(): |
47 | 50 |
"""Initializes the colour constants. |
... | ... | |
143 | 146 |
return rcode |
144 | 147 |
|
145 | 148 |
|
146 |
def GetSSHCommand(node, cmd, strict=True): |
|
149 |
def GetSSHCommand(node, cmd, strict=True, opts=None):
|
|
147 | 150 |
"""Builds SSH command to be executed. |
148 | 151 |
|
149 | 152 |
@type node: string |
150 | 153 |
@param node: node the command should run on |
151 | 154 |
@type cmd: string |
152 |
@param cmd: command to be executed in the node |
|
155 |
@param cmd: command to be executed in the node; if None or empty |
|
156 |
string, no command will be executed |
|
153 | 157 |
@type strict: boolean |
154 | 158 |
@param strict: whether to enable strict host key checking |
159 |
@type opts: list |
|
160 |
@param opts: list of additional options |
|
155 | 161 |
|
156 | 162 |
""" |
157 | 163 |
args = [ 'ssh', '-oEscapeChar=none', '-oBatchMode=yes', '-l', 'root', '-t' ] |
... | ... | |
163 | 169 |
args.append('-oStrictHostKeyChecking=%s' % tmp) |
164 | 170 |
args.append('-oClearAllForwardings=yes') |
165 | 171 |
args.append('-oForwardAgent=yes') |
172 |
if opts: |
|
173 |
args.extend(opts) |
|
174 |
if node in _MULTIPLEXERS: |
|
175 |
spath = _MULTIPLEXERS[node][0] |
|
176 |
args.append('-oControlPath=%s' % spath) |
|
177 |
args.append('-oControlMaster=no') |
|
166 | 178 |
args.append(node) |
167 |
args.append(cmd) |
|
179 |
if cmd: |
|
180 |
args.append(cmd) |
|
168 | 181 |
|
169 | 182 |
return args |
170 | 183 |
|
... | ... | |
184 | 197 |
return StartLocalCommand(GetSSHCommand(node, cmd, strict=strict)) |
185 | 198 |
|
186 | 199 |
|
200 |
def StartMultiplexer(node): |
|
201 |
"""Starts a multiplexer command. |
|
202 |
|
|
203 |
@param node: the node for which to open the multiplexer |
|
204 |
|
|
205 |
""" |
|
206 |
if node in _MULTIPLEXERS: |
|
207 |
return |
|
208 |
|
|
209 |
# Note: yes, we only need mktemp, since we'll remove the file anyway |
|
210 |
sname = tempfile.mktemp(prefix="ganeti-qa-multiplexer.") |
|
211 |
utils.RemoveFile(sname) |
|
212 |
opts = ["-N", "-oControlPath=%s" % sname, "-oControlMaster=yes"] |
|
213 |
print "Created socket at %s" % sname |
|
214 |
child = StartLocalCommand(GetSSHCommand(node, None, opts=opts)) |
|
215 |
_MULTIPLEXERS[node] = (sname, child) |
|
216 |
|
|
217 |
|
|
218 |
def CloseMultiplexers(): |
|
219 |
"""Closes all current multiplexers and cleans up. |
|
220 |
|
|
221 |
""" |
|
222 |
for node in _MULTIPLEXERS.keys(): |
|
223 |
(sname, child) = _MULTIPLEXERS.pop(node) |
|
224 |
utils.KillProcess(child.pid, timeout=10, waitpid=True) |
|
225 |
utils.RemoveFile(sname) |
|
226 |
|
|
227 |
|
|
187 | 228 |
def GetCommandOutput(node, cmd): |
188 | 229 |
"""Returns the output of a command executed on the given node. |
189 | 230 |
|
Also available in: Unified diff