Revision 526f866b lib/query.py
b/lib/query.py | ||
---|---|---|
64 | 64 |
from ganeti import ht |
65 | 65 |
from ganeti import runtime |
66 | 66 |
from ganeti import qlang |
67 |
from ganeti import jstore |
|
67 | 68 |
|
68 | 69 |
from ganeti.constants import (QFT_UNKNOWN, QFT_TEXT, QFT_BOOL, QFT_NUMBER, |
69 | 70 |
QFT_UNIT, QFT_TIMESTAMP, QFT_OTHER, |
... | ... | |
103 | 104 |
# Query field flags |
104 | 105 |
QFF_HOSTNAME = 0x01 |
105 | 106 |
QFF_IP_ADDRESS = 0x02 |
106 |
# Next values: 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x100, 0x200 |
|
107 |
QFF_ALL = (QFF_HOSTNAME | QFF_IP_ADDRESS) |
|
107 |
QFF_JOB_ID = 0x04 |
|
108 |
QFF_SPLIT_TIMESTAMP = 0x08 |
|
109 |
# Next values: 0x10, 0x20, 0x40, 0x80, 0x100, 0x200 |
|
110 |
QFF_ALL = (QFF_HOSTNAME | QFF_IP_ADDRESS | QFF_JOB_ID | QFF_SPLIT_TIMESTAMP) |
|
108 | 111 |
|
109 | 112 |
FIELD_NAME_RE = re.compile(r"^[a-z0-9/._]+$") |
110 | 113 |
TITLE_RE = re.compile(r"^[^\s]+$") |
... | ... | |
345 | 348 |
raise errors.ParameterError("Invalid regex pattern (%s)" % err) |
346 | 349 |
|
347 | 350 |
|
351 |
def _PrepareSplitTimestamp(value): |
|
352 |
"""Prepares a value for comparison by L{_MakeSplitTimestampComparison}. |
|
353 |
|
|
354 |
""" |
|
355 |
if ht.TNumber(value): |
|
356 |
return value |
|
357 |
else: |
|
358 |
return utils.MergeTime(value) |
|
359 |
|
|
360 |
|
|
361 |
def _MakeSplitTimestampComparison(fn): |
|
362 |
"""Compares split timestamp values after converting to float. |
|
363 |
|
|
364 |
""" |
|
365 |
return lambda lhs, rhs: fn(utils.MergeTime(lhs), rhs) |
|
366 |
|
|
367 |
|
|
368 |
def _MakeComparisonChecks(fn): |
|
369 |
"""Prepares flag-specific comparisons using a comparison function. |
|
370 |
|
|
371 |
""" |
|
372 |
return [ |
|
373 |
(QFF_SPLIT_TIMESTAMP, _MakeSplitTimestampComparison(fn), |
|
374 |
_PrepareSplitTimestamp), |
|
375 |
(QFF_JOB_ID, lambda lhs, rhs: fn(jstore.ParseJobId(lhs), rhs), |
|
376 |
jstore.ParseJobId), |
|
377 |
(None, fn, None), |
|
378 |
] |
|
379 |
|
|
380 |
|
|
348 | 381 |
class _FilterCompilerHelper: |
349 | 382 |
"""Converts a query filter to a callable usable for filtering. |
350 | 383 |
|
... | ... | |
363 | 396 |
|
364 | 397 |
List of tuples containing flags and a callable receiving the left- and |
365 | 398 |
right-hand side of the operator. The flags are an OR-ed value of C{QFF_*} |
366 |
(e.g. L{QFF_HOSTNAME}). |
|
399 |
(e.g. L{QFF_HOSTNAME} or L{QFF_SPLIT_TIMESTAMP}).
|
|
367 | 400 |
|
368 | 401 |
Order matters. The first item with flags will be used. Flags are checked |
369 | 402 |
using binary AND. |
... | ... | |
374 | 407 |
lambda lhs, rhs: utils.MatchNameComponent(rhs, [lhs], |
375 | 408 |
case_sensitive=False), |
376 | 409 |
None), |
410 |
(QFF_SPLIT_TIMESTAMP, _MakeSplitTimestampComparison(operator.eq), |
|
411 |
_PrepareSplitTimestamp), |
|
377 | 412 |
(None, operator.eq, None), |
378 | 413 |
] |
379 | 414 |
|
... | ... | |
403 | 438 |
qlang.OP_NOT_EQUAL: |
404 | 439 |
(_OPTYPE_BINARY, [(flags, compat.partial(_WrapNot, fn), valprepfn) |
405 | 440 |
for (flags, fn, valprepfn) in _EQUALITY_CHECKS]), |
406 |
qlang.OP_LT: (_OPTYPE_BINARY, [ |
|
407 |
(None, operator.lt, None), |
|
408 |
]), |
|
409 |
qlang.OP_GT: (_OPTYPE_BINARY, [ |
|
410 |
(None, operator.gt, None), |
|
411 |
]), |
|
412 |
qlang.OP_LE: (_OPTYPE_BINARY, [ |
|
413 |
(None, operator.le, None), |
|
414 |
]), |
|
415 |
qlang.OP_GE: (_OPTYPE_BINARY, [ |
|
416 |
(None, operator.ge, None), |
|
417 |
]), |
|
441 |
qlang.OP_LT: (_OPTYPE_BINARY, _MakeComparisonChecks(operator.lt)), |
|
442 |
qlang.OP_LE: (_OPTYPE_BINARY, _MakeComparisonChecks(operator.le)), |
|
443 |
qlang.OP_GT: (_OPTYPE_BINARY, _MakeComparisonChecks(operator.gt)), |
|
444 |
qlang.OP_GE: (_OPTYPE_BINARY, _MakeComparisonChecks(operator.ge)), |
|
418 | 445 |
qlang.OP_REGEXP: (_OPTYPE_BINARY, [ |
419 | 446 |
(None, lambda lhs, rhs: rhs.search(lhs), _PrepareRegex), |
420 | 447 |
]), |
... | ... | |
2239 | 2266 |
""" |
2240 | 2267 |
fields = [ |
2241 | 2268 |
(_MakeField("id", "ID", QFT_TEXT, "Job ID"), |
2242 |
None, 0, lambda _, (job_id, job): job_id),
|
|
2269 |
None, QFF_JOB_ID, lambda _, (job_id, job): job_id),
|
|
2243 | 2270 |
(_MakeField("status", "Status", QFT_TEXT, "Job status"), |
2244 | 2271 |
None, 0, _JobUnavail(lambda job: job.CalcStatus())), |
2245 | 2272 |
(_MakeField("priority", "Priority", QFT_NUMBER, |
... | ... | |
2270 | 2297 |
(_MakeField("oppriority", "OpCode_prio", QFT_OTHER, |
2271 | 2298 |
"List of opcode priorities"), |
2272 | 2299 |
None, 0, _PerJobOp(operator.attrgetter("priority"))), |
2273 |
(_MakeField("received_ts", "Received", QFT_OTHER, |
|
2274 |
"Timestamp of when job was received"), |
|
2275 |
None, 0, _JobTimestamp(operator.attrgetter("received_timestamp"))), |
|
2276 |
(_MakeField("start_ts", "Start", QFT_OTHER, |
|
2277 |
"Timestamp of job start"), |
|
2278 |
None, 0, _JobTimestamp(operator.attrgetter("start_timestamp"))), |
|
2279 |
(_MakeField("end_ts", "End", QFT_OTHER, |
|
2280 |
"Timestamp of job end"), |
|
2281 |
None, 0, _JobTimestamp(operator.attrgetter("end_timestamp"))), |
|
2282 | 2300 |
(_MakeField("summary", "Summary", QFT_OTHER, |
2283 | 2301 |
"List of per-opcode summaries"), |
2284 | 2302 |
None, 0, _PerJobOp(lambda op: op.input.Summary())), |
2285 | 2303 |
] |
2286 | 2304 |
|
2305 |
# Timestamp fields |
|
2306 |
for (name, attr, title, desc) in [ |
|
2307 |
("received_ts", "received_timestamp", "Received", |
|
2308 |
"Timestamp of when job was received"), |
|
2309 |
("start_ts", "start_timestamp", "Start", "Timestamp of job start"), |
|
2310 |
("end_ts", "end_timestamp", "End", "Timestamp of job end"), |
|
2311 |
]: |
|
2312 |
getter = operator.attrgetter(attr) |
|
2313 |
fields.extend([ |
|
2314 |
(_MakeField(name, title, QFT_OTHER, |
|
2315 |
"%s (tuple containing seconds and microseconds)" % desc), |
|
2316 |
None, QFF_SPLIT_TIMESTAMP, _JobTimestamp(getter)), |
|
2317 |
]) |
|
2318 |
|
|
2287 | 2319 |
return _PrepareFieldList(fields, []) |
2288 | 2320 |
|
2289 | 2321 |
|
Also available in: Unified diff