Statistics
| Branch: | Tag: | Revision:

root / lib / client / gnt_job.py @ 58bc8fbc

History | View | Annotate | Download (15.9 kB)

1 a09b9e3d Michael Hanselmann
#
2 7a1ecaed Iustin Pop
#
3 7a1ecaed Iustin Pop
4 76b62028 Iustin Pop
# Copyright (C) 2006, 2007, 2012 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 b459a848 Andrea Spadaccini
# pylint: disable=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 3086220e Michael Hanselmann
from ganeti import qlang
35 7a1ecaed Iustin Pop
36 7a1ecaed Iustin Pop
37 917b4e56 Iustin Pop
#: default list of fields for L{ListJobs}
38 60dd1473 Iustin Pop
_LIST_DEF_FIELDS = ["id", "status", "summary"]
39 7a5d3bbd Iustin Pop
40 917b4e56 Iustin Pop
#: map converting the job status contants to user-visible
41 917b4e56 Iustin Pop
#: names
42 af30b2fd Michael Hanselmann
_USER_JOB_STATUS = {
43 af30b2fd Michael Hanselmann
  constants.JOB_STATUS_QUEUED: "queued",
44 47099cd1 Michael Hanselmann
  constants.JOB_STATUS_WAITING: "waiting",
45 fbf0262f Michael Hanselmann
  constants.JOB_STATUS_CANCELING: "canceling",
46 af30b2fd Michael Hanselmann
  constants.JOB_STATUS_RUNNING: "running",
47 af30b2fd Michael Hanselmann
  constants.JOB_STATUS_CANCELED: "canceled",
48 af30b2fd Michael Hanselmann
  constants.JOB_STATUS_SUCCESS: "success",
49 af30b2fd Michael Hanselmann
  constants.JOB_STATUS_ERROR: "error",
50 af30b2fd Michael Hanselmann
  }
51 af30b2fd Michael Hanselmann
52 0ad64cf8 Michael Hanselmann
53 3086220e Michael Hanselmann
def _FormatStatus(value):
54 3086220e Michael Hanselmann
  """Formats a job status.
55 3086220e Michael Hanselmann

56 3086220e Michael Hanselmann
  """
57 3086220e Michael Hanselmann
  try:
58 3086220e Michael Hanselmann
    return _USER_JOB_STATUS[value]
59 3086220e Michael Hanselmann
  except KeyError:
60 3086220e Michael Hanselmann
    raise errors.ProgrammerError("Unknown job status code '%s'" % value)
61 3086220e Michael Hanselmann
62 3086220e Michael Hanselmann
63 e1c701e7 Michael Hanselmann
_JOB_LIST_FORMAT = {
64 e1c701e7 Michael Hanselmann
  "status": (_FormatStatus, False),
65 e1c701e7 Michael Hanselmann
  "summary": (lambda value: ",".join(str(item) for item in value), False),
66 e1c701e7 Michael Hanselmann
  }
67 e1c701e7 Michael Hanselmann
_JOB_LIST_FORMAT.update(dict.fromkeys(["opstart", "opexec", "opend"],
68 e1c701e7 Michael Hanselmann
                                      (lambda value: map(FormatTimestamp,
69 e1c701e7 Michael Hanselmann
                                                         value),
70 e1c701e7 Michael Hanselmann
                                       None)))
71 e1c701e7 Michael Hanselmann
72 e1c701e7 Michael Hanselmann
73 76b62028 Iustin Pop
def _ParseJobIds(args):
74 76b62028 Iustin Pop
  """Parses a list of string job IDs into integers.
75 76b62028 Iustin Pop

76 76b62028 Iustin Pop
  @param args: list of strings
77 76b62028 Iustin Pop
  @return: list of integers
78 76b62028 Iustin Pop
  @raise OpPrereqError: in case of invalid values
79 76b62028 Iustin Pop

80 76b62028 Iustin Pop
  """
81 76b62028 Iustin Pop
  try:
82 76b62028 Iustin Pop
    return [int(a) for a in args]
83 76b62028 Iustin Pop
  except (ValueError, TypeError), err:
84 76b62028 Iustin Pop
    raise errors.OpPrereqError("Invalid job ID passed: %s" % err,
85 76b62028 Iustin Pop
                               errors.ECODE_INVAL)
86 76b62028 Iustin Pop
87 76b62028 Iustin Pop
88 7a1ecaed Iustin Pop
def ListJobs(opts, args):
89 7a1ecaed Iustin Pop
  """List the jobs
90 7a1ecaed Iustin Pop

91 917b4e56 Iustin Pop
  @param opts: the command line options selected by the user
92 917b4e56 Iustin Pop
  @type args: list
93 917b4e56 Iustin Pop
  @param args: should be an empty list
94 917b4e56 Iustin Pop
  @rtype: int
95 917b4e56 Iustin Pop
  @return: the desired exit code
96 917b4e56 Iustin Pop

97 7a1ecaed Iustin Pop
  """
98 a4ebd726 Michael Hanselmann
  selected_fields = ParseFields(opts.output, _LIST_DEF_FIELDS)
99 7a1ecaed Iustin Pop
100 43d51ef2 Michael Hanselmann
  if opts.archived and "archived" not in selected_fields:
101 43d51ef2 Michael Hanselmann
    selected_fields.append("archived")
102 43d51ef2 Michael Hanselmann
103 f037e9d7 Michael Hanselmann
  qfilter = qlang.MakeSimpleFilter("status", opts.status_filter)
104 f037e9d7 Michael Hanselmann
105 d45a824b Iustin Pop
  cl = GetClient(query=True)
106 d45a824b Iustin Pop
107 3086220e Michael Hanselmann
  return GenericList(constants.QR_JOB, selected_fields, args, None,
108 3086220e Michael Hanselmann
                     opts.separator, not opts.no_headers,
109 e1c701e7 Michael Hanselmann
                     format_override=_JOB_LIST_FORMAT, verbose=opts.verbose,
110 f037e9d7 Michael Hanselmann
                     force_filter=opts.force_filter, namefield="id",
111 d45a824b Iustin Pop
                     qfilter=qfilter, isnumeric=True, cl=cl)
112 b8802cc4 Michael Hanselmann
113 dcbd6288 Guido Trotter
114 3086220e Michael Hanselmann
def ListJobFields(opts, args):
115 3086220e Michael Hanselmann
  """List job fields.
116 7a1ecaed Iustin Pop

117 3086220e Michael Hanselmann
  @param opts: the command line options selected by the user
118 3086220e Michael Hanselmann
  @type args: list
119 3086220e Michael Hanselmann
  @param args: fields to list, or empty for all
120 3086220e Michael Hanselmann
  @rtype: int
121 3086220e Michael Hanselmann
  @return: the desired exit code
122 3086220e Michael Hanselmann

123 3086220e Michael Hanselmann
  """
124 d45a824b Iustin Pop
  cl = GetClient(query=True)
125 d45a824b Iustin Pop
126 3086220e Michael Hanselmann
  return GenericListFields(constants.QR_JOB, args, opts.separator,
127 d45a824b Iustin Pop
                           not opts.no_headers, cl=cl)
128 7a1ecaed Iustin Pop
129 7a1ecaed Iustin Pop
130 0ad64cf8 Michael Hanselmann
def ArchiveJobs(opts, args):
131 917b4e56 Iustin Pop
  """Archive jobs.
132 917b4e56 Iustin Pop

133 917b4e56 Iustin Pop
  @param opts: the command line options selected by the user
134 917b4e56 Iustin Pop
  @type args: list
135 917b4e56 Iustin Pop
  @param args: should contain the job IDs to be archived
136 917b4e56 Iustin Pop
  @rtype: int
137 917b4e56 Iustin Pop
  @return: the desired exit code
138 917b4e56 Iustin Pop

139 917b4e56 Iustin Pop
  """
140 0ad64cf8 Michael Hanselmann
  client = GetClient()
141 0ad64cf8 Michael Hanselmann
142 aa9f8167 Iustin Pop
  rcode = 0
143 0ad64cf8 Michael Hanselmann
  for job_id in args:
144 aa9f8167 Iustin Pop
    if not client.ArchiveJob(job_id):
145 aa9f8167 Iustin Pop
      ToStderr("Failed to archive job with ID '%s'", job_id)
146 aa9f8167 Iustin Pop
      rcode = 1
147 0ad64cf8 Michael Hanselmann
148 aa9f8167 Iustin Pop
  return rcode
149 0ad64cf8 Michael Hanselmann
150 0ad64cf8 Michael Hanselmann
151 07cd723a Iustin Pop
def AutoArchiveJobs(opts, args):
152 917b4e56 Iustin Pop
  """Archive jobs based on age.
153 917b4e56 Iustin Pop

154 917b4e56 Iustin Pop
  This will archive jobs based on their age, or all jobs if a 'all' is
155 917b4e56 Iustin Pop
  passed.
156 917b4e56 Iustin Pop

157 917b4e56 Iustin Pop
  @param opts: the command line options selected by the user
158 917b4e56 Iustin Pop
  @type args: list
159 917b4e56 Iustin Pop
  @param args: should contain only one element, the age as a time spec
160 c41eea6e Iustin Pop
      that can be parsed by L{ganeti.cli.ParseTimespec} or the
161 c41eea6e Iustin Pop
      keyword I{all}, which will cause all jobs to be archived
162 917b4e56 Iustin Pop
  @rtype: int
163 917b4e56 Iustin Pop
  @return: the desired exit code
164 917b4e56 Iustin Pop

165 917b4e56 Iustin Pop
  """
166 07cd723a Iustin Pop
  client = GetClient()
167 07cd723a Iustin Pop
168 07cd723a Iustin Pop
  age = args[0]
169 07cd723a Iustin Pop
170 d0c8c01d Iustin Pop
  if age == "all":
171 07cd723a Iustin Pop
    age = -1
172 07cd723a Iustin Pop
  else:
173 07cd723a Iustin Pop
    age = ParseTimespec(age)
174 07cd723a Iustin Pop
175 f8ad5591 Michael Hanselmann
  (archived_count, jobs_left) = client.AutoArchiveJobs(age)
176 f8ad5591 Michael Hanselmann
  ToStdout("Archived %s jobs, %s unchecked left", archived_count, jobs_left)
177 f8ad5591 Michael Hanselmann
178 07cd723a Iustin Pop
  return 0
179 07cd723a Iustin Pop
180 07cd723a Iustin Pop
181 feec4cc5 Michael Hanselmann
def _MultiJobAction(opts, args, cl, stdout_fn, ask_fn, question, action_fn):
182 feec4cc5 Michael Hanselmann
  """Applies a function to multipe jobs.
183 917b4e56 Iustin Pop

184 feec4cc5 Michael Hanselmann
  @param opts: Command line options
185 917b4e56 Iustin Pop
  @type args: list
186 feec4cc5 Michael Hanselmann
  @param args: Job IDs
187 917b4e56 Iustin Pop
  @rtype: int
188 feec4cc5 Michael Hanselmann
  @return: Exit code
189 917b4e56 Iustin Pop

190 917b4e56 Iustin Pop
  """
191 e1c701e7 Michael Hanselmann
  if cl is None:
192 e1c701e7 Michael Hanselmann
    cl = GetClient()
193 e1c701e7 Michael Hanselmann
194 feec4cc5 Michael Hanselmann
  if stdout_fn is None:
195 feec4cc5 Michael Hanselmann
    stdout_fn = ToStdout
196 feec4cc5 Michael Hanselmann
197 feec4cc5 Michael Hanselmann
  if ask_fn is None:
198 feec4cc5 Michael Hanselmann
    ask_fn = AskUser
199 feec4cc5 Michael Hanselmann
200 06fef5e0 Michael Hanselmann
  result = constants.EXIT_SUCCESS
201 d2b92ffc Michael Hanselmann
202 e1c701e7 Michael Hanselmann
  if bool(args) ^ (opts.status_filter is None):
203 e1c701e7 Michael Hanselmann
    raise errors.OpPrereqError("Either a status filter or job ID(s) must be"
204 e1c701e7 Michael Hanselmann
                               " specified and never both", errors.ECODE_INVAL)
205 e1c701e7 Michael Hanselmann
206 e1c701e7 Michael Hanselmann
  if opts.status_filter is not None:
207 e1c701e7 Michael Hanselmann
    response = cl.Query(constants.QR_JOB, ["id", "status", "summary"],
208 e1c701e7 Michael Hanselmann
                        qlang.MakeSimpleFilter("status", opts.status_filter))
209 e1c701e7 Michael Hanselmann
210 e1c701e7 Michael Hanselmann
    jobs = [i for ((_, i), _, _) in response.data]
211 e1c701e7 Michael Hanselmann
    if not jobs:
212 e1c701e7 Michael Hanselmann
      raise errors.OpPrereqError("No jobs with the requested status have been"
213 e1c701e7 Michael Hanselmann
                                 " found", errors.ECODE_STATE)
214 e1c701e7 Michael Hanselmann
215 e1c701e7 Michael Hanselmann
    if not opts.force:
216 e1c701e7 Michael Hanselmann
      (_, table) = FormatQueryResult(response, header=True,
217 e1c701e7 Michael Hanselmann
                                     format_override=_JOB_LIST_FORMAT)
218 e1c701e7 Michael Hanselmann
      for line in table:
219 feec4cc5 Michael Hanselmann
        stdout_fn(line)
220 e1c701e7 Michael Hanselmann
221 feec4cc5 Michael Hanselmann
      if not ask_fn(question):
222 e1c701e7 Michael Hanselmann
        return constants.EXIT_CONFIRMATION
223 e1c701e7 Michael Hanselmann
  else:
224 e1c701e7 Michael Hanselmann
    jobs = args
225 e1c701e7 Michael Hanselmann
226 e1c701e7 Michael Hanselmann
  for job_id in jobs:
227 feec4cc5 Michael Hanselmann
    (success, msg) = action_fn(cl, job_id)
228 06fef5e0 Michael Hanselmann
229 06fef5e0 Michael Hanselmann
    if not success:
230 06fef5e0 Michael Hanselmann
      result = constants.EXIT_FAILURE
231 06fef5e0 Michael Hanselmann
232 feec4cc5 Michael Hanselmann
    stdout_fn(msg)
233 d2b92ffc Michael Hanselmann
234 06fef5e0 Michael Hanselmann
  return result
235 d2b92ffc Michael Hanselmann
236 d2b92ffc Michael Hanselmann
237 feec4cc5 Michael Hanselmann
def CancelJobs(opts, args, cl=None, _stdout_fn=ToStdout, _ask_fn=AskUser):
238 feec4cc5 Michael Hanselmann
  """Cancel not-yet-started jobs.
239 feec4cc5 Michael Hanselmann

240 feec4cc5 Michael Hanselmann
  @param opts: the command line options selected by the user
241 feec4cc5 Michael Hanselmann
  @type args: list
242 feec4cc5 Michael Hanselmann
  @param args: should contain the job IDs to be cancelled
243 feec4cc5 Michael Hanselmann
  @rtype: int
244 feec4cc5 Michael Hanselmann
  @return: the desired exit code
245 feec4cc5 Michael Hanselmann

246 feec4cc5 Michael Hanselmann
  """
247 feec4cc5 Michael Hanselmann
  return _MultiJobAction(opts, args, cl, _stdout_fn, _ask_fn,
248 feec4cc5 Michael Hanselmann
                         "Cancel job(s) listed above?",
249 feec4cc5 Michael Hanselmann
                         lambda cl, job_id: cl.CancelJob(job_id))
250 feec4cc5 Michael Hanselmann
251 feec4cc5 Michael Hanselmann
252 e9e07c9c Michael Hanselmann
def ChangePriority(opts, args):
253 e9e07c9c Michael Hanselmann
  """Change priority of jobs.
254 e9e07c9c Michael Hanselmann

255 e9e07c9c Michael Hanselmann
  @param opts: Command line options
256 e9e07c9c Michael Hanselmann
  @type args: list
257 e9e07c9c Michael Hanselmann
  @param args: Job IDs
258 e9e07c9c Michael Hanselmann
  @rtype: int
259 e9e07c9c Michael Hanselmann
  @return: Exit code
260 e9e07c9c Michael Hanselmann

261 e9e07c9c Michael Hanselmann
  """
262 e9e07c9c Michael Hanselmann
  if opts.priority is None:
263 e9e07c9c Michael Hanselmann
    ToStderr("--priority option must be given.")
264 e9e07c9c Michael Hanselmann
    return constants.EXIT_FAILURE
265 e9e07c9c Michael Hanselmann
266 e9e07c9c Michael Hanselmann
  return _MultiJobAction(opts, args, None, None, None,
267 e9e07c9c Michael Hanselmann
                         "Change priority of job(s) listed above?",
268 e9e07c9c Michael Hanselmann
                         lambda cl, job_id:
269 e9e07c9c Michael Hanselmann
                           cl.ChangeJobPriority(job_id, opts.priority))
270 e9e07c9c Michael Hanselmann
271 e9e07c9c Michael Hanselmann
272 191712c0 Iustin Pop
def ShowJobs(opts, args):
273 917b4e56 Iustin Pop
  """Show detailed information about jobs.
274 917b4e56 Iustin Pop

275 917b4e56 Iustin Pop
  @param opts: the command line options selected by the user
276 917b4e56 Iustin Pop
  @type args: list
277 917b4e56 Iustin Pop
  @param args: should contain the job IDs to be queried
278 917b4e56 Iustin Pop
  @rtype: int
279 917b4e56 Iustin Pop
  @return: the desired exit code
280 191712c0 Iustin Pop

281 191712c0 Iustin Pop
  """
282 c04bc777 Iustin Pop
  def format_msg(level, text):
283 191712c0 Iustin Pop
    """Display the text indented."""
284 3a24c527 Iustin Pop
    ToStdout("%s%s", "  " * level, text)
285 191712c0 Iustin Pop
286 191712c0 Iustin Pop
  def result_helper(value):
287 191712c0 Iustin Pop
    """Format a result field in a nice way."""
288 191712c0 Iustin Pop
    if isinstance(value, (tuple, list)):
289 1f864b60 Iustin Pop
      return "[%s]" % utils.CommaJoin(value)
290 191712c0 Iustin Pop
    else:
291 191712c0 Iustin Pop
      return str(value)
292 191712c0 Iustin Pop
293 aad81f98 Iustin Pop
  selected_fields = [
294 aad81f98 Iustin Pop
    "id", "status", "ops", "opresult", "opstatus", "oplog",
295 b9b5abcb Iustin Pop
    "opstart", "opexec", "opend", "received_ts", "start_ts", "end_ts",
296 aad81f98 Iustin Pop
    ]
297 191712c0 Iustin Pop
298 76b62028 Iustin Pop
  qfilter = qlang.MakeSimpleFilter("id", _ParseJobIds(args))
299 d45a824b Iustin Pop
  cl = GetClient(query=True)
300 d45a824b Iustin Pop
  result = cl.Query(constants.QR_JOB, selected_fields, qfilter).data
301 191712c0 Iustin Pop
302 191712c0 Iustin Pop
  first = True
303 191712c0 Iustin Pop
304 eba1aaad Michael Hanselmann
  for entry in result:
305 191712c0 Iustin Pop
    if not first:
306 c04bc777 Iustin Pop
      format_msg(0, "")
307 191712c0 Iustin Pop
    else:
308 191712c0 Iustin Pop
      first = False
309 aad81f98 Iustin Pop
310 eba1aaad Michael Hanselmann
    ((_, job_id), (rs_status, status), (_, ops), (_, opresult), (_, opstatus),
311 eba1aaad Michael Hanselmann
     (_, oplog), (_, opstart), (_, opexec), (_, opend), (_, recv_ts),
312 eba1aaad Michael Hanselmann
     (_, start_ts), (_, end_ts)) = entry
313 eba1aaad Michael Hanselmann
314 eba1aaad Michael Hanselmann
    # Detect non-normal results
315 eba1aaad Michael Hanselmann
    if rs_status != constants.RS_NORMAL:
316 eba1aaad Michael Hanselmann
      format_msg(0, "Job ID %s not found" % job_id)
317 aad81f98 Iustin Pop
      continue
318 aad81f98 Iustin Pop
319 c04bc777 Iustin Pop
    format_msg(0, "Job ID: %s" % job_id)
320 191712c0 Iustin Pop
    if status in _USER_JOB_STATUS:
321 191712c0 Iustin Pop
      status = _USER_JOB_STATUS[status]
322 191712c0 Iustin Pop
    else:
323 2f79bd34 Iustin Pop
      raise errors.ProgrammerError("Unknown job status code '%s'" % status)
324 191712c0 Iustin Pop
325 c04bc777 Iustin Pop
    format_msg(1, "Status: %s" % status)
326 aad81f98 Iustin Pop
327 aad81f98 Iustin Pop
    if recv_ts is not None:
328 c04bc777 Iustin Pop
      format_msg(1, "Received:         %s" % FormatTimestamp(recv_ts))
329 aad81f98 Iustin Pop
    else:
330 c04bc777 Iustin Pop
      format_msg(1, "Missing received timestamp (%s)" % str(recv_ts))
331 aad81f98 Iustin Pop
332 aad81f98 Iustin Pop
    if start_ts is not None:
333 aad81f98 Iustin Pop
      if recv_ts is not None:
334 aad81f98 Iustin Pop
        d1 = start_ts[0] - recv_ts[0] + (start_ts[1] - recv_ts[1]) / 1000000.0
335 aad81f98 Iustin Pop
        delta = " (delta %.6fs)" % d1
336 aad81f98 Iustin Pop
      else:
337 aad81f98 Iustin Pop
        delta = ""
338 c04bc777 Iustin Pop
      format_msg(1, "Processing start: %s%s" %
339 c04bc777 Iustin Pop
                 (FormatTimestamp(start_ts), delta))
340 aad81f98 Iustin Pop
    else:
341 c04bc777 Iustin Pop
      format_msg(1, "Processing start: unknown (%s)" % str(start_ts))
342 aad81f98 Iustin Pop
343 aad81f98 Iustin Pop
    if end_ts is not None:
344 aad81f98 Iustin Pop
      if start_ts is not None:
345 aad81f98 Iustin Pop
        d2 = end_ts[0] - start_ts[0] + (end_ts[1] - start_ts[1]) / 1000000.0
346 aad81f98 Iustin Pop
        delta = " (delta %.6fs)" % d2
347 aad81f98 Iustin Pop
      else:
348 aad81f98 Iustin Pop
        delta = ""
349 c04bc777 Iustin Pop
      format_msg(1, "Processing end:   %s%s" %
350 c04bc777 Iustin Pop
                 (FormatTimestamp(end_ts), delta))
351 aad81f98 Iustin Pop
    else:
352 c04bc777 Iustin Pop
      format_msg(1, "Processing end:   unknown (%s)" % str(end_ts))
353 aad81f98 Iustin Pop
354 aad81f98 Iustin Pop
    if end_ts is not None and recv_ts is not None:
355 aad81f98 Iustin Pop
      d3 = end_ts[0] - recv_ts[0] + (end_ts[1] - recv_ts[1]) / 1000000.0
356 c04bc777 Iustin Pop
      format_msg(1, "Total processing time: %.6f seconds" % d3)
357 aad81f98 Iustin Pop
    else:
358 c04bc777 Iustin Pop
      format_msg(1, "Total processing time: N/A")
359 c04bc777 Iustin Pop
    format_msg(1, "Opcodes:")
360 b9b5abcb Iustin Pop
    for (opcode, result, status, log, s_ts, x_ts, e_ts) in \
361 b9b5abcb Iustin Pop
            zip(ops, opresult, opstatus, oplog, opstart, opexec, opend):
362 c04bc777 Iustin Pop
      format_msg(2, "%s" % opcode["OP_ID"])
363 c04bc777 Iustin Pop
      format_msg(3, "Status: %s" % status)
364 aad81f98 Iustin Pop
      if isinstance(s_ts, (tuple, list)):
365 c04bc777 Iustin Pop
        format_msg(3, "Processing start: %s" % FormatTimestamp(s_ts))
366 aad81f98 Iustin Pop
      else:
367 c04bc777 Iustin Pop
        format_msg(3, "No processing start time")
368 b9b5abcb Iustin Pop
      if isinstance(x_ts, (tuple, list)):
369 c04bc777 Iustin Pop
        format_msg(3, "Execution start:  %s" % FormatTimestamp(x_ts))
370 b9b5abcb Iustin Pop
      else:
371 c04bc777 Iustin Pop
        format_msg(3, "No execution start time")
372 aad81f98 Iustin Pop
      if isinstance(e_ts, (tuple, list)):
373 c04bc777 Iustin Pop
        format_msg(3, "Processing end:   %s" % FormatTimestamp(e_ts))
374 aad81f98 Iustin Pop
      else:
375 c04bc777 Iustin Pop
        format_msg(3, "No processing end time")
376 c04bc777 Iustin Pop
      format_msg(3, "Input fields:")
377 598b5255 Michael Hanselmann
      for key in utils.NiceSort(opcode.keys()):
378 191712c0 Iustin Pop
        if key == "OP_ID":
379 191712c0 Iustin Pop
          continue
380 598b5255 Michael Hanselmann
        val = opcode[key]
381 191712c0 Iustin Pop
        if isinstance(val, (tuple, list)):
382 08db7c5c Iustin Pop
          val = ",".join([str(item) for item in val])
383 c04bc777 Iustin Pop
        format_msg(4, "%s: %s" % (key, val))
384 191712c0 Iustin Pop
      if result is None:
385 c04bc777 Iustin Pop
        format_msg(3, "No output data")
386 191712c0 Iustin Pop
      elif isinstance(result, (tuple, list)):
387 191712c0 Iustin Pop
        if not result:
388 c04bc777 Iustin Pop
          format_msg(3, "Result: empty sequence")
389 191712c0 Iustin Pop
        else:
390 c04bc777 Iustin Pop
          format_msg(3, "Result:")
391 191712c0 Iustin Pop
          for elem in result:
392 c04bc777 Iustin Pop
            format_msg(4, result_helper(elem))
393 191712c0 Iustin Pop
      elif isinstance(result, dict):
394 191712c0 Iustin Pop
        if not result:
395 c04bc777 Iustin Pop
          format_msg(3, "Result: empty dictionary")
396 191712c0 Iustin Pop
        else:
397 d1b47b16 Michael Hanselmann
          format_msg(3, "Result:")
398 191712c0 Iustin Pop
          for key, val in result.iteritems():
399 c04bc777 Iustin Pop
            format_msg(4, "%s: %s" % (key, result_helper(val)))
400 191712c0 Iustin Pop
      else:
401 c04bc777 Iustin Pop
        format_msg(3, "Result: %s" % result)
402 c04bc777 Iustin Pop
      format_msg(3, "Execution log:")
403 3386e7a9 Iustin Pop
      for serial, log_ts, log_type, log_msg in log:
404 3386e7a9 Iustin Pop
        time_txt = FormatTimestamp(log_ts)
405 8a7f1c61 Michael Hanselmann
        encoded = FormatLogMessage(log_type, log_msg)
406 c04bc777 Iustin Pop
        format_msg(4, "%s:%s:%s %s" % (serial, time_txt, log_type, encoded))
407 191712c0 Iustin Pop
  return 0
408 191712c0 Iustin Pop
409 191712c0 Iustin Pop
410 e7d6946c Michael Hanselmann
def WatchJob(opts, args):
411 e7d6946c Michael Hanselmann
  """Follow a job and print its output as it arrives.
412 e7d6946c Michael Hanselmann

413 e7d6946c Michael Hanselmann
  @param opts: the command line options selected by the user
414 e7d6946c Michael Hanselmann
  @type args: list
415 e7d6946c Michael Hanselmann
  @param args: Contains the job ID
416 e7d6946c Michael Hanselmann
  @rtype: int
417 e7d6946c Michael Hanselmann
  @return: the desired exit code
418 e7d6946c Michael Hanselmann

419 e7d6946c Michael Hanselmann
  """
420 e7d6946c Michael Hanselmann
  job_id = args[0]
421 e7d6946c Michael Hanselmann
422 e7d6946c Michael Hanselmann
  msg = ("Output from job %s follows" % job_id)
423 e7d6946c Michael Hanselmann
  ToStdout(msg)
424 e7d6946c Michael Hanselmann
  ToStdout("-" * len(msg))
425 e7d6946c Michael Hanselmann
426 e7d6946c Michael Hanselmann
  retcode = 0
427 e7d6946c Michael Hanselmann
  try:
428 e7d6946c Michael Hanselmann
    cli.PollJob(job_id)
429 e7d6946c Michael Hanselmann
  except errors.GenericError, err:
430 e7d6946c Michael Hanselmann
    (retcode, job_result) = cli.FormatError(err)
431 e7d6946c Michael Hanselmann
    ToStderr("Job %s failed: %s", job_id, job_result)
432 e7d6946c Michael Hanselmann
433 e7d6946c Michael Hanselmann
  return retcode
434 e7d6946c Michael Hanselmann
435 e7d6946c Michael Hanselmann
436 f037e9d7 Michael Hanselmann
_PENDING_OPT = \
437 f037e9d7 Michael Hanselmann
  cli_option("--pending", default=None,
438 f037e9d7 Michael Hanselmann
             action="store_const", dest="status_filter",
439 e1c701e7 Michael Hanselmann
             const=constants.JOBS_PENDING,
440 e1c701e7 Michael Hanselmann
             help="Select jobs pending execution or being cancelled")
441 f037e9d7 Michael Hanselmann
442 f037e9d7 Michael Hanselmann
_RUNNING_OPT = \
443 f037e9d7 Michael Hanselmann
  cli_option("--running", default=None,
444 f037e9d7 Michael Hanselmann
             action="store_const", dest="status_filter",
445 f037e9d7 Michael Hanselmann
             const=frozenset([
446 f037e9d7 Michael Hanselmann
               constants.JOB_STATUS_RUNNING,
447 f037e9d7 Michael Hanselmann
               ]),
448 f037e9d7 Michael Hanselmann
             help="Show jobs currently running only")
449 f037e9d7 Michael Hanselmann
450 f037e9d7 Michael Hanselmann
_ERROR_OPT = \
451 f037e9d7 Michael Hanselmann
  cli_option("--error", default=None,
452 f037e9d7 Michael Hanselmann
             action="store_const", dest="status_filter",
453 f037e9d7 Michael Hanselmann
             const=frozenset([
454 f037e9d7 Michael Hanselmann
               constants.JOB_STATUS_ERROR,
455 f037e9d7 Michael Hanselmann
               ]),
456 f037e9d7 Michael Hanselmann
             help="Show failed jobs only")
457 f037e9d7 Michael Hanselmann
458 f037e9d7 Michael Hanselmann
_FINISHED_OPT = \
459 f037e9d7 Michael Hanselmann
  cli_option("--finished", default=None,
460 f037e9d7 Michael Hanselmann
             action="store_const", dest="status_filter",
461 f037e9d7 Michael Hanselmann
             const=constants.JOBS_FINALIZED,
462 f037e9d7 Michael Hanselmann
             help="Show finished jobs only")
463 f037e9d7 Michael Hanselmann
464 43d51ef2 Michael Hanselmann
_ARCHIVED_OPT = \
465 43d51ef2 Michael Hanselmann
  cli_option("--archived", default=False,
466 43d51ef2 Michael Hanselmann
             action="store_true", dest="archived",
467 43d51ef2 Michael Hanselmann
             help="Include archived jobs in list (slow and expensive)")
468 43d51ef2 Michael Hanselmann
469 e1c701e7 Michael Hanselmann
_QUEUED_OPT = \
470 e1c701e7 Michael Hanselmann
  cli_option("--queued", default=None,
471 e1c701e7 Michael Hanselmann
             action="store_const", dest="status_filter",
472 e1c701e7 Michael Hanselmann
             const=frozenset([
473 e1c701e7 Michael Hanselmann
               constants.JOB_STATUS_QUEUED,
474 e1c701e7 Michael Hanselmann
               ]),
475 e1c701e7 Michael Hanselmann
             help="Select queued jobs only")
476 e1c701e7 Michael Hanselmann
477 e1c701e7 Michael Hanselmann
_WAITING_OPT = \
478 e1c701e7 Michael Hanselmann
  cli_option("--waiting", default=None,
479 e1c701e7 Michael Hanselmann
             action="store_const", dest="status_filter",
480 e1c701e7 Michael Hanselmann
             const=frozenset([
481 e1c701e7 Michael Hanselmann
               constants.JOB_STATUS_WAITING,
482 e1c701e7 Michael Hanselmann
               ]),
483 e1c701e7 Michael Hanselmann
             help="Select waiting jobs only")
484 e1c701e7 Michael Hanselmann
485 f037e9d7 Michael Hanselmann
486 7a1ecaed Iustin Pop
commands = {
487 d0c8c01d Iustin Pop
  "list": (
488 6ea815cf Iustin Pop
    ListJobs, [ArgJobId()],
489 f037e9d7 Michael Hanselmann
    [NOHDR_OPT, SEP_OPT, FIELDS_OPT, VERBOSE_OPT, FORCE_FILTER_OPT,
490 43d51ef2 Michael Hanselmann
     _PENDING_OPT, _RUNNING_OPT, _ERROR_OPT, _FINISHED_OPT, _ARCHIVED_OPT],
491 6ea815cf Iustin Pop
    "[job_id ...]",
492 3086220e Michael Hanselmann
    "Lists the jobs and their status. The available fields can be shown"
493 3086220e Michael Hanselmann
    " using the \"list-fields\" command (see the man page for details)."
494 3086220e Michael Hanselmann
    " The default field list is (in order): %s." %
495 3086220e Michael Hanselmann
    utils.CommaJoin(_LIST_DEF_FIELDS)),
496 3086220e Michael Hanselmann
  "list-fields": (
497 3086220e Michael Hanselmann
    ListJobFields, [ArgUnknown()],
498 3086220e Michael Hanselmann
    [NOHDR_OPT, SEP_OPT],
499 3086220e Michael Hanselmann
    "[fields...]",
500 3086220e Michael Hanselmann
    "Lists all available fields for jobs"),
501 d0c8c01d Iustin Pop
  "archive": (
502 064c21f8 Iustin Pop
    ArchiveJobs, [ArgJobId(min=1)], [],
503 6ea815cf Iustin Pop
    "<job-id> [<job-id> ...]", "Archive specified jobs"),
504 d0c8c01d Iustin Pop
  "autoarchive": (
505 6ea815cf Iustin Pop
    AutoArchiveJobs,
506 94182b63 Iustin Pop
    [ArgSuggest(min=1, max=1, choices=["1d", "1w", "4w", "all"])],
507 064c21f8 Iustin Pop
    [],
508 6ea815cf Iustin Pop
    "<age>", "Auto archive jobs older than the given age"),
509 d0c8c01d Iustin Pop
  "cancel": (
510 e1c701e7 Michael Hanselmann
    CancelJobs, [ArgJobId()],
511 e1c701e7 Michael Hanselmann
    [FORCE_OPT, _PENDING_OPT, _QUEUED_OPT, _WAITING_OPT],
512 e1c701e7 Michael Hanselmann
    "{[--force] {--pending | --queued | --waiting} |"
513 e1c701e7 Michael Hanselmann
    " <job-id> [<job-id> ...]}",
514 e1c701e7 Michael Hanselmann
    "Cancel jobs"),
515 d0c8c01d Iustin Pop
  "info": (
516 064c21f8 Iustin Pop
    ShowJobs, [ArgJobId(min=1)], [],
517 6ea815cf Iustin Pop
    "<job-id> [<job-id> ...]",
518 6ea815cf Iustin Pop
    "Show detailed information about the specified jobs"),
519 d0c8c01d Iustin Pop
  "watch": (
520 064c21f8 Iustin Pop
    WatchJob, [ArgJobId(min=1, max=1)], [],
521 6ea815cf Iustin Pop
    "<job-id>", "Follows a job and prints its output as it arrives"),
522 e9e07c9c Michael Hanselmann
  "change-priority": (
523 e9e07c9c Michael Hanselmann
    ChangePriority, [ArgJobId()],
524 e9e07c9c Michael Hanselmann
    [PRIORITY_OPT, FORCE_OPT, _PENDING_OPT, _QUEUED_OPT, _WAITING_OPT],
525 e9e07c9c Michael Hanselmann
    "--priority <priority> {[--force] {--pending | --queued | --waiting} |"
526 e9e07c9c Michael Hanselmann
    " <job-id> [<job-id> ...]}",
527 e9e07c9c Michael Hanselmann
    "Change the priority of jobs"),
528 7a1ecaed Iustin Pop
  }
529 7a1ecaed Iustin Pop
530 7a1ecaed Iustin Pop
531 029fe503 Guido Trotter
#: dictionary with aliases for commands
532 029fe503 Guido Trotter
aliases = {
533 029fe503 Guido Trotter
  "show": "info",
534 029fe503 Guido Trotter
  }
535 029fe503 Guido Trotter
536 029fe503 Guido Trotter
537 a09b9e3d Michael Hanselmann
def Main():
538 029fe503 Guido Trotter
  return GenericMain(commands, aliases=aliases)