X-Git-Url: https://code.grnet.gr/git/ganeti-local/blobdiff_plain/a2656173afe2017b1e31cf8134386c66bd7ba6e5..90ed09b092aab24babb633072f0ff091105f9655:/scripts/gnt-os diff --git a/scripts/gnt-os b/scripts/gnt-os index 82c2671..fd96cbe 100755 --- a/scripts/gnt-os +++ b/scripts/gnt-os @@ -18,175 +18,178 @@ # 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') -def _DiagnoseOSName(obj): - """Generate a status message for an OS diagnose object. +def ListOS(opts, args): + """List the valid OSes in the cluster. - Args: - obj: an diagnostic object as returned by OpDiagnoseOS + @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 - Returns: - string: the name of the OS in question """ + op = opcodes.OpDiagnoseOS(output_fields=["name", "valid", "variants"], + names=[]) + result = SubmitOpCode(op, opts=opts) - 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 - - Returns: - string: a description of the OS status - """ + if not result: + ToStderr("Can't get the OS list") + return 1 - if _DiagnoseOSValid(obj): - return "valid (path: %s)" % obj.path + if not opts.no_headers: + headers = {"name": "Name"} else: - return "%s (path: %s)" % (obj.args[2], 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, valid, variants) in result: + if valid: + 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": , "node2": }} - """ + 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"], + 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) - - valid_os = [] - for os_name, os_node_data in all_os.iteritems(): - if len(os_node_data) != num_nodes: - continue - valid = True - for l in os_node_data.values(): - if not _DiagnoseOSValid(l[0]): - valid = False - break + do_filter = bool(args) + + for (name, valid, variants, parameters, api_versions) in result: + if do_filter: + if name not in args: + continue + else: + args.remove(name) + ToStdout("%s:", name) + ToStdout(" - valid: %s", valid) if valid: - valid_os.append(os_name) + 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 not opts.no_headers: - headers = {"name": "Name"} - else: - headers = None + return 0 - data = GenerateTable(separator=None, headers=headers, fields=["name"], - data=[[os] for os in valid_os]) - for line in data: - logger.ToStdout(line) +def _OsStatus(status, diagnose): + """Beautifier function for OS status. - return 0 + @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() - result = SubmitOpCode(op) + op = opcodes.OpDiagnoseOS(output_fields=["name", "valid", "variants", + "node_status"], 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) - - format = "%-*s %-*s %s" - - max_name = len('Name') - if all_os: - max_name = max(max_name, max([len(name) for name in all_os])) - - max_node = len('Status/Node') - max_node = max(max_node, max([len(name) for name in node_data])) - - logger.ToStdout(format % (max_name, 'Name', max_node, 'Status/Node', - 'Details')) - has_bad = False - for os_name in all_os: + for os_name, _, os_variants, node_data 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_status = _DiagnoseOSStatus(first_os) - if _DiagnoseOSValid(first_os): - nodes_valid[node_name] = first_os_status + 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: + 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] = first_os_status + 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" @@ -199,32 +202,75 @@ def DiagnoseOS(opts, args): status = "partial valid" has_bad = True - def _OutputNodeHiddenOSStatus(dobj_list): - for dobj in dobj_list: - logger.ToStdout(format % (max_name, "", max_node, "", - "[hidden] %s" % - _DiagnoseOSStatus(dobj))) - - def _OutputPerNodeOSStatus(status_map): - map_k = utils.NiceSort(status_map.keys()) + def _OutputPerNodeOSStatus(msg_map): + map_k = utils.NiceSort(msg_map.keys()) for node_name in map_k: - logger.ToStdout(format % (max_name, "", max_node, - node_name, status_map[node_name])) - if node_name in all_os[os_name]: - _OutputNodeHiddenOSStatus(all_os[os_name][node_name]) + ToStdout(" Node: %s, status: %s", node_name, msg_map[node_name]) + for msg in nodes_hidden[node_name]: + ToStdout(msg) - logger.ToStdout(format % (max_name, os_name, max_node, status, "")) + 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("") 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"), + 'info': ( + ShowOSInfo, [ArgOs()], [], "", "Show detailed information about " + "operating systems"), + 'modify': ( + ModifyOS, ARGS_ONE_OS, [HVLIST_OPT, OSPARAMS_OPT], "", + "Modify the OS parameters"), } if __name__ == '__main__':