from ganeti.cli import *
from ganeti import constants
from ganeti import errors
+from ganeti import utils
+from ganeti import cli
#: default list of fields for L{ListJobs}
_USER_JOB_STATUS = {
constants.JOB_STATUS_QUEUED: "queued",
constants.JOB_STATUS_WAITLOCK: "waiting",
+ constants.JOB_STATUS_CANCELING: "canceling",
constants.JOB_STATUS_RUNNING: "running",
constants.JOB_STATUS_CANCELED: "canceled",
constants.JOB_STATUS_SUCCESS: "success",
else:
selected_fields = opts.output.split(",")
- output = GetClient().QueryJobs(None, selected_fields)
+ output = GetClient().QueryJobs(args, selected_fields)
if not opts.no_headers:
# TODO: Implement more fields
headers = {
"start_ts": "Start",
"end_ts": "End",
"received_ts": "Received",
+ "lock_status": "LockStatus",
}
else:
headers = None
- # we don't have yet unitfields here
- unitfields = None
- numfields = None
-
# change raw values to nicer strings
- for row in output:
+ for row_id, row in enumerate(output):
+ if row is None:
+ ToStderr("No such job: %s" % args[row_id])
+ continue
+
for idx, field in enumerate(selected_fields):
val = row[idx]
if field == "status":
val = FormatTimestamp(val)
elif field in ("opstart", "opend"):
val = [FormatTimestamp(entry) for entry in val]
+ elif field == "lock_status" and not val:
+ val = "-"
row[idx] = str(val)
data = GenerateTable(separator=opts.separator, headers=headers,
- fields=selected_fields, unitfields=unitfields,
- numfields=numfields, data=output)
+ fields=selected_fields, data=output)
for line in data:
ToStdout(line)
@param opts: the command line options selected by the user
@type args: list
@param args: should contain only one element, the age as a time spec
- that can be parsed by L{cli.ParseTimespec} or the keyword I{all},
- which will cause all jobs to be archived
+ that can be parsed by L{ganeti.cli.ParseTimespec} or the
+ keyword I{all}, which will cause all jobs to be archived
@rtype: int
@return: the desired exit code
else:
age = ParseTimespec(age)
- client.AutoArchiveJobs(age)
+ (archived_count, jobs_left) = client.AutoArchiveJobs(age)
+ ToStdout("Archived %s jobs, %s unchecked left", archived_count, jobs_left)
+
return 0
client = GetClient()
for job_id in args:
- client.CancelJob(job_id)
+ (success, msg) = client.CancelJob(job_id)
+ ToStdout(msg)
+ # TODO: Different exit value if not all jobs were canceled?
return 0
format(3, "Execution log:")
for serial, log_ts, log_type, log_msg in log:
time_txt = FormatTimestamp(log_ts)
- encoded = str(log_msg).encode('string_escape')
+ encoded = utils.SafeEncode(log_msg)
format(4, "%s:%s:%s %s" % (serial, time_txt, log_type, encoded))
return 0
+def WatchJob(opts, args):
+ """Follow a job and print its output as it arrives.
+
+ @param opts: the command line options selected by the user
+ @type args: list
+ @param args: Contains the job ID
+ @rtype: int
+ @return: the desired exit code
+
+ """
+ job_id = args[0]
+
+ msg = ("Output from job %s follows" % job_id)
+ ToStdout(msg)
+ ToStdout("-" * len(msg))
+
+ retcode = 0
+ try:
+ cli.PollJob(job_id)
+ except errors.GenericError, err:
+ (retcode, job_result) = cli.FormatError(err)
+ ToStderr("Job %s failed: %s", job_id, job_result)
+
+ return retcode
+
+
commands = {
- 'list': (ListJobs, ARGS_NONE,
- [DEBUG_OPT, NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT],
- "", "List the jobs and their status. The available fields are"
- " (see the man page for details): id, status, op_list,"
- " op_status, op_result."
- " The default field"
- " list is (in order): %s." % ", ".join(_LIST_DEF_FIELDS)),
- 'archive': (ArchiveJobs, ARGS_ANY,
- [DEBUG_OPT],
- "<job-id> [<job-id> ...]",
- "Archive specified jobs"),
- 'autoarchive': (AutoArchiveJobs, ARGS_ONE,
- [DEBUG_OPT],
- "<age>",
- "Auto archive jobs older than the given age"),
- 'cancel': (CancelJobs, ARGS_ANY,
- [DEBUG_OPT],
- "<job-id> [<job-id> ...]",
- "Cancel specified jobs"),
- 'info': (ShowJobs, ARGS_ANY, [DEBUG_OPT],
- "<job-id> [<job-id> ...]",
- "Show detailed information about the specified jobs"),
+ 'list': (
+ ListJobs, [ArgJobId()],
+ [NOHDR_OPT, SEP_OPT, FIELDS_OPT],
+ "[job_id ...]",
+ "List the jobs and their status. The available fields are"
+ " (see the man page for details): id, status, op_list,"
+ " op_status, op_result."
+ " The default field"
+ " list is (in order): %s." % ", ".join(_LIST_DEF_FIELDS)),
+ 'archive': (
+ ArchiveJobs, [ArgJobId(min=1)], [],
+ "<job-id> [<job-id> ...]", "Archive specified jobs"),
+ 'autoarchive': (
+ AutoArchiveJobs,
+ [ArgSuggest(min=1, max=1, choices=["1d", "1w", "4w"])],
+ [],
+ "<age>", "Auto archive jobs older than the given age"),
+ 'cancel': (
+ CancelJobs, [ArgJobId(min=1)], [],
+ "<job-id> [<job-id> ...]", "Cancel specified jobs"),
+ 'info': (
+ ShowJobs, [ArgJobId(min=1)], [],
+ "<job-id> [<job-id> ...]",
+ "Show detailed information about the specified jobs"),
+ 'watch': (
+ WatchJob, [ArgJobId(min=1, max=1)], [],
+ "<job-id>", "Follows a job and prints its output as it arrives"),
}