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
594
595
597 """List all locks.
598
599 @param opts: the command line options selected by the user
600 @type args: list
601 @param args: should be an empty list
602 @rtype: int
603 @return: the desired exit code
604
605 """
606 selected_fields = ParseFields(opts.output, _LIST_LOCKS_DEF_FIELDS)
607
608 def _DashIfNone(fn):
609 def wrapper(value):
610 if not value:
611 return "-"
612 return fn(value)
613 return wrapper
614
615 def _FormatPending(value):
616 """Format pending acquires.
617
618 """
619 return utils.CommaJoin("%s:%s" % (mode, ",".join(map(str, threads)))
620 for mode, threads in value)
621
622
623 fmtoverride = {
624 "mode": (_DashIfNone(str), False),
625 "owner": (_DashIfNone(",".join), False),
626 "pending": (_DashIfNone(_FormatPending), False),
627 }
628
629 while True:
630 ret = GenericList(constants.QR_LOCK, selected_fields, None, None,
631 opts.separator, not opts.no_headers,
632 format_override=fmtoverride, verbose=opts.verbose)
633
634 if ret != constants.EXIT_SUCCESS:
635 return ret
636
637 if not opts.interval:
638 break
639
640 ToStdout("")
641 time.sleep(opts.interval)
642
643 return 0
644
645
647 """Send commands to Metad.
648
649 @param opts: the command line options selected by the user
650 @type args: list
651 @param args: the command to send, followed by the command-specific arguments
652 @rtype: int
653 @return: the desired exit code
654
655 """
656 if args[0] == "echo":
657 if len(args) != 2:
658 ToStderr("Command 'echo' takes only precisely argument.")
659 return 1
660 result = metad.Client().Echo(args[1])
661 print "Answer: %s" % (result,)
662 else:
663 ToStderr("Command '%s' not supported", args[0])
664 return 1
665
666 return 0
667
668
670 """Send commands to WConfD.
671
672 @param opts: the command line options selected by the user
673 @type args: list
674 @param args: the command to send, followed by the command-specific arguments
675 @rtype: int
676 @return: the desired exit code
677
678 """
679 if args[0] == "echo":
680 if len(args) != 2:
681 ToStderr("Command 'echo' takes only precisely argument.")
682 return 1
683 result = wconfd.Client().Echo(args[1])
684 print "Answer: %s" % (result,)
685 elif args[0] == "cleanuplocks":
686 if len(args) != 1:
687 ToStderr("Command 'cleanuplocks' takes no arguments.")
688 return 1
689 wconfd.Client().CleanupLocks()
690 print "Stale locks cleaned up."
691 elif args[0] == "listlocks":
692 if len(args) != 2:
693 ToStderr("Command 'listlocks' takes precisely one argument.")
694 return 1
695 wconfdcontext = (int(args[1]),
696 utils.livelock.GuessLockfileFor("masterd_1"))
697 result = wconfd.Client().ListLocks(wconfdcontext)
698 print "Answer: %s" % (result,)
699 elif args[0] == "listalllocks":
700 if len(args) != 1:
701 ToStderr("Command 'listalllocks' takes no arguments.")
702 return 1
703 result = wconfd.Client().ListAllLocks()
704 print "Answer: %s" % (result,)
705 elif args[0] == "listalllocksowners":
706 if len(args) != 1:
707 ToStderr("Command 'listalllocks' takes no arguments.")
708 return 1
709 result = wconfd.Client().ListAllLocksOwners()
710 print "Answer: %s" % (result,)
711 elif args[0] == "flushconfig":
712 if len(args) != 1:
713 ToStderr("Command 'flushconfig' takes no arguments.")
714 return 1
715 wconfd.Client().FlushConfig()
716 print "Configuration flushed."
717 else:
718 ToStderr("Command '%s' not supported", args[0])
719 return 1
720
721 return 0
722
723
724 commands = {
725 "delay": (
726 Delay, [ArgUnknown(min=1, max=1)],
727 [cli_option("--no-master", dest="on_master", default=True,
728 action="store_false", help="Do not sleep in the master code"),
729 cli_option("-n", dest="on_nodes", default=[],
730 action="append", help="Select nodes to sleep on"),
731 cli_option("-r", "--repeat", type="int", default="0", dest="repeat",
732 help="Number of times to repeat the sleep"),
733 cli_option("-i", "--interruptible", default=False, dest="interruptible",
734 action="store_true",
735 help="Allows the opcode to be interrupted by using a domain "
736 "socket"),
737 cli_option("-l", "--no-locks", default=False, dest="no_locks",
738 action="store_true",
739 help="Don't take locks while performing the delay"),
740 DRY_RUN_OPT, PRIORITY_OPT] + SUBMIT_OPTS,
741 "[opts...] <duration>", "Executes a TestDelay OpCode"),
742 "submit-job": (
743 GenericOpCodes, [ArgFile(min=1)],
744 [VERBOSE_OPT,
745 cli_option("--op-repeat", type="int", default="1", dest="rep_op",
746 help="Repeat the opcode sequence this number of times"),
747 cli_option("--job-repeat", type="int", default="1", dest="rep_job",
748 help="Repeat the job this number of times"),
749 cli_option("--timing-stats", default=False,
750 action="store_true", help="Show timing stats"),
751 cli_option("--each", default=False, action="store_true",
752 help="Submit each job separately"),
753 DRY_RUN_OPT, PRIORITY_OPT,
754 ],
755 "<op_list_file...>", "Submits jobs built from json files"
756 " containing a list of serialized opcodes"),
757 "iallocator": (
758 TestAllocator, [ArgUnknown(min=1)],
759 [cli_option("--dir", dest="direction", default=constants.IALLOCATOR_DIR_IN,
760 choices=list(constants.VALID_IALLOCATOR_DIRECTIONS),
761 help="Show allocator input (in) or allocator"
762 " results (out)"),
763 IALLOCATOR_OPT,
764 cli_option("-m", "--mode", default="relocate",
765 choices=list(constants.VALID_IALLOCATOR_MODES),
766 help=("Request mode (one of %s)" %
767 utils.CommaJoin(constants.VALID_IALLOCATOR_MODES))),
768 cli_option("--memory", default=128, type="unit",
769 help="Memory size for the instance (MiB)"),
770 cli_option("--disks", default="4096,4096",
771 help="Comma separated list of disk sizes (MiB)"),
772 DISK_TEMPLATE_OPT,
773 cli_option("--nics", default="00:11:22:33:44:55",
774 help="Comma separated list of nics, each nic"
775 " definition is of form mac/ip/bridge, if"
776 " missing values are replace by None"),
777 OS_OPT,
778 cli_option("-p", "--vcpus", default=1, type="int",
779 help="Select number of VCPUs for the instance"),
780 cli_option("--tags", default=None,
781 help="Comma separated list of tags"),
782 cli_option("--evac-mode", default=constants.NODE_EVAC_ALL,
783 choices=list(constants.NODE_EVAC_MODES),
784 help=("Node evacuation mode (one of %s)" %
785 utils.CommaJoin(constants.NODE_EVAC_MODES))),
786 cli_option("--target-groups", help="Target groups for relocation",
787 default=[], action="append"),
788 cli_option("--spindle-use", help="How many spindles to use",
789 default=1, type="int"),
790 cli_option("--count", help="How many instances to allocate",
791 default=2, type="int"),
792 DRY_RUN_OPT, PRIORITY_OPT,
793 ],
794 "{opts...} <instance>", "Executes a TestAllocator OpCode"),
795 "test-jobqueue": (
796 TestJobqueue, ARGS_NONE, [PRIORITY_OPT],
797 "", "Test a few aspects of the job queue"),
798 "test-osparams": (
799 TestOsParams, ARGS_NONE, [OSPARAMS_SECRET_OPT] + SUBMIT_OPTS,
800 "[--os-parameters-secret <params>]",
801 "Test secret os parameter transmission"),
802 "locks": (
803 ListLocks, ARGS_NONE,
804 [NOHDR_OPT, SEP_OPT, FIELDS_OPT, INTERVAL_OPT, VERBOSE_OPT],
805 "[--interval N]", "Show a list of locks in the master daemon"),
806 "wconfd": (
807 Wconfd, [ArgUnknown(min=1)], [],
808 "<cmd> <args...>", "Directly talk to WConfD"),
809 "metad": (
810 Metad, [ArgUnknown(min=1)], [],
811 "<cmd> <args...>", "Directly talk to Metad"),
812 }
813
814
815 aliases = {
816 "allocator": "iallocator",
817 }
818
819
822