Statistics
| Branch: | Tag: | Revision:

root / scripts / gnt-job @ aa9f8167

History | View | Annotate | Download (11.3 kB)

1 7a1ecaed Iustin Pop
#!/usr/bin/python
2 7a1ecaed Iustin Pop
#
3 7a1ecaed Iustin Pop
4 7a1ecaed Iustin Pop
# Copyright (C) 2006, 2007 Google Inc.
5 7a1ecaed Iustin Pop
#
6 7a1ecaed Iustin Pop
# This program is free software; you can redistribute it and/or modify
7 7a1ecaed Iustin Pop
# it under the terms of the GNU General Public License as published by
8 7a1ecaed Iustin Pop
# the Free Software Foundation; either version 2 of the License, or
9 7a1ecaed Iustin Pop
# (at your option) any later version.
10 7a1ecaed Iustin Pop
#
11 7a1ecaed Iustin Pop
# This program is distributed in the hope that it will be useful, but
12 7a1ecaed Iustin Pop
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 7a1ecaed Iustin Pop
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 7a1ecaed Iustin Pop
# General Public License for more details.
15 7a1ecaed Iustin Pop
#
16 7a1ecaed Iustin Pop
# You should have received a copy of the GNU General Public License
17 7a1ecaed Iustin Pop
# along with this program; if not, write to the Free Software
18 7a1ecaed Iustin Pop
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 7a1ecaed Iustin Pop
# 02110-1301, USA.
20 7a1ecaed Iustin Pop
21 7260cfbe Iustin Pop
"""Job related commands"""
22 7a1ecaed Iustin Pop
23 2d54e29c Iustin Pop
# pylint: disable-msg=W0401,W0613,W0614,C0103
24 2f79bd34 Iustin Pop
# W0401: Wildcard import ganeti.cli
25 2d54e29c Iustin Pop
# W0613: Unused argument, since all functions follow the same API
26 2f79bd34 Iustin Pop
# W0614: Unused import %s from wildcard import (since we need cli)
27 7260cfbe Iustin Pop
# C0103: Invalid name gnt-job
28 2f79bd34 Iustin Pop
29 7a1ecaed Iustin Pop
import sys
30 7a1ecaed Iustin Pop
31 7a1ecaed Iustin Pop
from ganeti.cli import *
32 7a1ecaed Iustin Pop
from ganeti import constants
33 7a1ecaed Iustin Pop
from ganeti import errors
34 26f15862 Iustin Pop
from ganeti import utils
35 e7d6946c Michael Hanselmann
from ganeti import cli
36 7a1ecaed Iustin Pop
37 7a1ecaed Iustin Pop
38 917b4e56 Iustin Pop
#: default list of fields for L{ListJobs}
39 60dd1473 Iustin Pop
_LIST_DEF_FIELDS = ["id", "status", "summary"]
40 7a5d3bbd Iustin Pop
41 917b4e56 Iustin Pop
#: map converting the job status contants to user-visible
42 917b4e56 Iustin Pop
#: names
43 af30b2fd Michael Hanselmann
_USER_JOB_STATUS = {
44 af30b2fd Michael Hanselmann
  constants.JOB_STATUS_QUEUED: "queued",
45 e92376d7 Iustin Pop
  constants.JOB_STATUS_WAITLOCK: "waiting",
46 fbf0262f Michael Hanselmann
  constants.JOB_STATUS_CANCELING: "canceling",
47 af30b2fd Michael Hanselmann
  constants.JOB_STATUS_RUNNING: "running",
48 af30b2fd Michael Hanselmann
  constants.JOB_STATUS_CANCELED: "canceled",
49 af30b2fd Michael Hanselmann
  constants.JOB_STATUS_SUCCESS: "success",
50 af30b2fd Michael Hanselmann
  constants.JOB_STATUS_ERROR: "error",
51 af30b2fd Michael Hanselmann
  }
52 af30b2fd Michael Hanselmann
53 0ad64cf8 Michael Hanselmann
54 7a1ecaed Iustin Pop
def ListJobs(opts, args):
55 7a1ecaed Iustin Pop
  """List the jobs
56 7a1ecaed Iustin Pop
57 917b4e56 Iustin Pop
  @param opts: the command line options selected by the user
58 917b4e56 Iustin Pop
  @type args: list
59 917b4e56 Iustin Pop
  @param args: should be an empty list
60 917b4e56 Iustin Pop
  @rtype: int
61 917b4e56 Iustin Pop
  @return: the desired exit code
62 917b4e56 Iustin Pop
63 7a1ecaed Iustin Pop
  """
64 7a1ecaed Iustin Pop
  if opts.output is None:
65 7a5d3bbd Iustin Pop
    selected_fields = _LIST_DEF_FIELDS
66 7a5d3bbd Iustin Pop
  elif opts.output.startswith("+"):
67 7a5d3bbd Iustin Pop
    selected_fields = _LIST_DEF_FIELDS + opts.output[1:].split(",")
68 7a1ecaed Iustin Pop
  else:
69 7a1ecaed Iustin Pop
    selected_fields = opts.output.split(",")
70 7a1ecaed Iustin Pop
71 f1de3563 Iustin Pop
  output = GetClient().QueryJobs(args, selected_fields)
72 7a1ecaed Iustin Pop
  if not opts.no_headers:
73 af30b2fd Michael Hanselmann
    # TODO: Implement more fields
74 7a1ecaed Iustin Pop
    headers = {
75 7a1ecaed Iustin Pop
      "id": "ID",
76 7a1ecaed Iustin Pop
      "status": "Status",
77 af30b2fd Michael Hanselmann
      "ops": "OpCodes",
78 af30b2fd Michael Hanselmann
      "opresult": "OpCode_result",
79 af30b2fd Michael Hanselmann
      "opstatus": "OpCode_status",
80 5b23c34c Iustin Pop
      "oplog": "OpCode_log",
81 60dd1473 Iustin Pop
      "summary": "Summary",
82 aad81f98 Iustin Pop
      "opstart": "OpCode_start",
83 b9b5abcb Iustin Pop
      "opexec": "OpCode_exec",
84 aad81f98 Iustin Pop
      "opend": "OpCode_end",
85 aad81f98 Iustin Pop
      "start_ts": "Start",
86 aad81f98 Iustin Pop
      "end_ts": "End",
87 aad81f98 Iustin Pop
      "received_ts": "Received",
88 1d2dcdfd Michael Hanselmann
      "lock_status": "LockStatus",
89 7a1ecaed Iustin Pop
      }
90 7a1ecaed Iustin Pop
  else:
91 7a1ecaed Iustin Pop
    headers = None
92 7a1ecaed Iustin Pop
93 7a1ecaed Iustin Pop
  # change raw values to nicer strings
94 dcbd6288 Guido Trotter
  for row_id, row in enumerate(output):
95 dcbd6288 Guido Trotter
    if row is None:
96 dcbd6288 Guido Trotter
      ToStderr("No such job: %s" % args[row_id])
97 dcbd6288 Guido Trotter
      continue
98 dcbd6288 Guido Trotter
99 7a1ecaed Iustin Pop
    for idx, field in enumerate(selected_fields):
100 7a1ecaed Iustin Pop
      val = row[idx]
101 7a1ecaed Iustin Pop
      if field == "status":
102 af30b2fd Michael Hanselmann
        if val in _USER_JOB_STATUS:
103 af30b2fd Michael Hanselmann
          val = _USER_JOB_STATUS[val]
104 7a1ecaed Iustin Pop
        else:
105 7a1ecaed Iustin Pop
          raise errors.ProgrammerError("Unknown job status code '%s'" % val)
106 60dd1473 Iustin Pop
      elif field == "summary":
107 60dd1473 Iustin Pop
        val = ",".join(val)
108 aad81f98 Iustin Pop
      elif field in ("start_ts", "end_ts", "received_ts"):
109 aad81f98 Iustin Pop
        val = FormatTimestamp(val)
110 b9b5abcb Iustin Pop
      elif field in ("opstart", "opexec", "opend"):
111 aad81f98 Iustin Pop
        val = [FormatTimestamp(entry) for entry in val]
112 1d2dcdfd Michael Hanselmann
      elif field == "lock_status" and not val:
113 1d2dcdfd Michael Hanselmann
        val = "-"
114 7a1ecaed Iustin Pop
115 7a1ecaed Iustin Pop
      row[idx] = str(val)
116 7a1ecaed Iustin Pop
117 7a1ecaed Iustin Pop
  data = GenerateTable(separator=opts.separator, headers=headers,
118 f1de3563 Iustin Pop
                       fields=selected_fields, data=output)
119 7a1ecaed Iustin Pop
  for line in data:
120 3a24c527 Iustin Pop
    ToStdout(line)
121 7a1ecaed Iustin Pop
122 7a1ecaed Iustin Pop
  return 0
123 7a1ecaed Iustin Pop
124 7a1ecaed Iustin Pop
125 0ad64cf8 Michael Hanselmann
def ArchiveJobs(opts, args):
126 917b4e56 Iustin Pop
  """Archive jobs.
127 917b4e56 Iustin Pop
128 917b4e56 Iustin Pop
  @param opts: the command line options selected by the user
129 917b4e56 Iustin Pop
  @type args: list
130 917b4e56 Iustin Pop
  @param args: should contain the job IDs to be archived
131 917b4e56 Iustin Pop
  @rtype: int
132 917b4e56 Iustin Pop
  @return: the desired exit code
133 917b4e56 Iustin Pop
134 917b4e56 Iustin Pop
  """
135 0ad64cf8 Michael Hanselmann
  client = GetClient()
136 0ad64cf8 Michael Hanselmann
137 aa9f8167 Iustin Pop
  rcode = 0
138 0ad64cf8 Michael Hanselmann
  for job_id in args:
139 aa9f8167 Iustin Pop
    if not client.ArchiveJob(job_id):
140 aa9f8167 Iustin Pop
      ToStderr("Failed to archive job with ID '%s'", job_id)
141 aa9f8167 Iustin Pop
      rcode = 1
142 0ad64cf8 Michael Hanselmann
143 aa9f8167 Iustin Pop
  return rcode
144 0ad64cf8 Michael Hanselmann
145 0ad64cf8 Michael Hanselmann
146 07cd723a Iustin Pop
def AutoArchiveJobs(opts, args):
147 917b4e56 Iustin Pop
  """Archive jobs based on age.
148 917b4e56 Iustin Pop
149 917b4e56 Iustin Pop
  This will archive jobs based on their age, or all jobs if a 'all' is
150 917b4e56 Iustin Pop
  passed.
151 917b4e56 Iustin Pop
152 917b4e56 Iustin Pop
  @param opts: the command line options selected by the user
153 917b4e56 Iustin Pop
  @type args: list
154 917b4e56 Iustin Pop
  @param args: should contain only one element, the age as a time spec
155 c41eea6e Iustin Pop
      that can be parsed by L{ganeti.cli.ParseTimespec} or the
156 c41eea6e Iustin Pop
      keyword I{all}, which will cause all jobs to be archived
157 917b4e56 Iustin Pop
  @rtype: int
158 917b4e56 Iustin Pop
  @return: the desired exit code
159 917b4e56 Iustin Pop
160 917b4e56 Iustin Pop
  """
161 07cd723a Iustin Pop
  client = GetClient()
162 07cd723a Iustin Pop
163 07cd723a Iustin Pop
  age = args[0]
164 07cd723a Iustin Pop
165 07cd723a Iustin Pop
  if age == 'all':
166 07cd723a Iustin Pop
    age = -1
167 07cd723a Iustin Pop
  else:
168 07cd723a Iustin Pop
    age = ParseTimespec(age)
169 07cd723a Iustin Pop
170 f8ad5591 Michael Hanselmann
  (archived_count, jobs_left) = client.AutoArchiveJobs(age)
171 f8ad5591 Michael Hanselmann
  ToStdout("Archived %s jobs, %s unchecked left", archived_count, jobs_left)
172 f8ad5591 Michael Hanselmann
173 07cd723a Iustin Pop
  return 0
174 07cd723a Iustin Pop
175 07cd723a Iustin Pop
176 d2b92ffc Michael Hanselmann
def CancelJobs(opts, args):
177 917b4e56 Iustin Pop
  """Cancel not-yet-started jobs.
178 917b4e56 Iustin Pop
179 917b4e56 Iustin Pop
  @param opts: the command line options selected by the user
180 917b4e56 Iustin Pop
  @type args: list
181 917b4e56 Iustin Pop
  @param args: should contain the job IDs to be cancelled
182 917b4e56 Iustin Pop
  @rtype: int
183 917b4e56 Iustin Pop
  @return: the desired exit code
184 917b4e56 Iustin Pop
185 917b4e56 Iustin Pop
  """
186 d2b92ffc Michael Hanselmann
  client = GetClient()
187 d2b92ffc Michael Hanselmann
188 d2b92ffc Michael Hanselmann
  for job_id in args:
189 f4ad2ef0 Iustin Pop
    (_, msg) = client.CancelJob(job_id)
190 b28a3e8b Michael Hanselmann
    ToStdout(msg)
191 d2b92ffc Michael Hanselmann
192 b28a3e8b Michael Hanselmann
  # TODO: Different exit value if not all jobs were canceled?
193 d2b92ffc Michael Hanselmann
  return 0
194 d2b92ffc Michael Hanselmann
195 d2b92ffc Michael Hanselmann
196 191712c0 Iustin Pop
def ShowJobs(opts, args):
197 917b4e56 Iustin Pop
  """Show detailed information about jobs.
198 917b4e56 Iustin Pop
199 917b4e56 Iustin Pop
  @param opts: the command line options selected by the user
200 917b4e56 Iustin Pop
  @type args: list
201 917b4e56 Iustin Pop
  @param args: should contain the job IDs to be queried
202 917b4e56 Iustin Pop
  @rtype: int
203 917b4e56 Iustin Pop
  @return: the desired exit code
204 191712c0 Iustin Pop
205 191712c0 Iustin Pop
  """
206 c04bc777 Iustin Pop
  def format_msg(level, text):
207 191712c0 Iustin Pop
    """Display the text indented."""
208 3a24c527 Iustin Pop
    ToStdout("%s%s", "  " * level, text)
209 191712c0 Iustin Pop
210 191712c0 Iustin Pop
  def result_helper(value):
211 191712c0 Iustin Pop
    """Format a result field in a nice way."""
212 191712c0 Iustin Pop
    if isinstance(value, (tuple, list)):
213 1f864b60 Iustin Pop
      return "[%s]" % utils.CommaJoin(value)
214 191712c0 Iustin Pop
    else:
215 191712c0 Iustin Pop
      return str(value)
216 191712c0 Iustin Pop
217 aad81f98 Iustin Pop
  selected_fields = [
218 aad81f98 Iustin Pop
    "id", "status", "ops", "opresult", "opstatus", "oplog",
219 b9b5abcb Iustin Pop
    "opstart", "opexec", "opend", "received_ts", "start_ts", "end_ts",
220 aad81f98 Iustin Pop
    ]
221 191712c0 Iustin Pop
222 191712c0 Iustin Pop
  result = GetClient().QueryJobs(args, selected_fields)
223 191712c0 Iustin Pop
224 191712c0 Iustin Pop
  first = True
225 191712c0 Iustin Pop
226 b27b39b0 Iustin Pop
  for idx, entry in enumerate(result):
227 191712c0 Iustin Pop
    if not first:
228 c04bc777 Iustin Pop
      format_msg(0, "")
229 191712c0 Iustin Pop
    else:
230 191712c0 Iustin Pop
      first = False
231 aad81f98 Iustin Pop
232 aad81f98 Iustin Pop
    if entry is None:
233 b27b39b0 Iustin Pop
      if idx <= len(args):
234 c04bc777 Iustin Pop
        format_msg(0, "Job ID %s not found" % args[idx])
235 b27b39b0 Iustin Pop
      else:
236 b27b39b0 Iustin Pop
        # this should not happen, when we don't pass args it will be a
237 b27b39b0 Iustin Pop
        # valid job returned
238 c04bc777 Iustin Pop
        format_msg(0, "Job ID requested as argument %s not found" % (idx + 1))
239 aad81f98 Iustin Pop
      continue
240 aad81f98 Iustin Pop
241 aad81f98 Iustin Pop
    (job_id, status, ops, opresult, opstatus, oplog,
242 b9b5abcb Iustin Pop
     opstart, opexec, opend, recv_ts, start_ts, end_ts) = entry
243 c04bc777 Iustin Pop
    format_msg(0, "Job ID: %s" % job_id)
244 191712c0 Iustin Pop
    if status in _USER_JOB_STATUS:
245 191712c0 Iustin Pop
      status = _USER_JOB_STATUS[status]
246 191712c0 Iustin Pop
    else:
247 2f79bd34 Iustin Pop
      raise errors.ProgrammerError("Unknown job status code '%s'" % status)
248 191712c0 Iustin Pop
249 c04bc777 Iustin Pop
    format_msg(1, "Status: %s" % status)
250 aad81f98 Iustin Pop
251 aad81f98 Iustin Pop
    if recv_ts is not None:
252 c04bc777 Iustin Pop
      format_msg(1, "Received:         %s" % FormatTimestamp(recv_ts))
253 aad81f98 Iustin Pop
    else:
254 c04bc777 Iustin Pop
      format_msg(1, "Missing received timestamp (%s)" % str(recv_ts))
255 aad81f98 Iustin Pop
256 aad81f98 Iustin Pop
    if start_ts is not None:
257 aad81f98 Iustin Pop
      if recv_ts is not None:
258 aad81f98 Iustin Pop
        d1 = start_ts[0] - recv_ts[0] + (start_ts[1] - recv_ts[1]) / 1000000.0
259 aad81f98 Iustin Pop
        delta = " (delta %.6fs)" % d1
260 aad81f98 Iustin Pop
      else:
261 aad81f98 Iustin Pop
        delta = ""
262 c04bc777 Iustin Pop
      format_msg(1, "Processing start: %s%s" %
263 c04bc777 Iustin Pop
                 (FormatTimestamp(start_ts), delta))
264 aad81f98 Iustin Pop
    else:
265 c04bc777 Iustin Pop
      format_msg(1, "Processing start: unknown (%s)" % str(start_ts))
266 aad81f98 Iustin Pop
267 aad81f98 Iustin Pop
    if end_ts is not None:
268 aad81f98 Iustin Pop
      if start_ts is not None:
269 aad81f98 Iustin Pop
        d2 = end_ts[0] - start_ts[0] + (end_ts[1] - start_ts[1]) / 1000000.0
270 aad81f98 Iustin Pop
        delta = " (delta %.6fs)" % d2
271 aad81f98 Iustin Pop
      else:
272 aad81f98 Iustin Pop
        delta = ""
273 c04bc777 Iustin Pop
      format_msg(1, "Processing end:   %s%s" %
274 c04bc777 Iustin Pop
                 (FormatTimestamp(end_ts), delta))
275 aad81f98 Iustin Pop
    else:
276 c04bc777 Iustin Pop
      format_msg(1, "Processing end:   unknown (%s)" % str(end_ts))
277 aad81f98 Iustin Pop
278 aad81f98 Iustin Pop
    if end_ts is not None and recv_ts is not None:
279 aad81f98 Iustin Pop
      d3 = end_ts[0] - recv_ts[0] + (end_ts[1] - recv_ts[1]) / 1000000.0
280 c04bc777 Iustin Pop
      format_msg(1, "Total processing time: %.6f seconds" % d3)
281 aad81f98 Iustin Pop
    else:
282 c04bc777 Iustin Pop
      format_msg(1, "Total processing time: N/A")
283 c04bc777 Iustin Pop
    format_msg(1, "Opcodes:")
284 b9b5abcb Iustin Pop
    for (opcode, result, status, log, s_ts, x_ts, e_ts) in \
285 b9b5abcb Iustin Pop
            zip(ops, opresult, opstatus, oplog, opstart, opexec, opend):
286 c04bc777 Iustin Pop
      format_msg(2, "%s" % opcode["OP_ID"])
287 c04bc777 Iustin Pop
      format_msg(3, "Status: %s" % status)
288 aad81f98 Iustin Pop
      if isinstance(s_ts, (tuple, list)):
289 c04bc777 Iustin Pop
        format_msg(3, "Processing start: %s" % FormatTimestamp(s_ts))
290 aad81f98 Iustin Pop
      else:
291 c04bc777 Iustin Pop
        format_msg(3, "No processing start time")
292 b9b5abcb Iustin Pop
      if isinstance(x_ts, (tuple, list)):
293 c04bc777 Iustin Pop
        format_msg(3, "Execution start:  %s" % FormatTimestamp(x_ts))
294 b9b5abcb Iustin Pop
      else:
295 c04bc777 Iustin Pop
        format_msg(3, "No execution start time")
296 aad81f98 Iustin Pop
      if isinstance(e_ts, (tuple, list)):
297 c04bc777 Iustin Pop
        format_msg(3, "Processing end:   %s" % FormatTimestamp(e_ts))
298 aad81f98 Iustin Pop
      else:
299 c04bc777 Iustin Pop
        format_msg(3, "No processing end time")
300 c04bc777 Iustin Pop
      format_msg(3, "Input fields:")
301 191712c0 Iustin Pop
      for key, val in opcode.iteritems():
302 191712c0 Iustin Pop
        if key == "OP_ID":
303 191712c0 Iustin Pop
          continue
304 191712c0 Iustin Pop
        if isinstance(val, (tuple, list)):
305 08db7c5c Iustin Pop
          val = ",".join([str(item) for item in val])
306 c04bc777 Iustin Pop
        format_msg(4, "%s: %s" % (key, val))
307 191712c0 Iustin Pop
      if result is None:
308 c04bc777 Iustin Pop
        format_msg(3, "No output data")
309 191712c0 Iustin Pop
      elif isinstance(result, (tuple, list)):
310 191712c0 Iustin Pop
        if not result:
311 c04bc777 Iustin Pop
          format_msg(3, "Result: empty sequence")
312 191712c0 Iustin Pop
        else:
313 c04bc777 Iustin Pop
          format_msg(3, "Result:")
314 191712c0 Iustin Pop
          for elem in result:
315 c04bc777 Iustin Pop
            format_msg(4, result_helper(elem))
316 191712c0 Iustin Pop
      elif isinstance(result, dict):
317 191712c0 Iustin Pop
        if not result:
318 c04bc777 Iustin Pop
          format_msg(3, "Result: empty dictionary")
319 191712c0 Iustin Pop
        else:
320 191712c0 Iustin Pop
          for key, val in result.iteritems():
321 c04bc777 Iustin Pop
            format_msg(4, "%s: %s" % (key, result_helper(val)))
322 191712c0 Iustin Pop
      else:
323 c04bc777 Iustin Pop
        format_msg(3, "Result: %s" % result)
324 c04bc777 Iustin Pop
      format_msg(3, "Execution log:")
325 3386e7a9 Iustin Pop
      for serial, log_ts, log_type, log_msg in log:
326 3386e7a9 Iustin Pop
        time_txt = FormatTimestamp(log_ts)
327 8a7f1c61 Michael Hanselmann
        encoded = FormatLogMessage(log_type, log_msg)
328 c04bc777 Iustin Pop
        format_msg(4, "%s:%s:%s %s" % (serial, time_txt, log_type, encoded))
329 191712c0 Iustin Pop
  return 0
330 191712c0 Iustin Pop
331 191712c0 Iustin Pop
332 e7d6946c Michael Hanselmann
def WatchJob(opts, args):
333 e7d6946c Michael Hanselmann
  """Follow a job and print its output as it arrives.
334 e7d6946c Michael Hanselmann
335 e7d6946c Michael Hanselmann
  @param opts: the command line options selected by the user
336 e7d6946c Michael Hanselmann
  @type args: list
337 e7d6946c Michael Hanselmann
  @param args: Contains the job ID
338 e7d6946c Michael Hanselmann
  @rtype: int
339 e7d6946c Michael Hanselmann
  @return: the desired exit code
340 e7d6946c Michael Hanselmann
341 e7d6946c Michael Hanselmann
  """
342 e7d6946c Michael Hanselmann
  job_id = args[0]
343 e7d6946c Michael Hanselmann
344 e7d6946c Michael Hanselmann
  msg = ("Output from job %s follows" % job_id)
345 e7d6946c Michael Hanselmann
  ToStdout(msg)
346 e7d6946c Michael Hanselmann
  ToStdout("-" * len(msg))
347 e7d6946c Michael Hanselmann
348 e7d6946c Michael Hanselmann
  retcode = 0
349 e7d6946c Michael Hanselmann
  try:
350 e7d6946c Michael Hanselmann
    cli.PollJob(job_id)
351 e7d6946c Michael Hanselmann
  except errors.GenericError, err:
352 e7d6946c Michael Hanselmann
    (retcode, job_result) = cli.FormatError(err)
353 e7d6946c Michael Hanselmann
    ToStderr("Job %s failed: %s", job_id, job_result)
354 e7d6946c Michael Hanselmann
355 e7d6946c Michael Hanselmann
  return retcode
356 e7d6946c Michael Hanselmann
357 e7d6946c Michael Hanselmann
358 7a1ecaed Iustin Pop
commands = {
359 6ea815cf Iustin Pop
  'list': (
360 6ea815cf Iustin Pop
    ListJobs, [ArgJobId()],
361 064c21f8 Iustin Pop
    [NOHDR_OPT, SEP_OPT, FIELDS_OPT],
362 6ea815cf Iustin Pop
    "[job_id ...]",
363 6ea815cf Iustin Pop
    "List the jobs and their status. The available fields are"
364 6ea815cf Iustin Pop
    " (see the man page for details): id, status, op_list,"
365 6ea815cf Iustin Pop
    " op_status, op_result."
366 6ea815cf Iustin Pop
    " The default field"
367 1f864b60 Iustin Pop
    " list is (in order): %s." % utils.CommaJoin(_LIST_DEF_FIELDS)),
368 6ea815cf Iustin Pop
  'archive': (
369 064c21f8 Iustin Pop
    ArchiveJobs, [ArgJobId(min=1)], [],
370 6ea815cf Iustin Pop
    "<job-id> [<job-id> ...]", "Archive specified jobs"),
371 6ea815cf Iustin Pop
  'autoarchive': (
372 6ea815cf Iustin Pop
    AutoArchiveJobs,
373 94182b63 Iustin Pop
    [ArgSuggest(min=1, max=1, choices=["1d", "1w", "4w", "all"])],
374 064c21f8 Iustin Pop
    [],
375 6ea815cf Iustin Pop
    "<age>", "Auto archive jobs older than the given age"),
376 6ea815cf Iustin Pop
  'cancel': (
377 064c21f8 Iustin Pop
    CancelJobs, [ArgJobId(min=1)], [],
378 6ea815cf Iustin Pop
    "<job-id> [<job-id> ...]", "Cancel specified jobs"),
379 6ea815cf Iustin Pop
  'info': (
380 064c21f8 Iustin Pop
    ShowJobs, [ArgJobId(min=1)], [],
381 6ea815cf Iustin Pop
    "<job-id> [<job-id> ...]",
382 6ea815cf Iustin Pop
    "Show detailed information about the specified jobs"),
383 6ea815cf Iustin Pop
  'watch': (
384 064c21f8 Iustin Pop
    WatchJob, [ArgJobId(min=1, max=1)], [],
385 6ea815cf Iustin Pop
    "<job-id>", "Follows a job and prints its output as it arrives"),
386 7a1ecaed Iustin Pop
  }
387 7a1ecaed Iustin Pop
388 7a1ecaed Iustin Pop
389 7a1ecaed Iustin Pop
if __name__ == '__main__':
390 7a1ecaed Iustin Pop
  sys.exit(GenericMain(commands))