From e7b61bb02f87d4b580b059dda56625b575384b2a Mon Sep 17 00:00:00 2001
From: Iustin Pop <iustin@google.com>
Date: Mon, 22 Mar 2010 17:23:36 +0100
Subject: [PATCH] Introduce a bool CLI option type

This option type enforces its value to either True or False, relieving
the scripts from manually parsing the values in each function.

We also update the bash completion code to use the option type if
possible.

Signed-off-by: Iustin Pop <iustin@google.com>
Reviewed-by: Guido Trotter <ultrotter@google.com>
---
 autotools/build-bash-completion |  4 ++++
 lib/cli.py                      | 26 +++++++++++++++++++++-----
 scripts/gnt-node                | 21 ++++-----------------
 3 files changed, 29 insertions(+), 22 deletions(-)

diff --git a/autotools/build-bash-completion b/autotools/build-bash-completion
index 56204af00..79258c2cc 100755
--- a/autotools/build-bash-completion
+++ b/autotools/build-bash-completion
@@ -312,6 +312,10 @@ class CompletionWriter:
       # Only static choices implemented so far (e.g. no node list)
       suggest = getattr(opt, "completion_suggest", None)
 
+      # our custom option type
+      if opt.type == "bool":
+        suggest = ["yes", "no"]
+
       if not suggest:
         suggest = opt.choices
 
diff --git a/lib/cli.py b/lib/cli.py
index 9c480d67a..5df4aaeca 100644
--- a/lib/cli.py
+++ b/lib/cli.py
@@ -457,6 +457,21 @@ def check_key_val(option, opt, value):  # pylint: disable-msg=W0613
   return _SplitKeyVal(opt, value)
 
 
+def check_bool(option, opt, value): # pylint: disable-msg=W0613
+  """Custom parser for yes/no options.
+
+  This will store the parsed value as either True or False.
+
+  """
+  value = value.lower()
+  if value == constants.VALUE_FALSE or value == "no":
+    return False
+  elif value == constants.VALUE_TRUE or value == "yes":
+    return True
+  else:
+    raise errors.ParameterError("Invalid boolean value '%s'" % value)
+
+
 # completion_suggestion is normally a list. Using numeric values not evaluating
 # to False for dynamic completion.
 (OPT_COMPL_MANY_NODES,
@@ -487,18 +502,19 @@ class CliOption(Option):
     "identkeyval",
     "keyval",
     "unit",
+    "bool",
     )
   TYPE_CHECKER = Option.TYPE_CHECKER.copy()
   TYPE_CHECKER["identkeyval"] = check_ident_key_val
   TYPE_CHECKER["keyval"] = check_key_val
   TYPE_CHECKER["unit"] = check_unit
+  TYPE_CHECKER["bool"] = check_bool
 
 
 # optparse.py sets make_option, so we do it for our own option class, too
 cli_option = CliOption
 
 
-_YESNO = ("yes", "no")
 _YORNO = "yes|no"
 
 DEBUG_OPT = cli_option("-d", "--debug", default=0, action="count",
@@ -759,19 +775,19 @@ NOSSH_KEYCHECK_OPT = cli_option("--no-ssh-key-check", dest="ssh_key_check",
 
 
 MC_OPT = cli_option("-C", "--master-candidate", dest="master_candidate",
-                    choices=_YESNO, default=None, metavar=_YORNO,
+                    type="bool", default=None, metavar=_YORNO,
                     help="Set the master_candidate flag on the node")
 
 OFFLINE_OPT = cli_option("-O", "--offline", dest="offline", metavar=_YORNO,
-                         choices=_YESNO, default=None,
+                         type="bool", default=None,
                          help="Set the offline flag on the node")
 
 DRAINED_OPT = cli_option("-D", "--drained", dest="drained", metavar=_YORNO,
-                         choices=_YESNO, default=None,
+                         type="bool", default=None,
                          help="Set the drained flag on the node")
 
 ALLOCATABLE_OPT = cli_option("--allocatable", dest="allocatable",
-                             choices=_YESNO, default=None, metavar=_YORNO,
+                             type="bool", default=None, metavar=_YORNO,
                              help="Set the allocatable flag on a volume")
 
 NOLVM_STORAGE_OPT = cli_option("--no-lvm-storage", dest="lvm_storage",
diff --git a/scripts/gnt-node b/scripts/gnt-node
index 5c985619e..61c4f2714 100755
--- a/scripts/gnt-node
+++ b/scripts/gnt-node
@@ -571,7 +571,7 @@ def ModifyStorage(opts, args):
   changes = {}
 
   if opts.allocatable is not None:
-    changes[constants.SF_ALLOCATABLE] = (opts.allocatable == "yes")
+    changes[constants.SF_ALLOCATABLE] = opts.allocatable
 
   if changes:
     op = opcodes.OpModifyNodeStorage(node_name=node_name,
@@ -618,23 +618,10 @@ def SetNodeParams(opts, args):
     ToStderr("Please give at least one of the parameters.")
     return 1
 
-  if opts.master_candidate is not None:
-    candidate = opts.master_candidate == 'yes'
-  else:
-    candidate = None
-  if opts.offline is not None:
-    offline = opts.offline == 'yes'
-  else:
-    offline = None
-
-  if opts.drained is not None:
-    drained = opts.drained == 'yes'
-  else:
-    drained = None
   op = opcodes.OpSetNodeParams(node_name=args[0],
-                               master_candidate=candidate,
-                               offline=offline,
-                               drained=drained,
+                               master_candidate=opts.master_candidate,
+                               offline=opts.offline,
+                               drained=opts.drained,
                                force=opts.force,
                                auto_promote=opts.auto_promote)
 
-- 
GitLab