Statistics
| Branch: | Tag: | Revision:

root / lib / client / gnt_job.py @ 42c161cf

History | View | Annotate | Download (11.3 kB)

1 a09b9e3d Michael Hanselmann
#
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
from ganeti.cli import *
30 7a1ecaed Iustin Pop
from ganeti import constants
31 7a1ecaed Iustin Pop
from ganeti import errors
32 26f15862 Iustin Pop
from ganeti import utils
33 e7d6946c Michael Hanselmann
from ganeti import cli
34 7a1ecaed Iustin Pop
35 7a1ecaed Iustin Pop
36 917b4e56 Iustin Pop
#: default list of fields for L{ListJobs}
37 60dd1473 Iustin Pop
_LIST_DEF_FIELDS = ["id", "status", "summary"]
38 7a5d3bbd Iustin Pop
39 917b4e56 Iustin Pop
#: map converting the job status contants to user-visible
40 917b4e56 Iustin Pop
#: names
41 af30b2fd Michael Hanselmann
_USER_JOB_STATUS = {
42 af30b2fd Michael Hanselmann
  constants.JOB_STATUS_QUEUED: "queued",
43 e92376d7 Iustin Pop
  constants.JOB_STATUS_WAITLOCK: "waiting",
44 fbf0262f Michael Hanselmann
  constants.JOB_STATUS_CANCELING: "canceling",
45 af30b2fd Michael Hanselmann
  constants.JOB_STATUS_RUNNING: "running",
46 af30b2fd Michael Hanselmann
  constants.JOB_STATUS_CANCELED: "canceled",
47 af30b2fd Michael Hanselmann
  constants.JOB_STATUS_SUCCESS: "success",
48 af30b2fd Michael Hanselmann
  constants.JOB_STATUS_ERROR: "error",
49 af30b2fd Michael Hanselmann
  }
50 af30b2fd Michael Hanselmann
51 0ad64cf8 Michael Hanselmann
52 7a1ecaed Iustin Pop
def ListJobs(opts, args):
53 7a1ecaed Iustin Pop
  """List the jobs
54 7a1ecaed Iustin Pop

55 917b4e56 Iustin Pop
  @param opts: the command line options selected by the user
56 917b4e56 Iustin Pop
  @type args: list
57 917b4e56 Iustin Pop
  @param args: should be an empty list
58 917b4e56 Iustin Pop
  @rtype: int
59 917b4e56 Iustin Pop
  @return: the desired exit code
60 917b4e56 Iustin Pop

61 7a1ecaed Iustin Pop
  """
62 a4ebd726 Michael Hanselmann
  selected_fields = ParseFields(opts.output, _LIST_DEF_FIELDS)
63 7a1ecaed Iustin Pop
64 f1de3563 Iustin Pop
  output = GetClient().QueryJobs(args, selected_fields)
65 7a1ecaed Iustin Pop
  if not opts.no_headers:
66 af30b2fd Michael Hanselmann
    # TODO: Implement more fields
67 7a1ecaed Iustin Pop
    headers = {
68 7a1ecaed Iustin Pop
      "id": "ID",
69 7a1ecaed Iustin Pop
      "status": "Status",
70 b8802cc4 Michael Hanselmann
      "priority": "Prio",
71 af30b2fd Michael Hanselmann
      "ops": "OpCodes",
72 af30b2fd Michael Hanselmann
      "opresult": "OpCode_result",
73 af30b2fd Michael Hanselmann
      "opstatus": "OpCode_status",
74 5b23c34c Iustin Pop
      "oplog": "OpCode_log",
75 60dd1473 Iustin Pop
      "summary": "Summary",
76 aad81f98 Iustin Pop
      "opstart": "OpCode_start",
77 b9b5abcb Iustin Pop
      "opexec": "OpCode_exec",
78 aad81f98 Iustin Pop
      "opend": "OpCode_end",
79 b8802cc4 Michael Hanselmann
      "oppriority": "OpCode_prio",
80 aad81f98 Iustin Pop
      "start_ts": "Start",
81 aad81f98 Iustin Pop
      "end_ts": "End",
82 aad81f98 Iustin Pop
      "received_ts": "Received",
83 7a1ecaed Iustin Pop
      }
84 7a1ecaed Iustin Pop
  else:
85 7a1ecaed Iustin Pop
    headers = None
86 7a1ecaed Iustin Pop
87 b8802cc4 Michael Hanselmann
  numfields = ["priority"]
88 b8802cc4 Michael Hanselmann
89 7a1ecaed Iustin Pop
  # change raw values to nicer strings
90 dcbd6288 Guido Trotter
  for row_id, row in enumerate(output):
91 dcbd6288 Guido Trotter
    if row is None:
92 dcbd6288 Guido Trotter
      ToStderr("No such job: %s" % args[row_id])
93 dcbd6288 Guido Trotter
      continue
94 dcbd6288 Guido Trotter
95 7a1ecaed Iustin Pop
    for idx, field in enumerate(selected_fields):
96 7a1ecaed Iustin Pop
      val = row[idx]
97 7a1ecaed Iustin Pop
      if field == "status":
98 af30b2fd Michael Hanselmann
        if val in _USER_JOB_STATUS:
99 af30b2fd Michael Hanselmann
          val = _USER_JOB_STATUS[val]
100 7a1ecaed Iustin Pop
        else:
101 7a1ecaed Iustin Pop
          raise errors.ProgrammerError("Unknown job status code '%s'" % val)
102 60dd1473 Iustin Pop
      elif field == "summary":
103 60dd1473 Iustin Pop
        val = ",".join(val)
104 aad81f98 Iustin Pop
      elif field in ("start_ts", "end_ts", "received_ts"):
105 aad81f98 Iustin Pop
        val = FormatTimestamp(val)
106 b9b5abcb Iustin Pop
      elif field in ("opstart", "opexec", "opend"):
107 aad81f98 Iustin Pop
        val = [FormatTimestamp(entry) for entry in val]
108 7a1ecaed Iustin Pop
109 7a1ecaed Iustin Pop
      row[idx] = str(val)
110 7a1ecaed Iustin Pop
111 7a1ecaed Iustin Pop
  data = GenerateTable(separator=opts.separator, headers=headers,
112 b8802cc4 Michael Hanselmann
                       fields=selected_fields, data=output,
113 b8802cc4 Michael Hanselmann
                       numfields=numfields)
114 7a1ecaed Iustin Pop
  for line in data:
115 3a24c527 Iustin Pop
    ToStdout(line)
116 7a1ecaed Iustin Pop
117 7a1ecaed Iustin Pop
  return 0
118 7a1ecaed Iustin Pop
119 7a1ecaed Iustin Pop
120 0ad64cf8 Michael Hanselmann
def ArchiveJobs(opts, args):
121 917b4e56 Iustin Pop
  """Archive jobs.
122 917b4e56 Iustin Pop

123 917b4e56 Iustin Pop
  @param opts: the command line options selected by the user
124 917b4e56 Iustin Pop
  @type args: list
125 917b4e56 Iustin Pop
  @param args: should contain the job IDs to be archived
126 917b4e56 Iustin Pop
  @rtype: int
127 917b4e56 Iustin Pop
  @return: the desired exit code
128 917b4e56 Iustin Pop

129 917b4e56 Iustin Pop
  """
130 0ad64cf8 Michael Hanselmann
  client = GetClient()
131 0ad64cf8 Michael Hanselmann
132 aa9f8167 Iustin Pop
  rcode = 0
133 0ad64cf8 Michael Hanselmann
  for job_id in args:
134 aa9f8167 Iustin Pop
    if not client.ArchiveJob(job_id):
135 aa9f8167 Iustin Pop
      ToStderr("Failed to archive job with ID '%s'", job_id)
136 aa9f8167 Iustin Pop
      rcode = 1
137 0ad64cf8 Michael Hanselmann
138 aa9f8167 Iustin Pop
  return rcode
139 0ad64cf8 Michael Hanselmann
140 0ad64cf8 Michael Hanselmann
141 07cd723a Iustin Pop
def AutoArchiveJobs(opts, args):
142 917b4e56 Iustin Pop
  """Archive jobs based on age.
143 917b4e56 Iustin Pop

144 917b4e56 Iustin Pop
  This will archive jobs based on their age, or all jobs if a 'all' is
145 917b4e56 Iustin Pop
  passed.
146 917b4e56 Iustin Pop

147 917b4e56 Iustin Pop
  @param opts: the command line options selected by the user
148 917b4e56 Iustin Pop
  @type args: list
149 917b4e56 Iustin Pop
  @param args: should contain only one element, the age as a time spec
150 c41eea6e Iustin Pop
      that can be parsed by L{ganeti.cli.ParseTimespec} or the
151 c41eea6e Iustin Pop
      keyword I{all}, which will cause all jobs to be archived
152 917b4e56 Iustin Pop
  @rtype: int
153 917b4e56 Iustin Pop
  @return: the desired exit code
154 917b4e56 Iustin Pop

155 917b4e56 Iustin Pop
  """
156 07cd723a Iustin Pop
  client = GetClient()
157 07cd723a Iustin Pop
158 07cd723a Iustin Pop
  age = args[0]
159 07cd723a Iustin Pop
160 07cd723a Iustin Pop
  if age == 'all':
161 07cd723a Iustin Pop
    age = -1
162 07cd723a Iustin Pop
  else:
163 07cd723a Iustin Pop
    age = ParseTimespec(age)
164 07cd723a Iustin Pop
165 f8ad5591 Michael Hanselmann
  (archived_count, jobs_left) = client.AutoArchiveJobs(age)
166 f8ad5591 Michael Hanselmann
  ToStdout("Archived %s jobs, %s unchecked left", archived_count, jobs_left)
167 f8ad5591 Michael Hanselmann
168 07cd723a Iustin Pop
  return 0
169 07cd723a Iustin Pop
170 07cd723a Iustin Pop
171 d2b92ffc Michael Hanselmann
def CancelJobs(opts, args):
172 917b4e56 Iustin Pop
  """Cancel not-yet-started jobs.
173 917b4e56 Iustin Pop

174 917b4e56 Iustin Pop
  @param opts: the command line options selected by the user
175 917b4e56 Iustin Pop
  @type args: list
176 917b4e56 Iustin Pop
  @param args: should contain the job IDs to be cancelled
177 917b4e56 Iustin Pop
  @rtype: int
178 917b4e56 Iustin Pop
  @return: the desired exit code
179 917b4e56 Iustin Pop

180 917b4e56 Iustin Pop
  """
181 d2b92ffc Michael Hanselmann
  client = GetClient()
182 06fef5e0 Michael Hanselmann
  result = constants.EXIT_SUCCESS
183 d2b92ffc Michael Hanselmann
184 d2b92ffc Michael Hanselmann
  for job_id in args:
185 06fef5e0 Michael Hanselmann
    (success, msg) = client.CancelJob(job_id)
186 06fef5e0 Michael Hanselmann
187 06fef5e0 Michael Hanselmann
    if not success:
188 06fef5e0 Michael Hanselmann
      result = constants.EXIT_FAILURE
189 06fef5e0 Michael Hanselmann
190 b28a3e8b Michael Hanselmann
    ToStdout(msg)
191 d2b92ffc Michael Hanselmann
192 06fef5e0 Michael Hanselmann
  return result
193 d2b92ffc Michael Hanselmann
194 d2b92ffc Michael Hanselmann
195 191712c0 Iustin Pop
def ShowJobs(opts, args):
196 917b4e56 Iustin Pop
  """Show detailed information about jobs.
197 917b4e56 Iustin Pop

198 917b4e56 Iustin Pop
  @param opts: the command line options selected by the user
199 917b4e56 Iustin Pop
  @type args: list
200 917b4e56 Iustin Pop
  @param args: should contain the job IDs to be queried
201 917b4e56 Iustin Pop
  @rtype: int
202 917b4e56 Iustin Pop
  @return: the desired exit code
203 191712c0 Iustin Pop

204 191712c0 Iustin Pop
  """
205 c04bc777 Iustin Pop
  def format_msg(level, text):
206 191712c0 Iustin Pop
    """Display the text indented."""
207 3a24c527 Iustin Pop
    ToStdout("%s%s", "  " * level, text)
208 191712c0 Iustin Pop
209 191712c0 Iustin Pop
  def result_helper(value):
210 191712c0 Iustin Pop
    """Format a result field in a nice way."""
211 191712c0 Iustin Pop
    if isinstance(value, (tuple, list)):
212 1f864b60 Iustin Pop
      return "[%s]" % utils.CommaJoin(value)
213 191712c0 Iustin Pop
    else:
214 191712c0 Iustin Pop
      return str(value)
215 191712c0 Iustin Pop
216 aad81f98 Iustin Pop
  selected_fields = [
217 aad81f98 Iustin Pop
    "id", "status", "ops", "opresult", "opstatus", "oplog",
218 b9b5abcb Iustin Pop
    "opstart", "opexec", "opend", "received_ts", "start_ts", "end_ts",
219 aad81f98 Iustin Pop
    ]
220 191712c0 Iustin Pop
221 191712c0 Iustin Pop
  result = GetClient().QueryJobs(args, selected_fields)
222 191712c0 Iustin Pop
223 191712c0 Iustin Pop
  first = True
224 191712c0 Iustin Pop
225 b27b39b0 Iustin Pop
  for idx, entry in enumerate(result):
226 191712c0 Iustin Pop
    if not first:
227 c04bc777 Iustin Pop
      format_msg(0, "")
228 191712c0 Iustin Pop
    else:
229 191712c0 Iustin Pop
      first = False
230 aad81f98 Iustin Pop
231 aad81f98 Iustin Pop
    if entry is None:
232 b27b39b0 Iustin Pop
      if idx <= len(args):
233 c04bc777 Iustin Pop
        format_msg(0, "Job ID %s not found" % args[idx])
234 b27b39b0 Iustin Pop
      else:
235 b27b39b0 Iustin Pop
        # this should not happen, when we don't pass args it will be a
236 b27b39b0 Iustin Pop
        # valid job returned
237 c04bc777 Iustin Pop
        format_msg(0, "Job ID requested as argument %s not found" % (idx + 1))
238 aad81f98 Iustin Pop
      continue
239 aad81f98 Iustin Pop
240 aad81f98 Iustin Pop
    (job_id, status, ops, opresult, opstatus, oplog,
241 b9b5abcb Iustin Pop
     opstart, opexec, opend, recv_ts, start_ts, end_ts) = entry
242 c04bc777 Iustin Pop
    format_msg(0, "Job ID: %s" % job_id)
243 191712c0 Iustin Pop
    if status in _USER_JOB_STATUS:
244 191712c0 Iustin Pop
      status = _USER_JOB_STATUS[status]
245 191712c0 Iustin Pop
    else:
246 2f79bd34 Iustin Pop
      raise errors.ProgrammerError("Unknown job status code '%s'" % status)
247 191712c0 Iustin Pop
248 c04bc777 Iustin Pop
    format_msg(1, "Status: %s" % status)
249 aad81f98 Iustin Pop
250 aad81f98 Iustin Pop
    if recv_ts is not None:
251 c04bc777 Iustin Pop
      format_msg(1, "Received:         %s" % FormatTimestamp(recv_ts))
252 aad81f98 Iustin Pop
    else:
253 c04bc777 Iustin Pop
      format_msg(1, "Missing received timestamp (%s)" % str(recv_ts))
254 aad81f98 Iustin Pop
255 aad81f98 Iustin Pop
    if start_ts is not None:
256 aad81f98 Iustin Pop
      if recv_ts is not None:
257 aad81f98 Iustin Pop
        d1 = start_ts[0] - recv_ts[0] + (start_ts[1] - recv_ts[1]) / 1000000.0
258 aad81f98 Iustin Pop
        delta = " (delta %.6fs)" % d1
259 aad81f98 Iustin Pop
      else:
260 aad81f98 Iustin Pop
        delta = ""
261 c04bc777 Iustin Pop
      format_msg(1, "Processing start: %s%s" %
262 c04bc777 Iustin Pop
                 (FormatTimestamp(start_ts), delta))
263 aad81f98 Iustin Pop
    else:
264 c04bc777 Iustin Pop
      format_msg(1, "Processing start: unknown (%s)" % str(start_ts))
265 aad81f98 Iustin Pop
266 aad81f98 Iustin Pop
    if end_ts is not None:
267 aad81f98 Iustin Pop
      if start_ts is not None:
268 aad81f98 Iustin Pop
        d2 = end_ts[0] - start_ts[0] + (end_ts[1] - start_ts[1]) / 1000000.0
269 aad81f98 Iustin Pop
        delta = " (delta %.6fs)" % d2
270 aad81f98 Iustin Pop
      else:
271 aad81f98 Iustin Pop
        delta = ""
272 c04bc777 Iustin Pop
      format_msg(1, "Processing end:   %s%s" %
273 c04bc777 Iustin Pop
                 (FormatTimestamp(end_ts), delta))
274 aad81f98 Iustin Pop
    else:
275 c04bc777 Iustin Pop
      format_msg(1, "Processing end:   unknown (%s)" % str(end_ts))
276 aad81f98 Iustin Pop
277 aad81f98 Iustin Pop
    if end_ts is not None and recv_ts is not None:
278 aad81f98 Iustin Pop
      d3 = end_ts[0] - recv_ts[0] + (end_ts[1] - recv_ts[1]) / 1000000.0
279 c04bc777 Iustin Pop
      format_msg(1, "Total processing time: %.6f seconds" % d3)
280 aad81f98 Iustin Pop
    else:
281 c04bc777 Iustin Pop
      format_msg(1, "Total processing time: N/A")
282 c04bc777 Iustin Pop
    format_msg(1, "Opcodes:")
283 b9b5abcb Iustin Pop
    for (opcode, result, status, log, s_ts, x_ts, e_ts) in \
284 b9b5abcb Iustin Pop
            zip(ops, opresult, opstatus, oplog, opstart, opexec, opend):
285 c04bc777 Iustin Pop
      format_msg(2, "%s" % opcode["OP_ID"])
286 c04bc777 Iustin Pop
      format_msg(3, "Status: %s" % status)
287 aad81f98 Iustin Pop
      if isinstance(s_ts, (tuple, list)):
288 c04bc777 Iustin Pop
        format_msg(3, "Processing start: %s" % FormatTimestamp(s_ts))
289 aad81f98 Iustin Pop
      else:
290 c04bc777 Iustin Pop
        format_msg(3, "No processing start time")
291 b9b5abcb Iustin Pop
      if isinstance(x_ts, (tuple, list)):
292 c04bc777 Iustin Pop
        format_msg(3, "Execution start:  %s" % FormatTimestamp(x_ts))
293 b9b5abcb Iustin Pop
      else:
294 c04bc777 Iustin Pop
        format_msg(3, "No execution start time")
295 aad81f98 Iustin Pop
      if isinstance(e_ts, (tuple, list)):
296 c04bc777 Iustin Pop
        format_msg(3, "Processing end:   %s" % FormatTimestamp(e_ts))
297 aad81f98 Iustin Pop
      else:
298 c04bc777 Iustin Pop
        format_msg(3, "No processing end time")
299 c04bc777 Iustin Pop
      format_msg(3, "Input fields:")
300 598b5255 Michael Hanselmann
      for key in utils.NiceSort(opcode.keys()):
301 191712c0 Iustin Pop
        if key == "OP_ID":
302 191712c0 Iustin Pop
          continue
303 598b5255 Michael Hanselmann
        val = opcode[key]
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 d1b47b16 Michael Hanselmann
          format_msg(3, "Result:")
321 191712c0 Iustin Pop
          for key, val in result.iteritems():
322 c04bc777 Iustin Pop
            format_msg(4, "%s: %s" % (key, result_helper(val)))
323 191712c0 Iustin Pop
      else:
324 c04bc777 Iustin Pop
        format_msg(3, "Result: %s" % result)
325 c04bc777 Iustin Pop
      format_msg(3, "Execution log:")
326 3386e7a9 Iustin Pop
      for serial, log_ts, log_type, log_msg in log:
327 3386e7a9 Iustin Pop
        time_txt = FormatTimestamp(log_ts)
328 8a7f1c61 Michael Hanselmann
        encoded = FormatLogMessage(log_type, log_msg)
329 c04bc777 Iustin Pop
        format_msg(4, "%s:%s:%s %s" % (serial, time_txt, log_type, encoded))
330 191712c0 Iustin Pop
  return 0
331 191712c0 Iustin Pop
332 191712c0 Iustin Pop
333 e7d6946c Michael Hanselmann
def WatchJob(opts, args):
334 e7d6946c Michael Hanselmann
  """Follow a job and print its output as it arrives.
335 e7d6946c Michael Hanselmann

336 e7d6946c Michael Hanselmann
  @param opts: the command line options selected by the user
337 e7d6946c Michael Hanselmann
  @type args: list
338 e7d6946c Michael Hanselmann
  @param args: Contains the job ID
339 e7d6946c Michael Hanselmann
  @rtype: int
340 e7d6946c Michael Hanselmann
  @return: the desired exit code
341 e7d6946c Michael Hanselmann

342 e7d6946c Michael Hanselmann
  """
343 e7d6946c Michael Hanselmann
  job_id = args[0]
344 e7d6946c Michael Hanselmann
345 e7d6946c Michael Hanselmann
  msg = ("Output from job %s follows" % job_id)
346 e7d6946c Michael Hanselmann
  ToStdout(msg)
347 e7d6946c Michael Hanselmann
  ToStdout("-" * len(msg))
348 e7d6946c Michael Hanselmann
349 e7d6946c Michael Hanselmann
  retcode = 0
350 e7d6946c Michael Hanselmann
  try:
351 e7d6946c Michael Hanselmann
    cli.PollJob(job_id)
352 e7d6946c Michael Hanselmann
  except errors.GenericError, err:
353 e7d6946c Michael Hanselmann
    (retcode, job_result) = cli.FormatError(err)
354 e7d6946c Michael Hanselmann
    ToStderr("Job %s failed: %s", job_id, job_result)
355 e7d6946c Michael Hanselmann
356 e7d6946c Michael Hanselmann
  return retcode
357 e7d6946c Michael Hanselmann
358 e7d6946c Michael Hanselmann
359 7a1ecaed Iustin Pop
commands = {
360 6ea815cf Iustin Pop
  'list': (
361 6ea815cf Iustin Pop
    ListJobs, [ArgJobId()],
362 064c21f8 Iustin Pop
    [NOHDR_OPT, SEP_OPT, FIELDS_OPT],
363 6ea815cf Iustin Pop
    "[job_id ...]",
364 6ea815cf Iustin Pop
    "List the jobs and their status. The available fields are"
365 6ea815cf Iustin Pop
    " (see the man page for details): id, status, op_list,"
366 6ea815cf Iustin Pop
    " op_status, op_result."
367 6ea815cf Iustin Pop
    " The default field"
368 1f864b60 Iustin Pop
    " list is (in order): %s." % utils.CommaJoin(_LIST_DEF_FIELDS)),
369 6ea815cf Iustin Pop
  'archive': (
370 064c21f8 Iustin Pop
    ArchiveJobs, [ArgJobId(min=1)], [],
371 6ea815cf Iustin Pop
    "<job-id> [<job-id> ...]", "Archive specified jobs"),
372 6ea815cf Iustin Pop
  'autoarchive': (
373 6ea815cf Iustin Pop
    AutoArchiveJobs,
374 94182b63 Iustin Pop
    [ArgSuggest(min=1, max=1, choices=["1d", "1w", "4w", "all"])],
375 064c21f8 Iustin Pop
    [],
376 6ea815cf Iustin Pop
    "<age>", "Auto archive jobs older than the given age"),
377 6ea815cf Iustin Pop
  'cancel': (
378 064c21f8 Iustin Pop
    CancelJobs, [ArgJobId(min=1)], [],
379 6ea815cf Iustin Pop
    "<job-id> [<job-id> ...]", "Cancel specified jobs"),
380 6ea815cf Iustin Pop
  'info': (
381 064c21f8 Iustin Pop
    ShowJobs, [ArgJobId(min=1)], [],
382 6ea815cf Iustin Pop
    "<job-id> [<job-id> ...]",
383 6ea815cf Iustin Pop
    "Show detailed information about the specified jobs"),
384 6ea815cf Iustin Pop
  'watch': (
385 064c21f8 Iustin Pop
    WatchJob, [ArgJobId(min=1, max=1)], [],
386 6ea815cf Iustin Pop
    "<job-id>", "Follows a job and prints its output as it arrives"),
387 7a1ecaed Iustin Pop
  }
388 7a1ecaed Iustin Pop
389 7a1ecaed Iustin Pop
390 a09b9e3d Michael Hanselmann
def Main():
391 a09b9e3d Michael Hanselmann
  return GenericMain(commands)