Add RAPI resource for instance console
[ganeti-local] / lib / cli.py
index 3812941..ce97e99 100644 (file)
@@ -1,7 +1,7 @@
 #
 #
 
-# Copyright (C) 2006, 2007, 2008, 2009, 2010 Google Inc.
+# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Google Inc.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -178,6 +178,7 @@ __all__ = [
   "ToStderr", "ToStdout",
   "FormatError",
   "FormatQueryResult",
+  "FormatParameterDict",
   "GenerateTable",
   "AskUser",
   "FormatTimestamp",
@@ -421,7 +422,7 @@ def AddTags(opts, args):
   _ExtendTags(opts, args)
   if not args:
     raise errors.OpPrereqError("No tags to be added")
-  op = opcodes.OpAddTags(kind=kind, name=name, tags=args)
+  op = opcodes.OpTagsSet(kind=kind, name=name, tags=args)
   SubmitOpCode(op, opts=opts)
 
 
@@ -438,7 +439,7 @@ def RemoveTags(opts, args):
   _ExtendTags(opts, args)
   if not args:
     raise errors.OpPrereqError("No tags to be removed")
-  op = opcodes.OpDelTags(kind=kind, name=name, tags=args)
+  op = opcodes.OpTagsDel(kind=kind, name=name, tags=args)
   SubmitOpCode(op, opts=opts)
 
 
@@ -602,7 +603,7 @@ SEP_OPT = cli_option("--separator", default=None,
 
 USEUNITS_OPT = cli_option("--units", default=None,
                           dest="units", choices=('h', 'm', 'g', 't'),
-                          help="Specify units for output (one of hmgt)")
+                          help="Specify units for output (one of h/m/g/t)")
 
 FIELDS_OPT = cli_option("-o", "--output", dest="output", action="store",
                         type="string", metavar="FIELDS",
@@ -884,18 +885,20 @@ NOSSH_KEYCHECK_OPT = cli_option("--no-ssh-key-check", dest="ssh_key_check",
                                 default=True, action="store_false",
                                 help="Disable SSH key fingerprint checking")
 
-
 MC_OPT = cli_option("-C", "--master-candidate", dest="master_candidate",
                     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,
                          type="bool", default=None,
-                         help="Set the offline flag on the node")
+                         help=("Set the offline flag on the node"
+                               " (cluster does not communicate with offline"
+                               " nodes)"))
 
 DRAINED_OPT = cli_option("-D", "--drained", dest="drained", metavar=_YORNO,
                          type="bool", default=None,
-                         help="Set the drained flag on the node")
+                         help=("Set the drained flag on the node"
+                               " (excluded from allocation operations)"))
 
 CAPAB_MASTER_OPT = cli_option("--master-capable", dest="master_capable",
                     type="bool", default=None, metavar=_YORNO,
@@ -928,8 +931,9 @@ CP_SIZE_OPT = cli_option("-C", "--candidate-pool-size", default=None,
                          help="Set the candidate pool size")
 
 VG_NAME_OPT = cli_option("--vg-name", dest="vg_name",
-                         help="Enables LVM and specifies the volume group"
-                         " name (cluster-wide) for disk allocation [xenvg]",
+                         help=("Enables LVM and specifies the volume group"
+                               " name (cluster-wide) for disk allocation"
+                               " [%s]" % constants.DEFAULT_VG),
                          metavar="VG", default=None)
 
 YES_DOIT_OPT = cli_option("--yes-do-it", dest="yes_do_it",
@@ -947,10 +951,11 @@ MAC_PREFIX_OPT = cli_option("-m", "--mac-prefix", dest="mac_prefix",
 
 MASTER_NETDEV_OPT = cli_option("--master-netdev", dest="master_netdev",
                                help="Specify the node interface (cluster-wide)"
-                               " on which the master IP address will be added "
-                               " [%s]" % constants.DEFAULT_BRIDGE,
+                               " on which the master IP address will be added"
+                               " (cluster init default: %s)" %
+                               constants.DEFAULT_BRIDGE,
                                metavar="NETDEV",
-                               default=constants.DEFAULT_BRIDGE)
+                               default=None)
 
 GLOBAL_FILEDIR_OPT = cli_option("--file-storage-dir", dest="file_storage_dir",
                                 help="Specify the default directory (cluster-"
@@ -1844,8 +1849,11 @@ def FormatError(err):
     obuf.write("Cannot communicate with the master daemon.\nIs it running"
                " and listening for connections?")
   elif isinstance(err, luxi.TimeoutError):
-    obuf.write("Timeout while talking to the master daemon. Error:\n"
-               "%s" % msg)
+    obuf.write("Timeout while talking to the master daemon. Jobs might have"
+               " been submitted and will continue to run even if the call"
+               " timed out. Useful commands in this situation are \"gnt-job"
+               " list\", \"gnt-job cancel\" and \"gnt-job watch\". Error:\n")
+    obuf.write(msg)
   elif isinstance(err, luxi.PermissionError):
     obuf.write("It seems you don't have permissions to connect to the"
                " master daemon.\nPlease retry as a different user.")
@@ -2049,7 +2057,7 @@ def GenericInstanceCreate(mode, opts, args):
   else:
     raise errors.ProgrammerError("Invalid creation mode %s" % mode)
 
-  op = opcodes.OpCreateInstance(instance_name=instance,
+  op = opcodes.OpInstanceCreate(instance_name=instance,
                                 disks=disks,
                                 disk_template=opts.disk_template,
                                 nics=nics,
@@ -2384,21 +2392,24 @@ class _QueryColumnFormatter:
     # Report status
     self._status_fn(status)
 
-    if status == constants.QRFS_NORMAL:
+    if status == constants.RS_NORMAL:
       return self._fn(value)
 
     assert value is None, \
            "Found value %r for abnormal status %s" % (value, status)
 
-    if status == constants.QRFS_UNKNOWN:
+    if status == constants.RS_UNKNOWN:
       return "(unknown)"
 
-    if status == constants.QRFS_NODATA:
+    if status == constants.RS_NODATA:
       return "(nodata)"
 
-    if status == constants.QRFS_UNAVAIL:
+    if status == constants.RS_UNAVAIL:
       return "(unavail)"
 
+    if status == constants.RS_OFFLINE:
+      return "(offline)"
+
     raise NotImplementedError("Unknown status %s" % status)
 
 
@@ -2410,7 +2421,7 @@ def FormatQueryResult(result, unit=None, format_override=None, separator=None,
   @param result: result of query operation
   @type unit: string
   @param unit: Unit used for formatting fields of type L{constants.QFT_UNIT},
-    see L{utils.FormatUnit}
+    see L{utils.text.FormatUnit}
   @type format_override: dict
   @param format_override: Dictionary for overriding field formatting functions,
     indexed by field name, contents like L{_DEFAULT_FORMAT_QUERY}
@@ -2429,7 +2440,7 @@ def FormatQueryResult(result, unit=None, format_override=None, separator=None,
   if format_override is None:
     format_override = {}
 
-  stats = dict.fromkeys(constants.QRFS_ALL, 0)
+  stats = dict.fromkeys(constants.RS_ALL, 0)
 
   def _RecordStatus(status):
     if status in stats:
@@ -2446,16 +2457,16 @@ def FormatQueryResult(result, unit=None, format_override=None, separator=None,
   table = FormatTable(result.data, columns, header, separator)
 
   # Collect statistics
-  assert len(stats) == len(constants.QRFS_ALL)
+  assert len(stats) == len(constants.RS_ALL)
   assert compat.all(count >= 0 for count in stats.values())
 
   # Determine overall status. If there was no data, unknown fields must be
   # detected via the field definitions.
-  if (stats[constants.QRFS_UNKNOWN] or
+  if (stats[constants.RS_UNKNOWN] or
       (not result.data and _GetUnknownFields(result.fields))):
     status = QR_UNKNOWN
   elif compat.any(count > 0 for key, count in stats.items()
-                  if key != constants.QRFS_NORMAL):
+                  if key != constants.RS_NORMAL):
     status = QR_INCOMPLETE
   else:
     status = QR_NORMAL
@@ -2934,3 +2945,21 @@ class JobExecutor(object):
         else:
           ToStderr("Failure for %s: %s", name, result)
       return [row[1:3] for row in self.jobs]
+
+
+def FormatParameterDict(buf, param_dict, actual, level=1):
+  """Formats a parameter dictionary.
+
+  @type buf: L{StringIO}
+  @param buf: the buffer into which to write
+  @type param_dict: dict
+  @param param_dict: the own parameters
+  @type actual: dict
+  @param actual: the current parameter set (including defaults)
+  @param level: Level of indent
+
+  """
+  indent = "  " * level
+  for key in sorted(actual):
+    val = param_dict.get(key, "default (%s)" % actual[key])
+    buf.write("%s- %s: %s\n" % (indent, key, val))