From ec223efb51e42a4acf76dc25609c170ce9d147be Mon Sep 17 00:00:00 2001
From: Iustin Pop <iustin@google.com>
Date: Fri, 14 Sep 2007 09:02:56 +0000
Subject: [PATCH] Change LUQueryNodes to return raw values and support
 selective listing

LUQueryNodes it's very similar to LUQueryNodeData, but it lacks two
features:
  - instance list (it has count though), both primary and secondary
  - selective node listing

In order to support these features, we change it to return raw values
instead of stringified ones (like the recent change to LUQueryInstances)
and to support query-ing of a restricted set of nodes.

This CL also modifies the gnt-node script to conform to the new protocol
and the opcode OpQueryNodes to support the new "nodes" attribute.

Reviewed-by: imsnah
---
 lib/cmdlib.py    | 45 +++++++++++++++++++++++++++------------------
 lib/opcodes.py   |  2 +-
 scripts/gnt-node | 23 +++++++++++++++++++----
 3 files changed, 47 insertions(+), 23 deletions(-)

diff --git a/lib/cmdlib.py b/lib/cmdlib.py
index 9e16c68a0..a0669dbba 100644
--- a/lib/cmdlib.py
+++ b/lib/cmdlib.py
@@ -1129,7 +1129,7 @@ class LUQueryNodes(NoHooksLU):
   """Logical unit for querying nodes.
 
   """
-  _OP_REQP = ["output_fields"]
+  _OP_REQP = ["output_fields", "nodes"]
 
   def CheckPrereq(self):
     """Check prerequisites.
@@ -1140,19 +1140,21 @@ class LUQueryNodes(NoHooksLU):
     self.dynamic_fields = frozenset(["dtotal", "dfree",
                                      "mtotal", "mnode", "mfree"])
 
-    _CheckOutputFields(static=["name", "pinst", "sinst", "pip", "sip"],
+    _CheckOutputFields(static=["name", "pinst_cnt", "sinst_cnt",
+                               "pinst_list", "sinst_list",
+                               "pip", "sip"],
                        dynamic=self.dynamic_fields,
                        selected=self.op.output_fields)
 
+    self.wanted_nodes = _GetWantedNodes(self, self.op.nodes)
 
   def Exec(self, feedback_fn):
     """Computes the list of nodes and their attributes.
 
     """
-    nodenames = utils.NiceSort(self.cfg.GetNodeList())
+    nodenames = self.wanted_nodes
     nodelist = [self.cfg.GetNodeInfo(name) for name in nodenames]
 
-
     # begin data gathering
 
     if self.dynamic_fields.intersection(self.op.output_fields):
@@ -1173,17 +1175,21 @@ class LUQueryNodes(NoHooksLU):
     else:
       live_data = dict.fromkeys(nodenames, {})
 
-    node_to_primary = dict.fromkeys(nodenames, 0)
-    node_to_secondary = dict.fromkeys(nodenames, 0)
+    node_to_primary = dict([(name, set()) for name in nodenames])
+    node_to_secondary = dict([(name, set()) for name in nodenames])
 
-    if "pinst" in self.op.output_fields or "sinst" in self.op.output_fields:
+    inst_fields = frozenset(("pinst_cnt", "pinst_list",
+                             "sinst_cnt", "sinst_list"))
+    if inst_fields & frozenset(self.op.output_fields):
       instancelist = self.cfg.GetInstanceList()
 
-      for instance in instancelist:
-        instanceinfo = self.cfg.GetInstanceInfo(instance)
-        node_to_primary[instanceinfo.primary_node] += 1
-        for secnode in instanceinfo.secondary_nodes:
-          node_to_secondary[secnode] += 1
+      for instance_name in instancelist:
+        inst = self.cfg.GetInstanceInfo(instance_name)
+        if inst.primary_node in node_to_primary:
+          node_to_primary[inst.primary_node].add(inst.name)
+        for secnode in inst.secondary_nodes:
+          if secnode in node_to_secondary:
+            node_to_secondary[secnode].add(inst.name)
 
     # end data gathering
 
@@ -1193,19 +1199,22 @@ class LUQueryNodes(NoHooksLU):
       for field in self.op.output_fields:
         if field == "name":
           val = node.name
-        elif field == "pinst":
-          val = node_to_primary[node.name]
-        elif field == "sinst":
-          val = node_to_secondary[node.name]
+        elif field == "pinst_list":
+          val = list(node_to_primary[node.name])
+        elif field == "sinst_list":
+          val = list(node_to_secondary[node.name])
+        elif field == "pinst_cnt":
+          val = len(node_to_primary[node.name])
+        elif field == "sinst_cnt":
+          val = len(node_to_secondary[node.name])
         elif field == "pip":
           val = node.primary_ip
         elif field == "sip":
           val = node.secondary_ip
         elif field in self.dynamic_fields:
-          val = live_data[node.name].get(field, "?")
+          val = live_data[node.name].get(field, None)
         else:
           raise errors.ParameterError(field)
-        val = str(val)
         node_output.append(val)
       output.append(node_output)
 
diff --git a/lib/opcodes.py b/lib/opcodes.py
index 7f04f5017..e9a125b83 100644
--- a/lib/opcodes.py
+++ b/lib/opcodes.py
@@ -113,7 +113,7 @@ class OpAddNode(OpCode):
 class OpQueryNodes(OpCode):
   """Compute the list of nodes."""
   OP_ID = "OP_NODE_QUERY"
-  __slots__ = ["output_fields"]
+  __slots__ = ["output_fields", "nodes"]
 
 
 class OpQueryNodeData(OpCode):
diff --git a/scripts/gnt-node b/scripts/gnt-node
index c4a43116c..9fbc10a0f 100755
--- a/scripts/gnt-node
+++ b/scripts/gnt-node
@@ -41,15 +41,16 @@ def ListNodes(opts, args):
   if opts.output is None:
     selected_fields = ["name", "dtotal", "dfree",
                        "mtotal", "mnode", "mfree",
-                       "pinst", "sinst"]
+                       "pinst_cnt", "sinst_cnt"]
   else:
     selected_fields = opts.output.split(",")
 
-  op = opcodes.OpQueryNodes(output_fields=selected_fields)
+  op = opcodes.OpQueryNodes(output_fields=selected_fields, nodes=[])
   output = SubmitOpCode(op)
 
   if not opts.no_headers:
-    headers = {"name": "Node", "pinst": "Pinst", "sinst": "Sinst",
+    headers = {"name": "Node", "pinst_cnt": "Pinst", "sinst_cnt": "Sinst",
+               "pinst_list": "PriInstances", "sinst_list": "SecInstances",
                "pip": "PrimaryIP", "sip": "SecondaryIP",
                "dtotal": "DTotal", "dfree": "DFree",
                "mtotal": "MTotal", "mnode": "MNode", "mfree": "MFree"}
@@ -61,7 +62,21 @@ def ListNodes(opts, args):
   else:
     unitfields = None
 
-  numfields = ["dtotal", "dfree", "mtotal", "mnode", "mfree", "pinst", "sinst"]
+  numfields = ["dtotal", "dfree",
+               "mtotal", "mnode", "mfree",
+               "pinst_cnt", "sinst_cnt"]
+
+  # change raw values to nicer strings
+  for row in output:
+    for idx, field in enumerate(selected_fields):
+      val = row[idx]
+      if field == "pinst_list":
+        val = ",".join(val)
+      elif field == "sinst_list":
+        val = ",".join(val)
+      elif val is None:
+        val = "?"
+      row[idx] = str(val)
 
   data = GenerateTable(separator=opts.separator, headers=headers,
                        fields=selected_fields, unitfields=unitfields,
-- 
GitLab