Statistics
| Branch: | Tag: | Revision:

root / scripts / gnt-job @ 3a24c527

History | View | Annotate | Download (8.5 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 7a1ecaed Iustin Pop
import sys
23 7a1ecaed Iustin Pop
import os
24 7a1ecaed Iustin Pop
import itertools
25 5b23c34c Iustin Pop
import time
26 7a1ecaed Iustin Pop
from optparse import make_option
27 7a1ecaed Iustin Pop
from cStringIO import StringIO
28 7a1ecaed Iustin Pop
29 7a1ecaed Iustin Pop
from ganeti.cli import *
30 7a1ecaed Iustin Pop
from ganeti import opcodes
31 7a1ecaed Iustin Pop
from ganeti import constants
32 7a1ecaed Iustin Pop
from ganeti import utils
33 7a1ecaed Iustin Pop
from ganeti import errors
34 7a1ecaed Iustin Pop
35 7a1ecaed Iustin Pop
36 60dd1473 Iustin Pop
_LIST_DEF_FIELDS = ["id", "status", "summary"]
37 7a5d3bbd Iustin Pop
38 af30b2fd Michael Hanselmann
_USER_JOB_STATUS = {
39 af30b2fd Michael Hanselmann
  constants.JOB_STATUS_QUEUED: "queued",
40 e92376d7 Iustin Pop
  constants.JOB_STATUS_WAITLOCK: "waiting",
41 af30b2fd Michael Hanselmann
  constants.JOB_STATUS_RUNNING: "running",
42 af30b2fd Michael Hanselmann
  constants.JOB_STATUS_CANCELED: "canceled",
43 af30b2fd Michael Hanselmann
  constants.JOB_STATUS_SUCCESS: "success",
44 af30b2fd Michael Hanselmann
  constants.JOB_STATUS_ERROR: "error",
45 af30b2fd Michael Hanselmann
  }
46 af30b2fd Michael Hanselmann
47 0ad64cf8 Michael Hanselmann
48 7a1ecaed Iustin Pop
def ListJobs(opts, args):
49 7a1ecaed Iustin Pop
  """List the jobs
50 7a1ecaed Iustin Pop
51 7a1ecaed Iustin Pop
  """
52 7a1ecaed Iustin Pop
  if opts.output is None:
53 7a5d3bbd Iustin Pop
    selected_fields = _LIST_DEF_FIELDS
54 7a5d3bbd Iustin Pop
  elif opts.output.startswith("+"):
55 7a5d3bbd Iustin Pop
    selected_fields = _LIST_DEF_FIELDS + opts.output[1:].split(",")
56 7a1ecaed Iustin Pop
  else:
57 7a1ecaed Iustin Pop
    selected_fields = opts.output.split(",")
58 7a1ecaed Iustin Pop
59 af30b2fd Michael Hanselmann
  output = GetClient().QueryJobs(None, selected_fields)
60 7a1ecaed Iustin Pop
  if not opts.no_headers:
61 af30b2fd Michael Hanselmann
    # TODO: Implement more fields
62 7a1ecaed Iustin Pop
    headers = {
63 7a1ecaed Iustin Pop
      "id": "ID",
64 7a1ecaed Iustin Pop
      "status": "Status",
65 af30b2fd Michael Hanselmann
      "ops": "OpCodes",
66 af30b2fd Michael Hanselmann
      "opresult": "OpCode_result",
67 af30b2fd Michael Hanselmann
      "opstatus": "OpCode_status",
68 5b23c34c Iustin Pop
      "oplog": "OpCode_log",
69 60dd1473 Iustin Pop
      "summary": "Summary",
70 aad81f98 Iustin Pop
      "opstart": "OpCode_start",
71 aad81f98 Iustin Pop
      "opend": "OpCode_end",
72 aad81f98 Iustin Pop
      "start_ts": "Start",
73 aad81f98 Iustin Pop
      "end_ts": "End",
74 aad81f98 Iustin Pop
      "received_ts": "Received",
75 7a1ecaed Iustin Pop
      }
76 7a1ecaed Iustin Pop
  else:
77 7a1ecaed Iustin Pop
    headers = None
78 7a1ecaed Iustin Pop
79 7a1ecaed Iustin Pop
  # we don't have yet unitfields here
80 7a1ecaed Iustin Pop
  unitfields = None
81 5ce81b28 Michael Hanselmann
  numfields = None
82 7a1ecaed Iustin Pop
83 7a1ecaed Iustin Pop
  # change raw values to nicer strings
84 7a1ecaed Iustin Pop
  for row in output:
85 7a1ecaed Iustin Pop
    for idx, field in enumerate(selected_fields):
86 7a1ecaed Iustin Pop
      val = row[idx]
87 7a1ecaed Iustin Pop
      if field == "status":
88 af30b2fd Michael Hanselmann
        if val in _USER_JOB_STATUS:
89 af30b2fd Michael Hanselmann
          val = _USER_JOB_STATUS[val]
90 7a1ecaed Iustin Pop
        else:
91 7a1ecaed Iustin Pop
          raise errors.ProgrammerError("Unknown job status code '%s'" % val)
92 60dd1473 Iustin Pop
      elif field == "summary":
93 60dd1473 Iustin Pop
        val = ",".join(val)
94 aad81f98 Iustin Pop
      elif field in ("start_ts", "end_ts", "received_ts"):
95 aad81f98 Iustin Pop
        val = FormatTimestamp(val)
96 aad81f98 Iustin Pop
      elif field in ("opstart", "opend"):
97 aad81f98 Iustin Pop
        val = [FormatTimestamp(entry) for entry in val]
98 7a1ecaed Iustin Pop
99 7a1ecaed Iustin Pop
      row[idx] = str(val)
100 7a1ecaed Iustin Pop
101 7a1ecaed Iustin Pop
  data = GenerateTable(separator=opts.separator, headers=headers,
102 7a1ecaed Iustin Pop
                       fields=selected_fields, unitfields=unitfields,
103 7a1ecaed Iustin Pop
                       numfields=numfields, data=output)
104 7a1ecaed Iustin Pop
  for line in data:
105 3a24c527 Iustin Pop
    ToStdout(line)
106 7a1ecaed Iustin Pop
107 7a1ecaed Iustin Pop
  return 0
108 7a1ecaed Iustin Pop
109 7a1ecaed Iustin Pop
110 0ad64cf8 Michael Hanselmann
def ArchiveJobs(opts, args):
111 0ad64cf8 Michael Hanselmann
  client = GetClient()
112 0ad64cf8 Michael Hanselmann
113 0ad64cf8 Michael Hanselmann
  for job_id in args:
114 0ad64cf8 Michael Hanselmann
    client.ArchiveJob(job_id)
115 0ad64cf8 Michael Hanselmann
116 0ad64cf8 Michael Hanselmann
  return 0
117 0ad64cf8 Michael Hanselmann
118 0ad64cf8 Michael Hanselmann
119 07cd723a Iustin Pop
def AutoArchiveJobs(opts, args):
120 07cd723a Iustin Pop
  client = GetClient()
121 07cd723a Iustin Pop
122 07cd723a Iustin Pop
  age = args[0]
123 07cd723a Iustin Pop
124 07cd723a Iustin Pop
  if age == 'all':
125 07cd723a Iustin Pop
    age = -1
126 07cd723a Iustin Pop
  else:
127 07cd723a Iustin Pop
    age = ParseTimespec(age)
128 07cd723a Iustin Pop
129 07cd723a Iustin Pop
  client.AutoArchiveJobs(age)
130 07cd723a Iustin Pop
  return 0
131 07cd723a Iustin Pop
132 07cd723a Iustin Pop
133 d2b92ffc Michael Hanselmann
def CancelJobs(opts, args):
134 d2b92ffc Michael Hanselmann
  client = GetClient()
135 d2b92ffc Michael Hanselmann
136 d2b92ffc Michael Hanselmann
  for job_id in args:
137 d2b92ffc Michael Hanselmann
    client.CancelJob(job_id)
138 d2b92ffc Michael Hanselmann
139 d2b92ffc Michael Hanselmann
  return 0
140 d2b92ffc Michael Hanselmann
141 d2b92ffc Michael Hanselmann
142 191712c0 Iustin Pop
def ShowJobs(opts, args):
143 191712c0 Iustin Pop
  """List the jobs
144 191712c0 Iustin Pop
145 191712c0 Iustin Pop
  """
146 191712c0 Iustin Pop
  def format(level, text):
147 191712c0 Iustin Pop
    """Display the text indented."""
148 3a24c527 Iustin Pop
    ToStdout("%s%s", "  " * level, text)
149 191712c0 Iustin Pop
150 191712c0 Iustin Pop
  def result_helper(value):
151 191712c0 Iustin Pop
    """Format a result field in a nice way."""
152 191712c0 Iustin Pop
    if isinstance(value, (tuple, list)):
153 191712c0 Iustin Pop
      return "[%s]" % (", ".join(str(elem) for elem in value))
154 191712c0 Iustin Pop
    else:
155 191712c0 Iustin Pop
      return str(value)
156 191712c0 Iustin Pop
157 aad81f98 Iustin Pop
  selected_fields = [
158 aad81f98 Iustin Pop
    "id", "status", "ops", "opresult", "opstatus", "oplog",
159 aad81f98 Iustin Pop
    "opstart", "opend", "received_ts", "start_ts", "end_ts",
160 aad81f98 Iustin Pop
    ]
161 191712c0 Iustin Pop
162 191712c0 Iustin Pop
  result = GetClient().QueryJobs(args, selected_fields)
163 191712c0 Iustin Pop
164 191712c0 Iustin Pop
  first = True
165 191712c0 Iustin Pop
166 b27b39b0 Iustin Pop
  for idx, entry in enumerate(result):
167 191712c0 Iustin Pop
    if not first:
168 191712c0 Iustin Pop
      format(0, "")
169 191712c0 Iustin Pop
    else:
170 191712c0 Iustin Pop
      first = False
171 aad81f98 Iustin Pop
172 aad81f98 Iustin Pop
    if entry is None:
173 b27b39b0 Iustin Pop
      if idx <= len(args):
174 b27b39b0 Iustin Pop
        format(0, "Job ID %s not found" % args[idx])
175 b27b39b0 Iustin Pop
      else:
176 b27b39b0 Iustin Pop
        # this should not happen, when we don't pass args it will be a
177 b27b39b0 Iustin Pop
        # valid job returned
178 b27b39b0 Iustin Pop
        format(0, "Job ID requested as argument %s not found" % (idx + 1))
179 aad81f98 Iustin Pop
      continue
180 aad81f98 Iustin Pop
181 aad81f98 Iustin Pop
    (job_id, status, ops, opresult, opstatus, oplog,
182 aad81f98 Iustin Pop
     opstart, opend, recv_ts, start_ts, end_ts) = entry
183 191712c0 Iustin Pop
    format(0, "Job ID: %s" % job_id)
184 191712c0 Iustin Pop
    if status in _USER_JOB_STATUS:
185 191712c0 Iustin Pop
      status = _USER_JOB_STATUS[status]
186 191712c0 Iustin Pop
    else:
187 191712c0 Iustin Pop
      raise errors.ProgrammerError("Unknown job status code '%s'" % val)
188 191712c0 Iustin Pop
189 191712c0 Iustin Pop
    format(1, "Status: %s" % status)
190 aad81f98 Iustin Pop
191 aad81f98 Iustin Pop
    if recv_ts is not None:
192 aad81f98 Iustin Pop
      format(1, "Received:         %s" % FormatTimestamp(recv_ts))
193 aad81f98 Iustin Pop
    else:
194 aad81f98 Iustin Pop
      format(1, "Missing received timestamp (%s)" % str(recv_ts))
195 aad81f98 Iustin Pop
196 aad81f98 Iustin Pop
    if start_ts is not None:
197 aad81f98 Iustin Pop
      if recv_ts is not None:
198 aad81f98 Iustin Pop
        d1 = start_ts[0] - recv_ts[0] + (start_ts[1] - recv_ts[1]) / 1000000.0
199 aad81f98 Iustin Pop
        delta = " (delta %.6fs)" % d1
200 aad81f98 Iustin Pop
      else:
201 aad81f98 Iustin Pop
        delta = ""
202 aad81f98 Iustin Pop
      format(1, "Processing start: %s%s" % (FormatTimestamp(start_ts), delta))
203 aad81f98 Iustin Pop
    else:
204 aad81f98 Iustin Pop
      format(1, "Processing start: unknown (%s)" % str(start_ts))
205 aad81f98 Iustin Pop
206 aad81f98 Iustin Pop
    if end_ts is not None:
207 aad81f98 Iustin Pop
      if start_ts is not None:
208 aad81f98 Iustin Pop
        d2 = end_ts[0] - start_ts[0] + (end_ts[1] - start_ts[1]) / 1000000.0
209 aad81f98 Iustin Pop
        delta = " (delta %.6fs)" % d2
210 aad81f98 Iustin Pop
      else:
211 aad81f98 Iustin Pop
        delta = ""
212 aad81f98 Iustin Pop
      format(1, "Processing end:   %s%s" % (FormatTimestamp(end_ts), delta))
213 aad81f98 Iustin Pop
    else:
214 aad81f98 Iustin Pop
      format(1, "Processing end:   unknown (%s)" % str(end_ts))
215 aad81f98 Iustin Pop
216 aad81f98 Iustin Pop
    if end_ts is not None and recv_ts is not None:
217 aad81f98 Iustin Pop
      d3 = end_ts[0] - recv_ts[0] + (end_ts[1] - recv_ts[1]) / 1000000.0
218 aad81f98 Iustin Pop
      format(1, "Total processing time: %.6f seconds" % d3)
219 aad81f98 Iustin Pop
    else:
220 aad81f98 Iustin Pop
      format(1, "Total processing time: N/A")
221 191712c0 Iustin Pop
    format(1, "Opcodes:")
222 aad81f98 Iustin Pop
    for (opcode, result, status, log, s_ts, e_ts) in \
223 aad81f98 Iustin Pop
            zip(ops, opresult, opstatus, oplog, opstart, opend):
224 191712c0 Iustin Pop
      format(2, "%s" % opcode["OP_ID"])
225 191712c0 Iustin Pop
      format(3, "Status: %s" % status)
226 aad81f98 Iustin Pop
      if isinstance(s_ts, (tuple, list)):
227 aad81f98 Iustin Pop
        format(3, "Processing start: %s" % FormatTimestamp(s_ts))
228 aad81f98 Iustin Pop
      else:
229 aad81f98 Iustin Pop
        format(3, "No processing start time")
230 aad81f98 Iustin Pop
      if isinstance(e_ts, (tuple, list)):
231 aad81f98 Iustin Pop
        format(3, "Processing end:   %s" % FormatTimestamp(e_ts))
232 aad81f98 Iustin Pop
      else:
233 aad81f98 Iustin Pop
        format(3, "No processing end time")
234 191712c0 Iustin Pop
      format(3, "Input fields:")
235 191712c0 Iustin Pop
      for key, val in opcode.iteritems():
236 191712c0 Iustin Pop
        if key == "OP_ID":
237 191712c0 Iustin Pop
          continue
238 191712c0 Iustin Pop
        if isinstance(val, (tuple, list)):
239 191712c0 Iustin Pop
          val = ",".join(val)
240 191712c0 Iustin Pop
        format(4, "%s: %s" % (key, val))
241 191712c0 Iustin Pop
      if result is None:
242 191712c0 Iustin Pop
        format(3, "No output data")
243 191712c0 Iustin Pop
      elif isinstance(result, (tuple, list)):
244 191712c0 Iustin Pop
        if not result:
245 191712c0 Iustin Pop
          format(3, "Result: empty sequence")
246 191712c0 Iustin Pop
        else:
247 191712c0 Iustin Pop
          format(3, "Result:")
248 191712c0 Iustin Pop
          for elem in result:
249 191712c0 Iustin Pop
            format(4, result_helper(elem))
250 191712c0 Iustin Pop
      elif isinstance(result, dict):
251 191712c0 Iustin Pop
        if not result:
252 191712c0 Iustin Pop
          format(3, "Result: empty dictionary")
253 191712c0 Iustin Pop
        else:
254 191712c0 Iustin Pop
          for key, val in result.iteritems():
255 191712c0 Iustin Pop
            format(4, "%s: %s" % (key, result_helper(val)))
256 191712c0 Iustin Pop
      else:
257 191712c0 Iustin Pop
        format(3, "Result: %s" % result)
258 5b23c34c Iustin Pop
      format(3, "Execution log:")
259 3386e7a9 Iustin Pop
      for serial, log_ts, log_type, log_msg in log:
260 3386e7a9 Iustin Pop
        time_txt = FormatTimestamp(log_ts)
261 5b23c34c Iustin Pop
        encoded = str(log_msg).encode('string_escape')
262 5b23c34c Iustin Pop
        format(4, "%s:%s:%s %s" % (serial, time_txt, log_type, encoded))
263 191712c0 Iustin Pop
  return 0
264 191712c0 Iustin Pop
265 191712c0 Iustin Pop
266 7a1ecaed Iustin Pop
commands = {
267 7a1ecaed Iustin Pop
  'list': (ListJobs, ARGS_NONE,
268 9a033156 Iustin Pop
            [DEBUG_OPT, NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT],
269 9a033156 Iustin Pop
            "", "List the jobs and their status. The available fields are"
270 35049ff2 Iustin Pop
           " (see the man page for details): id, status, op_list,"
271 35049ff2 Iustin Pop
           " op_status, op_result."
272 7a1ecaed Iustin Pop
           " The default field"
273 0ad64cf8 Michael Hanselmann
           " list is (in order): %s." % ", ".join(_LIST_DEF_FIELDS)),
274 0ad64cf8 Michael Hanselmann
  'archive': (ArchiveJobs, ARGS_ANY,
275 0ad64cf8 Michael Hanselmann
              [DEBUG_OPT],
276 0ad64cf8 Michael Hanselmann
              "<job-id> [<job-id> ...]",
277 0ad64cf8 Michael Hanselmann
              "Archive specified jobs"),
278 07cd723a Iustin Pop
  'autoarchive': (AutoArchiveJobs, ARGS_ONE,
279 07cd723a Iustin Pop
              [DEBUG_OPT],
280 07cd723a Iustin Pop
              "<age>",
281 07cd723a Iustin Pop
              "Auto archive jobs older than the given age"),
282 d2b92ffc Michael Hanselmann
  'cancel': (CancelJobs, ARGS_ANY,
283 d2b92ffc Michael Hanselmann
             [DEBUG_OPT],
284 d2b92ffc Michael Hanselmann
             "<job-id> [<job-id> ...]",
285 d2b92ffc Michael Hanselmann
             "Cancel specified jobs"),
286 191712c0 Iustin Pop
  'info': (ShowJobs, ARGS_ANY, [DEBUG_OPT],
287 191712c0 Iustin Pop
           "<job-id> [<job-id> ...]",
288 191712c0 Iustin Pop
           "Show detailed information about the specified jobs"),
289 7a1ecaed Iustin Pop
  }
290 7a1ecaed Iustin Pop
291 7a1ecaed Iustin Pop
292 7a1ecaed Iustin Pop
if __name__ == '__main__':
293 7a1ecaed Iustin Pop
  sys.exit(GenericMain(commands))