root / lib / client / gnt_debug.py @ 55b7e783
History | View | Annotate | Download (22.9 kB)
1 |
#
|
---|---|
2 |
#
|
3 |
|
4 |
# Copyright (C) 2006, 2007, 2010, 2011, 2012 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 |
"""Debugging commands"""
|
22 |
|
23 |
# pylint: disable=W0401,W0614,C0103
|
24 |
# W0401: Wildcard import ganeti.cli
|
25 |
# W0614: Unused import %s from wildcard import (since we need cli)
|
26 |
# C0103: Invalid name gnt-backup
|
27 |
|
28 |
import simplejson |
29 |
import time |
30 |
import socket |
31 |
import logging |
32 |
|
33 |
from ganeti.cli import * |
34 |
from ganeti import cli |
35 |
from ganeti import constants |
36 |
from ganeti import opcodes |
37 |
from ganeti import utils |
38 |
from ganeti import errors |
39 |
from ganeti import compat |
40 |
from ganeti import ht |
41 |
|
42 |
|
43 |
#: Default fields for L{ListLocks}
|
44 |
_LIST_LOCKS_DEF_FIELDS = [ |
45 |
"name",
|
46 |
"mode",
|
47 |
"owner",
|
48 |
"pending",
|
49 |
] |
50 |
|
51 |
|
52 |
def Delay(opts, args): |
53 |
"""Sleeps for a while
|
54 |
|
55 |
@param opts: the command line options selected by the user
|
56 |
@type args: list
|
57 |
@param args: should contain only one element, the duration
|
58 |
the sleep
|
59 |
@rtype: int
|
60 |
@return: the desired exit code
|
61 |
|
62 |
"""
|
63 |
delay = float(args[0]) |
64 |
op = opcodes.OpTestDelay(duration=delay, |
65 |
on_master=opts.on_master, |
66 |
on_nodes=opts.on_nodes, |
67 |
repeat=opts.repeat) |
68 |
SubmitOrSend(op, opts) |
69 |
|
70 |
return 0 |
71 |
|
72 |
|
73 |
def GenericOpCodes(opts, args): |
74 |
"""Send any opcode to the master.
|
75 |
|
76 |
@param opts: the command line options selected by the user
|
77 |
@type args: list
|
78 |
@param args: should contain only one element, the path of
|
79 |
the file with the opcode definition
|
80 |
@rtype: int
|
81 |
@return: the desired exit code
|
82 |
|
83 |
"""
|
84 |
cl = cli.GetClient() |
85 |
jex = cli.JobExecutor(cl=cl, verbose=opts.verbose, opts=opts) |
86 |
|
87 |
job_cnt = 0
|
88 |
op_cnt = 0
|
89 |
if opts.timing_stats:
|
90 |
ToStdout("Loading...")
|
91 |
for job_idx in range(opts.rep_job): |
92 |
for fname in args: |
93 |
# pylint: disable=W0142
|
94 |
op_data = simplejson.loads(utils.ReadFile(fname)) |
95 |
op_list = [opcodes.OpCode.LoadOpCode(val) for val in op_data] |
96 |
op_list = op_list * opts.rep_op |
97 |
jex.QueueJob("file %s/%d" % (fname, job_idx), *op_list)
|
98 |
op_cnt += len(op_list)
|
99 |
job_cnt += 1
|
100 |
|
101 |
if opts.timing_stats:
|
102 |
t1 = time.time() |
103 |
ToStdout("Submitting...")
|
104 |
|
105 |
jex.SubmitPending(each=opts.each) |
106 |
|
107 |
if opts.timing_stats:
|
108 |
t2 = time.time() |
109 |
ToStdout("Executing...")
|
110 |
|
111 |
jex.GetResults() |
112 |
if opts.timing_stats:
|
113 |
t3 = time.time() |
114 |
ToStdout("C:op %4d" % op_cnt)
|
115 |
ToStdout("C:job %4d" % job_cnt)
|
116 |
ToStdout("T:submit %4.4f" % (t2 - t1))
|
117 |
ToStdout("T:exec %4.4f" % (t3 - t2))
|
118 |
ToStdout("T:total %4.4f" % (t3 - t1))
|
119 |
return 0 |
120 |
|
121 |
|
122 |
def TestAllocator(opts, args): |
123 |
"""Runs the test allocator opcode.
|
124 |
|
125 |
@param opts: the command line options selected by the user
|
126 |
@type args: list
|
127 |
@param args: should contain only one element, the iallocator name
|
128 |
@rtype: int
|
129 |
@return: the desired exit code
|
130 |
|
131 |
"""
|
132 |
try:
|
133 |
disks = [{ |
134 |
constants.IDISK_SIZE: utils.ParseUnit(val), |
135 |
constants.IDISK_MODE: constants.DISK_RDWR, |
136 |
} for val in opts.disks.split(",")] |
137 |
except errors.UnitParseError, err:
|
138 |
ToStderr("Invalid disks parameter '%s': %s", opts.disks, err)
|
139 |
return 1 |
140 |
|
141 |
nics = [val.split("/") for val in opts.nics.split(",")] |
142 |
for row in nics: |
143 |
while len(row) < 3: |
144 |
row.append(None)
|
145 |
for i in range(3): |
146 |
if row[i] == "": |
147 |
row[i] = None
|
148 |
nic_dict = [{ |
149 |
constants.INIC_MAC: v[0],
|
150 |
constants.INIC_IP: v[1],
|
151 |
# The iallocator interface defines a "bridge" item
|
152 |
"bridge": v[2], |
153 |
} for v in nics] |
154 |
|
155 |
if opts.tags is None: |
156 |
opts.tags = [] |
157 |
else:
|
158 |
opts.tags = opts.tags.split(",")
|
159 |
if opts.target_groups is None: |
160 |
target_groups = [] |
161 |
else:
|
162 |
target_groups = opts.target_groups |
163 |
|
164 |
op = opcodes.OpTestAllocator(mode=opts.mode, |
165 |
name=args[0],
|
166 |
instances=args, |
167 |
memory=opts.memory, |
168 |
disks=disks, |
169 |
disk_template=opts.disk_template, |
170 |
nics=nic_dict, |
171 |
os=opts.os, |
172 |
vcpus=opts.vcpus, |
173 |
tags=opts.tags, |
174 |
direction=opts.direction, |
175 |
iallocator=opts.iallocator, |
176 |
evac_mode=opts.evac_mode, |
177 |
target_groups=target_groups, |
178 |
spindle_use=opts.spindle_use, |
179 |
count=opts.count) |
180 |
result = SubmitOpCode(op, opts=opts) |
181 |
ToStdout("%s" % result)
|
182 |
return 0 |
183 |
|
184 |
|
185 |
def _TestJobDependency(opts): |
186 |
"""Tests job dependencies.
|
187 |
|
188 |
"""
|
189 |
ToStdout("Testing job dependencies")
|
190 |
|
191 |
cl = cli.GetClient() |
192 |
|
193 |
try:
|
194 |
SubmitOpCode(opcodes.OpTestDelay(duration=0, depends=[(-1, None)]), cl=cl) |
195 |
except errors.GenericError, err:
|
196 |
if opts.debug:
|
197 |
ToStdout("Ignoring error for 'wrong dependencies' test: %s", err)
|
198 |
else:
|
199 |
raise errors.OpExecError("Submitting plain opcode with relative job ID" |
200 |
" did not fail as expected")
|
201 |
|
202 |
# TODO: Test dependencies on errors
|
203 |
jobs = [ |
204 |
[opcodes.OpTestDelay(duration=1)],
|
205 |
[opcodes.OpTestDelay(duration=1,
|
206 |
depends=[(-1, [])])],
|
207 |
[opcodes.OpTestDelay(duration=1,
|
208 |
depends=[(-2, [constants.JOB_STATUS_SUCCESS])])],
|
209 |
[opcodes.OpTestDelay(duration=1,
|
210 |
depends=[])], |
211 |
[opcodes.OpTestDelay(duration=1,
|
212 |
depends=[(-2, [constants.JOB_STATUS_SUCCESS])])],
|
213 |
] |
214 |
|
215 |
# Function for checking result
|
216 |
check_fn = ht.TListOf(ht.TAnd(ht.TIsLength(2),
|
217 |
ht.TItems([ht.TBool, |
218 |
ht.TOr(ht.TNonEmptyString, |
219 |
ht.TJobId)]))) |
220 |
|
221 |
result = cl.SubmitManyJobs(jobs) |
222 |
if not check_fn(result): |
223 |
raise errors.OpExecError("Job submission doesn't match %s: %s" % |
224 |
(check_fn, result)) |
225 |
|
226 |
# Wait for jobs to finish
|
227 |
jex = JobExecutor(cl=cl, opts=opts) |
228 |
|
229 |
for (status, job_id) in result: |
230 |
jex.AddJobId(None, status, job_id)
|
231 |
|
232 |
job_results = jex.GetResults() |
233 |
if not compat.all(row[0] for row in job_results): |
234 |
raise errors.OpExecError("At least one of the submitted jobs failed: %s" % |
235 |
job_results) |
236 |
|
237 |
# Get details about jobs
|
238 |
data = cl.QueryJobs([job_id for (_, job_id) in result], |
239 |
["id", "opexec", "ops"]) |
240 |
data_job_id = [job_id for (job_id, _, _) in data] |
241 |
data_opexec = [opexec for (_, opexec, _) in data] |
242 |
data_op = [[opcodes.OpCode.LoadOpCode(op) for op in ops] |
243 |
for (_, _, ops) in data] |
244 |
|
245 |
assert compat.all(not op.depends or len(op.depends) == 1 |
246 |
for ops in data_op |
247 |
for op in ops) |
248 |
|
249 |
# Check resolved job IDs in dependencies
|
250 |
for (job_idx, res_jobdep) in [(1, data_job_id[0]), |
251 |
(2, data_job_id[0]), |
252 |
(4, data_job_id[2])]: |
253 |
if data_op[job_idx][0].depends[0][0] != res_jobdep: |
254 |
raise errors.OpExecError("Job %s's opcode doesn't depend on correct job" |
255 |
" ID (%s)" % (job_idx, res_jobdep))
|
256 |
|
257 |
# Check execution order
|
258 |
if not (data_opexec[0] <= data_opexec[1] and |
259 |
data_opexec[0] <= data_opexec[2] and |
260 |
data_opexec[2] <= data_opexec[4]): |
261 |
raise errors.OpExecError("Jobs did not run in correct order: %s" % data) |
262 |
|
263 |
assert len(jobs) == 5 and compat.all(len(ops) == 1 for ops in jobs) |
264 |
|
265 |
ToStdout("Job dependency tests were successful")
|
266 |
|
267 |
|
268 |
def _TestJobSubmission(opts): |
269 |
"""Tests submitting jobs.
|
270 |
|
271 |
"""
|
272 |
ToStdout("Testing job submission")
|
273 |
|
274 |
testdata = [ |
275 |
(0, 0, constants.OP_PRIO_LOWEST), |
276 |
(0, 0, constants.OP_PRIO_HIGHEST), |
277 |
] |
278 |
|
279 |
for priority in (constants.OP_PRIO_SUBMIT_VALID | |
280 |
frozenset([constants.OP_PRIO_LOWEST,
|
281 |
constants.OP_PRIO_HIGHEST])): |
282 |
for offset in [-1, +1]: |
283 |
testdata.extend([ |
284 |
(0, 0, priority + offset), |
285 |
(3, 0, priority + offset), |
286 |
(0, 3, priority + offset), |
287 |
(4, 2, priority + offset), |
288 |
]) |
289 |
|
290 |
cl = cli.GetClient() |
291 |
|
292 |
for before, after, failpriority in testdata: |
293 |
ops = [] |
294 |
ops.extend([opcodes.OpTestDelay(duration=0) for _ in range(before)]) |
295 |
ops.append(opcodes.OpTestDelay(duration=0, priority=failpriority))
|
296 |
ops.extend([opcodes.OpTestDelay(duration=0) for _ in range(after)]) |
297 |
|
298 |
try:
|
299 |
cl.SubmitJob(ops) |
300 |
except errors.GenericError, err:
|
301 |
if opts.debug:
|
302 |
ToStdout("Ignoring error for 'wrong priority' test: %s", err)
|
303 |
else:
|
304 |
raise errors.OpExecError("Submitting opcode with priority %s did not" |
305 |
" fail when it should (allowed are %s)" %
|
306 |
(failpriority, constants.OP_PRIO_SUBMIT_VALID)) |
307 |
|
308 |
jobs = [ |
309 |
[opcodes.OpTestDelay(duration=0),
|
310 |
opcodes.OpTestDelay(duration=0, dry_run=False), |
311 |
opcodes.OpTestDelay(duration=0, dry_run=True)], |
312 |
ops, |
313 |
] |
314 |
result = cl.SubmitManyJobs(jobs) |
315 |
if not (len(result) == 2 and |
316 |
compat.all(len(i) == 2 for i in result) and |
317 |
isinstance(result[0][1], int) and |
318 |
isinstance(result[1][1], basestring) and |
319 |
result[0][0] and not result[1][0]): |
320 |
raise errors.OpExecError("Submitting multiple jobs did not work as" |
321 |
" expected, result %s" % result)
|
322 |
assert len(result) == 2 |
323 |
|
324 |
ToStdout("Job submission tests were successful")
|
325 |
|
326 |
|
327 |
class _JobQueueTestReporter(cli.StdioJobPollReportCb): |
328 |
def __init__(self): |
329 |
"""Initializes this class.
|
330 |
|
331 |
"""
|
332 |
cli.StdioJobPollReportCb.__init__(self)
|
333 |
self._expected_msgcount = 0 |
334 |
self._all_testmsgs = []
|
335 |
self._testmsgs = None |
336 |
self._job_id = None |
337 |
|
338 |
def GetTestMessages(self): |
339 |
"""Returns all test log messages received so far.
|
340 |
|
341 |
"""
|
342 |
return self._all_testmsgs |
343 |
|
344 |
def GetJobId(self): |
345 |
"""Returns the job ID.
|
346 |
|
347 |
"""
|
348 |
return self._job_id |
349 |
|
350 |
def ReportLogMessage(self, job_id, serial, timestamp, log_type, log_msg): |
351 |
"""Handles a log message.
|
352 |
|
353 |
"""
|
354 |
if self._job_id is None: |
355 |
self._job_id = job_id
|
356 |
elif self._job_id != job_id: |
357 |
raise errors.ProgrammerError("The same reporter instance was used for" |
358 |
" more than one job")
|
359 |
|
360 |
if log_type == constants.ELOG_JQUEUE_TEST:
|
361 |
(sockname, test, arg) = log_msg |
362 |
return self._ProcessTestMessage(job_id, sockname, test, arg) |
363 |
|
364 |
elif (log_type == constants.ELOG_MESSAGE and |
365 |
log_msg.startswith(constants.JQT_MSGPREFIX)): |
366 |
if self._testmsgs is None: |
367 |
raise errors.OpExecError("Received test message without a preceding" |
368 |
" start message")
|
369 |
testmsg = log_msg[len(constants.JQT_MSGPREFIX):]
|
370 |
self._testmsgs.append(testmsg)
|
371 |
self._all_testmsgs.append(testmsg)
|
372 |
return
|
373 |
|
374 |
return cli.StdioJobPollReportCb.ReportLogMessage(self, job_id, serial, |
375 |
timestamp, log_type, |
376 |
log_msg) |
377 |
|
378 |
def _ProcessTestMessage(self, job_id, sockname, test, arg): |
379 |
"""Handles a job queue test message.
|
380 |
|
381 |
"""
|
382 |
if test not in constants.JQT_ALL: |
383 |
raise errors.OpExecError("Received invalid test message %s" % test) |
384 |
|
385 |
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) |
386 |
try:
|
387 |
sock.settimeout(30.0)
|
388 |
|
389 |
logging.debug("Connecting to %s", sockname)
|
390 |
sock.connect(sockname) |
391 |
|
392 |
logging.debug("Checking status")
|
393 |
jobdetails = cli.GetClient().QueryJobs([job_id], ["status"])[0] |
394 |
if not jobdetails: |
395 |
raise errors.OpExecError("Can't find job %s" % job_id) |
396 |
|
397 |
status = jobdetails[0]
|
398 |
|
399 |
logging.debug("Status of job %s is %s", job_id, status)
|
400 |
|
401 |
if test == constants.JQT_EXPANDNAMES:
|
402 |
if status != constants.JOB_STATUS_WAITING:
|
403 |
raise errors.OpExecError("Job status while expanding names is '%s'," |
404 |
" not '%s' as expected" %
|
405 |
(status, constants.JOB_STATUS_WAITING)) |
406 |
elif test in (constants.JQT_EXEC, constants.JQT_LOGMSG): |
407 |
if status != constants.JOB_STATUS_RUNNING:
|
408 |
raise errors.OpExecError("Job status while executing opcode is '%s'," |
409 |
" not '%s' as expected" %
|
410 |
(status, constants.JOB_STATUS_RUNNING)) |
411 |
|
412 |
if test == constants.JQT_STARTMSG:
|
413 |
logging.debug("Expecting %s test messages", arg)
|
414 |
self._testmsgs = []
|
415 |
elif test == constants.JQT_LOGMSG:
|
416 |
if len(self._testmsgs) != arg: |
417 |
raise errors.OpExecError("Received %s test messages when %s are" |
418 |
" expected" % (len(self._testmsgs), arg)) |
419 |
finally:
|
420 |
logging.debug("Closing socket")
|
421 |
sock.close() |
422 |
|
423 |
|
424 |
def TestJobqueue(opts, _): |
425 |
"""Runs a few tests on the job queue.
|
426 |
|
427 |
"""
|
428 |
_TestJobSubmission(opts) |
429 |
_TestJobDependency(opts) |
430 |
|
431 |
(TM_SUCCESS, |
432 |
TM_MULTISUCCESS, |
433 |
TM_FAIL, |
434 |
TM_PARTFAIL) = range(4) |
435 |
TM_ALL = frozenset([TM_SUCCESS, TM_MULTISUCCESS, TM_FAIL, TM_PARTFAIL])
|
436 |
|
437 |
for mode in TM_ALL: |
438 |
test_messages = [ |
439 |
"Testing mode %s" % mode,
|
440 |
"Hello World",
|
441 |
"A",
|
442 |
"",
|
443 |
"B"
|
444 |
"Foo|bar|baz",
|
445 |
utils.TimestampForFilename(), |
446 |
] |
447 |
|
448 |
fail = mode in (TM_FAIL, TM_PARTFAIL)
|
449 |
|
450 |
if mode == TM_PARTFAIL:
|
451 |
ToStdout("Testing partial job failure")
|
452 |
ops = [ |
453 |
opcodes.OpTestJqueue(notify_waitlock=True, notify_exec=True, |
454 |
log_messages=test_messages, fail=False),
|
455 |
opcodes.OpTestJqueue(notify_waitlock=True, notify_exec=True, |
456 |
log_messages=test_messages, fail=False),
|
457 |
opcodes.OpTestJqueue(notify_waitlock=True, notify_exec=True, |
458 |
log_messages=test_messages, fail=True),
|
459 |
opcodes.OpTestJqueue(notify_waitlock=True, notify_exec=True, |
460 |
log_messages=test_messages, fail=False),
|
461 |
] |
462 |
expect_messages = 3 * [test_messages]
|
463 |
expect_opstatus = [ |
464 |
constants.OP_STATUS_SUCCESS, |
465 |
constants.OP_STATUS_SUCCESS, |
466 |
constants.OP_STATUS_ERROR, |
467 |
constants.OP_STATUS_ERROR, |
468 |
] |
469 |
expect_resultlen = 2
|
470 |
elif mode == TM_MULTISUCCESS:
|
471 |
ToStdout("Testing multiple successful opcodes")
|
472 |
ops = [ |
473 |
opcodes.OpTestJqueue(notify_waitlock=True, notify_exec=True, |
474 |
log_messages=test_messages, fail=False),
|
475 |
opcodes.OpTestJqueue(notify_waitlock=True, notify_exec=True, |
476 |
log_messages=test_messages, fail=False),
|
477 |
] |
478 |
expect_messages = 2 * [test_messages]
|
479 |
expect_opstatus = [ |
480 |
constants.OP_STATUS_SUCCESS, |
481 |
constants.OP_STATUS_SUCCESS, |
482 |
] |
483 |
expect_resultlen = 2
|
484 |
else:
|
485 |
if mode == TM_SUCCESS:
|
486 |
ToStdout("Testing job success")
|
487 |
expect_opstatus = [constants.OP_STATUS_SUCCESS] |
488 |
elif mode == TM_FAIL:
|
489 |
ToStdout("Testing job failure")
|
490 |
expect_opstatus = [constants.OP_STATUS_ERROR] |
491 |
else:
|
492 |
raise errors.ProgrammerError("Unknown test mode %s" % mode) |
493 |
|
494 |
ops = [ |
495 |
opcodes.OpTestJqueue(notify_waitlock=True,
|
496 |
notify_exec=True,
|
497 |
log_messages=test_messages, |
498 |
fail=fail), |
499 |
] |
500 |
expect_messages = [test_messages] |
501 |
expect_resultlen = 1
|
502 |
|
503 |
cl = cli.GetClient() |
504 |
cli.SetGenericOpcodeOpts(ops, opts) |
505 |
|
506 |
# Send job to master daemon
|
507 |
job_id = cli.SendJob(ops, cl=cl) |
508 |
|
509 |
reporter = _JobQueueTestReporter() |
510 |
results = None
|
511 |
|
512 |
try:
|
513 |
results = cli.PollJob(job_id, cl=cl, reporter=reporter) |
514 |
except errors.OpExecError, err:
|
515 |
if not fail: |
516 |
raise
|
517 |
ToStdout("Ignoring error for 'job fail' test: %s", err)
|
518 |
else:
|
519 |
if fail:
|
520 |
raise errors.OpExecError("Job didn't fail when it should") |
521 |
|
522 |
# Check length of result
|
523 |
if fail:
|
524 |
if results is not None: |
525 |
raise errors.OpExecError("Received result from failed job") |
526 |
elif len(results) != expect_resultlen: |
527 |
raise errors.OpExecError("Received %s results (%s), expected %s" % |
528 |
(len(results), results, expect_resultlen))
|
529 |
|
530 |
# Check received log messages
|
531 |
all_messages = [i for j in expect_messages for i in j] |
532 |
if reporter.GetTestMessages() != all_messages:
|
533 |
raise errors.OpExecError("Received test messages don't match input" |
534 |
" (input %r, received %r)" %
|
535 |
(all_messages, reporter.GetTestMessages())) |
536 |
|
537 |
# Check final status
|
538 |
reported_job_id = reporter.GetJobId() |
539 |
if reported_job_id != job_id:
|
540 |
raise errors.OpExecError("Reported job ID %s doesn't match" |
541 |
"submission job ID %s" %
|
542 |
(reported_job_id, job_id)) |
543 |
|
544 |
jobdetails = cli.GetClient().QueryJobs([job_id], ["status", "opstatus"])[0] |
545 |
if not jobdetails: |
546 |
raise errors.OpExecError("Can't find job %s" % job_id) |
547 |
|
548 |
if fail:
|
549 |
exp_status = constants.JOB_STATUS_ERROR |
550 |
else:
|
551 |
exp_status = constants.JOB_STATUS_SUCCESS |
552 |
|
553 |
(final_status, final_opstatus) = jobdetails |
554 |
if final_status != exp_status:
|
555 |
raise errors.OpExecError("Final job status is %s, not %s as expected" % |
556 |
(final_status, exp_status)) |
557 |
if len(final_opstatus) != len(ops): |
558 |
raise errors.OpExecError("Did not receive status for all opcodes (got %s," |
559 |
" expected %s)" %
|
560 |
(len(final_opstatus), len(ops))) |
561 |
if final_opstatus != expect_opstatus:
|
562 |
raise errors.OpExecError("Opcode status is %s, expected %s" % |
563 |
(final_opstatus, expect_opstatus)) |
564 |
|
565 |
ToStdout("Job queue test successful")
|
566 |
|
567 |
return 0 |
568 |
|
569 |
|
570 |
def ListLocks(opts, args): # pylint: disable=W0613 |
571 |
"""List all locks.
|
572 |
|
573 |
@param opts: the command line options selected by the user
|
574 |
@type args: list
|
575 |
@param args: should be an empty list
|
576 |
@rtype: int
|
577 |
@return: the desired exit code
|
578 |
|
579 |
"""
|
580 |
selected_fields = ParseFields(opts.output, _LIST_LOCKS_DEF_FIELDS) |
581 |
|
582 |
def _DashIfNone(fn): |
583 |
def wrapper(value): |
584 |
if not value: |
585 |
return "-" |
586 |
return fn(value)
|
587 |
return wrapper
|
588 |
|
589 |
def _FormatPending(value): |
590 |
"""Format pending acquires.
|
591 |
|
592 |
"""
|
593 |
return utils.CommaJoin("%s:%s" % (mode, ",".join(threads)) |
594 |
for mode, threads in value) |
595 |
|
596 |
# Format raw values
|
597 |
fmtoverride = { |
598 |
"mode": (_DashIfNone(str), False), |
599 |
"owner": (_DashIfNone(",".join), False), |
600 |
"pending": (_DashIfNone(_FormatPending), False), |
601 |
} |
602 |
|
603 |
while True: |
604 |
ret = GenericList(constants.QR_LOCK, selected_fields, None, None, |
605 |
opts.separator, not opts.no_headers,
|
606 |
format_override=fmtoverride, verbose=opts.verbose) |
607 |
|
608 |
if ret != constants.EXIT_SUCCESS:
|
609 |
return ret
|
610 |
|
611 |
if not opts.interval: |
612 |
break
|
613 |
|
614 |
ToStdout("")
|
615 |
time.sleep(opts.interval) |
616 |
|
617 |
return 0 |
618 |
|
619 |
|
620 |
commands = { |
621 |
"delay": (
|
622 |
Delay, [ArgUnknown(min=1, max=1)], |
623 |
[cli_option("--no-master", dest="on_master", default=True, |
624 |
action="store_false", help="Do not sleep in the master code"), |
625 |
cli_option("-n", dest="on_nodes", default=[], |
626 |
action="append", help="Select nodes to sleep on"), |
627 |
cli_option("-r", "--repeat", type="int", default="0", dest="repeat", |
628 |
help="Number of times to repeat the sleep"),
|
629 |
DRY_RUN_OPT, PRIORITY_OPT, SUBMIT_OPT, |
630 |
], |
631 |
"[opts...] <duration>", "Executes a TestDelay OpCode"), |
632 |
"submit-job": (
|
633 |
GenericOpCodes, [ArgFile(min=1)],
|
634 |
[VERBOSE_OPT, |
635 |
cli_option("--op-repeat", type="int", default="1", dest="rep_op", |
636 |
help="Repeat the opcode sequence this number of times"),
|
637 |
cli_option("--job-repeat", type="int", default="1", dest="rep_job", |
638 |
help="Repeat the job this number of times"),
|
639 |
cli_option("--timing-stats", default=False, |
640 |
action="store_true", help="Show timing stats"), |
641 |
cli_option("--each", default=False, action="store_true", |
642 |
help="Submit each job separately"),
|
643 |
DRY_RUN_OPT, PRIORITY_OPT, |
644 |
], |
645 |
"<op_list_file...>", "Submits jobs built from json files" |
646 |
" containing a list of serialized opcodes"),
|
647 |
"iallocator": (
|
648 |
TestAllocator, [ArgUnknown(min=1)],
|
649 |
[cli_option("--dir", dest="direction", default=constants.IALLOCATOR_DIR_IN, |
650 |
choices=list(constants.VALID_IALLOCATOR_DIRECTIONS),
|
651 |
help="Show allocator input (in) or allocator"
|
652 |
" results (out)"),
|
653 |
IALLOCATOR_OPT, |
654 |
cli_option("-m", "--mode", default="relocate", |
655 |
choices=list(constants.VALID_IALLOCATOR_MODES),
|
656 |
help=("Request mode (one of %s)" %
|
657 |
utils.CommaJoin(constants.VALID_IALLOCATOR_MODES))), |
658 |
cli_option("--memory", default=128, type="unit", |
659 |
help="Memory size for the instance (MiB)"),
|
660 |
cli_option("--disks", default="4096,4096", |
661 |
help="Comma separated list of disk sizes (MiB)"),
|
662 |
DISK_TEMPLATE_OPT, |
663 |
cli_option("--nics", default="00:11:22:33:44:55", |
664 |
help="Comma separated list of nics, each nic"
|
665 |
" definition is of form mac/ip/bridge, if"
|
666 |
" missing values are replace by None"),
|
667 |
OS_OPT, |
668 |
cli_option("-p", "--vcpus", default=1, type="int", |
669 |
help="Select number of VCPUs for the instance"),
|
670 |
cli_option("--tags", default=None, |
671 |
help="Comma separated list of tags"),
|
672 |
cli_option("--evac-mode", default=constants.IALLOCATOR_NEVAC_ALL,
|
673 |
choices=list(constants.IALLOCATOR_NEVAC_MODES),
|
674 |
help=("Node evacuation mode (one of %s)" %
|
675 |
utils.CommaJoin(constants.IALLOCATOR_NEVAC_MODES))), |
676 |
cli_option("--target-groups", help="Target groups for relocation", |
677 |
default=[], action="append"),
|
678 |
cli_option("--spindle-use", help="How many spindles to use", |
679 |
default=1, type="int"), |
680 |
cli_option("--count", help="How many instances to allocate", |
681 |
default=2, type="int"), |
682 |
DRY_RUN_OPT, PRIORITY_OPT, |
683 |
], |
684 |
"{opts...} <instance>", "Executes a TestAllocator OpCode"), |
685 |
"test-jobqueue": (
|
686 |
TestJobqueue, ARGS_NONE, [PRIORITY_OPT], |
687 |
"", "Test a few aspects of the job queue"), |
688 |
"locks": (
|
689 |
ListLocks, ARGS_NONE, |
690 |
[NOHDR_OPT, SEP_OPT, FIELDS_OPT, INTERVAL_OPT, VERBOSE_OPT], |
691 |
"[--interval N]", "Show a list of locks in the master daemon"), |
692 |
} |
693 |
|
694 |
#: dictionary with aliases for commands
|
695 |
aliases = { |
696 |
"allocator": "iallocator", |
697 |
} |
698 |
|
699 |
|
700 |
def Main(): |
701 |
return GenericMain(commands, aliases=aliases)
|