root / scripts / gnt-job @ 191712c0
History | View | Annotate | Download (5.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 | 7a1ecaed | Iustin Pop | from optparse import make_option |
26 | 7a1ecaed | Iustin Pop | from cStringIO import StringIO |
27 | 7a1ecaed | Iustin Pop | |
28 | 7a1ecaed | Iustin Pop | from ganeti.cli import * |
29 | 7a1ecaed | Iustin Pop | from ganeti import opcodes |
30 | 7a1ecaed | Iustin Pop | from ganeti import logger |
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 | af30b2fd | Michael Hanselmann | constants.JOB_STATUS_RUNNING: "running", |
41 | af30b2fd | Michael Hanselmann | constants.JOB_STATUS_CANCELED: "canceled", |
42 | af30b2fd | Michael Hanselmann | constants.JOB_STATUS_SUCCESS: "success", |
43 | af30b2fd | Michael Hanselmann | constants.JOB_STATUS_ERROR: "error", |
44 | af30b2fd | Michael Hanselmann | } |
45 | af30b2fd | Michael Hanselmann | |
46 | 0ad64cf8 | Michael Hanselmann | |
47 | 7a1ecaed | Iustin Pop | def ListJobs(opts, args): |
48 | 7a1ecaed | Iustin Pop | """List the jobs |
49 | 7a1ecaed | Iustin Pop | |
50 | 7a1ecaed | Iustin Pop | """ |
51 | 7a1ecaed | Iustin Pop | if opts.output is None: |
52 | 7a5d3bbd | Iustin Pop | selected_fields = _LIST_DEF_FIELDS |
53 | 7a5d3bbd | Iustin Pop | elif opts.output.startswith("+"): |
54 | 7a5d3bbd | Iustin Pop | selected_fields = _LIST_DEF_FIELDS + opts.output[1:].split(",") |
55 | 7a1ecaed | Iustin Pop | else: |
56 | 7a1ecaed | Iustin Pop | selected_fields = opts.output.split(",") |
57 | 7a1ecaed | Iustin Pop | |
58 | af30b2fd | Michael Hanselmann | output = GetClient().QueryJobs(None, selected_fields) |
59 | 7a1ecaed | Iustin Pop | if not opts.no_headers: |
60 | af30b2fd | Michael Hanselmann | # TODO: Implement more fields |
61 | 7a1ecaed | Iustin Pop | headers = { |
62 | 7a1ecaed | Iustin Pop | "id": "ID", |
63 | 7a1ecaed | Iustin Pop | "status": "Status", |
64 | af30b2fd | Michael Hanselmann | "ops": "OpCodes", |
65 | af30b2fd | Michael Hanselmann | "opresult": "OpCode_result", |
66 | af30b2fd | Michael Hanselmann | "opstatus": "OpCode_status", |
67 | 60dd1473 | Iustin Pop | "summary": "Summary", |
68 | 7a1ecaed | Iustin Pop | } |
69 | 7a1ecaed | Iustin Pop | else: |
70 | 7a1ecaed | Iustin Pop | headers = None |
71 | 7a1ecaed | Iustin Pop | |
72 | 7a1ecaed | Iustin Pop | # we don't have yet unitfields here |
73 | 7a1ecaed | Iustin Pop | unitfields = None |
74 | 5ce81b28 | Michael Hanselmann | numfields = None |
75 | 7a1ecaed | Iustin Pop | |
76 | 7a1ecaed | Iustin Pop | # change raw values to nicer strings |
77 | 7a1ecaed | Iustin Pop | for row in output: |
78 | 7a1ecaed | Iustin Pop | for idx, field in enumerate(selected_fields): |
79 | 7a1ecaed | Iustin Pop | val = row[idx] |
80 | 7a1ecaed | Iustin Pop | if field == "status": |
81 | af30b2fd | Michael Hanselmann | if val in _USER_JOB_STATUS: |
82 | af30b2fd | Michael Hanselmann | val = _USER_JOB_STATUS[val] |
83 | 7a1ecaed | Iustin Pop | else: |
84 | 7a1ecaed | Iustin Pop | raise errors.ProgrammerError("Unknown job status code '%s'" % val) |
85 | 60dd1473 | Iustin Pop | elif field == "summary": |
86 | 60dd1473 | Iustin Pop | val = ",".join(val) |
87 | 7a1ecaed | Iustin Pop | |
88 | 7a1ecaed | Iustin Pop | row[idx] = str(val) |
89 | 7a1ecaed | Iustin Pop | |
90 | 7a1ecaed | Iustin Pop | data = GenerateTable(separator=opts.separator, headers=headers, |
91 | 7a1ecaed | Iustin Pop | fields=selected_fields, unitfields=unitfields, |
92 | 7a1ecaed | Iustin Pop | numfields=numfields, data=output) |
93 | 7a1ecaed | Iustin Pop | for line in data: |
94 | 7a1ecaed | Iustin Pop | print line |
95 | 7a1ecaed | Iustin Pop | |
96 | 7a1ecaed | Iustin Pop | return 0 |
97 | 7a1ecaed | Iustin Pop | |
98 | 7a1ecaed | Iustin Pop | |
99 | 0ad64cf8 | Michael Hanselmann | def ArchiveJobs(opts, args): |
100 | 0ad64cf8 | Michael Hanselmann | client = GetClient() |
101 | 0ad64cf8 | Michael Hanselmann | |
102 | 0ad64cf8 | Michael Hanselmann | for job_id in args: |
103 | 0ad64cf8 | Michael Hanselmann | client.ArchiveJob(job_id) |
104 | 0ad64cf8 | Michael Hanselmann | |
105 | 0ad64cf8 | Michael Hanselmann | return 0 |
106 | 0ad64cf8 | Michael Hanselmann | |
107 | 0ad64cf8 | Michael Hanselmann | |
108 | d2b92ffc | Michael Hanselmann | def CancelJobs(opts, args): |
109 | d2b92ffc | Michael Hanselmann | client = GetClient() |
110 | d2b92ffc | Michael Hanselmann | |
111 | d2b92ffc | Michael Hanselmann | for job_id in args: |
112 | d2b92ffc | Michael Hanselmann | client.CancelJob(job_id) |
113 | d2b92ffc | Michael Hanselmann | |
114 | d2b92ffc | Michael Hanselmann | return 0 |
115 | d2b92ffc | Michael Hanselmann | |
116 | d2b92ffc | Michael Hanselmann | |
117 | 191712c0 | Iustin Pop | def ShowJobs(opts, args): |
118 | 191712c0 | Iustin Pop | """List the jobs |
119 | 191712c0 | Iustin Pop | |
120 | 191712c0 | Iustin Pop | """ |
121 | 191712c0 | Iustin Pop | def format(level, text): |
122 | 191712c0 | Iustin Pop | """Display the text indented.""" |
123 | 191712c0 | Iustin Pop | print "%s%s" % (" " * level, text) |
124 | 191712c0 | Iustin Pop | |
125 | 191712c0 | Iustin Pop | def result_helper(value): |
126 | 191712c0 | Iustin Pop | """Format a result field in a nice way.""" |
127 | 191712c0 | Iustin Pop | if isinstance(value, (tuple, list)): |
128 | 191712c0 | Iustin Pop | return "[%s]" % (", ".join(str(elem) for elem in value)) |
129 | 191712c0 | Iustin Pop | else: |
130 | 191712c0 | Iustin Pop | return str(value) |
131 | 191712c0 | Iustin Pop | |
132 | 191712c0 | Iustin Pop | selected_fields = ["id", "status", "ops", "opresult", "opstatus"] |
133 | 191712c0 | Iustin Pop | |
134 | 191712c0 | Iustin Pop | result = GetClient().QueryJobs(args, selected_fields) |
135 | 191712c0 | Iustin Pop | |
136 | 191712c0 | Iustin Pop | first = True |
137 | 191712c0 | Iustin Pop | |
138 | 191712c0 | Iustin Pop | for job_id, status, ops, opresult, opstatus in result: |
139 | 191712c0 | Iustin Pop | if not first: |
140 | 191712c0 | Iustin Pop | format(0, "") |
141 | 191712c0 | Iustin Pop | else: |
142 | 191712c0 | Iustin Pop | first = False |
143 | 191712c0 | Iustin Pop | format(0, "Job ID: %s" % job_id) |
144 | 191712c0 | Iustin Pop | if status in _USER_JOB_STATUS: |
145 | 191712c0 | Iustin Pop | status = _USER_JOB_STATUS[status] |
146 | 191712c0 | Iustin Pop | else: |
147 | 191712c0 | Iustin Pop | raise errors.ProgrammerError("Unknown job status code '%s'" % val) |
148 | 191712c0 | Iustin Pop | |
149 | 191712c0 | Iustin Pop | format(1, "Status: %s" % status) |
150 | 191712c0 | Iustin Pop | format(1, "Opcodes:") |
151 | 191712c0 | Iustin Pop | for opcode, result, status in zip(ops, opresult, opstatus): |
152 | 191712c0 | Iustin Pop | format(2, "%s" % opcode["OP_ID"]) |
153 | 191712c0 | Iustin Pop | format(3, "Status: %s" % status) |
154 | 191712c0 | Iustin Pop | format(3, "Input fields:") |
155 | 191712c0 | Iustin Pop | for key, val in opcode.iteritems(): |
156 | 191712c0 | Iustin Pop | if key == "OP_ID": |
157 | 191712c0 | Iustin Pop | continue |
158 | 191712c0 | Iustin Pop | if isinstance(val, (tuple, list)): |
159 | 191712c0 | Iustin Pop | val = ",".join(val) |
160 | 191712c0 | Iustin Pop | format(4, "%s: %s" % (key, val)) |
161 | 191712c0 | Iustin Pop | if result is None: |
162 | 191712c0 | Iustin Pop | format(3, "No output data") |
163 | 191712c0 | Iustin Pop | elif isinstance(result, (tuple, list)): |
164 | 191712c0 | Iustin Pop | if not result: |
165 | 191712c0 | Iustin Pop | format(3, "Result: empty sequence") |
166 | 191712c0 | Iustin Pop | else: |
167 | 191712c0 | Iustin Pop | format(3, "Result:") |
168 | 191712c0 | Iustin Pop | for elem in result: |
169 | 191712c0 | Iustin Pop | format(4, result_helper(elem)) |
170 | 191712c0 | Iustin Pop | elif isinstance(result, dict): |
171 | 191712c0 | Iustin Pop | if not result: |
172 | 191712c0 | Iustin Pop | format(3, "Result: empty dictionary") |
173 | 191712c0 | Iustin Pop | else: |
174 | 191712c0 | Iustin Pop | for key, val in result.iteritems(): |
175 | 191712c0 | Iustin Pop | format(4, "%s: %s" % (key, result_helper(val))) |
176 | 191712c0 | Iustin Pop | else: |
177 | 191712c0 | Iustin Pop | format(3, "Result: %s" % result) |
178 | 191712c0 | Iustin Pop | return 0 |
179 | 191712c0 | Iustin Pop | |
180 | 191712c0 | Iustin Pop | |
181 | 7a1ecaed | Iustin Pop | commands = { |
182 | 7a1ecaed | Iustin Pop | 'list': (ListJobs, ARGS_NONE, |
183 | 9a033156 | Iustin Pop | [DEBUG_OPT, NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT], |
184 | 9a033156 | Iustin Pop | "", "List the jobs and their status. The available fields are" |
185 | 35049ff2 | Iustin Pop | " (see the man page for details): id, status, op_list," |
186 | 35049ff2 | Iustin Pop | " op_status, op_result." |
187 | 7a1ecaed | Iustin Pop | " The default field" |
188 | 0ad64cf8 | Michael Hanselmann | " list is (in order): %s." % ", ".join(_LIST_DEF_FIELDS)), |
189 | 0ad64cf8 | Michael Hanselmann | 'archive': (ArchiveJobs, ARGS_ANY, |
190 | 0ad64cf8 | Michael Hanselmann | [DEBUG_OPT], |
191 | 0ad64cf8 | Michael Hanselmann | "<job-id> [<job-id> ...]", |
192 | 0ad64cf8 | Michael Hanselmann | "Archive specified jobs"), |
193 | d2b92ffc | Michael Hanselmann | 'cancel': (CancelJobs, ARGS_ANY, |
194 | d2b92ffc | Michael Hanselmann | [DEBUG_OPT], |
195 | d2b92ffc | Michael Hanselmann | "<job-id> [<job-id> ...]", |
196 | d2b92ffc | Michael Hanselmann | "Cancel specified jobs"), |
197 | 191712c0 | Iustin Pop | 'info': (ShowJobs, ARGS_ANY, [DEBUG_OPT], |
198 | 191712c0 | Iustin Pop | "<job-id> [<job-id> ...]", |
199 | 191712c0 | Iustin Pop | "Show detailed information about the specified jobs"), |
200 | 7a1ecaed | Iustin Pop | } |
201 | 7a1ecaed | Iustin Pop | |
202 | 7a1ecaed | Iustin Pop | |
203 | 7a1ecaed | Iustin Pop | if __name__ == '__main__': |
204 | 7a1ecaed | Iustin Pop | sys.exit(GenericMain(commands)) |