"""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
from ganeti import utils
from ganeti import errors
from ganeti import compat
+from ganeti import ht
#: Default fields for L{ListLocks}
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
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
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],
op = opcodes.OpTestAllocator(mode=opts.mode,
name=args[0],
- evac_nodes=args,
instances=args,
memory=opts.memory,
disks=disks,
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.
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',"
"""
_TestJobSubmission(opts)
+ _TestJobDependency(opts)
(TM_SUCCESS,
TM_MULTISUCCESS,
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
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"),
DRY_RUN_OPT, PRIORITY_OPT,
],
"[opts...] <duration>", "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",
],
"<op_list_file...>", "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),
"allocator": "iallocator",
}
+
def Main():
return GenericMain(commands, aliases=aliases)