Rename OpConnectConsole and LUConnectConsole
[ganeti-local] / lib / client / gnt_instance.py
index f0188a9..8799a54 100644 (file)
@@ -27,6 +27,7 @@
 
 import itertools
 import simplejson
+import logging
 from cStringIO import StringIO
 
 from ganeti.cli import *
@@ -36,6 +37,8 @@ from ganeti import compat
 from ganeti import utils
 from ganeti import errors
 from ganeti import netutils
+from ganeti import ssh
+from ganeti import objects
 
 
 _SHUTDOWN_CLUSTER = "cluster"
@@ -586,7 +589,7 @@ def ActivateDisks(opts, args):
 
   """
   instance_name = args[0]
-  op = opcodes.OpActivateInstanceDisks(instance_name=instance_name,
+  op = opcodes.OpInstanceActivateDisks(instance_name=instance_name,
                                        ignore_size=opts.ignore_size)
   disks_info = SubmitOrSend(op, opts)
   for host, iname, nname in disks_info:
@@ -885,16 +888,67 @@ def ConnectToInstanceConsole(opts, args):
   """
   instance_name = args[0]
 
-  op = opcodes.OpConnectConsole(instance_name=instance_name)
-  cmd = SubmitOpCode(op, opts=opts)
+  op = opcodes.OpInstanceConsole(instance_name=instance_name)
 
-  if opts.show_command:
-    ToStdout("%s", utils.ShellQuoteArgs(cmd))
+  cl = GetClient()
+  try:
+    cluster_name = cl.QueryConfigValues(["cluster_name"])[0]
+    console_data = SubmitOpCode(op, opts=opts, cl=cl)
+  finally:
+    # Ensure client connection is closed while external commands are run
+    cl.Close()
+
+  del cl
+
+  return _DoConsole(objects.InstanceConsole.FromDict(console_data),
+                    opts.show_command, cluster_name)
+
+
+def _DoConsole(console, show_command, cluster_name, feedback_fn=ToStdout,
+               _runcmd_fn=utils.RunCmd):
+  """Acts based on the result of L{opcodes.OpInstanceConsole}.
+
+  @type console: L{objects.InstanceConsole}
+  @param console: Console object
+  @type show_command: bool
+  @param show_command: Whether to just display commands
+  @type cluster_name: string
+  @param cluster_name: Cluster name as retrieved from master daemon
+
+  """
+  assert console.Validate()
+
+  if console.kind == constants.CONS_MESSAGE:
+    feedback_fn(console.message)
+  elif console.kind == constants.CONS_VNC:
+    feedback_fn("Instance %s has VNC listening on %s:%s (display %s),"
+                " URL <vnc://%s:%s/>",
+                console.instance, console.host, console.port,
+                console.display, console.host, console.port)
+  elif console.kind == constants.CONS_SSH:
+    # Convert to string if not already one
+    if isinstance(console.command, basestring):
+      cmd = console.command
+    else:
+      cmd = utils.ShellQuoteArgs(console.command)
+
+    srun = ssh.SshRunner(cluster_name=cluster_name)
+    ssh_cmd = srun.BuildCmd(console.host, console.user, cmd,
+                            batch=True, quiet=False, tty=True)
+
+    if show_command:
+      feedback_fn(utils.ShellQuoteArgs(ssh_cmd))
+    else:
+      result = _runcmd_fn(ssh_cmd, interactive=True)
+      if result.failed:
+        logging.error("Console command \"%s\" failed with reason '%s' and"
+                      " output %r", result.cmd, result.fail_reason,
+                      result.output)
+        raise errors.OpExecError("Connection to console of instance %s failed,"
+                                 " please check cluster configuration" %
+                                 console.instance)
   else:
-    result = utils.RunCmd(cmd, interactive=True)
-    if result.failed:
-      raise errors.OpExecError("Console command \"%s\" failed: %s" %
-                               (utils.ShellQuoteArgs(cmd), result.fail_reason))
+    raise errors.GenericError("Unknown console type '%s'" % console.kind)
 
   return constants.EXIT_SUCCESS
 
@@ -1066,21 +1120,6 @@ def _FormatList(buf, data, indent_level):
       _FormatList(buf, elem, indent_level+1)
 
 
-def _FormatParameterDict(buf, per_inst, actual):
-  """Formats a parameter dictionary.
-
-  @type buf: L{StringIO}
-  @param buf: the buffer into which to write
-  @type per_inst: dict
-  @param per_inst: the instance's own parameters
-  @type actual: dict
-  @param actual: the current parameter set (including defaults)
-
-  """
-  for key in sorted(actual):
-    val = per_inst.get(key, "default (%s)" % actual[key])
-    buf.write("    - %s: %s\n" % (key, val))
-
 def ShowInstanceConfig(opts, args):
   """Compute instance run-time status.
 
@@ -1129,7 +1168,8 @@ def ShowInstanceConfig(opts, args):
     buf.write("    - primary: %s\n" % instance["pnode"])
     buf.write("    - secondaries: %s\n" % utils.CommaJoin(instance["snodes"]))
     buf.write("  Operating system: %s\n" % instance["os"])
-    _FormatParameterDict(buf, instance["os_instance"], instance["os_actual"])
+    FormatParameterDict(buf, instance["os_instance"], instance["os_actual"],
+                        level=2)
     if instance.has_key("network_port"):
       buf.write("  Allocated network port: %s\n" %
                 compat.TryToRoman(instance["network_port"],
@@ -1156,7 +1196,8 @@ def ShowInstanceConfig(opts, args):
                                       vnc_bind_address)
       buf.write("    - console connection: vnc to %s\n" % vnc_console_port)
 
-    _FormatParameterDict(buf, instance["hv_instance"], instance["hv_actual"])
+    FormatParameterDict(buf, instance["hv_instance"], instance["hv_actual"],
+                        level=2)
     buf.write("  Hardware:\n")
     buf.write("    - VCPUs: %s\n" %
               compat.TryToRoman(instance["be_actual"][constants.BE_VCPUS],
@@ -1168,6 +1209,7 @@ def ShowInstanceConfig(opts, args):
     for idx, (ip, mac, mode, link) in enumerate(instance["nics"]):
       buf.write("      - nic/%d: MAC: %s, IP: %s, mode: %s, link: %s\n" %
                 (idx, mac, ip, mode, link))
+    buf.write("  Disk template: %s\n" % instance["disk_template"])
     buf.write("  Disks:\n")
 
     for idx, device in enumerate(instance["disks"]):