#!/usr/bin/python
#
-# Copyright (C) 2006, 2007 Google Inc.
+# Copyright (C) 2006, 2007, 2010 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
# 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 constants
from ganeti import opcodes
-from ganeti import logger
-from ganeti import objects
from ganeti import utils
-from ganeti import errors
-
-
-def _DiagnoseOSValid(obj):
- """Verify whether an OS diagnose object represents a valid OS
-
- Args:
- obj: an diagnostic object as returned by OpDiagnoseOS
-
- Returns:
- bool: OS validity status
-
- """
- if isinstance(obj, objects.OS):
- return True
- elif isinstance(obj, errors.InvalidOS):
- return False
- else:
- raise errors.ProgrammerError("unknown OS diagnose type: '%s'" % type(obj))
-
-def _DiagnoseOSName(obj):
- """Generate a status message for an OS diagnose object.
- Args:
- obj: an diagnostic object as returned by OpDiagnoseOS
-
- Returns:
- string: the name of the OS in question
-
- """
- if _DiagnoseOSValid(obj):
- return obj.name
- else:
- return obj.args[0]
-
-
-def _DiagnoseOSStatus(obj):
- """Generate a status message for an OS diagnose object.
-
- Args:
- obj: an diagnostic object as returned by OpDiagnoseOS
+def ListOS(opts, args):
+ """List the valid OSes in the cluster.
- Returns:
- string: a description of the OS status
+ @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
"""
- if _DiagnoseOSValid(obj):
- return "valid"
- else:
- return obj.args[2]
-
-
-def _DiagnoseOSPath(obj):
- """Get the path out of an OS diagnose object.
+ op = opcodes.OpDiagnoseOS(output_fields=["name", "variants"], names=[])
+ result = SubmitOpCode(op, opts=opts)
- Args:
- obj: an diagnostic object as returned by OpDiagnoseOS
-
- Returns:
- string: the OS path
+ if not result:
+ ToStderr("Can't get the OS list")
+ return 1
- """
- if _DiagnoseOSValid(obj):
- return obj.path
+ if not opts.no_headers:
+ headers = {"name": "Name"}
else:
- return obj.args[1]
-
+ headers = None
-def _DiagnoseByOS(rlist):
- """Remap an OpDiagnoseOS() return list into an a per-os per-node dictionary
+ os_names = []
+ for (name, variants) in result:
+ os_names.extend([[n] for n in CalculateOSNames(name, variants)])
- Args:
- rlist: a map with nodes as keys and diagnoseobjects as values
+ data = GenerateTable(separator=None, headers=headers, fields=["name"],
+ data=os_names, units=None)
- Returns:
- map: a map with osnames as keys and as value another map, with nodes as
- keys and diagnoseobjects as values
- e.g. {"debian-etch": {"node1": <object>, "node2": <object>}}
+ for line in data:
+ ToStdout(line)
- """
- all_os = {}
- for node_name, nr in rlist.iteritems():
- if not nr:
- continue
- for obj in nr:
- os_name = _DiagnoseOSName(obj)
- if os_name not in all_os:
- all_os[os_name] = {}
- if node_name not in all_os[os_name]:
- all_os[os_name][node_name] = []
- all_os[os_name][node_name].append(obj)
+ return 0
- return all_os
+def ShowOSInfo(opts, args):
+ """List detailed information about OSes in the cluster.
-def ListOS(opts, args):
- """List the OSes existing on this node.
+ @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()
- result = SubmitOpCode(op)
+ op = opcodes.OpDiagnoseOS(output_fields=["name", "valid", "variants",
+ "parameters", "api_versions",
+ "blacklisted", "hidden"],
+ names=[])
+ result = SubmitOpCode(op, opts=opts)
if not result:
- logger.ToStdout("Can't get the OS list")
+ ToStderr("Can't get the OS list")
return 1
- node_data = result
- num_nodes = len(node_data)
- all_os = _DiagnoseByOS(node_data)
+ do_filter = bool(args)
- valid_os = []
- for os_name, os_node_data in all_os.iteritems():
- if len(os_node_data) != num_nodes:
- continue
+ for (name, valid, variants, parameters, api_versions, blk, hid) in result:
+ if do_filter:
+ if name not in args:
+ continue
+ else:
+ args.remove(name)
+ ToStdout("%s:", name)
+ ToStdout(" - valid: %s", valid)
+ ToStdout(" - hidden: %s", hid)
+ ToStdout(" - blacklisted: %s", blk)
+ if valid:
+ ToStdout(" - API versions:")
+ for version in sorted(api_versions):
+ ToStdout(" - %s", version)
+ ToStdout(" - variants:")
+ for vname in variants:
+ ToStdout(" - %s", vname)
+ ToStdout(" - parameters:")
+ for pname, pdesc in parameters:
+ ToStdout(" - %s: %s", pname, pdesc)
+ ToStdout("")
+
+ if args:
+ for name in args:
+ ToStdout("%s: ", name)
+ ToStdout("")
- if utils.all(os_node_data.values(), lambda l: _DiagnoseOSValid(l[0])):
- valid_os.append(os_name)
+ return 0
- if not opts.no_headers:
- headers = {"name": "Name"}
- else:
- headers = None
- data = GenerateTable(separator=None, headers=headers, fields=["name"],
- data=[[os] for os in valid_os])
+def _OsStatus(status, diagnose):
+ """Beautifier function for OS status.
- for line in data:
- logger.ToStdout(line)
+ @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
- return 0
+ """
+ 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()
- result = SubmitOpCode(op)
+ op = opcodes.OpDiagnoseOS(output_fields=["name", "valid", "variants",
+ "node_status", "hidden",
+ "blacklisted"], names=[])
+ result = SubmitOpCode(op, opts=opts)
if not result:
- logger.ToStdout("Can't get the OS list")
+ ToStderr("Can't get the OS list")
return 1
- node_data = result
- all_os = _DiagnoseByOS(node_data)
-
has_bad = False
- for os_name in all_os:
+ for os_name, _, os_variants, node_data, hid, blk in result:
nodes_valid = {}
nodes_bad = {}
- for node_name in node_data:
- if node_name in all_os[os_name]:
- first_os = all_os[os_name][node_name].pop(0)
- first_os_msg = ("%s (path: %s)" %
- (_DiagnoseOSStatus(first_os),
- _DiagnoseOSPath(first_os)))
- if _DiagnoseOSValid(first_os):
- nodes_valid[node_name] = first_os_msg
+ 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
+ (fo_path, fo_status, fo_msg, fo_variants,
+ fo_params, fo_api) = node_info.pop(0)
+ fo_msg = "%s (path: %s)" % (_OsStatus(fo_status, fo_msg), fo_path)
+ if fo_api:
+ max_os_api = max(fo_api)
+ fo_msg += " [API versions: %s]" % utils.CommaJoin(fo_api)
else:
- nodes_bad[node_name] = first_os_msg
+ max_os_api = 0
+ fo_msg += " [no API versions declared]"
+
+ if max_os_api >= constants.OS_API_V15:
+ if fo_variants:
+ fo_msg += " [variants: %s]" % utils.CommaJoin(fo_variants)
+ else:
+ fo_msg += " [no variants]"
+ if max_os_api >= constants.OS_API_V20:
+ if fo_params:
+ fo_msg += (" [parameters: %s]" %
+ utils.CommaJoin([v[0] for v in fo_params]))
+ else:
+ fo_msg += " [no parameters]"
+ if fo_status:
+ nodes_valid[node_name] = fo_msg
+ else:
+ nodes_bad[node_name] = fo_msg
+ for hpath, hstatus, hmsg, _, _, _ in node_info:
+ nodes_hidden[node_name].append(" [hidden] path: %s, status: %s" %
+ (hpath, _OsStatus(hstatus, hmsg)))
else:
nodes_bad[node_name] = "OS not found"
status = "partial valid"
has_bad = True
- def _OutputNodeHiddenOSStatus(dobj_list):
- for dobj in dobj_list:
- logger.ToStdout(" [hidden] path: %s, status: %s" %
- (_DiagnoseOSPath(dobj), _DiagnoseOSStatus(dobj)))
-
def _OutputPerNodeOSStatus(msg_map):
map_k = utils.NiceSort(msg_map.keys())
for node_name in map_k:
- logger.ToStdout(" Node: %s, status: %s" %
- (node_name, msg_map[node_name]))
- if node_name in all_os[os_name]:
- _OutputNodeHiddenOSStatus(all_os[os_name][node_name])
-
- logger.ToStdout("OS: %s [global status: %s]" % (os_name, status))
+ ToStdout(" Node: %s, status: %s", node_name, msg_map[node_name])
+ for msg in nodes_hidden[node_name]:
+ ToStdout(msg)
+
+ st_msg = "OS: %s [global status: %s]" % (os_name, status)
+ if hid:
+ st_msg += " [hidden]"
+ if blk:
+ st_msg += " [blacklisted]"
+ ToStdout(st_msg)
+ if os_variants:
+ ToStdout(" Variants: [%s]" % utils.CommaJoin(os_variants))
_OutputPerNodeOSStatus(nodes_valid)
_OutputPerNodeOSStatus(nodes_bad)
- logger.ToStdout("")
+ ToStdout("")
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 opts.hidden is not None:
+ if opts.hidden:
+ ohid = [(constants.DDM_ADD, os)]
+ else:
+ ohid = [(constants.DDM_REMOVE, os)]
+ else:
+ ohid = None
+
+ if opts.blacklisted is not None:
+ if opts.blacklisted:
+ oblk = [(constants.DDM_ADD, os)]
+ else:
+ oblk = [(constants.DDM_REMOVE, os)]
+ else:
+ oblk = None
+
+ if not (os_hvp or osp or ohid or oblk):
+ ToStderr("At least one of OS parameters or hypervisor parameters"
+ " must be passed")
+ return 1
+
+ op = opcodes.OpSetClusterParams(os_hvp=os_hvp,
+ osparams=osp,
+ hidden_os=ohid,
+ blacklisted_os=oblk)
+ SubmitOpCode(op, opts=opts)
+
+ 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, PRIORITY_OPT],
+ "", "Lists all valid operating systems on the cluster"),
+ 'diagnose': (
+ DiagnoseOS, ARGS_NONE, [PRIORITY_OPT],
+ "", "Diagnose all operating systems"),
+ 'info': (
+ ShowOSInfo, [ArgOs()], [PRIORITY_OPT],
+ "", "Show detailed information about "
+ "operating systems"),
+ 'modify': (
+ ModifyOS, ARGS_ONE_OS,
+ [HVLIST_OPT, OSPARAMS_OPT, DRY_RUN_OPT, PRIORITY_OPT,
+ HID_OS_OPT, BLK_OS_OPT],
+ "", "Modify the OS parameters"),
}
if __name__ == '__main__':