| # |
| # |
| |
| # Copyright (C) 2006, 2007, 2010, 2011, 2012 Google Inc. |
| # All rights reserved. |
| # |
| # Redistribution and use in source and binary forms, with or without |
| # modification, are permitted provided that the following conditions are |
| # met: |
| # |
| # 1. Redistributions of source code must retain the above copyright notice, |
| # this list of conditions and the following disclaimer. |
| # |
| # 2. Redistributions in binary form must reproduce the above copyright |
| # notice, this list of conditions and the following disclaimer in the |
| # documentation and/or other materials provided with the distribution. |
| # |
| # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS |
| # IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
| # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR |
| # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
| # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| """Debugging commands""" |
| |
| # pylint: disable=W0401,W0614,C0103 |
| # W0401: Wildcard import ganeti.cli |
| # W0614: Unused import %s from wildcard import (since we need cli) |
| # C0103: Invalid name gnt-backup |
| |
| import simplejson |
| import time |
| import socket |
| import logging |
| |
| from ganeti.cli import * |
| from ganeti import cli |
| from ganeti import constants |
| from ganeti import opcodes |
| from ganeti import utils |
| from ganeti import errors |
| from ganeti import compat |
| from ganeti import ht |
| from ganeti import metad |
| from ganeti import wconfd |
| |
| |
| #: Default fields for L{ListLocks} |
| _LIST_LOCKS_DEF_FIELDS = [ |
| "name", |
| "mode", |
| "owner", |
| "pending", |
| ] |
| |
| |
| def Delay(opts, args): |
| """Sleeps for a while |
| |
| @param opts: the command line options selected by the user |
| @type args: list |
| @param args: should contain only one element, the duration |
| the sleep |
| @rtype: int |
| @return: the desired exit code |
| |
| """ |
| delay = float(args[0]) |
| op = opcodes.OpTestDelay(duration=delay, |
| on_master=opts.on_master, |
| on_nodes=opts.on_nodes, |
| repeat=opts.repeat, |
| interruptible=opts.interruptible, |
| no_locks=opts.no_locks) |
| SubmitOrSend(op, opts) |
| |
| return 0 |
| |
| |
| def GenericOpCodes(opts, args): |
| """Send any opcode to the master. |
| |
| @param opts: the command line options selected by the user |
| @type args: list |
| @param args: should contain only one element, the path of |
| the file with the opcode definition |
| @rtype: int |
| @return: the desired exit code |
| |
| """ |
| cl = cli.GetClient() |
| jex = cli.JobExecutor(cl=cl, verbose=opts.verbose, opts=opts) |
| |
| job_cnt = 0 |
| op_cnt = 0 |
| if opts.timing_stats: |
| ToStdout("Loading...") |
| for job_idx in range(opts.rep_job): |
| for fname in args: |
| # pylint: disable=W0142 |
| op_data = simplejson.loads(utils.ReadFile(fname)) |
| op_list = [opcodes.OpCode.LoadOpCode(val) for val in op_data] |
| op_list = op_list * opts.rep_op |
| jex.QueueJob("file %s/%d" % (fname, job_idx), *op_list) |
| op_cnt += len(op_list) |
| job_cnt += 1 |
| |
| if opts.timing_stats: |
| t1 = time.time() |
| ToStdout("Submitting...") |
| |
| jex.SubmitPending(each=opts.each) |
| |
| if opts.timing_stats: |
| t2 = time.time() |
| ToStdout("Executing...") |
| |
| jex.GetResults() |
| if opts.timing_stats: |
| t3 = time.time() |
| ToStdout("C:op %4d" % op_cnt) |
| ToStdout("C:job %4d" % job_cnt) |
| ToStdout("T:submit %4.4f" % (t2 - t1)) |
| ToStdout("T:exec %4.4f" % (t3 - t2)) |
| ToStdout("T:total %4.4f" % (t3 - t1)) |
| return 0 |
| |
| |
| def TestAllocator(opts, args): |
| """Runs the test allocator opcode. |
| |
| @param opts: the command line options selected by the user |
| @type args: list |
| @param args: should contain only one element, the iallocator name |
| @rtype: int |
| @return: the desired exit code |
| |
| """ |
| try: |
| disks = [{ |
| constants.IDISK_SIZE: utils.ParseUnit(val), |
| constants.IDISK_MODE: constants.DISK_RDWR, |
| } for val in opts.disks.split(",")] |
| except errors.UnitParseError, err: |
| ToStderr("Invalid disks parameter '%s': %s", opts.disks, err) |
| return 1 |
| |
| nics = [val.split("/") for val in opts.nics.split(",")] |
| for row in nics: |
| while len(row) < 3: |
| row.append(None) |
| for i in range(3): |
| if row[i] == "": |
| row[i] = None |
| nic_dict = [{ |
| constants.INIC_MAC: v[0], |
| constants.INIC_IP: v[1], |
| # The iallocator interface defines a "bridge" item |
| "bridge": v[2], |
| } for v in nics] |
| |
| if opts.tags is None: |
| opts.tags = [] |
| else: |
| opts.tags = opts.tags.split(",") |
| if opts.target_groups is None: |
| target_groups = [] |
| else: |
| target_groups = opts.target_groups |
| |
| op = opcodes.OpTestAllocator(mode=opts.mode, |
| name=args[0], |
| instances=args, |
| memory=opts.memory, |
| disks=disks, |
| disk_template=opts.disk_template, |
| nics=nic_dict, |
| os=opts.os, |
| vcpus=opts.vcpus, |
| tags=opts.tags, |
| direction=opts.direction, |
| iallocator=opts.iallocator, |
| evac_mode=opts.evac_mode, |
| target_groups=target_groups, |
| spindle_use=opts.spindle_use, |
| count=opts.count) |
| result = SubmitOpCode(op, opts=opts) |
| ToStdout("%s" % result) |
| return 0 |
| |
| |
| def _TestJobDependency(opts): |
| """Tests job dependencies. |
| |
| """ |
| ToStdout("Testing job dependencies") |
| |
| try: |
| cl = cli.GetClient() |
| SubmitOpCode(opcodes.OpTestDelay(duration=0, depends=[(-1, None)]), cl=cl) |
| except errors.GenericError, err: |
| if opts.debug: |
| ToStdout("Ignoring error for 'wrong dependencies' test: %s", err) |
| else: |
| raise errors.OpExecError("Submitting plain opcode with relative job ID" |
| " did not fail as expected") |
| |
| # TODO: Test dependencies on errors |
| jobs = [ |
| [opcodes.OpTestDelay(duration=1)], |
| [opcodes.OpTestDelay(duration=1, |
| depends=[(-1, [])])], |
| [opcodes.OpTestDelay(duration=1, |
| depends=[(-2, [constants.JOB_STATUS_SUCCESS])])], |
| [opcodes.OpTestDelay(duration=1, |
| depends=[])], |
| [opcodes.OpTestDelay(duration=1, |
| depends=[(-2, [constants.JOB_STATUS_SUCCESS])])], |
| ] |
| |
| # Function for checking result |
| check_fn = ht.TListOf(ht.TAnd(ht.TIsLength(2), |
| ht.TItems([ht.TBool, |
| ht.TOr(ht.TNonEmptyString, |
| ht.TJobId)]))) |
| |
| cl = cli.GetClient() |
| result = cl.SubmitManyJobs(jobs) |
| if not check_fn(result): |
| raise errors.OpExecError("Job submission doesn't match %s: %s" % |
| (check_fn, result)) |
| |
| # Wait for jobs to finish |
| jex = JobExecutor(cl=cl, opts=opts) |
| |
| for (status, job_id) in result: |
| jex.AddJobId(None, status, job_id) |
| |
| job_results = jex.GetResults() |
| if not compat.all(row[0] for row in job_results): |
| raise errors.OpExecError("At least one of the submitted jobs failed: %s" % |
| job_results) |
| |
| # Get details about jobs |
| data = cl.QueryJobs([job_id for (_, job_id) in result], |
| ["id", "opexec", "ops"]) |
| data_job_id = [job_id for (job_id, _, _) in data] |
| data_opexec = [opexec for (_, opexec, _) in data] |
| data_op = [[opcodes.OpCode.LoadOpCode(op) for op in ops] |
| for (_, _, ops) in data] |
| |
| assert compat.all(not op.depends or len(op.depends) == 1 |
| for ops in data_op |
| for op in ops) |
| |
| # Check resolved job IDs in dependencies |
| for (job_idx, res_jobdep) in [(1, data_job_id[0]), |
| (2, data_job_id[0]), |
| (4, data_job_id[2])]: |
| if data_op[job_idx][0].depends[0][0] != res_jobdep: |
| raise errors.OpExecError("Job %s's opcode doesn't depend on correct job" |
| " ID (%s)" % (job_idx, res_jobdep)) |
| |
| # Check execution order |
| if not (data_opexec[0] <= data_opexec[1] and |
| data_opexec[0] <= data_opexec[2] and |
| data_opexec[2] <= data_opexec[4]): |
| raise errors.OpExecError("Jobs did not run in correct order: %s" % data) |
| |
| assert len(jobs) == 5 and compat.all(len(ops) == 1 for ops in jobs) |
| |
| ToStdout("Job dependency tests were successful") |
| |
| |
| def _TestJobSubmission(opts): |
| """Tests submitting jobs. |
| |
| """ |
| ToStdout("Testing job submission") |
| |
| testdata = [ |
| (0, 0, constants.OP_PRIO_LOWEST), |
| (0, 0, constants.OP_PRIO_HIGHEST), |
| ] |
| |
| for priority in (constants.OP_PRIO_SUBMIT_VALID | |
| frozenset([constants.OP_PRIO_LOWEST, |
| constants.OP_PRIO_HIGHEST])): |
| for offset in [-1, +1]: |
| testdata.extend([ |
| (0, 0, priority + offset), |
| (3, 0, priority + offset), |
| (0, 3, priority + offset), |
| (4, 2, priority + offset), |
| ]) |
| |
| for before, after, failpriority in testdata: |
| ops = [] |
| ops.extend([opcodes.OpTestDelay(duration=0) for _ in range(before)]) |
| ops.append(opcodes.OpTestDelay(duration=0, priority=failpriority)) |
| ops.extend([opcodes.OpTestDelay(duration=0) for _ in range(after)]) |
| |
| try: |
| cl = cli.GetClient() |
| cl.SubmitJob(ops) |
| except errors.GenericError, err: |
| if opts.debug: |
| ToStdout("Ignoring error for 'wrong priority' test: %s", err) |
| else: |
| raise errors.OpExecError("Submitting opcode with priority %s did not" |
| " fail when it should (allowed are %s)" % |
| (failpriority, constants.OP_PRIO_SUBMIT_VALID)) |
| |
| jobs = [ |
| [opcodes.OpTestDelay(duration=0), |
| opcodes.OpTestDelay(duration=0, dry_run=False), |
| opcodes.OpTestDelay(duration=0, dry_run=True)], |
| ops, |
| ] |
| try: |
| cl = cli.GetClient() |
| cl.SubmitManyJobs(jobs) |
| except errors.GenericError, err: |
| if opts.debug: |
| ToStdout("Ignoring error for 'wrong priority' test: %s", err) |
| else: |
| raise errors.OpExecError("Submitting manyjobs with an incorrect one" |
| " did not fail when it should.") |
| ToStdout("Job submission tests were successful") |
| |
| |
| class _JobQueueTestReporter(cli.StdioJobPollReportCb): |
| def __init__(self): |
| """Initializes this class. |
| |
| """ |
| cli.StdioJobPollReportCb.__init__(self) |
| self._expected_msgcount = 0 |
| self._all_testmsgs = [] |
| self._testmsgs = None |
| self._job_id = None |
| |
| def GetTestMessages(self): |
| """Returns all test log messages received so far. |
| |
| """ |
| return self._all_testmsgs |
| |
| def GetJobId(self): |
| """Returns the job ID. |
| |
| """ |
| return self._job_id |
| |
| def ReportLogMessage(self, job_id, serial, timestamp, log_type, log_msg): |
| """Handles a log message. |
| |
| """ |
| if self._job_id is None: |
| self._job_id = job_id |
| elif self._job_id != job_id: |
| raise errors.ProgrammerError("The same reporter instance was used for" |
| " more than one job") |
| |
| if log_type == constants.ELOG_JQUEUE_TEST: |
| (sockname, test, arg) = log_msg |
| return self._ProcessTestMessage(job_id, sockname, test, arg) |
| |
| elif (log_type == constants.ELOG_MESSAGE and |
| log_msg.startswith(constants.JQT_MSGPREFIX)): |
| if self._testmsgs is None: |
| raise errors.OpExecError("Received test message without a preceding" |
| " start message") |
| testmsg = log_msg[len(constants.JQT_MSGPREFIX):] |
| self._testmsgs.append(testmsg) |
| self._all_testmsgs.append(testmsg) |
| return |
| |
| return cli.StdioJobPollReportCb.ReportLogMessage(self, job_id, serial, |
| timestamp, log_type, |
| log_msg) |
| |
| def _ProcessTestMessage(self, job_id, sockname, test, arg): |
| """Handles a job queue test message. |
| |
| """ |
| if test not in constants.JQT_ALL: |
| raise errors.OpExecError("Received invalid test message %s" % test) |
| |
| sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) |
| try: |
| sock.settimeout(30.0) |
| |
| logging.debug("Connecting to %s", sockname) |
| sock.connect(sockname) |
| |
| logging.debug("Checking status") |
| jobdetails = cli.GetClient().QueryJobs([job_id], ["status"])[0] |
| if not jobdetails: |
| raise errors.OpExecError("Can't find job %s" % job_id) |
| |
| status = jobdetails[0] |
| |
| logging.debug("Status of job %s is %s", job_id, status) |
| |
| if test == constants.JQT_EXPANDNAMES: |
| if status != constants.JOB_STATUS_WAITING: |
| raise errors.OpExecError("Job status while expanding names is '%s'," |
| " not '%s' as expected" % |
| (status, constants.JOB_STATUS_WAITING)) |
| elif test in (constants.JQT_EXEC, constants.JQT_LOGMSG): |
| if status != constants.JOB_STATUS_RUNNING: |
| raise errors.OpExecError("Job status while executing opcode is '%s'," |
| " not '%s' as expected" % |
| (status, constants.JOB_STATUS_RUNNING)) |
| |
| if test == constants.JQT_STARTMSG: |
| logging.debug("Expecting %s test messages", arg) |
| self._testmsgs = [] |
| elif test == constants.JQT_LOGMSG: |
| if len(self._testmsgs) != arg: |
| raise errors.OpExecError("Received %s test messages when %s are" |
| " expected" % (len(self._testmsgs), arg)) |
| finally: |
| logging.debug("Closing socket") |
| sock.close() |
| |
| |
| def TestJobqueue(opts, _): |
| """Runs a few tests on the job queue. |
| |
| """ |
| _TestJobSubmission(opts) |
| _TestJobDependency(opts) |
| |
| (TM_SUCCESS, |
| TM_MULTISUCCESS, |
| TM_FAIL, |
| TM_PARTFAIL) = range(4) |
| TM_ALL = compat.UniqueFrozenset([ |
| TM_SUCCESS, |
| TM_MULTISUCCESS, |
| TM_FAIL, |
| TM_PARTFAIL, |
| ]) |
| |
| for mode in TM_ALL: |
| test_messages = [ |
| "Testing mode %s" % mode, |
| "Hello World", |
| "A", |
| "", |
| "B", |
| "Foo|bar|baz", |
| utils.TimestampForFilename(), |
| ] |
| |
| fail = mode in (TM_FAIL, TM_PARTFAIL) |
| |
| if mode == TM_PARTFAIL: |
| ToStdout("Testing partial job failure") |
| ops = [ |
| opcodes.OpTestJqueue(notify_waitlock=True, notify_exec=True, |
| log_messages=test_messages, fail=False), |
| opcodes.OpTestJqueue(notify_waitlock=True, notify_exec=True, |
| log_messages=test_messages, fail=False), |
| opcodes.OpTestJqueue(notify_waitlock=True, notify_exec=True, |
| log_messages=test_messages, fail=True), |
| opcodes.OpTestJqueue(notify_waitlock=True, notify_exec=True, |
| log_messages=test_messages, fail=False), |
| ] |
| expect_messages = 3 * [test_messages] |
| expect_opstatus = [ |
| constants.OP_STATUS_SUCCESS, |
| constants.OP_STATUS_SUCCESS, |
| constants.OP_STATUS_ERROR, |
| constants.OP_STATUS_ERROR, |
| ] |
| expect_resultlen = 2 |
| elif mode == TM_MULTISUCCESS: |
| ToStdout("Testing multiple successful opcodes") |
| ops = [ |
| opcodes.OpTestJqueue(notify_waitlock=True, notify_exec=True, |
| log_messages=test_messages, fail=False), |
| opcodes.OpTestJqueue(notify_waitlock=True, notify_exec=True, |
| log_messages=test_messages, fail=False), |
| ] |
| expect_messages = 2 * [test_messages] |
| expect_opstatus = [ |
| constants.OP_STATUS_SUCCESS, |
| constants.OP_STATUS_SUCCESS, |
| ] |
| expect_resultlen = 2 |
| else: |
| if mode == TM_SUCCESS: |
| ToStdout("Testing job success") |
| expect_opstatus = [constants.OP_STATUS_SUCCESS] |
| elif mode == TM_FAIL: |
| ToStdout("Testing job failure") |
| expect_opstatus = [constants.OP_STATUS_ERROR] |
| else: |
| raise errors.ProgrammerError("Unknown test mode %s" % mode) |
| |
| ops = [ |
| opcodes.OpTestJqueue(notify_waitlock=True, |
| notify_exec=True, |
| log_messages=test_messages, |
| fail=fail), |
| ] |
| expect_messages = [test_messages] |
| expect_resultlen = 1 |
| |
| cl = cli.GetClient() |
| cli.SetGenericOpcodeOpts(ops, opts) |
| |
| # Send job to master daemon |
| job_id = cli.SendJob(ops, cl=cl) |
| |
| reporter = _JobQueueTestReporter() |
| results = None |
| |
| try: |
| results = cli.PollJob(job_id, cl=cl, reporter=reporter) |
| except errors.OpExecError, err: |
| if not fail: |
| raise |
| ToStdout("Ignoring error for 'job fail' test: %s", err) |
| else: |
| if fail: |
| raise errors.OpExecError("Job didn't fail when it should") |
| |
| # Check length of result |
| if fail: |
| if results is not None: |
| raise errors.OpExecError("Received result from failed job") |
| elif len(results) != expect_resultlen: |
| raise errors.OpExecError("Received %s results (%s), expected %s" % |
| (len(results), results, expect_resultlen)) |
| |
| # Check received log messages |
| all_messages = [i for j in expect_messages for i in j] |
| if reporter.GetTestMessages() != all_messages: |
| raise errors.OpExecError("Received test messages don't match input" |
| " (input %r, received %r)" % |
| (all_messages, reporter.GetTestMessages())) |
| |
| # Check final status |
| reported_job_id = reporter.GetJobId() |
| if reported_job_id != job_id: |
| raise errors.OpExecError("Reported job ID %s doesn't match" |
| "submission job ID %s" % |
| (reported_job_id, job_id)) |
| |
| jobdetails = cli.GetClient().QueryJobs([job_id], ["status", "opstatus"])[0] |
| if not jobdetails: |
| raise errors.OpExecError("Can't find job %s" % job_id) |
| |
| if fail: |
| exp_status = constants.JOB_STATUS_ERROR |
| else: |
| exp_status = constants.JOB_STATUS_SUCCESS |
| |
| (final_status, final_opstatus) = jobdetails |
| if final_status != exp_status: |
| raise errors.OpExecError("Final job status is %s, not %s as expected" % |
| (final_status, exp_status)) |
| if len(final_opstatus) != len(ops): |
| raise errors.OpExecError("Did not receive status for all opcodes (got %s," |
| " expected %s)" % |
| (len(final_opstatus), len(ops))) |
| if final_opstatus != expect_opstatus: |
| raise errors.OpExecError("Opcode status is %s, expected %s" % |
| (final_opstatus, expect_opstatus)) |
| |
| ToStdout("Job queue test successful") |
| |
| return 0 |
| |
| |
| def TestOsParams(opts, _): |
| """Set secret os parameters. |
| |
| """ |
| op = opcodes.OpTestOsParams(osparams_secret=opts.osparams_secret) |
| SubmitOrSend(op, opts) |
| |
| return 0 |
| |
| |
| def ListLocks(opts, args): # pylint: disable=W0613 |
| """List all locks. |
| |
| @param opts: the command line options selected by the user |
| @type args: list |
| @param args: should be an empty list |
| @rtype: int |
| @return: the desired exit code |
| |
| """ |
| selected_fields = ParseFields(opts.output, _LIST_LOCKS_DEF_FIELDS) |
| |
| def _DashIfNone(fn): |
| def wrapper(value): |
| if not value: |
| return "-" |
| return fn(value) |
| return wrapper |
| |
| def _FormatPending(value): |
| """Format pending acquires. |
| |
| """ |
| return utils.CommaJoin("%s:%s" % (mode, ",".join(map(str, threads))) |
| for mode, threads in value) |
| |
| # Format raw values |
| fmtoverride = { |
| "mode": (_DashIfNone(str), False), |
| "owner": (_DashIfNone(",".join), False), |
| "pending": (_DashIfNone(_FormatPending), False), |
| } |
| |
| while True: |
| ret = GenericList(constants.QR_LOCK, selected_fields, None, None, |
| opts.separator, not opts.no_headers, |
| format_override=fmtoverride, verbose=opts.verbose) |
| |
| if ret != constants.EXIT_SUCCESS: |
| return ret |
| |
| if not opts.interval: |
| break |
| |
| ToStdout("") |
| time.sleep(opts.interval) |
| |
| return 0 |
| |
| |
| def Metad(opts, args): # pylint: disable=W0613 |
| """Send commands to Metad. |
| |
| @param opts: the command line options selected by the user |
| @type args: list |
| @param args: the command to send, followed by the command-specific arguments |
| @rtype: int |
| @return: the desired exit code |
| |
| """ |
| if args[0] == "echo": |
| if len(args) != 2: |
| ToStderr("Command 'echo' takes only precisely argument.") |
| return 1 |
| result = metad.Client().Echo(args[1]) |
| print "Answer: %s" % (result,) |
| else: |
| ToStderr("Command '%s' not supported", args[0]) |
| return 1 |
| |
| return 0 |
| |
| |
| def Wconfd(opts, args): # pylint: disable=W0613 |
| """Send commands to WConfD. |
| |
| @param opts: the command line options selected by the user |
| @type args: list |
| @param args: the command to send, followed by the command-specific arguments |
| @rtype: int |
| @return: the desired exit code |
| |
| """ |
| if args[0] == "echo": |
| if len(args) != 2: |
| ToStderr("Command 'echo' takes only precisely argument.") |
| return 1 |
| result = wconfd.Client().Echo(args[1]) |
| print "Answer: %s" % (result,) |
| elif args[0] == "cleanuplocks": |
| if len(args) != 1: |
| ToStderr("Command 'cleanuplocks' takes no arguments.") |
| return 1 |
| wconfd.Client().CleanupLocks() |
| print "Stale locks cleaned up." |
| elif args[0] == "listlocks": |
| if len(args) != 2: |
| ToStderr("Command 'listlocks' takes precisely one argument.") |
| return 1 |
| wconfdcontext = (int(args[1]), |
| utils.livelock.GuessLockfileFor("masterd_1")) |
| result = wconfd.Client().ListLocks(wconfdcontext) |
| print "Answer: %s" % (result,) |
| elif args[0] == "listalllocks": |
| if len(args) != 1: |
| ToStderr("Command 'listalllocks' takes no arguments.") |
| return 1 |
| result = wconfd.Client().ListAllLocks() |
| print "Answer: %s" % (result,) |
| elif args[0] == "listalllocksowners": |
| if len(args) != 1: |
| ToStderr("Command 'listalllocks' takes no arguments.") |
| return 1 |
| result = wconfd.Client().ListAllLocksOwners() |
| print "Answer: %s" % (result,) |
| elif args[0] == "flushconfig": |
| if len(args) != 1: |
| ToStderr("Command 'flushconfig' takes no arguments.") |
| return 1 |
| wconfd.Client().FlushConfig() |
| print "Configuration flushed." |
| else: |
| ToStderr("Command '%s' not supported", args[0]) |
| return 1 |
| |
| return 0 |
| |
| |
| commands = { |
| "delay": ( |
| Delay, [ArgUnknown(min=1, max=1)], |
| [cli_option("--no-master", dest="on_master", default=True, |
| action="store_false", help="Do not sleep in the master code"), |
| cli_option("-n", dest="on_nodes", default=[], |
| action="append", help="Select nodes to sleep on"), |
| cli_option("-r", "--repeat", type="int", default="0", dest="repeat", |
| help="Number of times to repeat the sleep"), |
| cli_option("-i", "--interruptible", default=False, dest="interruptible", |
| action="store_true", |
| help="Allows the opcode to be interrupted by using a domain " |
| "socket"), |
| cli_option("-l", "--no-locks", default=False, dest="no_locks", |
| action="store_true", |
| help="Don't take locks while performing the delay"), |
| DRY_RUN_OPT, PRIORITY_OPT] + SUBMIT_OPTS, |
| "[opts...] <duration>", "Executes a TestDelay OpCode"), |
| "submit-job": ( |
| GenericOpCodes, [ArgFile(min=1)], |
| [VERBOSE_OPT, |
| cli_option("--op-repeat", type="int", default="1", dest="rep_op", |
| help="Repeat the opcode sequence this number of times"), |
| cli_option("--job-repeat", type="int", default="1", dest="rep_job", |
| help="Repeat the job this number of times"), |
| cli_option("--timing-stats", default=False, |
| action="store_true", help="Show timing stats"), |
| cli_option("--each", default=False, action="store_true", |
| help="Submit each job separately"), |
| DRY_RUN_OPT, PRIORITY_OPT, |
| ], |
| "<op_list_file...>", "Submits jobs built from json files" |
| " containing a list of serialized opcodes"), |
| "iallocator": ( |
| TestAllocator, [ArgUnknown(min=1)], |
| [cli_option("--dir", dest="direction", default=constants.IALLOCATOR_DIR_IN, |
| choices=list(constants.VALID_IALLOCATOR_DIRECTIONS), |
| help="Show allocator input (in) or allocator" |
| " results (out)"), |
| IALLOCATOR_OPT, |
| cli_option("-m", "--mode", default="relocate", |
| choices=list(constants.VALID_IALLOCATOR_MODES), |
| help=("Request mode (one of %s)" % |
| utils.CommaJoin(constants.VALID_IALLOCATOR_MODES))), |
| cli_option("--memory", default=128, type="unit", |
| help="Memory size for the instance (MiB)"), |
| cli_option("--disks", default="4096,4096", |
| help="Comma separated list of disk sizes (MiB)"), |
| DISK_TEMPLATE_OPT, |
| cli_option("--nics", default="00:11:22:33:44:55", |
| help="Comma separated list of nics, each nic" |
| " definition is of form mac/ip/bridge, if" |
| " missing values are replace by None"), |
| OS_OPT, |
| cli_option("-p", "--vcpus", default=1, type="int", |
| help="Select number of VCPUs for the instance"), |
| cli_option("--tags", default=None, |
| help="Comma separated list of tags"), |
| cli_option("--evac-mode", default=constants.NODE_EVAC_ALL, |
| choices=list(constants.NODE_EVAC_MODES), |
| help=("Node evacuation mode (one of %s)" % |
| utils.CommaJoin(constants.NODE_EVAC_MODES))), |
| cli_option("--target-groups", help="Target groups for relocation", |
| default=[], action="append"), |
| cli_option("--spindle-use", help="How many spindles to use", |
| default=1, type="int"), |
| cli_option("--count", help="How many instances to allocate", |
| default=2, type="int"), |
| DRY_RUN_OPT, PRIORITY_OPT, |
| ], |
| "{opts...} <instance>", "Executes a TestAllocator OpCode"), |
| "test-jobqueue": ( |
| TestJobqueue, ARGS_NONE, [PRIORITY_OPT], |
| "", "Test a few aspects of the job queue"), |
| "test-osparams": ( |
| TestOsParams, ARGS_NONE, [OSPARAMS_SECRET_OPT] + SUBMIT_OPTS, |
| "[--os-parameters-secret <params>]", |
| "Test secret os parameter transmission"), |
| "locks": ( |
| ListLocks, ARGS_NONE, |
| [NOHDR_OPT, SEP_OPT, FIELDS_OPT, INTERVAL_OPT, VERBOSE_OPT], |
| "[--interval N]", "Show a list of locks in the master daemon"), |
| "wconfd": ( |
| Wconfd, [ArgUnknown(min=1)], [], |
| "<cmd> <args...>", "Directly talk to WConfD"), |
| "metad": ( |
| Metad, [ArgUnknown(min=1)], [], |
| "<cmd> <args...>", "Directly talk to Metad"), |
| } |
| |
| #: dictionary with aliases for commands |
| aliases = { |
| "allocator": "iallocator", |
| } |
| |
| |
| def Main(): |
| return GenericMain(commands, aliases=aliases) |