Statistics
| Branch: | Tag: | Revision:

root / scripts / gnt-job @ d04aaa2f

History | View | Annotate | Download (10 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 7a1ecaed Iustin Pop
22 2f79bd34 Iustin Pop
# pylint: disable-msg=W0401,W0614
23 2f79bd34 Iustin Pop
# W0401: Wildcard import ganeti.cli
24 2f79bd34 Iustin Pop
# W0614: Unused import %s from wildcard import (since we need cli)
25 2f79bd34 Iustin Pop
26 7a1ecaed Iustin Pop
import sys
27 7a1ecaed Iustin Pop
28 7a1ecaed Iustin Pop
from ganeti.cli import *
29 7a1ecaed Iustin Pop
from ganeti import constants
30 7a1ecaed Iustin Pop
from ganeti import errors
31 26f15862 Iustin Pop
from ganeti import utils
32 7a1ecaed Iustin Pop
33 7a1ecaed Iustin Pop
34 917b4e56 Iustin Pop
#: default list of fields for L{ListJobs}
35 60dd1473 Iustin Pop
_LIST_DEF_FIELDS = ["id", "status", "summary"]
36 7a5d3bbd Iustin Pop
37 917b4e56 Iustin Pop
#: map converting the job status contants to user-visible
38 917b4e56 Iustin Pop
#: names
39 af30b2fd Michael Hanselmann
_USER_JOB_STATUS = {
40 af30b2fd Michael Hanselmann
  constants.JOB_STATUS_QUEUED: "queued",
41 e92376d7 Iustin Pop
  constants.JOB_STATUS_WAITLOCK: "waiting",
42 fbf0262f Michael Hanselmann
  constants.JOB_STATUS_CANCELING: "canceling",
43 af30b2fd Michael Hanselmann
  constants.JOB_STATUS_RUNNING: "running",
44 af30b2fd Michael Hanselmann
  constants.JOB_STATUS_CANCELED: "canceled",
45 af30b2fd Michael Hanselmann
  constants.JOB_STATUS_SUCCESS: "success",
46 af30b2fd Michael Hanselmann
  constants.JOB_STATUS_ERROR: "error",
47 af30b2fd Michael Hanselmann
  }
48 af30b2fd Michael Hanselmann
49 0ad64cf8 Michael Hanselmann
50 7a1ecaed Iustin Pop
def ListJobs(opts, args):
51 7a1ecaed Iustin Pop
  """List the jobs
52 7a1ecaed Iustin Pop
53 917b4e56 Iustin Pop
  @param opts: the command line options selected by the user
54 917b4e56 Iustin Pop
  @type args: list
55 917b4e56 Iustin Pop
  @param args: should be an empty list
56 917b4e56 Iustin Pop
  @rtype: int
57 917b4e56 Iustin Pop
  @return: the desired exit code
58 917b4e56 Iustin Pop
59 7a1ecaed Iustin Pop
  """
60 7a1ecaed Iustin Pop
  if opts.output is None:
61 7a5d3bbd Iustin Pop
    selected_fields = _LIST_DEF_FIELDS
62 7a5d3bbd Iustin Pop
  elif opts.output.startswith("+"):
63 7a5d3bbd Iustin Pop
    selected_fields = _LIST_DEF_FIELDS + opts.output[1:].split(",")
64 7a1ecaed Iustin Pop
  else:
65 7a1ecaed Iustin Pop
    selected_fields = opts.output.split(",")
66 7a1ecaed Iustin Pop
67 f1de3563 Iustin Pop
  output = GetClient().QueryJobs(args, selected_fields)
68 7a1ecaed Iustin Pop
  if not opts.no_headers:
69 af30b2fd Michael Hanselmann
    # TODO: Implement more fields
70 7a1ecaed Iustin Pop
    headers = {
71 7a1ecaed Iustin Pop
      "id": "ID",
72 7a1ecaed Iustin Pop
      "status": "Status",
73 af30b2fd Michael Hanselmann
      "ops": "OpCodes",
74 af30b2fd Michael Hanselmann
      "opresult": "OpCode_result",
75 af30b2fd Michael Hanselmann
      "opstatus": "OpCode_status",
76 5b23c34c Iustin Pop
      "oplog": "OpCode_log",
77 60dd1473 Iustin Pop
      "summary": "Summary",
78 aad81f98 Iustin Pop
      "opstart": "OpCode_start",
79 aad81f98 Iustin Pop
      "opend": "OpCode_end",
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 7a1ecaed Iustin Pop
  # change raw values to nicer strings
88 dcbd6288 Guido Trotter
  for row_id, row in enumerate(output):
89 dcbd6288 Guido Trotter
    if row is None:
90 dcbd6288 Guido Trotter
      ToStderr("No such job: %s" % args[row_id])
91 dcbd6288 Guido Trotter
      continue
92 dcbd6288 Guido Trotter
93 7a1ecaed Iustin Pop
    for idx, field in enumerate(selected_fields):
94 7a1ecaed Iustin Pop
      val = row[idx]
95 7a1ecaed Iustin Pop
      if field == "status":
96 af30b2fd Michael Hanselmann
        if val in _USER_JOB_STATUS:
97 af30b2fd Michael Hanselmann
          val = _USER_JOB_STATUS[val]
98 7a1ecaed Iustin Pop
        else:
99 7a1ecaed Iustin Pop
          raise errors.ProgrammerError("Unknown job status code '%s'" % val)
100 60dd1473 Iustin Pop
      elif field == "summary":
101 60dd1473 Iustin Pop
        val = ",".join(val)
102 aad81f98 Iustin Pop
      elif field in ("start_ts", "end_ts", "received_ts"):
103 aad81f98 Iustin Pop
        val = FormatTimestamp(val)
104 aad81f98 Iustin Pop
      elif field in ("opstart", "opend"):
105 aad81f98 Iustin Pop
        val = [FormatTimestamp(entry) for entry in val]
106 7a1ecaed Iustin Pop
107 7a1ecaed Iustin Pop
      row[idx] = str(val)
108 7a1ecaed Iustin Pop
109 7a1ecaed Iustin Pop
  data = GenerateTable(separator=opts.separator, headers=headers,
110 f1de3563 Iustin Pop
                       fields=selected_fields, data=output)
111 7a1ecaed Iustin Pop
  for line in data:
112 3a24c527 Iustin Pop
    ToStdout(line)
113 7a1ecaed Iustin Pop
114 7a1ecaed Iustin Pop
  return 0
115 7a1ecaed Iustin Pop
116 7a1ecaed Iustin Pop
117 0ad64cf8 Michael Hanselmann
def ArchiveJobs(opts, args):
118 917b4e56 Iustin Pop
  """Archive jobs.
119 917b4e56 Iustin Pop
120 917b4e56 Iustin Pop
  @param opts: the command line options selected by the user
121 917b4e56 Iustin Pop
  @type args: list
122 917b4e56 Iustin Pop
  @param args: should contain the job IDs to be archived
123 917b4e56 Iustin Pop
  @rtype: int
124 917b4e56 Iustin Pop
  @return: the desired exit code
125 917b4e56 Iustin Pop
126 917b4e56 Iustin Pop
  """
127 0ad64cf8 Michael Hanselmann
  client = GetClient()
128 0ad64cf8 Michael Hanselmann
129 0ad64cf8 Michael Hanselmann
  for job_id in args:
130 0ad64cf8 Michael Hanselmann
    client.ArchiveJob(job_id)
131 0ad64cf8 Michael Hanselmann
132 0ad64cf8 Michael Hanselmann
  return 0
133 0ad64cf8 Michael Hanselmann
134 0ad64cf8 Michael Hanselmann
135 07cd723a Iustin Pop
def AutoArchiveJobs(opts, args):
136 917b4e56 Iustin Pop
  """Archive jobs based on age.
137 917b4e56 Iustin Pop
138 917b4e56 Iustin Pop
  This will archive jobs based on their age, or all jobs if a 'all' is
139 917b4e56 Iustin Pop
  passed.
140 917b4e56 Iustin Pop
141 917b4e56 Iustin Pop
  @param opts: the command line options selected by the user
142 917b4e56 Iustin Pop
  @type args: list
143 917b4e56 Iustin Pop
  @param args: should contain only one element, the age as a time spec
144 c41eea6e Iustin Pop
      that can be parsed by L{ganeti.cli.ParseTimespec} or the
145 c41eea6e Iustin Pop
      keyword I{all}, which will cause all jobs to be archived
146 917b4e56 Iustin Pop
  @rtype: int
147 917b4e56 Iustin Pop
  @return: the desired exit code
148 917b4e56 Iustin Pop
149 917b4e56 Iustin Pop
  """
150 07cd723a Iustin Pop
  client = GetClient()
151 07cd723a Iustin Pop
152 07cd723a Iustin Pop
  age = args[0]
153 07cd723a Iustin Pop
154 07cd723a Iustin Pop
  if age == 'all':
155 07cd723a Iustin Pop
    age = -1
156 07cd723a Iustin Pop
  else:
157 07cd723a Iustin Pop
    age = ParseTimespec(age)
158 07cd723a Iustin Pop
159 f8ad5591 Michael Hanselmann
  (archived_count, jobs_left) = client.AutoArchiveJobs(age)
160 f8ad5591 Michael Hanselmann
  ToStdout("Archived %s jobs, %s unchecked left", archived_count, jobs_left)
161 f8ad5591 Michael Hanselmann
162 07cd723a Iustin Pop
  return 0
163 07cd723a Iustin Pop
164 07cd723a Iustin Pop
165 d2b92ffc Michael Hanselmann
def CancelJobs(opts, args):
166 917b4e56 Iustin Pop
  """Cancel not-yet-started jobs.
167 917b4e56 Iustin Pop
168 917b4e56 Iustin Pop
  @param opts: the command line options selected by the user
169 917b4e56 Iustin Pop
  @type args: list
170 917b4e56 Iustin Pop
  @param args: should contain the job IDs to be cancelled
171 917b4e56 Iustin Pop
  @rtype: int
172 917b4e56 Iustin Pop
  @return: the desired exit code
173 917b4e56 Iustin Pop
174 917b4e56 Iustin Pop
  """
175 d2b92ffc Michael Hanselmann
  client = GetClient()
176 d2b92ffc Michael Hanselmann
177 d2b92ffc Michael Hanselmann
  for job_id in args:
178 b28a3e8b Michael Hanselmann
    (success, msg) = client.CancelJob(job_id)
179 b28a3e8b Michael Hanselmann
    ToStdout(msg)
180 d2b92ffc Michael Hanselmann
181 b28a3e8b Michael Hanselmann
  # TODO: Different exit value if not all jobs were canceled?
182 d2b92ffc Michael Hanselmann
  return 0
183 d2b92ffc Michael Hanselmann
184 d2b92ffc Michael Hanselmann
185 191712c0 Iustin Pop
def ShowJobs(opts, args):
186 917b4e56 Iustin Pop
  """Show detailed information about jobs.
187 917b4e56 Iustin Pop
188 917b4e56 Iustin Pop
  @param opts: the command line options selected by the user
189 917b4e56 Iustin Pop
  @type args: list
190 917b4e56 Iustin Pop
  @param args: should contain the job IDs to be queried
191 917b4e56 Iustin Pop
  @rtype: int
192 917b4e56 Iustin Pop
  @return: the desired exit code
193 191712c0 Iustin Pop
194 191712c0 Iustin Pop
  """
195 191712c0 Iustin Pop
  def format(level, text):
196 191712c0 Iustin Pop
    """Display the text indented."""
197 3a24c527 Iustin Pop
    ToStdout("%s%s", "  " * level, text)
198 191712c0 Iustin Pop
199 191712c0 Iustin Pop
  def result_helper(value):
200 191712c0 Iustin Pop
    """Format a result field in a nice way."""
201 191712c0 Iustin Pop
    if isinstance(value, (tuple, list)):
202 191712c0 Iustin Pop
      return "[%s]" % (", ".join(str(elem) for elem in value))
203 191712c0 Iustin Pop
    else:
204 191712c0 Iustin Pop
      return str(value)
205 191712c0 Iustin Pop
206 aad81f98 Iustin Pop
  selected_fields = [
207 aad81f98 Iustin Pop
    "id", "status", "ops", "opresult", "opstatus", "oplog",
208 aad81f98 Iustin Pop
    "opstart", "opend", "received_ts", "start_ts", "end_ts",
209 aad81f98 Iustin Pop
    ]
210 191712c0 Iustin Pop
211 191712c0 Iustin Pop
  result = GetClient().QueryJobs(args, selected_fields)
212 191712c0 Iustin Pop
213 191712c0 Iustin Pop
  first = True
214 191712c0 Iustin Pop
215 b27b39b0 Iustin Pop
  for idx, entry in enumerate(result):
216 191712c0 Iustin Pop
    if not first:
217 191712c0 Iustin Pop
      format(0, "")
218 191712c0 Iustin Pop
    else:
219 191712c0 Iustin Pop
      first = False
220 aad81f98 Iustin Pop
221 aad81f98 Iustin Pop
    if entry is None:
222 b27b39b0 Iustin Pop
      if idx <= len(args):
223 b27b39b0 Iustin Pop
        format(0, "Job ID %s not found" % args[idx])
224 b27b39b0 Iustin Pop
      else:
225 b27b39b0 Iustin Pop
        # this should not happen, when we don't pass args it will be a
226 b27b39b0 Iustin Pop
        # valid job returned
227 b27b39b0 Iustin Pop
        format(0, "Job ID requested as argument %s not found" % (idx + 1))
228 aad81f98 Iustin Pop
      continue
229 aad81f98 Iustin Pop
230 aad81f98 Iustin Pop
    (job_id, status, ops, opresult, opstatus, oplog,
231 aad81f98 Iustin Pop
     opstart, opend, recv_ts, start_ts, end_ts) = entry
232 191712c0 Iustin Pop
    format(0, "Job ID: %s" % job_id)
233 191712c0 Iustin Pop
    if status in _USER_JOB_STATUS:
234 191712c0 Iustin Pop
      status = _USER_JOB_STATUS[status]
235 191712c0 Iustin Pop
    else:
236 2f79bd34 Iustin Pop
      raise errors.ProgrammerError("Unknown job status code '%s'" % status)
237 191712c0 Iustin Pop
238 191712c0 Iustin Pop
    format(1, "Status: %s" % status)
239 aad81f98 Iustin Pop
240 aad81f98 Iustin Pop
    if recv_ts is not None:
241 aad81f98 Iustin Pop
      format(1, "Received:         %s" % FormatTimestamp(recv_ts))
242 aad81f98 Iustin Pop
    else:
243 aad81f98 Iustin Pop
      format(1, "Missing received timestamp (%s)" % str(recv_ts))
244 aad81f98 Iustin Pop
245 aad81f98 Iustin Pop
    if start_ts is not None:
246 aad81f98 Iustin Pop
      if recv_ts is not None:
247 aad81f98 Iustin Pop
        d1 = start_ts[0] - recv_ts[0] + (start_ts[1] - recv_ts[1]) / 1000000.0
248 aad81f98 Iustin Pop
        delta = " (delta %.6fs)" % d1
249 aad81f98 Iustin Pop
      else:
250 aad81f98 Iustin Pop
        delta = ""
251 aad81f98 Iustin Pop
      format(1, "Processing start: %s%s" % (FormatTimestamp(start_ts), delta))
252 aad81f98 Iustin Pop
    else:
253 aad81f98 Iustin Pop
      format(1, "Processing start: unknown (%s)" % str(start_ts))
254 aad81f98 Iustin Pop
255 aad81f98 Iustin Pop
    if end_ts is not None:
256 aad81f98 Iustin Pop
      if start_ts is not None:
257 aad81f98 Iustin Pop
        d2 = end_ts[0] - start_ts[0] + (end_ts[1] - start_ts[1]) / 1000000.0
258 aad81f98 Iustin Pop
        delta = " (delta %.6fs)" % d2
259 aad81f98 Iustin Pop
      else:
260 aad81f98 Iustin Pop
        delta = ""
261 aad81f98 Iustin Pop
      format(1, "Processing end:   %s%s" % (FormatTimestamp(end_ts), delta))
262 aad81f98 Iustin Pop
    else:
263 aad81f98 Iustin Pop
      format(1, "Processing end:   unknown (%s)" % str(end_ts))
264 aad81f98 Iustin Pop
265 aad81f98 Iustin Pop
    if end_ts is not None and recv_ts is not None:
266 aad81f98 Iustin Pop
      d3 = end_ts[0] - recv_ts[0] + (end_ts[1] - recv_ts[1]) / 1000000.0
267 aad81f98 Iustin Pop
      format(1, "Total processing time: %.6f seconds" % d3)
268 aad81f98 Iustin Pop
    else:
269 aad81f98 Iustin Pop
      format(1, "Total processing time: N/A")
270 191712c0 Iustin Pop
    format(1, "Opcodes:")
271 aad81f98 Iustin Pop
    for (opcode, result, status, log, s_ts, e_ts) in \
272 aad81f98 Iustin Pop
            zip(ops, opresult, opstatus, oplog, opstart, opend):
273 191712c0 Iustin Pop
      format(2, "%s" % opcode["OP_ID"])
274 191712c0 Iustin Pop
      format(3, "Status: %s" % status)
275 aad81f98 Iustin Pop
      if isinstance(s_ts, (tuple, list)):
276 aad81f98 Iustin Pop
        format(3, "Processing start: %s" % FormatTimestamp(s_ts))
277 aad81f98 Iustin Pop
      else:
278 aad81f98 Iustin Pop
        format(3, "No processing start time")
279 aad81f98 Iustin Pop
      if isinstance(e_ts, (tuple, list)):
280 aad81f98 Iustin Pop
        format(3, "Processing end:   %s" % FormatTimestamp(e_ts))
281 aad81f98 Iustin Pop
      else:
282 aad81f98 Iustin Pop
        format(3, "No processing end time")
283 191712c0 Iustin Pop
      format(3, "Input fields:")
284 191712c0 Iustin Pop
      for key, val in opcode.iteritems():
285 191712c0 Iustin Pop
        if key == "OP_ID":
286 191712c0 Iustin Pop
          continue
287 191712c0 Iustin Pop
        if isinstance(val, (tuple, list)):
288 08db7c5c Iustin Pop
          val = ",".join([str(item) for item in val])
289 191712c0 Iustin Pop
        format(4, "%s: %s" % (key, val))
290 191712c0 Iustin Pop
      if result is None:
291 191712c0 Iustin Pop
        format(3, "No output data")
292 191712c0 Iustin Pop
      elif isinstance(result, (tuple, list)):
293 191712c0 Iustin Pop
        if not result:
294 191712c0 Iustin Pop
          format(3, "Result: empty sequence")
295 191712c0 Iustin Pop
        else:
296 191712c0 Iustin Pop
          format(3, "Result:")
297 191712c0 Iustin Pop
          for elem in result:
298 191712c0 Iustin Pop
            format(4, result_helper(elem))
299 191712c0 Iustin Pop
      elif isinstance(result, dict):
300 191712c0 Iustin Pop
        if not result:
301 191712c0 Iustin Pop
          format(3, "Result: empty dictionary")
302 191712c0 Iustin Pop
        else:
303 191712c0 Iustin Pop
          for key, val in result.iteritems():
304 191712c0 Iustin Pop
            format(4, "%s: %s" % (key, result_helper(val)))
305 191712c0 Iustin Pop
      else:
306 191712c0 Iustin Pop
        format(3, "Result: %s" % result)
307 5b23c34c Iustin Pop
      format(3, "Execution log:")
308 3386e7a9 Iustin Pop
      for serial, log_ts, log_type, log_msg in log:
309 3386e7a9 Iustin Pop
        time_txt = FormatTimestamp(log_ts)
310 26f15862 Iustin Pop
        encoded = utils.SafeEncode(log_msg)
311 5b23c34c Iustin Pop
        format(4, "%s:%s:%s %s" % (serial, time_txt, log_type, encoded))
312 191712c0 Iustin Pop
  return 0
313 191712c0 Iustin Pop
314 191712c0 Iustin Pop
315 7a1ecaed Iustin Pop
commands = {
316 f1de3563 Iustin Pop
  'list': (ListJobs, ARGS_ANY,
317 f1de3563 Iustin Pop
            [DEBUG_OPT, NOHDR_OPT, SEP_OPT, FIELDS_OPT],
318 f1de3563 Iustin Pop
            "[job_id ...]",
319 f1de3563 Iustin Pop
           "List the jobs and their status. The available fields are"
320 35049ff2 Iustin Pop
           " (see the man page for details): id, status, op_list,"
321 35049ff2 Iustin Pop
           " op_status, op_result."
322 7a1ecaed Iustin Pop
           " The default field"
323 0ad64cf8 Michael Hanselmann
           " list is (in order): %s." % ", ".join(_LIST_DEF_FIELDS)),
324 0ad64cf8 Michael Hanselmann
  'archive': (ArchiveJobs, ARGS_ANY,
325 0ad64cf8 Michael Hanselmann
              [DEBUG_OPT],
326 0ad64cf8 Michael Hanselmann
              "<job-id> [<job-id> ...]",
327 0ad64cf8 Michael Hanselmann
              "Archive specified jobs"),
328 07cd723a Iustin Pop
  'autoarchive': (AutoArchiveJobs, ARGS_ONE,
329 07cd723a Iustin Pop
              [DEBUG_OPT],
330 07cd723a Iustin Pop
              "<age>",
331 07cd723a Iustin Pop
              "Auto archive jobs older than the given age"),
332 d2b92ffc Michael Hanselmann
  'cancel': (CancelJobs, ARGS_ANY,
333 d2b92ffc Michael Hanselmann
             [DEBUG_OPT],
334 d2b92ffc Michael Hanselmann
             "<job-id> [<job-id> ...]",
335 d2b92ffc Michael Hanselmann
             "Cancel specified jobs"),
336 191712c0 Iustin Pop
  'info': (ShowJobs, ARGS_ANY, [DEBUG_OPT],
337 191712c0 Iustin Pop
           "<job-id> [<job-id> ...]",
338 191712c0 Iustin Pop
           "Show detailed information about the specified jobs"),
339 7a1ecaed Iustin Pop
  }
340 7a1ecaed Iustin Pop
341 7a1ecaed Iustin Pop
342 7a1ecaed Iustin Pop
if __name__ == '__main__':
343 7a1ecaed Iustin Pop
  sys.exit(GenericMain(commands))