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