From c1912a48875ae86b13286827e4df885911e5c1d0 Mon Sep 17 00:00:00 2001
From: Michael Hanselmann <hansmi@google.com>
Date: Fri, 21 Dec 2012 14:44:52 +0100
Subject: [PATCH] gnt-* list-fields: Show friendly field type

For people writing query filters (documented in ganeti(7)) knowing a field's
type can be useful.

$ gnt-instance list-fields name be/memory
Name      Type         Title        Description
name      Text         Instance     Instance name
be/memory Storage size ConfigMaxMem The "maxmem" backend parameter

Signed-off-by: Michael Hanselmann <hansmi@google.com>
Reviewed-by: Iustin Pop <iustin@google.com>
---
 lib/cli.py                  | 29 ++++++++++++++++++++++++++++-
 test/ganeti.cli_unittest.py | 34 ++++++++++++++++++++++++++++++++++
 2 files changed, 62 insertions(+), 1 deletion(-)

diff --git a/lib/cli.py b/lib/cli.py
index 0162bddd1..9a258f453 100644
--- a/lib/cli.py
+++ b/lib/cli.py
@@ -315,6 +315,17 @@ TISPECS_CLUSTER_TYPES = {
   constants.ISPECS_STD: constants.VTYPE_INT,
   }
 
+#: User-friendly names for query2 field types
+_QFT_NAMES = {
+  constants.QFT_UNKNOWN: "Unknown",
+  constants.QFT_TEXT: "Text",
+  constants.QFT_BOOL: "Boolean",
+  constants.QFT_NUMBER: "Number",
+  constants.QFT_UNIT: "Storage size",
+  constants.QFT_TIMESTAMP: "Timestamp",
+  constants.QFT_OTHER: "Custom",
+  }
+
 
 class _Argument:
   def __init__(self, min=0, max=None): # pylint: disable=W0622
@@ -3064,6 +3075,21 @@ def GenericList(resource, fields, names, unit, separator, header, cl=None,
   return constants.EXIT_SUCCESS
 
 
+def _FieldDescValues(fdef):
+  """Helper function for L{GenericListFields} to get query field description.
+
+  @type fdef: L{objects.QueryFieldDefinition}
+  @rtype: list
+
+  """
+  return [
+    fdef.name,
+    _QFT_NAMES.get(fdef.kind, fdef.kind),
+    fdef.title,
+    fdef.doc,
+    ]
+
+
 def GenericListFields(resource, fields, separator, header, cl=None):
   """Generic implementation for listing fields for a resource.
 
@@ -3088,11 +3114,12 @@ def GenericListFields(resource, fields, separator, header, cl=None):
 
   columns = [
     TableColumn("Name", str, False),
+    TableColumn("Type", str, False),
     TableColumn("Title", str, False),
     TableColumn("Description", str, False),
     ]
 
-  rows = [[fdef.name, fdef.title, fdef.doc] for fdef in response.fields]
+  rows = map(_FieldDescValues, response.fields)
 
   for line in FormatTable(rows, columns, header, separator):
     ToStdout(line)
diff --git a/test/ganeti.cli_unittest.py b/test/ganeti.cli_unittest.py
index 5cb486953..3ebde5fe0 100755
--- a/test/ganeti.cli_unittest.py
+++ b/test/ganeti.cli_unittest.py
@@ -1010,5 +1010,39 @@ class TestParseArgs(unittest.TestCase):
                       ["test", "list"], cmd, aliases, set())
 
 
+class TestQftNames(unittest.TestCase):
+  def testComplete(self):
+    self.assertEqual(frozenset(cli._QFT_NAMES), constants.QFT_ALL)
+
+  def testUnique(self):
+    lcnames = map(lambda s: s.lower(), cli._QFT_NAMES.values())
+    self.assertFalse(utils.FindDuplicates(lcnames))
+
+  def testUppercase(self):
+    for name in cli._QFT_NAMES.values():
+      self.assertEqual(name[0], name[0].upper())
+
+
+class TestFieldDescValues(unittest.TestCase):
+  def testKnownKind(self):
+    fdef = objects.QueryFieldDefinition(name="aname",
+                                        title="Atitle",
+                                        kind=constants.QFT_TEXT,
+                                        doc="aaa doc aaa")
+    self.assertEqual(cli._FieldDescValues(fdef),
+                     ["aname", "Text", "Atitle", "aaa doc aaa"])
+
+  def testUnknownKind(self):
+    kind = "#foo#"
+
+    self.assertFalse(kind in constants.QFT_ALL)
+    self.assertFalse(kind in cli._QFT_NAMES)
+
+    fdef = objects.QueryFieldDefinition(name="zname", title="Ztitle",
+                                        kind=kind, doc="zzz doc zzz")
+    self.assertEqual(cli._FieldDescValues(fdef),
+                     ["zname", kind, "Ztitle", "zzz doc zzz"])
+
+
 if __name__ == "__main__":
   testutils.GanetiTestProgram()
-- 
GitLab