def _BuildNodeFields():
  fields = [
    (_MakeField("pip", "PrimaryIP", QFT_TEXT, "Primary IP address"),
     NQ_CONFIG, 0, _GetItemAttr("primary_ip")),
    (_MakeField("sip", "SecondaryIP", QFT_TEXT, "Secondary IP address"),
     NQ_CONFIG, 0, _GetItemAttr("secondary_ip")),
    (_MakeField("tags", "Tags", QFT_OTHER, "Tags"), NQ_CONFIG, 0,
     lambda ctx, node: list(node.GetTags())),
    (_MakeField("master", "IsMaster", QFT_BOOL, "Whether node is master"),
     NQ_CONFIG, 0, lambda ctx, node: node.uuid == ctx.master_uuid),
    (_MakeField("group", "Group", QFT_TEXT, "Node group"), NQ_GROUP, 0,
     _GetGroup(_GetNodeGroup)),
    (_MakeField("group.uuid", "GroupUUID", QFT_TEXT, "UUID of node group"),
     NQ_CONFIG, 0, _GetItemAttr("group")),
    (_MakeField("powered", "Powered", QFT_BOOL,
                "Whether node is thought to be powered on"),
     NQ_OOB, 0, _GetNodePower),
    (_MakeField("ndparams", "NodeParameters", QFT_OTHER,
                "Merged node parameters"),
     NQ_GROUP, 0, _GetGroup(_GetNdParams)),
    (_MakeField("custom_ndparams", "CustomNodeParameters", QFT_OTHER,
                "Custom node parameters"),
      NQ_GROUP, 0, _GetItemAttr("ndparams")),
    # FIXME: The code below return custom hv_state instead of filled one.
    # Anyway, this functionality is unlikely to be used.
    (_MakeField("hv_state", "HypervisorState", QFT_OTHER,
                "Static hypervisor state for default hypervisor only"),
     NQ_CONFIG, 0, _GetItemAttr("hv_state_static")),
    (_MakeField("custom_hv_state", "CustomHypervisorState", QFT_OTHER,
                "Custom static hypervisor state"),
     NQ_CONFIG, 0, _GetItemAttr("hv_state_static")),
    (_MakeField("disk_state", "DiskState", QFT_OTHER, "Disk state"),
     NQ_CONFIG, 0, _GetItemAttr("disk_state_static")),
    ]

  fields.extend(_BuildNDFields(False))

  # Node role
  role_values = (constants.NR_MASTER, constants.NR_MCANDIDATE,
                 constants.NR_REGULAR, constants.NR_DRAINED,
                 constants.NR_OFFLINE)
  role_doc = ("Node role; \"%s\" for master, \"%s\" for master candidate,"
              " \"%s\" for regular, \"%s\" for drained, \"%s\" for offline" %
              role_values)
  fields.append((_MakeField("role", "Role", QFT_TEXT, role_doc), NQ_CONFIG, 0,
                 lambda ctx, node: _GetNodeRole(node, ctx.master_uuid)))
  assert set(role_values) == constants.NR_ALL

  def _GetLength(getter):
    return lambda ctx, node: len(getter(ctx)[node.uuid])

  def _GetList(getter):
    return lambda ctx, node: utils.NiceSort(
                               [ctx.inst_uuid_to_inst_name[uuid]
                                for uuid in getter(ctx)[node.uuid]])

  # Add fields operating on instance lists
  for prefix, titleprefix, docword, getter in \
      [("p", "Pri", "primary", operator.attrgetter("node_to_primary")),
       ("s", "Sec", "secondary", operator.attrgetter("node_to_secondary"))]:
    # TODO: Allow filterting by hostname in list
    fields.extend([
      (_MakeField("%sinst_cnt" % prefix, "%sinst" % prefix.upper(), QFT_NUMBER,
                  "Number of instances with this node as %s" % docword),
       NQ_INST, 0, _GetLength(getter)),
      (_MakeField("%sinst_list" % prefix, "%sInstances" % titleprefix,
                  QFT_OTHER,
                  "List of instances with this node as %s" % docword),
       NQ_INST, 0, _GetList(getter)),
      ])

  # Add simple fields
  fields.extend([
    (_MakeField(name, title, kind, doc), NQ_CONFIG, flags, _GetItemAttr(name))
    for (name, (title, kind, flags, doc)) in _NODE_SIMPLE_FIELDS.items()])

  # Add fields requiring live data
  fields.extend([
    (_MakeField(name, title, kind, doc), NQ_LIVE, 0,
     compat.partial(_GetLiveNodeField, nfield, kind))
    for (name, (title, kind, nfield, doc)) in _NODE_LIVE_FIELDS.items()])

  # Add timestamps
  fields.extend(_GetItemTimestampFields(NQ_CONFIG))

  return _PrepareFieldList(fields, [])
Builds list of fields for node queries.
dataset/ETHPy150Open ganeti/ganeti/lib/query.py/_BuildNodeFields