Revision 793a8f7c

b/doc/rapi.rst
651 651

  
652 652
Cancel a not-yet-started job.
653 653

  
654

  
655
``/2/jobs/[job_id]/wait``
656
+++++++++++++++++++++++++
657

  
658
``GET``
659
~~~~~~~
660

  
661
Waits for changes on a job. Takes the following body parameters in a
662
dict:
663

  
664
``fields``
665
  The job fields on which to watch for changes.
666

  
667
``previous_job_info``
668
  Previously received field values or None if not yet available.
669

  
670
``previous_log_serial``
671
  Highest log serial number received so far or None if not yet
672
  available.
673

  
674
Returns None if no changes have been detected and a dict with two keys,
675
``job_info`` and ``log_entries`` otherwise.
676

  
677

  
654 678
``/2/nodes``
655 679
++++++++++++
656 680

  
b/lib/luxi.py
64 64
DEF_CTMO = 10
65 65
DEF_RWTO = 60
66 66

  
67
# WaitForJobChange timeout
68
WFJC_TIMEOUT = (DEF_RWTO - 1) / 2
69

  
67 70

  
68 71
class ProtocolError(Exception):
69 72
  """Denotes an error in the server communication"""
......
373 376
    return self.CallMethod(REQ_AUTOARCHIVE_JOBS, (age, timeout))
374 377

  
375 378
  def WaitForJobChangeOnce(self, job_id, fields,
376
                           prev_job_info, prev_log_serial):
377
    timeout = (DEF_RWTO - 1) / 2
379
                           prev_job_info, prev_log_serial,
380
                           timeout=WFJC_TIMEOUT):
381
    """Waits for changes on a job.
382

  
383
    @param job_id: Job ID
384
    @type fields: list
385
    @param fields: List of field names to be observed
386
    @type prev_job_info: None or list
387
    @param prev_job_info: Previously received job information
388
    @type prev_log_serial: None or int/long
389
    @param prev_log_serial: Highest log serial number previously received
390
    @type timeout: int/float
391
    @param timeout: Timeout in seconds (values larger than L{WFJC_TIMEOUT} will
392
                    be capped to that value)
393

  
394
    """
395
    assert timeout >= 0, "Timeout can not be negative"
378 396
    return self.CallMethod(REQ_WAIT_FOR_JOB_CHANGE,
379 397
                           (job_id, fields, prev_job_info,
380
                            prev_log_serial, timeout))
398
                            prev_log_serial,
399
                            min(WFJC_TIMEOUT, timeout)))
381 400

  
382 401
  def WaitForJobChange(self, job_id, fields, prev_job_info, prev_log_serial):
383 402
    while True:
b/lib/rapi/connector.py
209 209
    "/2/jobs": rlib2.R_2_jobs,
210 210
    re.compile(r'/2/jobs/(%s)$' % job_id_pattern):
211 211
      rlib2.R_2_jobs_id,
212
    re.compile(r'/2/jobs/(%s)/wait$' % job_id_pattern):
213
      rlib2.R_2_jobs_id_wait,
212 214

  
213 215
    "/2/tags": rlib2.R_2_tags,
214 216
    "/2/info": rlib2.R_2_info,
b/lib/rapi/rlib2.py
83 83
  "R": _NR_REGULAR,
84 84
  }
85 85

  
86
# Timeout for /2/jobs/[job_id]/wait. Gives job up to 10 seconds to change.
87
_WFJC_TIMEOUT = 10
88

  
86 89

  
87 90
class R_version(baserlib.R_Generic):
88 91
  """/version resource.
......
211 214
    return result
212 215

  
213 216

  
217
class R_2_jobs_id_wait(baserlib.R_Generic):
218
  """/2/jobs/[job_id]/wait resource.
219

  
220
  """
221
  # WaitForJobChange provides access to sensitive information and blocks
222
  # machine resources (it's a blocking RAPI call), hence restricting access.
223
  GET_ACCESS = [rapi.RAPI_ACCESS_WRITE]
224

  
225
  def GET(self):
226
    """Waits for job changes.
227

  
228
    """
229
    job_id = self.items[0]
230

  
231
    fields = self.getBodyParameter("fields")
232
    prev_job_info = self.getBodyParameter("previous_job_info", None)
233
    prev_log_serial = self.getBodyParameter("previous_log_serial", None)
234

  
235
    if not isinstance(fields, list):
236
      raise http.HttpBadRequest("The 'fields' parameter should be a list")
237

  
238
    if not (prev_job_info is None or isinstance(prev_job_info, list)):
239
      raise http.HttpBadRequest("The 'previous_job_info' parameter should"
240
                                " be a list")
241

  
242
    if not (prev_log_serial is None or
243
            isinstance(prev_log_serial, (int, long))):
244
      raise http.HttpBadRequest("The 'previous_log_serial' parameter should"
245
                                " be a number")
246

  
247
    client = baserlib.GetClient()
248
    result = client.WaitForJobChangeOnce(job_id, fields,
249
                                         prev_job_info, prev_log_serial,
250
                                         timeout=_WFJC_TIMEOUT)
251
    if not result:
252
      raise http.HttpNotFound()
253

  
254
    if result == constants.JOB_NOTCHANGED:
255
      # No changes
256
      return None
257

  
258
    (job_info, log_entries) = result
259

  
260
    return {
261
      "job_info": job_info,
262
      "log_entries": log_entries,
263
      }
264

  
265

  
214 266
class R_2_nodes(baserlib.R_Generic):
215 267
  """/2/nodes resource.
216 268

  

Also available in: Unified diff