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