gnt-debug: rename allocator to iallocator
[ganeti-local] / lib / cli.py
index 50bb158..10bcf95 100644 (file)
@@ -27,6 +27,7 @@ import textwrap
 import os.path
 import time
 import logging
 import os.path
 import time
 import logging
+import errno
 from cStringIO import StringIO
 
 from ganeti import utils
 from cStringIO import StringIO
 
 from ganeti import utils
@@ -77,6 +78,7 @@ __all__ = [
   "FIELDS_OPT",
   "FILESTORE_DIR_OPT",
   "FILESTORE_DRIVER_OPT",
   "FIELDS_OPT",
   "FILESTORE_DIR_OPT",
   "FILESTORE_DRIVER_OPT",
+  "FORCE_FILTER_OPT",
   "FORCE_OPT",
   "FORCE_VARIANT_OPT",
   "GLOBAL_FILEDIR_OPT",
   "FORCE_OPT",
   "FORCE_VARIANT_OPT",
   "GLOBAL_FILEDIR_OPT",
@@ -128,6 +130,7 @@ __all__ = [
   "NOSTART_OPT",
   "NOSSH_KEYCHECK_OPT",
   "NOVOTING_OPT",
   "NOSTART_OPT",
   "NOSSH_KEYCHECK_OPT",
   "NOVOTING_OPT",
+  "NO_REMEMBER_OPT",
   "NWSYNC_OPT",
   "ON_PRIMARY_OPT",
   "ON_SECONDARY_OPT",
   "NWSYNC_OPT",
   "ON_PRIMARY_OPT",
   "ON_SECONDARY_OPT",
@@ -344,7 +347,8 @@ ARGS_MANY_NODES = [ArgNode()]
 ARGS_MANY_GROUPS = [ArgGroup()]
 ARGS_ONE_INSTANCE = [ArgInstance(min=1, max=1)]
 ARGS_ONE_NODE = [ArgNode(min=1, max=1)]
 ARGS_MANY_GROUPS = [ArgGroup()]
 ARGS_ONE_INSTANCE = [ArgInstance(min=1, max=1)]
 ARGS_ONE_NODE = [ArgNode(min=1, max=1)]
-ARGS_ONE_GROUP = [ArgInstance(min=1, max=1)]
+# TODO
+ARGS_ONE_GROUP = [ArgGroup(min=1, max=1)]
 ARGS_ONE_OS = [ArgOs(min=1, max=1)]
 
 
 ARGS_ONE_OS = [ArgOs(min=1, max=1)]
 
 
@@ -359,7 +363,9 @@ def _ExtractTagsObject(opts, args):
   kind = opts.tag_type
   if kind == constants.TAG_CLUSTER:
     retval = kind, kind
   kind = opts.tag_type
   if kind == constants.TAG_CLUSTER:
     retval = kind, kind
-  elif kind == constants.TAG_NODE or kind == constants.TAG_INSTANCE:
+  elif kind in (constants.TAG_NODEGROUP,
+                constants.TAG_NODE,
+                constants.TAG_INSTANCE):
     if not args:
       raise errors.OpPrereqError("no arguments passed to the command")
     name = args.pop(0)
     if not args:
       raise errors.OpPrereqError("no arguments passed to the command")
     name = args.pop(0)
@@ -660,8 +666,8 @@ NWSYNC_OPT = cli_option("--no-wait-for-sync", dest="wait_for_sync",
                         help="Don't wait for sync (DANGEROUS!)")
 
 DISK_TEMPLATE_OPT = cli_option("-t", "--disk-template", dest="disk_template",
                         help="Don't wait for sync (DANGEROUS!)")
 
 DISK_TEMPLATE_OPT = cli_option("-t", "--disk-template", dest="disk_template",
-                               help="Custom disk setup (diskless, file,"
-                               " plain or drbd)",
+                               help=("Custom disk setup (%s)" %
+                                     utils.CommaJoin(constants.DISK_TEMPLATES)),
                                default=None, metavar="TEMPL",
                                choices=list(constants.DISK_TEMPLATES))
 
                                default=None, metavar="TEMPL",
                                choices=list(constants.DISK_TEMPLATES))
 
@@ -861,12 +867,16 @@ NEW_SECONDARY_OPT = cli_option("-n", "--new-secondary", dest="dst_node",
 ON_PRIMARY_OPT = cli_option("-p", "--on-primary", dest="on_primary",
                             default=False, action="store_true",
                             help="Replace the disk(s) on the primary"
 ON_PRIMARY_OPT = cli_option("-p", "--on-primary", dest="on_primary",
                             default=False, action="store_true",
                             help="Replace the disk(s) on the primary"
-                            " node (only for the drbd template)")
+                                 " node (applies only to internally mirrored"
+                                 " disk templates, e.g. %s)" %
+                                 utils.CommaJoin(constants.DTS_INT_MIRROR))
 
 ON_SECONDARY_OPT = cli_option("-s", "--on-secondary", dest="on_secondary",
                               default=False, action="store_true",
                               help="Replace the disk(s) on the secondary"
 
 ON_SECONDARY_OPT = cli_option("-s", "--on-secondary", dest="on_secondary",
                               default=False, action="store_true",
                               help="Replace the disk(s) on the secondary"
-                              " node (only for the drbd template)")
+                                   " node (applies only to internally mirrored"
+                                   " disk templates, e.g. %s)" %
+                                   utils.CommaJoin(constants.DTS_INT_MIRROR))
 
 AUTO_PROMOTE_OPT = cli_option("--auto-promote", dest="auto_promote",
                               default=False, action="store_true",
 
 AUTO_PROMOTE_OPT = cli_option("--auto-promote", dest="auto_promote",
                               default=False, action="store_true",
@@ -876,7 +886,9 @@ AUTO_PROMOTE_OPT = cli_option("--auto-promote", dest="auto_promote",
 AUTO_REPLACE_OPT = cli_option("-a", "--auto", dest="auto",
                               default=False, action="store_true",
                               help="Automatically replace faulty disks"
 AUTO_REPLACE_OPT = cli_option("-a", "--auto", dest="auto",
                               default=False, action="store_true",
                               help="Automatically replace faulty disks"
-                              " (only for the drbd template)")
+                                   " (applies only to internally mirrored"
+                                   " disk templates, e.g. %s)" %
+                                   utils.CommaJoin(constants.DTS_INT_MIRROR))
 
 IGNORE_SIZE_OPT = cli_option("--ignore-size", dest="ignore_size",
                              default=False, action="store_true",
 
 IGNORE_SIZE_OPT = cli_option("--ignore-size", dest="ignore_size",
                              default=False, action="store_true",
@@ -1181,6 +1193,17 @@ POWER_DELAY_OPT = cli_option("--power-delay", dest="power_delay", type="float",
                              default=constants.OOB_POWER_DELAY,
                              help="Time in seconds to wait between power-ons")
 
                              default=constants.OOB_POWER_DELAY,
                              help="Time in seconds to wait between power-ons")
 
+FORCE_FILTER_OPT = cli_option("-F", "--filter", dest="force_filter",
+                              action="store_true", default=False,
+                              help=("Whether command argument should be treated"
+                                    " as filter"))
+
+NO_REMEMBER_OPT = cli_option("--no-remember",
+                             dest="no_remember",
+                             action="store_true", default=False,
+                             help="Perform but do not record the change"
+                             " in the configuration")
+
 
 #: Options provided by all commands
 COMMON_OPTS = [DEBUG_OPT]
 
 #: Options provided by all commands
 COMMON_OPTS = [DEBUG_OPT]
@@ -1975,6 +1998,12 @@ def GenericMain(commands, override=None, aliases=None):
     ToStderr("Aborted. Note that if the operation created any jobs, they"
              " might have been submitted and"
              " will continue to run in the background.")
     ToStderr("Aborted. Note that if the operation created any jobs, they"
              " might have been submitted and"
              " will continue to run in the background.")
+  except IOError, err:
+    if err.errno == errno.EPIPE:
+      # our terminal went away, we'll exit
+      sys.exit(constants.EXIT_FAILURE)
+    else:
+      raise
 
   return result
 
 
   return result
 
@@ -2563,7 +2592,7 @@ def _WarnUnknownFields(fdefs):
 
 
 def GenericList(resource, fields, names, unit, separator, header, cl=None,
 
 
 def GenericList(resource, fields, names, unit, separator, header, cl=None,
-                format_override=None, verbose=False):
+                format_override=None, verbose=False, force_filter=False):
   """Generic implementation for listing all items of a resource.
 
   @param resource: One of L{constants.QR_VIA_LUXI}
   """Generic implementation for listing all items of a resource.
 
   @param resource: One of L{constants.QR_VIA_LUXI}
@@ -2579,6 +2608,8 @@ def GenericList(resource, fields, names, unit, separator, header, cl=None,
   @param separator: String used to separate fields
   @type header: bool
   @param header: Whether to show header row
   @param separator: String used to separate fields
   @type header: bool
   @param header: Whether to show header row
+  @type force_filter: bool
+  @param force_filter: Whether to always treat names as filter
   @type format_override: dict
   @param format_override: Dictionary for overriding field formatting functions,
     indexed by field name, contents like L{_DEFAULT_FORMAT_QUERY}
   @type format_override: dict
   @param format_override: Dictionary for overriding field formatting functions,
     indexed by field name, contents like L{_DEFAULT_FORMAT_QUERY}
@@ -2592,7 +2623,20 @@ def GenericList(resource, fields, names, unit, separator, header, cl=None,
   if not names:
     names = None
 
   if not names:
     names = None
 
-  response = cl.Query(resource, fields, qlang.MakeSimpleFilter("name", names))
+  if (force_filter or
+      (names and len(names) == 1 and qlang.MaybeFilter(names[0]))):
+    try:
+      (filter_text, ) = names
+    except ValueError:
+      raise errors.OpPrereqError("Exactly one argument must be given as a"
+                                 " filter")
+
+    logging.debug("Parsing '%s' as filter", filter_text)
+    filter_ = qlang.ParseFilter(filter_text)
+  else:
+    filter_ = qlang.MakeSimpleFilter("name", names)
+
+  response = cl.Query(resource, fields, filter_)
 
   found_unknown = _WarnUnknownFields(response.fields)
 
 
   found_unknown = _WarnUnknownFields(response.fields)
 
@@ -2847,13 +2891,20 @@ def _ToStream(stream, txt, *args):
   @param txt: the message
 
   """
   @param txt: the message
 
   """
-  if args:
-    args = tuple(args)
-    stream.write(txt % args)
-  else:
-    stream.write(txt)
-  stream.write('\n')
-  stream.flush()
+  try:
+    if args:
+      args = tuple(args)
+      stream.write(txt % args)
+    else:
+      stream.write(txt)
+    stream.write('\n')
+    stream.flush()
+  except IOError, err:
+    if err.errno == errno.EPIPE:
+      # our terminal went away, we'll exit
+      sys.exit(constants.EXIT_FAILURE)
+    else:
+      raise
 
 
 def ToStdout(txt, *args):
 
 
 def ToStdout(txt, *args):