Add support for modifying cluster OS parameters
[ganeti-local] / scripts / gnt-os
index 642545e..e7177c3 100755 (executable)
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 # 02110-1301, USA.
 
+"""OS scripts related commands"""
+
+# pylint: disable-msg=W0401,W0613,W0614,C0103
+# W0401: Wildcard import ganeti.cli
+# W0613: Unused argument, since all functions follow the same API
+# W0614: Unused import %s from wildcard import (since we need cli)
+# C0103: Invalid name gnt-os
 
 import sys
-from optparse import make_option
 
 from ganeti.cli import *
 from ganeti import opcodes
-from ganeti import objects
 from ganeti import utils
-from ganeti import errors
-from ganeti import constants
 
 
 def ListOS(opts, args):
-  """List the OSes existing on this node.
+  """List the valid OSes in the cluster.
+
+  @param opts: the command line options selected by the user
+  @type args: list
+  @param args: should be an empty list
+  @rtype: int
+  @return: the desired exit code
 
   """
-  op = opcodes.OpDiagnoseOS(output_fields=["name", "valid"], names=[])
-  result = SubmitOpCode(op)
+  op = opcodes.OpDiagnoseOS(output_fields=["name", "valid", "variants"],
+                            names=[])
+  result = SubmitOpCode(op, opts=opts)
 
   if not result:
     ToStderr("Can't get the OS list")
@@ -46,8 +56,13 @@ def ListOS(opts, args):
   else:
     headers = None
 
+  os_names = []
+  for (name, valid, variants) in result:
+    if valid:
+      os_names.extend([[n] for n in CalculateOSNames(name, variants)])
+
   data = GenerateTable(separator=None, headers=headers, fields=["name"],
-                       data=[[row[0]] for row in result if row[1]])
+                       data=os_names, units=None)
 
   for line in data:
     ToStdout(line)
@@ -55,13 +70,35 @@ def ListOS(opts, args):
   return 0
 
 
+def _OsStatus(status, diagnose):
+  """Beautifier function for OS status.
+
+  @type status: boolean
+  @param status: is the OS valid
+  @type diagnose: string
+  @param diagnose: the error message for invalid OSes
+  @rtype: string
+  @return: a formatted status
+
+  """
+  if status:
+    return "valid"
+  else:
+    return "invalid - %s" % diagnose
+
 def DiagnoseOS(opts, args):
   """Analyse all OSes on this cluster.
 
+  @param opts: the command line options selected by the user
+  @type args: list
+  @param args: should be an empty list
+  @rtype: int
+  @return: the desired exit code
+
   """
-  op = opcodes.OpDiagnoseOS(output_fields=["name", "valid", "node_status"],
-                            names=[])
-  result = SubmitOpCode(op)
+  op = opcodes.OpDiagnoseOS(output_fields=["name", "valid", "variants",
+                                           "node_status"], names=[])
+  result = SubmitOpCode(op, opts=opts)
 
   if not result:
     ToStderr("Can't get the OS list")
@@ -69,23 +106,27 @@ def DiagnoseOS(opts, args):
 
   has_bad = False
 
-  for os_name, os_valid, node_data in result:
+  for os_name, _, os_variants, node_data in result:
     nodes_valid = {}
     nodes_bad = {}
     nodes_hidden = {}
     for node_name, node_info in node_data.iteritems():
       nodes_hidden[node_name] = []
       if node_info: # at least one entry in the per-node list
-        first_os_status, first_os_path = node_info.pop(0)
-        first_os_msg = ("%s (path: %s)" %
-                        (first_os_status, first_os_path))
-        if first_os_status == constants.OS_VALID_STATUS:
+        (first_os_path, first_os_status, first_os_msg,
+         first_os_variants, _) = node_info.pop(0)
+        if not first_os_variants:
+          first_os_variants = []
+        first_os_msg = ("%s (path: %s) [variants: %s]" %
+                        (_OsStatus(first_os_status, first_os_msg),
+                         first_os_path, utils.CommaJoin(first_os_variants)))
+        if first_os_status:
           nodes_valid[node_name] = first_os_msg
         else:
           nodes_bad[node_name] = first_os_msg
-        for hstatus, hpath in node_info:
+        for hpath, hstatus, hmsg in node_info:
           nodes_hidden[node_name].append("    [hidden] path: %s, status: %s" %
-                                         (hpath, hstatus))
+                                         (hpath, _OsStatus(hstatus, hmsg)))
       else:
         nodes_bad[node_name] = "OS not found"
 
@@ -106,6 +147,8 @@ def DiagnoseOS(opts, args):
           ToStdout(msg)
 
     ToStdout("OS: %s [global status: %s]", os_name, status)
+    if os_variants:
+      ToStdout("  Variants: [%s]" % utils.CommaJoin(os_variants))
     _OutputPerNodeOSStatus(nodes_valid)
     _OutputPerNodeOSStatus(nodes_bad)
     ToStdout("")
@@ -113,11 +156,55 @@ def DiagnoseOS(opts, args):
   return int(has_bad)
 
 
+def ModifyOS(opts, args):
+  """Modify OS parameters for one OS.
+
+  @param opts: the command line options selected by the user
+  @type args: list
+  @param args: should be a list with one entry
+  @rtype: int
+  @return: the desired exit code
+
+  """
+  os = args[0]
+
+  if opts.hvparams:
+    os_hvp = {os: dict(opts.hvparams)}
+  else:
+    os_hvp = None
+
+  if opts.osparams:
+    osp = {os: opts.osparams}
+  else:
+    osp = None
+
+  if not (os_hvp or osp):
+    ToStderr("At least one of OS parameters or hypervisor parameters"
+             " must be passed")
+    return 1
+
+  op = opcodes.OpSetClusterParams(vg_name=None,
+                                  enabled_hypervisors=None,
+                                  hvparams=None,
+                                  beparams=None,
+                                  nicparams=None,
+                                  candidate_pool_size=None,
+                                  os_hvp=os_hvp,
+                                  osparams=osp)
+  SubmitOpCode(op)
+
+  return 0
+
+
 commands = {
-  'list': (ListOS, ARGS_NONE, [DEBUG_OPT, NOHDR_OPT], "",
-           "Lists all valid OSes on the master"),
-  'diagnose': (DiagnoseOS, ARGS_NONE, [DEBUG_OPT], "",
-               "Diagnose all OSes"),
+  'list': (
+    ListOS, ARGS_NONE, [NOHDR_OPT], "", "Lists all valid operating systems"
+    " on the cluster"),
+  'diagnose': (
+    DiagnoseOS, ARGS_NONE, [], "", "Diagnose all operating systems"),
+  'modify': (
+    ModifyOS, ARGS_ONE_OS, [HVLIST_OPT, OSPARAMS_OPT], "",
+    "Modify the OS parameters"),
   }
 
 if __name__ == '__main__':