Statistics
| Branch: | Tag: | Revision:

root / scripts / gnt-job @ 07813a9e

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