Revision 1c8addc6 lib/query.py

b/lib/query.py
38 38
 NQ_LIVE,
39 39
 NQ_GROUP) = range(1, 5)
40 40

  
41
(IQ_CONFIG,
42
 IQ_LIVE,
43
 IQ_DISKUSAGE) = range(100, 103)
44

  
41 45

  
42 46
FIELD_NAME_RE = re.compile(r"^[a-z0-9/._]+$")
43 47
TITLE_RE = re.compile(r"^[^\s]+$")
......
438 442
  return _PrepareFieldList(fields)
439 443

  
440 444

  
445
class InstanceQueryData:
446
  """Data container for instance data queries.
447

  
448
  """
449
  def __init__(self, instances, cluster, disk_usage, offline_nodes, bad_nodes,
450
               live_data):
451
    """Initializes this class.
452

  
453
    @param instances: List of instance objects
454
    @param cluster: Cluster object
455
    @type disk_usage: dict; instance name as key
456
    @param disk_usage: Per-instance disk usage
457
    @type offline_nodes: list of strings
458
    @param offline_nodes: List of offline nodes
459
    @type bad_nodes: list of strings
460
    @param bad_nodes: List of faulty nodes
461
    @type live_data: dict; instance name as key
462
    @param live_data: Per-instance live data
463

  
464
    """
465
    assert len(set(bad_nodes) & set(offline_nodes)) == len(offline_nodes), \
466
           "Offline nodes not included in bad nodes"
467
    assert not (set(live_data.keys()) & set(bad_nodes)), \
468
           "Found live data for bad or offline nodes"
469

  
470
    self.instances = instances
471
    self.cluster = cluster
472
    self.disk_usage = disk_usage
473
    self.offline_nodes = offline_nodes
474
    self.bad_nodes = bad_nodes
475
    self.live_data = live_data
476

  
477
    # Used for individual rows
478
    self.inst_hvparams = None
479
    self.inst_beparams = None
480
    self.inst_nicparams = None
481

  
482
  def __iter__(self):
483
    """Iterate over all instances.
484

  
485
    This function has side-effects and only one instance of the resulting
486
    generator should be used at a time.
487

  
488
    """
489
    for inst in self.instances:
490
      self.inst_hvparams = self.cluster.FillHV(inst, skip_globals=True)
491
      self.inst_beparams = self.cluster.FillBE(inst)
492
      self.inst_nicparams = [self.cluster.SimpleFillNIC(nic.nicparams)
493
                             for nic in inst.nics]
494

  
495
      yield inst
496

  
497

  
498
def _GetInstOperState(ctx, inst):
499
  """Get instance's operational status.
500

  
501
  @type ctx: L{InstanceQueryData}
502
  @type inst: L{objects.Instance}
503
  @param inst: Instance object
504

  
505
  """
506
  if inst.primary_node in ctx.bad_nodes:
507
    return (constants.QRFS_NODATA, None)
508
  else:
509
    return (constants.QRFS_NORMAL, bool(ctx.live_data.get(inst.name)))
510

  
511

  
512
def _GetInstLiveData(name):
513
  """Build function for retrieving live data.
514

  
515
  @type name: string
516
  @param name: Live data field name
517

  
518
  """
519
  def fn(ctx, inst):
520
    """Get live data for an instance.
521

  
522
    @type ctx: L{InstanceQueryData}
523
    @type inst: L{objects.Instance}
524
    @param inst: Instance object
525

  
526
    """
527
    if (inst.primary_node in ctx.bad_nodes or
528
        inst.primary_node in ctx.offline_nodes):
529
      return (constants.QRFS_NODATA, None)
530

  
531
    if inst.name in ctx.live_data:
532
      data = ctx.live_data[inst.name]
533
      if name in data:
534
        return (constants.QRFS_NORMAL, data[name])
535

  
536
    return (constants.QRFS_UNAVAIL, None)
537

  
538
  return fn
539

  
540

  
541
def _GetInstStatus(ctx, inst):
542
  """Get instance status.
543

  
544
  @type ctx: L{InstanceQueryData}
545
  @type inst: L{objects.Instance}
546
  @param inst: Instance object
547

  
548
  """
549
  if inst.primary_node in ctx.offline_nodes:
550
    return (constants.QRFS_NORMAL, "ERROR_nodeoffline")
551

  
552
  if inst.primary_node in ctx.bad_nodes:
553
    return (constants.QRFS_NORMAL, "ERROR_nodedown")
554

  
555
  if bool(ctx.live_data.get(inst.name)):
556
    if inst.admin_up:
557
      return (constants.QRFS_NORMAL, "running")
558
    else:
559
      return (constants.QRFS_NORMAL, "ERROR_up")
560

  
561
  if inst.admin_up:
562
    return (constants.QRFS_NORMAL, "ERROR_down")
563

  
564
  return (constants.QRFS_NORMAL, "ADMIN_down")
565

  
566

  
567
def _GetInstDiskSize(index):
568
  """Build function for retrieving disk size.
569

  
570
  @type index: int
571
  @param index: Disk index
572

  
573
  """
574
  def fn(_, inst):
575
    """Get size of a disk.
576

  
577
    @type inst: L{objects.Instance}
578
    @param inst: Instance object
579

  
580
    """
581
    try:
582
      return (constants.QRFS_NORMAL, inst.disks[index].size)
583
    except IndexError:
584
      return (constants.QRFS_UNAVAIL, None)
585

  
586
  return fn
587

  
588

  
589
def _GetInstNic(index, cb):
590
  """Build function for calling another function with an instance NIC.
591

  
592
  @type index: int
593
  @param index: NIC index
594
  @type cb: callable
595
  @param cb: Callback
596

  
597
  """
598
  def fn(ctx, inst):
599
    """Call helper function with instance NIC.
600

  
601
    @type ctx: L{InstanceQueryData}
602
    @type inst: L{objects.Instance}
603
    @param inst: Instance object
604

  
605
    """
606
    try:
607
      nic = inst.nics[index]
608
    except IndexError:
609
      return (constants.QRFS_UNAVAIL, None)
610

  
611
    return cb(ctx, index, nic)
612

  
613
  return fn
614

  
615

  
616
def _GetInstNicIp(ctx, _, nic): # pylint: disable-msg=W0613
617
  """Get a NIC's IP address.
618

  
619
  @type ctx: L{InstanceQueryData}
620
  @type nic: L{objects.NIC}
621
  @param nic: NIC object
622

  
623
  """
624
  if nic.ip is None:
625
    return (constants.QRFS_UNAVAIL, None)
626
  else:
627
    return (constants.QRFS_NORMAL, nic.ip)
628

  
629

  
630
def _GetInstNicBridge(ctx, index, _):
631
  """Get a NIC's bridge.
632

  
633
  @type ctx: L{InstanceQueryData}
634
  @type index: int
635
  @param index: NIC index
636

  
637
  """
638
  assert len(ctx.inst_nicparams) >= index
639

  
640
  nicparams = ctx.inst_nicparams[index]
641

  
642
  if nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
643
    return (constants.QRFS_NORMAL, nicparams[constants.NIC_LINK])
644
  else:
645
    return (constants.QRFS_UNAVAIL, None)
646

  
647

  
648
def _GetInstAllNicBridges(ctx, inst):
649
  """Get all network bridges for an instance.
650

  
651
  @type ctx: L{InstanceQueryData}
652
  @type inst: L{objects.Instance}
653
  @param inst: Instance object
654

  
655
  """
656
  assert len(ctx.inst_nicparams) == len(inst.nics)
657

  
658
  result = []
659

  
660
  for nicp in ctx.inst_nicparams:
661
    if nicp[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
662
      result.append(nicp[constants.NIC_LINK])
663
    else:
664
      result.append(None)
665

  
666
  assert len(result) == len(inst.nics)
667

  
668
  return (constants.QRFS_NORMAL, result)
669

  
670

  
671
def _GetInstNicParam(name):
672
  """Build function for retrieving a NIC parameter.
673

  
674
  @type name: string
675
  @param name: Parameter name
676

  
677
  """
678
  def fn(ctx, index, _):
679
    """Get a NIC's bridge.
680

  
681
    @type ctx: L{InstanceQueryData}
682
    @type inst: L{objects.Instance}
683
    @param inst: Instance object
684
    @type nic: L{objects.NIC}
685
    @param nic: NIC object
686

  
687
    """
688
    assert len(ctx.inst_nicparams) >= index
689
    return (constants.QRFS_NORMAL, ctx.inst_nicparams[index][name])
690

  
691
  return fn
692

  
693

  
694
def _GetInstanceNetworkFields():
695
  """Get instance fields involving network interfaces.
696

  
697
  @return: List of field definitions used as input for L{_PrepareFieldList}
698

  
699
  """
700
  nic_mac_fn = lambda ctx, _, nic: (constants.QRFS_NORMAL, nic.mac)
701
  nic_mode_fn = _GetInstNicParam(constants.NIC_MODE)
702
  nic_link_fn = _GetInstNicParam(constants.NIC_LINK)
703

  
704
  fields = [
705
    # First NIC (legacy)
706
    (_MakeField("ip", "IP_address", constants.QFT_TEXT), IQ_CONFIG,
707
     _GetInstNic(0, _GetInstNicIp)),
708
    (_MakeField("mac", "MAC_address", constants.QFT_TEXT), IQ_CONFIG,
709
     _GetInstNic(0, nic_mac_fn)),
710
    (_MakeField("bridge", "Bridge", constants.QFT_TEXT), IQ_CONFIG,
711
     _GetInstNic(0, _GetInstNicBridge)),
712
    (_MakeField("nic_mode", "NIC_Mode", constants.QFT_TEXT), IQ_CONFIG,
713
     _GetInstNic(0, nic_mode_fn)),
714
    (_MakeField("nic_link", "NIC_Link", constants.QFT_TEXT), IQ_CONFIG,
715
     _GetInstNic(0, nic_link_fn)),
716

  
717
    # All NICs
718
    (_MakeField("nic.count", "NICs", constants.QFT_NUMBER), IQ_CONFIG,
719
     lambda ctx, inst: (constants.QRFS_NORMAL, len(inst.nics))),
720
    (_MakeField("nic.macs", "NIC_MACs", constants.QFT_OTHER), IQ_CONFIG,
721
     lambda ctx, inst: (constants.QRFS_NORMAL, [nic.mac for nic in inst.nics])),
722
    (_MakeField("nic.ips", "NIC_IPs", constants.QFT_OTHER), IQ_CONFIG,
723
     lambda ctx, inst: (constants.QRFS_NORMAL, [nic.ip for nic in inst.nics])),
724
    (_MakeField("nic.modes", "NIC_modes", constants.QFT_OTHER), IQ_CONFIG,
725
     lambda ctx, inst: (constants.QRFS_NORMAL,
726
                        [nicp[constants.NIC_MODE]
727
                         for nicp in ctx.inst_nicparams])),
728
    (_MakeField("nic.links", "NIC_links", constants.QFT_OTHER), IQ_CONFIG,
729
     lambda ctx, inst: (constants.QRFS_NORMAL,
730
                        [nicp[constants.NIC_LINK]
731
                         for nicp in ctx.inst_nicparams])),
732
    (_MakeField("nic.bridges", "NIC_bridges", constants.QFT_OTHER), IQ_CONFIG,
733
     _GetInstAllNicBridges),
734
    ]
735

  
736
  # NICs by number
737
  for i in range(constants.MAX_NICS):
738
    fields.extend([
739
      (_MakeField("nic.ip/%s" % i, "NicIP/%s" % i, constants.QFT_TEXT),
740
       IQ_CONFIG, _GetInstNic(i, _GetInstNicIp)),
741
      (_MakeField("nic.mac/%s" % i, "NicMAC/%s" % i, constants.QFT_TEXT),
742
       IQ_CONFIG, _GetInstNic(i, nic_mac_fn)),
743
      (_MakeField("nic.mode/%s" % i, "NicMode/%s" % i, constants.QFT_TEXT),
744
       IQ_CONFIG, _GetInstNic(i, nic_mode_fn)),
745
      (_MakeField("nic.link/%s" % i, "NicLink/%s" % i, constants.QFT_TEXT),
746
       IQ_CONFIG, _GetInstNic(i, nic_link_fn)),
747
      (_MakeField("nic.bridge/%s" % i, "NicBridge/%s" % i, constants.QFT_TEXT),
748
       IQ_CONFIG, _GetInstNic(i, _GetInstNicBridge)),
749
      ])
750

  
751
  return fields
752

  
753

  
754
def _GetInstDiskUsage(ctx, inst):
755
  """Get disk usage for an instance.
756

  
757
  @type ctx: L{InstanceQueryData}
758
  @type inst: L{objects.Instance}
759
  @param inst: Instance object
760

  
761
  """
762
  usage = ctx.disk_usage[inst.name]
763

  
764
  if usage is None:
765
    usage = 0
766

  
767
  return (constants.QRFS_NORMAL, usage)
768

  
769

  
770
def _GetInstanceDiskFields():
771
  """Get instance fields involving disks.
772

  
773
  @return: List of field definitions used as input for L{_PrepareFieldList}
774

  
775
  """
776
  fields = [
777
    (_MakeField("disk_usage", "DiskUsage", constants.QFT_UNIT), IQ_DISKUSAGE,
778
     _GetInstDiskUsage),
779
    (_MakeField("sda_size", "LegacyDisk/0", constants.QFT_UNIT), IQ_CONFIG,
780
     _GetInstDiskSize(0)),
781
    (_MakeField("sdb_size", "LegacyDisk/1", constants.QFT_UNIT), IQ_CONFIG,
782
     _GetInstDiskSize(1)),
783
    (_MakeField("disk.count", "Disks", constants.QFT_NUMBER), IQ_CONFIG,
784
     lambda ctx, inst: (constants.QRFS_NORMAL, len(inst.disks))),
785
    (_MakeField("disk.sizes", "Disk_sizes", constants.QFT_OTHER), IQ_CONFIG,
786
     lambda ctx, inst: (constants.QRFS_NORMAL,
787
                        [disk.size for disk in inst.disks])),
788
    ]
789

  
790
  # Disks by number
791
  fields.extend([
792
    (_MakeField("disk.size/%s" % i, "Disk/%s" % i, constants.QFT_UNIT),
793
     IQ_CONFIG, _GetInstDiskSize(i))
794
    for i in range(constants.MAX_DISKS)
795
    ])
796

  
797
  return fields
798

  
799

  
800
def _GetInstanceParameterFields():
801
  """Get instance fields involving parameters.
802

  
803
  @return: List of field definitions used as input for L{_PrepareFieldList}
804

  
805
  """
806
  # TODO: Consider moving titles closer to constants
807
  be_title = {
808
    constants.BE_AUTO_BALANCE: "Auto_balance",
809
    constants.BE_MEMORY: "Configured_memory",
810
    constants.BE_VCPUS: "VCPUs",
811
    }
812

  
813
  hv_title = {
814
    constants.HV_ACPI: "ACPI",
815
    constants.HV_BOOT_ORDER: "Boot_order",
816
    constants.HV_CDROM_IMAGE_PATH: "CDROM_image_path",
817
    constants.HV_DISK_TYPE: "Disk_type",
818
    constants.HV_INITRD_PATH: "Initrd_path",
819
    constants.HV_KERNEL_PATH: "Kernel_path",
820
    constants.HV_NIC_TYPE: "NIC_type",
821
    constants.HV_PAE: "PAE",
822
    constants.HV_VNC_BIND_ADDRESS: "VNC_bind_address",
823
    }
824

  
825
  fields = [
826
    # Filled parameters
827
    (_MakeField("hvparams", "HypervisorParameters", constants.QFT_OTHER),
828
     IQ_CONFIG, lambda ctx, _: (constants.QRFS_NORMAL, ctx.inst_hvparams)),
829
    (_MakeField("beparams", "BackendParameters", constants.QFT_OTHER),
830
     IQ_CONFIG, lambda ctx, _: (constants.QRFS_NORMAL, ctx.inst_beparams)),
831
    (_MakeField("vcpus", "LegacyVCPUs", constants.QFT_NUMBER), IQ_CONFIG,
832
     lambda ctx, _: (constants.QRFS_NORMAL,
833
                     ctx.inst_beparams[constants.BE_VCPUS])),
834

  
835
    # Unfilled parameters
836
    (_MakeField("custom_hvparams", "CustomHypervisorParameters",
837
                constants.QFT_OTHER),
838
     IQ_CONFIG, lambda ctx, inst: (constants.QRFS_NORMAL, inst.hvparams)),
839
    (_MakeField("custom_beparams", "CustomBackendParameters",
840
                constants.QFT_OTHER),
841
     IQ_CONFIG, lambda ctx, inst: (constants.QRFS_NORMAL, inst.beparams)),
842
    (_MakeField("custom_nicparams", "CustomNicParameters",
843
                constants.QFT_OTHER),
844
     IQ_CONFIG, lambda ctx, inst: (constants.QRFS_NORMAL,
845
                                   [nic.nicparams for nic in inst.nics])),
846
    ]
847

  
848
  # HV params
849
  def _GetInstHvParam(name):
850
    return lambda ctx, _: (constants.QRFS_NORMAL,
851
                           ctx.inst_hvparams.get(name, None))
852

  
853
  fields.extend([
854
    # For now all hypervisor parameters are exported as QFT_OTHER
855
    (_MakeField("hv/%s" % name, hv_title.get(name, "hv/%s" % name),
856
                constants.QFT_OTHER),
857
     IQ_CONFIG, _GetInstHvParam(name))
858
    for name in constants.HVS_PARAMETERS
859
    if name not in constants.HVC_GLOBALS
860
    ])
861

  
862
  # BE params
863
  def _GetInstBeParam(name):
864
    return lambda ctx, _: (constants.QRFS_NORMAL,
865
                           ctx.inst_beparams.get(name, None))
866

  
867
  fields.extend([
868
    # For now all backend parameters are exported as QFT_OTHER
869
    (_MakeField("be/%s" % name, be_title.get(name, "be/%s" % name),
870
                constants.QFT_OTHER),
871
     IQ_CONFIG, _GetInstBeParam(name))
872
    for name in constants.BES_PARAMETERS
873
    ])
874

  
875
  return fields
876

  
877

  
878
_INST_SIMPLE_FIELDS = {
879
  "ctime": ("CTime", constants.QFT_TIMESTAMP),
880
  "disk_template": ("Disk_template", constants.QFT_TEXT),
881
  "hypervisor": ("Hypervisor", constants.QFT_TEXT),
882
  "mtime": ("MTime", constants.QFT_TIMESTAMP),
883
  "name": ("Node", constants.QFT_TEXT),
884
  # Depending on the hypervisor, the port can be None
885
  "network_port": ("Network_port", constants.QFT_OTHER),
886
  "os": ("OS", constants.QFT_TEXT),
887
  "serial_no": ("SerialNo", constants.QFT_NUMBER),
888
  "uuid": ("UUID", constants.QFT_TEXT),
889
  }
890

  
891

  
892
def _BuildInstanceFields():
893
  """Builds list of fields for instance queries.
894

  
895
  """
896
  fields = [
897
    (_MakeField("pnode", "Primary_node", constants.QFT_TEXT), IQ_CONFIG,
898
     lambda ctx, inst: (constants.QRFS_NORMAL, inst.primary_node)),
899
    (_MakeField("snodes", "Secondary_Nodes", constants.QFT_OTHER), IQ_CONFIG,
900
     lambda ctx, inst: (constants.QRFS_NORMAL, list(inst.secondary_nodes))),
901
    (_MakeField("admin_state", "Autostart", constants.QFT_BOOL), IQ_CONFIG,
902
     lambda ctx, inst: (constants.QRFS_NORMAL, inst.admin_up)),
903
    (_MakeField("tags", "Tags", constants.QFT_OTHER), IQ_CONFIG,
904
     lambda ctx, inst: (constants.QRFS_NORMAL, list(inst.GetTags()))),
905
    ]
906

  
907
  # Add simple fields
908
  fields.extend([(_MakeField(name, title, kind), IQ_CONFIG, _GetItemAttr(name))
909
                 for (name, (title, kind)) in _INST_SIMPLE_FIELDS.items()])
910

  
911
  # Fields requiring talking to the node
912
  fields.extend([
913
    (_MakeField("oper_state", "Running", constants.QFT_BOOL), IQ_LIVE,
914
     _GetInstOperState),
915
    (_MakeField("oper_ram", "RuntimeMemory", constants.QFT_UNIT), IQ_LIVE,
916
     _GetInstLiveData("memory")),
917
    (_MakeField("oper_vcpus", "RuntimeVCPUs", constants.QFT_NUMBER), IQ_LIVE,
918
     _GetInstLiveData("vcpus")),
919
    (_MakeField("status", "Status", constants.QFT_TEXT), IQ_LIVE,
920
     _GetInstStatus),
921
    ])
922

  
923
  fields.extend(_GetInstanceParameterFields())
924
  fields.extend(_GetInstanceDiskFields())
925
  fields.extend(_GetInstanceNetworkFields())
926

  
927
  return _PrepareFieldList(fields)
928

  
929

  
441 930
#: Fields available for node queries
442 931
NODE_FIELDS = _BuildNodeFields()
932

  
933
#: Fields available for instance queries
934
INSTANCE_FIELDS = _BuildInstanceFields()

Also available in: Unified diff