Revision a6070ef7
b/doc/design-query2.rst | ||
---|---|---|
170 | 170 |
Value unavailable for item (numeric 3) |
171 | 171 |
Used if, for example, NIC 3 is requested for an instance with only |
172 | 172 |
one network interface. Value must be ``None``. |
173 |
Resource offline (numeric 4) |
|
174 |
Used if resource is marked offline. Value must be ``None``. |
|
173 | 175 |
|
174 | 176 |
Example response after requesting the fields ``name``, ``mfree``, |
175 | 177 |
``xyz``, ``mtotal``, ``nic0.ip``, ``nic1.ip`` and ``nic2.ip``:: |
b/lib/cli.py | ||
---|---|---|
2402 | 2402 |
if status == constants.QRFS_UNAVAIL: |
2403 | 2403 |
return "(unavail)" |
2404 | 2404 |
|
2405 |
if status == constants.QRFS_OFFLINE: |
|
2406 |
return "(offline)" |
|
2407 |
|
|
2405 | 2408 |
raise NotImplementedError("Unknown status %s" % status) |
2406 | 2409 |
|
2407 | 2410 |
|
b/lib/constants.py | ||
---|---|---|
978 | 978 |
QFT_OTHER, |
979 | 979 |
]) |
980 | 980 |
|
981 |
# Query result field status (don't change values as they're used by clients) |
|
981 |
# Query result field status (don't change or reuse values as they're used by |
|
982 |
# clients) |
|
982 | 983 |
#: Normal field status |
983 | 984 |
QRFS_NORMAL = 0 |
984 | 985 |
#: Unknown field |
985 | 986 |
QRFS_UNKNOWN = 1 |
986 |
#: No data (e.g. node offline)
|
|
987 |
#: No data (e.g. RPC error), can be used instead of L{QRFS_OFFLINE}
|
|
987 | 988 |
QRFS_NODATA = 2 |
988 | 989 |
#: Value unavailable for item |
989 | 990 |
QRFS_UNAVAIL = 3 |
991 |
#: Resource marked offline |
|
992 |
QRFS_OFFLINE = 4 |
|
990 | 993 |
|
991 | 994 |
QRFS_ALL = frozenset([ |
992 | 995 |
QRFS_NORMAL, |
993 | 996 |
QRFS_UNKNOWN, |
994 | 997 |
QRFS_NODATA, |
995 | 998 |
QRFS_UNAVAIL, |
999 |
QRFS_OFFLINE, |
|
996 | 1000 |
]) |
997 | 1001 |
|
998 | 1002 |
# max dynamic devices |
b/lib/query.py | ||
---|---|---|
421 | 421 |
return (constants.QRFS_NORMAL, ng.name) |
422 | 422 |
|
423 | 423 |
|
424 |
def _GetLiveNodeField(field, kind, ctx, _):
|
|
424 |
def _GetLiveNodeField(field, kind, ctx, node):
|
|
425 | 425 |
"""Gets the value of a "live" field from L{NodeQueryData}. |
426 | 426 |
|
427 | 427 |
@param field: Live field name |
428 | 428 |
@param kind: Data kind, one of L{constants.QFT_ALL} |
429 | 429 |
@type ctx: L{NodeQueryData} |
430 |
@type node: L{objects.Node} |
|
431 |
@param node: Node object |
|
430 | 432 |
|
431 | 433 |
""" |
434 |
if node.offline: |
|
435 |
return (constants.QRFS_OFFLINE, None) |
|
436 |
|
|
432 | 437 |
if not ctx.curlive_data: |
433 | 438 |
return (constants.QRFS_NODATA, None) |
434 | 439 |
|
... | ... | |
571 | 576 |
@param inst: Instance object |
572 | 577 |
|
573 | 578 |
""" |
579 |
# Can't use QRFS_OFFLINE here as it would describe the instance to be offline |
|
580 |
# when we actually don't know due to missing data |
|
574 | 581 |
if inst.primary_node in ctx.bad_nodes: |
575 | 582 |
return (constants.QRFS_NODATA, None) |
576 | 583 |
else: |
... | ... | |
594 | 601 |
""" |
595 | 602 |
if (inst.primary_node in ctx.bad_nodes or |
596 | 603 |
inst.primary_node in ctx.offline_nodes): |
604 |
# Can't use QRFS_OFFLINE here as it would describe the instance to be |
|
605 |
# offline when we actually don't know due to missing data |
|
597 | 606 |
return (constants.QRFS_NODATA, None) |
598 | 607 |
|
599 | 608 |
if inst.name in ctx.live_data: |
b/test/ganeti.cli_unittest.py | ||
---|---|---|
379 | 379 |
kind=constants.QFT_BOOL), |
380 | 380 |
objects.QueryFieldDefinition(name="nodata", title="NoData", |
381 | 381 |
kind=constants.QFT_TEXT), |
382 |
objects.QueryFieldDefinition(name="offline", title="OffLine", |
|
383 |
kind=constants.QFT_TEXT), |
|
382 | 384 |
] |
383 | 385 |
|
384 | 386 |
response = objects.QueryResponse(fields=fields, data=[ |
385 | 387 |
[(constants.QRFS_NORMAL, 1), (constants.QRFS_UNKNOWN, None), |
386 |
(constants.QRFS_NORMAL, False), (constants.QRFS_NORMAL, "")], |
|
388 |
(constants.QRFS_NORMAL, False), (constants.QRFS_NORMAL, ""), |
|
389 |
(constants.QRFS_OFFLINE, None)], |
|
387 | 390 |
[(constants.QRFS_NORMAL, 2), (constants.QRFS_UNKNOWN, None), |
388 |
(constants.QRFS_NODATA, None), (constants.QRFS_NORMAL, "x")], |
|
391 |
(constants.QRFS_NODATA, None), (constants.QRFS_NORMAL, "x"), |
|
392 |
(constants.QRFS_OFFLINE, None)], |
|
389 | 393 |
[(constants.QRFS_NORMAL, 3), (constants.QRFS_UNKNOWN, None), |
390 |
(constants.QRFS_NORMAL, False), (constants.QRFS_UNAVAIL, None)], |
|
394 |
(constants.QRFS_NORMAL, False), (constants.QRFS_UNAVAIL, None), |
|
395 |
(constants.QRFS_OFFLINE, None)], |
|
391 | 396 |
]) |
392 | 397 |
|
393 | 398 |
self.assertEqual(cli.FormatQueryResult(response, header=True, |
394 | 399 |
separator="|"), |
395 | 400 |
(cli.QR_UNKNOWN, [ |
396 |
"ID|unk|Unavail|NoData", |
|
397 |
"1|(unknown)|N|", |
|
398 |
"2|(unknown)|(nodata)|x", |
|
399 |
"3|(unknown)|N|(unavail)", |
|
401 |
"ID|unk|Unavail|NoData|OffLine",
|
|
402 |
"1|(unknown)|N||(offline)",
|
|
403 |
"2|(unknown)|(nodata)|x|(offline)",
|
|
404 |
"3|(unknown)|N|(unavail)|(offline)",
|
|
400 | 405 |
])) |
401 | 406 |
|
402 | 407 |
def testNoData(self): |
... | ... | |
433 | 438 |
kind=constants.QFT_BOOL), |
434 | 439 |
objects.QueryFieldDefinition(name="nodata", title="NoData", |
435 | 440 |
kind=constants.QFT_TEXT), |
441 |
objects.QueryFieldDefinition(name="offline", title="OffLine", |
|
442 |
kind=constants.QFT_TEXT), |
|
436 | 443 |
] |
437 | 444 |
|
438 | 445 |
response = objects.QueryResponse(fields=fields, data=[ |
439 | 446 |
[(constants.QRFS_NORMAL, 1), (constants.QRFS_NORMAL, False), |
440 |
(constants.QRFS_NORMAL, "")], |
|
447 |
(constants.QRFS_NORMAL, ""), (constants.QRFS_OFFLINE, None)],
|
|
441 | 448 |
[(constants.QRFS_NORMAL, 2), (constants.QRFS_NODATA, None), |
442 |
(constants.QRFS_NORMAL, "x")], |
|
449 |
(constants.QRFS_NORMAL, "x"), (constants.QRFS_NORMAL, "abc")],
|
|
443 | 450 |
[(constants.QRFS_NORMAL, 3), (constants.QRFS_NORMAL, False), |
444 |
(constants.QRFS_UNAVAIL, None)], |
|
451 |
(constants.QRFS_UNAVAIL, None), (constants.QRFS_OFFLINE, None)],
|
|
445 | 452 |
]) |
446 | 453 |
|
447 | 454 |
self.assertEqual(cli.FormatQueryResult(response, header=False, |
448 | 455 |
separator="|"), |
449 | 456 |
(cli.QR_INCOMPLETE, [ |
450 |
"1|N|", |
|
451 |
"2|(nodata)|x", |
|
452 |
"3|N|(unavail)", |
|
457 |
"1|N||(offline)",
|
|
458 |
"2|(nodata)|x|abc",
|
|
459 |
"3|N|(unavail)|(offline)",
|
|
453 | 460 |
])) |
454 | 461 |
|
455 | 462 |
def testInvalidFieldType(self): |
b/test/ganeti.query_unittest.py | ||
---|---|---|
434 | 434 |
|
435 | 435 |
def testGetLiveNodeField(self): |
436 | 436 |
nodes = [ |
437 |
objects.Node(name="node1", drained=False), |
|
438 |
objects.Node(name="node2", drained=True), |
|
439 |
objects.Node(name="node3", drained=False), |
|
437 |
objects.Node(name="node1", drained=False, offline=False), |
|
438 |
objects.Node(name="node2", drained=True, offline=False), |
|
439 |
objects.Node(name="node3", drained=False, offline=False), |
|
440 |
objects.Node(name="node4", drained=False, offline=True), |
|
440 | 441 |
] |
441 | 442 |
live_data = dict.fromkeys([node.name for node in nodes], {}) |
442 | 443 |
|
443 | 444 |
# No data |
444 | 445 |
nqd = query.NodeQueryData(None, None, None, None, None, None) |
445 | 446 |
self.assertEqual(query._GetLiveNodeField("hello", constants.QFT_NUMBER, |
446 |
nqd, None),
|
|
447 |
nqd, nodes[0]),
|
|
447 | 448 |
(constants.QRFS_NODATA, None)) |
448 | 449 |
|
449 | 450 |
# Missing field |
... | ... | |
452 | 453 |
"other": 2, |
453 | 454 |
}) |
454 | 455 |
self.assertEqual(query._GetLiveNodeField("hello", constants.QFT_NUMBER, |
455 |
ctx, None),
|
|
456 |
ctx, nodes[0]),
|
|
456 | 457 |
(constants.QRFS_UNAVAIL, None)) |
457 | 458 |
|
458 | 459 |
# Wrong format/datatype |
... | ... | |
461 | 462 |
"other": 2, |
462 | 463 |
}) |
463 | 464 |
self.assertEqual(query._GetLiveNodeField("hello", constants.QFT_NUMBER, |
464 |
ctx, None),
|
|
465 |
ctx, nodes[0]),
|
|
465 | 466 |
(constants.QRFS_UNAVAIL, None)) |
466 | 467 |
|
468 |
# Offline node |
|
469 |
assert nodes[3].offline |
|
470 |
ctx = _QueryData(None, curlive_data={}) |
|
471 |
self.assertEqual(query._GetLiveNodeField("hello", constants.QFT_NUMBER, |
|
472 |
ctx, nodes[3]), |
|
473 |
(constants.QRFS_OFFLINE, None)) |
|
474 |
|
|
467 | 475 |
# Wrong field type |
468 | 476 |
ctx = _QueryData(None, curlive_data={"hello": 123}) |
469 | 477 |
self.assertRaises(AssertionError, query._GetLiveNodeField, |
470 |
"hello", constants.QFT_BOOL, ctx, None)
|
|
478 |
"hello", constants.QFT_BOOL, ctx, nodes[0])
|
|
471 | 479 |
|
472 | 480 |
|
473 | 481 |
class TestInstanceQuery(unittest.TestCase): |
Also available in: Unified diff