X-Git-Url: https://code.grnet.gr/git/ganeti-local/blobdiff_plain/dd47a0f073593b714a43b33256aef83f75860e6a..b6267745ede04b3c943bc02e004bdb9347e0f564:/lib/client/gnt_debug.py diff --git a/lib/client/gnt_debug.py b/lib/client/gnt_debug.py index 8065dd7..228733b 100644 --- a/lib/client/gnt_debug.py +++ b/lib/client/gnt_debug.py @@ -20,7 +20,7 @@ """Debugging commands""" -# pylint: disable-msg=W0401,W0614,C0103 +# 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 @@ -37,6 +37,7 @@ from ganeti import opcodes from ganeti import utils from ganeti import errors from ganeti import compat +from ganeti import ht #: Default fields for L{ListLocks} @@ -89,7 +90,7 @@ def GenericOpCodes(opts, args): ToStdout("Loading...") for job_idx in range(opts.rep_job): for fname in args: - # pylint: disable-msg=W0142 + # 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 @@ -112,9 +113,9 @@ def GenericOpCodes(opts, args): 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)) + ToStdout("T:submit %4.4f" % (t2 - t1)) + ToStdout("T:exec %4.4f" % (t3 - t2)) + ToStdout("T:total %4.4f" % (t3 - t1)) return 0 @@ -142,7 +143,7 @@ def TestAllocator(opts, args): while len(row) < 3: row.append(None) for i in range(3): - if row[i] == '': + if row[i] == "": row[i] = None nic_dict = [{ constants.INIC_MAC: v[0], @@ -162,7 +163,6 @@ def TestAllocator(opts, args): op = opcodes.OpTestAllocator(mode=opts.mode, name=args[0], - evac_nodes=args, instances=args, memory=opts.memory, disks=disks, @@ -173,13 +173,96 @@ def TestAllocator(opts, args): tags=opts.tags, direction=opts.direction, allocator=opts.iallocator, - reloc_mode=opts.reloc_mode, + evac_mode=opts.evac_mode, target_groups=target_groups) result = SubmitOpCode(op, opts=opts) ToStdout("%s" % result) return 0 +def _TestJobDependency(opts): + """Tests job dependencies. + + """ + ToStdout("Testing job dependencies") + + cl = cli.GetClient() + + try: + SubmitOpCode(opcodes.OpTestDelay(duration=0, depends=[(-1, None)]), cl=cl) + except errors.GenericError, err: + if opts.debug: + ToStdout("Ignoring error: %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)]))) + + 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. @@ -313,10 +396,10 @@ class _JobQueueTestReporter(cli.StdioJobPollReportCb): logging.debug("Status of job %s is %s", job_id, status) if test == constants.JQT_EXPANDNAMES: - if status != constants.JOB_STATUS_WAITLOCK: + if status != constants.JOB_STATUS_WAITING: raise errors.OpExecError("Job status while expanding names is '%s'," " not '%s' as expected" % - (status, constants.JOB_STATUS_WAITLOCK)) + (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'," @@ -340,6 +423,7 @@ def TestJobqueue(opts, _): """ _TestJobSubmission(opts) + _TestJobDependency(opts) (TM_SUCCESS, TM_MULTISUCCESS, @@ -480,7 +564,7 @@ def TestJobqueue(opts, _): return 0 -def ListLocks(opts, args): # pylint: disable-msg=W0613 +def ListLocks(opts, args): # pylint: disable=W0613 """List all locks. @param opts: the command line options selected by the user @@ -531,7 +615,7 @@ def ListLocks(opts, args): # pylint: disable-msg=W0613 commands = { - 'delay': ( + "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"), @@ -542,7 +626,7 @@ commands = { DRY_RUN_OPT, PRIORITY_OPT, ], "[opts...] ", "Executes a TestDelay OpCode"), - 'submit-job': ( + "submit-job": ( GenericOpCodes, [ArgFile(min=1)], [VERBOSE_OPT, cli_option("--op-repeat", type="int", default="1", dest="rep_op", @@ -557,7 +641,7 @@ commands = { ], "", "Submits jobs built from json files" " containing a list of serialized opcodes"), - 'iallocator': ( + "iallocator": ( TestAllocator, [ArgUnknown(min=1)], [cli_option("--dir", dest="direction", default=constants.IALLOCATOR_DIR_IN, choices=list(constants.VALID_IALLOCATOR_DIRECTIONS), @@ -582,11 +666,12 @@ commands = { help="Select number of VCPUs for the instance"), cli_option("--tags", default=None, help="Comma separated list of tags"), - cli_option("--reloc-mode", default=constants.IALLOCATOR_MRELOC_ANY, - choices=list(constants.IALLOCATOR_MRELOC_MODES), - help=("Instance relocation mode (one of %s)" % - utils.CommaJoin(constants.IALLOCATOR_MRELOC_MODES))), - cli_option("--target-groups", help="Target groups for relocation"), + cli_option("--evac-mode", default=constants.IALLOCATOR_NEVAC_ALL, + choices=list(constants.IALLOCATOR_NEVAC_MODES), + help=("Node evacuation mode (one of %s)" % + utils.CommaJoin(constants.IALLOCATOR_NEVAC_MODES))), + cli_option("--target-groups", help="Target groups for relocation", + default=[], action="append"), DRY_RUN_OPT, PRIORITY_OPT, ], "{opts...} ", "Executes a TestAllocator OpCode"), @@ -604,5 +689,6 @@ aliases = { "allocator": "iallocator", } + def Main(): return GenericMain(commands, aliases=aliases)