diff --git a/lib/jqueue.py b/lib/jqueue.py
index 9aa0baba7a51e558a3ecf262133c23982b3e2d65..0eb769960fe59e99d7ecfa4328ca20d7c832d3ae 100644
--- a/lib/jqueue.py
+++ b/lib/jqueue.py
@@ -1107,6 +1107,10 @@ class JobQueue(object):
"""
logging.debug("Waiting for changes in job %s", job_id)
+
+ job_info = None
+ log_entries = None
+
end_time = time.time() + timeout
while True:
delta_time = end_time - time.time()
@@ -1148,7 +1152,10 @@ class JobQueue(object):
logging.debug("Job %s changed", job_id)
- return (job_info, log_entries)
+ if job_info is None and log_entries is None:
+ return None
+ else:
+ return (job_info, log_entries)
@utils.LockedMethod
@_RequireOpenQueue
@@ -1172,8 +1179,8 @@ class JobQueue(object):
if job_status not in (constants.JOB_STATUS_QUEUED,
constants.JOB_STATUS_WAITLOCK):
- logging.debug("Job %s is no longer in the queue", job.id)
- return (False, "Job %s is no longer in the queue" % job.id)
+ logging.debug("Job %s is no longer waiting in the queue", job.id)
+ return (False, "Job %s is no longer waiting in the queue" % job.id)
if job_status == constants.JOB_STATUS_QUEUED:
self.CancelJobUnlocked(job)
diff --git a/man/gnt-job.sgml b/man/gnt-job.sgml
index bf81ec7062e1c476caa9564b87008556633845e7..e31d417894ae1c727a783c9f91ea04a852cecd1d 100644
--- a/man/gnt-job.sgml
+++ b/man/gnt-job.sgml
@@ -231,6 +231,20 @@
</para>
</refsect2>
+
+ <refsect2>
+ <title>WATCH</title>
+ <cmdsynopsis>
+ <command>watch</command>
+ <arg>id</arg>
+ </cmdsynopsis>
+
+ <para>
+ This command follows the output of the job by the given
+ <replaceable>id</replaceable> and prints it.
+ </para>
+ </refsect2>
+
</refsect1>
&footer;
diff --git a/scripts/gnt-job b/scripts/gnt-job
index 2da75a35b1da77b5ccf864de88ccfbc2aa0d95d3..1402583e6ae8ba80c3d628aaac0ed2cb7730a7b5 100755
--- a/scripts/gnt-job
+++ b/scripts/gnt-job
@@ -29,6 +29,7 @@ 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}
@@ -312,6 +313,32 @@ def ShowJobs(opts, args):
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_ANY,
[DEBUG_OPT, NOHDR_OPT, SEP_OPT, FIELDS_OPT],
@@ -336,6 +363,9 @@ commands = {
'info': (ShowJobs, ARGS_ANY, [DEBUG_OPT],
"<job-id> [<job-id> ...]",
"Show detailed information about the specified jobs"),
+ 'watch': (WatchJob, ARGS_ONE, [DEBUG_OPT],
+ "<job-id>",
+ "Follows a job and prints its output as it arrives"),
}