X-Git-Url: https://code.grnet.gr/git/ganeti-local/blobdiff_plain/b2e233a59249766e85fbbc86fadc04833c3de21a..82437b280123d50fcab4f63e8ddfb79fdf6f6786:/lib/client/gnt_cluster.py diff --git a/lib/client/gnt_cluster.py b/lib/client/gnt_cluster.py index 0410c54..bbee602 100644 --- a/lib/client/gnt_cluster.py +++ b/lib/client/gnt_cluster.py @@ -1,7 +1,7 @@ # # -# Copyright (C) 2006, 2007, 2010, 2011 Google Inc. +# Copyright (C) 2006, 2007, 2010, 2011, 2012, 2013 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 @@ -42,6 +42,7 @@ from ganeti import objects from ganeti import uidpool from ganeti import compat from ganeti import netutils +from ganeti import pathutils ON_OPT = cli_option("--on", default=False, @@ -49,8 +50,12 @@ ON_OPT = cli_option("--on", default=False, help="Recover from an EPO") GROUPS_OPT = cli_option("--groups", default=False, - action="store_true", dest="groups", - help="Arguments are node groups instead of nodes") + action="store_true", dest="groups", + help="Arguments are node groups instead of nodes") + +FORCE_FAILOVER = cli_option("--yes-do-it", dest="yes_do_it", + help="Override interactive check for --no-voting", + default=False, action="store_true") _EPO_PING_INTERVAL = 30 # 30 seconds between pings _EPO_PING_TIMEOUT = 1 # 1 second @@ -98,6 +103,16 @@ def InitCluster(opts, args): beparams = opts.beparams nicparams = opts.nicparams + diskparams = dict(opts.diskparams) + + # check the disk template types here, as we cannot rely on the type check done + # by the opcode parameter types + diskparams_keys = set(diskparams.keys()) + if not (diskparams_keys <= constants.DISK_TEMPLATES): + unknown = utils.NiceSort(diskparams_keys - constants.DISK_TEMPLATES) + ToStderr("Disk templates unknown: %s" % utils.CommaJoin(unknown)) + return 1 + # prepare beparams dict beparams = objects.FillDict(constants.BEC_DEFAULTS, beparams) utils.ForceDictType(beparams, constants.BES_PARAMETER_COMPAT) @@ -120,6 +135,26 @@ def InitCluster(opts, args): hvparams[hv] = objects.FillDict(constants.HVC_DEFAULTS[hv], hvparams[hv]) utils.ForceDictType(hvparams[hv], constants.HVS_PARAMETER_TYPES) + # prepare diskparams dict + for templ in constants.DISK_TEMPLATES: + if templ not in diskparams: + diskparams[templ] = {} + diskparams[templ] = objects.FillDict(constants.DISK_DT_DEFAULTS[templ], + diskparams[templ]) + utils.ForceDictType(diskparams[templ], constants.DISK_DT_TYPES) + + # prepare ipolicy dict + ipolicy = CreateIPolicyFromOpts( + ispecs_mem_size=opts.ispecs_mem_size, + ispecs_cpu_count=opts.ispecs_cpu_count, + ispecs_disk_count=opts.ispecs_disk_count, + ispecs_disk_size=opts.ispecs_disk_size, + ispecs_nic_count=opts.ispecs_nic_count, + ipolicy_disk_templates=opts.ipolicy_disk_templates, + ipolicy_vcpu_ratio=opts.ipolicy_vcpu_ratio, + ipolicy_spindle_ratio=opts.ipolicy_spindle_ratio, + fill_all=True) + if opts.candidate_pool_size is None: opts.candidate_pool_size = constants.MASTER_POOL_SIZE_DEFAULT @@ -151,6 +186,19 @@ def InitCluster(opts, args): ToStderr("Invalid master netmask value: %s" % str(err)) return 1 + if opts.disk_state: + disk_state = utils.FlatToDict(opts.disk_state) + else: + disk_state = {} + + hv_state = dict(opts.hv_state) + + enabled_storage_types = opts.enabled_storage_types + if enabled_storage_types is not None: + enabled_storage_types = enabled_storage_types.split(",") + else: + enabled_storage_types = list(constants.DEFAULT_ENABLED_STORAGE_TYPES) + bootstrap.InitCluster(cluster_name=args[0], secondary_ip=opts.secondary_ip, vg_name=vg_name, @@ -164,6 +212,8 @@ def InitCluster(opts, args): beparams=beparams, nicparams=nicparams, ndparams=ndparams, + diskparams=diskparams, + ipolicy=ipolicy, candidate_pool_size=opts.candidate_pool_size, modify_etc_hosts=opts.modify_etc_hosts, modify_ssh_setup=opts.modify_ssh_setup, @@ -174,6 +224,9 @@ def InitCluster(opts, args): primary_ip_version=primary_ip_version, prealloc_wipe_disks=opts.prealloc_wipe_disks, use_external_mip_script=external_ip_setup_script, + hv_state=hv_state, + disk_state=disk_state, + enabled_storage_types=enabled_storage_types, ) op = opcodes.OpClusterPostInit() SubmitOpCode(op, opts=opts) @@ -288,7 +341,7 @@ def ShowClusterVersion(opts, args): @return: the desired exit code """ - cl = GetClient() + cl = GetClient(query=True) result = cl.QueryClusterInfo() ToStdout("Software version: %s", result["software_version"]) ToStdout("Internode protocol: %s", result["protocol_version"]) @@ -313,24 +366,24 @@ def ShowClusterMaster(opts, args): return 0 -def _PrintGroupedParams(paramsdict, level=1, roman=False): - """Print Grouped parameters (be, nic, disk) by group. +def _FormatGroupedParams(paramsdict, roman=False): + """Format Grouped parameters (be, nic, disk) by group. @type paramsdict: dict of dicts @param paramsdict: {group: {param: value, ...}, ...} - @type level: int - @param level: Level of indention + @rtype: dict of dicts + @return: copy of the input dictionaries with strings as values """ - indent = " " * level - for item, val in sorted(paramsdict.items()): + ret = {} + for (item, val) in paramsdict.items(): if isinstance(val, dict): - ToStdout("%s- %s:", indent, item) - _PrintGroupedParams(val, level=level + 1, roman=roman) + ret[item] = _FormatGroupedParams(val, roman=roman) elif roman and isinstance(val, int): - ToStdout("%s %s: %s", indent, item, compat.TryToRoman(val)) + ret[item] = compat.TryToRoman(val) else: - ToStdout("%s %s: %s", indent, item, val) + ret[item] = str(val) + return ret def ShowClusterConfig(opts, args): @@ -343,80 +396,104 @@ def ShowClusterConfig(opts, args): @return: the desired exit code """ - cl = GetClient() + cl = GetClient(query=True) result = cl.QueryClusterInfo() - ToStdout("Cluster name: %s", result["name"]) - ToStdout("Cluster UUID: %s", result["uuid"]) - - ToStdout("Creation time: %s", utils.FormatTime(result["ctime"])) - ToStdout("Modification time: %s", utils.FormatTime(result["mtime"])) - - ToStdout("Master node: %s", result["master"]) - - ToStdout("Architecture (this node): %s (%s)", - result["architecture"][0], result["architecture"][1]) - if result["tags"]: tags = utils.CommaJoin(utils.NiceSort(result["tags"])) else: tags = "(none)" - - ToStdout("Tags: %s", tags) - - ToStdout("Default hypervisor: %s", result["default_hypervisor"]) - ToStdout("Enabled hypervisors: %s", - utils.CommaJoin(result["enabled_hypervisors"])) - - ToStdout("Hypervisor parameters:") - _PrintGroupedParams(result["hvparams"]) - - ToStdout("OS-specific hypervisor parameters:") - _PrintGroupedParams(result["os_hvp"]) - - ToStdout("OS parameters:") - _PrintGroupedParams(result["osparams"]) - - ToStdout("Hidden OSes: %s", utils.CommaJoin(result["hidden_os"])) - ToStdout("Blacklisted OSes: %s", utils.CommaJoin(result["blacklisted_os"])) - - ToStdout("Cluster parameters:") - ToStdout(" - candidate pool size: %s", - compat.TryToRoman(result["candidate_pool_size"], - convert=opts.roman_integers)) - ToStdout(" - master netdev: %s", result["master_netdev"]) - ToStdout(" - master netmask: %s", result["master_netmask"]) - ToStdout(" - use external master IP address setup script: %s", - result["use_external_mip_script"]) - ToStdout(" - lvm volume group: %s", result["volume_group_name"]) if result["reserved_lvs"]: reserved_lvs = utils.CommaJoin(result["reserved_lvs"]) else: reserved_lvs = "(none)" - ToStdout(" - lvm reserved volumes: %s", reserved_lvs) - ToStdout(" - drbd usermode helper: %s", result["drbd_usermode_helper"]) - ToStdout(" - file storage path: %s", result["file_storage_dir"]) - ToStdout(" - shared file storage path: %s", - result["shared_file_storage_dir"]) - ToStdout(" - maintenance of node health: %s", - result["maintain_node_health"]) - ToStdout(" - uid pool: %s", - uidpool.FormatUidPool(result["uid_pool"], - roman=opts.roman_integers)) - ToStdout(" - default instance allocator: %s", result["default_iallocator"]) - ToStdout(" - primary ip version: %d", result["primary_ip_version"]) - ToStdout(" - preallocation wipe disks: %s", result["prealloc_wipe_disks"]) - ToStdout(" - OS search path: %s", utils.CommaJoin(constants.OS_SEARCH_PATH)) - - ToStdout("Default node parameters:") - _PrintGroupedParams(result["ndparams"], roman=opts.roman_integers) - - ToStdout("Default instance parameters:") - _PrintGroupedParams(result["beparams"], roman=opts.roman_integers) - - ToStdout("Default nic parameters:") - _PrintGroupedParams(result["nicparams"], roman=opts.roman_integers) + info = [ + ("Cluster name", result["name"]), + ("Cluster UUID", result["uuid"]), + + ("Creation time", utils.FormatTime(result["ctime"])), + ("Modification time", utils.FormatTime(result["mtime"])), + + ("Master node", result["master"]), + + ("Architecture (this node)", + "%s (%s)" % (result["architecture"][0], result["architecture"][1])), + + ("Tags", tags), + + ("Default hypervisor", result["default_hypervisor"]), + ("Enabled hypervisors", + utils.CommaJoin(result["enabled_hypervisors"])), + + ("Hypervisor parameters", _FormatGroupedParams(result["hvparams"])), + + ("OS-specific hypervisor parameters", + _FormatGroupedParams(result["os_hvp"])), + + ("OS parameters", _FormatGroupedParams(result["osparams"])), + + ("Hidden OSes", utils.CommaJoin(result["hidden_os"])), + ("Blacklisted OSes", utils.CommaJoin(result["blacklisted_os"])), + + ("Cluster parameters", [ + ("candidate pool size", + compat.TryToRoman(result["candidate_pool_size"], + convert=opts.roman_integers)), + ("master netdev", result["master_netdev"]), + ("master netmask", result["master_netmask"]), + ("use external master IP address setup script", + result["use_external_mip_script"]), + ("lvm volume group", result["volume_group_name"]), + ("lvm reserved volumes", reserved_lvs), + ("drbd usermode helper", result["drbd_usermode_helper"]), + ("file storage path", result["file_storage_dir"]), + ("shared file storage path", result["shared_file_storage_dir"]), + ("maintenance of node health", result["maintain_node_health"]), + ("uid pool", uidpool.FormatUidPool(result["uid_pool"])), + ("default instance allocator", result["default_iallocator"]), + ("primary ip version", result["primary_ip_version"]), + ("preallocation wipe disks", result["prealloc_wipe_disks"]), + ("OS search path", utils.CommaJoin(pathutils.OS_SEARCH_PATH)), + ("ExtStorage Providers search path", + utils.CommaJoin(pathutils.ES_SEARCH_PATH)), + ("enabled storage types", + utils.CommaJoin(result["enabled_storage_types"])), + ]), + + ("Default node parameters", + _FormatGroupedParams(result["ndparams"], roman=opts.roman_integers)), + + ("Default instance parameters", + _FormatGroupedParams(result["beparams"], roman=opts.roman_integers)), + + ("Default nic parameters", + _FormatGroupedParams(result["nicparams"], roman=opts.roman_integers)), + + ("Default disk parameters", + _FormatGroupedParams(result["diskparams"], roman=opts.roman_integers)), + + ("Instance policy - limits for instances", + [ + (key, + _FormatGroupedParams(result["ipolicy"][constants.ISPECS_MINMAX][key], + roman=opts.roman_integers)) + for key in constants.ISPECS_MINMAX_KEYS + ] + + [ + (constants.ISPECS_STD, + _FormatGroupedParams(result["ipolicy"][constants.ISPECS_STD], + roman=opts.roman_integers)), + ("enabled disk templates", + utils.CommaJoin(result["ipolicy"][constants.IPOLICY_DTS])), + ] + + [ + (key, result["ipolicy"][key]) + for key in constants.IPOLICY_PARAMETERS + ]), + ] + + PrintGenericInfo(info) return 0 @@ -444,7 +521,7 @@ def ClusterCopyFile(opts, args): secondary_ips=opts.use_replication_network, nodegroup=opts.nodegroup) - srun = ssh.SshRunner(cluster_name=cluster_name) + srun = ssh.SshRunner(cluster_name) for node in results: if not srun.CopyFileToNode(node, filename): ToStderr("Copy of file %s to node %s failed", filename, node) @@ -479,10 +556,19 @@ def RunClusterCommand(opts, args): nodes.append(master_node) for name in nodes: - result = srun.Run(name, "root", command) + result = srun.Run(name, constants.SSH_LOGIN_USER, command) + + if opts.failure_only and result.exit_code == constants.EXIT_SUCCESS: + # Do not output anything for successful commands + continue + ToStdout("------------------------------------------------") - ToStdout("node: %s", name) - ToStdout("%s", result.output) + if opts.show_machine_names: + for line in result.output.splitlines(): + ToStdout("%s: %s", name, line) + else: + ToStdout("node: %s", name) + ToStdout("%s", result.output) ToStdout("return code = %s", result.exit_code) return 0 @@ -608,6 +694,8 @@ def VerifyDisks(opts, args): ToStdout("You need to replace or recreate disks for all the above" " instances if this message persists after fixing broken nodes.") retcode = constants.EXIT_FAILURE + elif not instances: + ToStdout("No disks need to be activated.") return retcode @@ -641,7 +729,7 @@ def MasterFailover(opts, args): @return: the desired exit code """ - if opts.no_voting: + if opts.no_voting and not opts.yes_do_it: usertext = ("This will perform the failover even if most other nodes" " are down, or if this node is outdated. This is dangerous" " as it can lead to a non-consistent cluster. Check the" @@ -725,7 +813,7 @@ def _ReadAndVerifyCert(cert_filename, verify_private_key=False): return pem -def _RenewCrypto(new_cluster_cert, new_rapi_cert, #pylint: disable=R0911 +def _RenewCrypto(new_cluster_cert, new_rapi_cert, # pylint: disable=R0911 rapi_cert_filename, new_spice_cert, spice_cert_filename, spice_cacert_filename, new_confd_hmac_key, new_cds, cds_filename, force): @@ -817,20 +905,20 @@ def _RenewCrypto(new_cluster_cert, new_rapi_cert, #pylint: disable=R0911 files_to_copy = [] if new_cluster_cert: - files_to_copy.append(constants.NODED_CERT_FILE) + files_to_copy.append(pathutils.NODED_CERT_FILE) if new_rapi_cert or rapi_cert_pem: - files_to_copy.append(constants.RAPI_CERT_FILE) + files_to_copy.append(pathutils.RAPI_CERT_FILE) if new_spice_cert or spice_cert_pem: - files_to_copy.append(constants.SPICE_CERT_FILE) - files_to_copy.append(constants.SPICE_CACERT_FILE) + files_to_copy.append(pathutils.SPICE_CERT_FILE) + files_to_copy.append(pathutils.SPICE_CACERT_FILE) if new_confd_hmac_key: - files_to_copy.append(constants.CONFD_HMAC_KEY) + files_to_copy.append(pathutils.CONFD_HMAC_KEY) if new_cds or cds: - files_to_copy.append(constants.CLUSTER_DOMAIN_SECRET_FILE) + files_to_copy.append(pathutils.CLUSTER_DOMAIN_SECRET_FILE) if files_to_copy: for node_name in ctx.nonmaster_nodes: @@ -876,7 +964,8 @@ def SetClusterParams(opts, args): if not (not opts.lvm_storage or opts.vg_name or not opts.drbd_storage or opts.drbd_helper or opts.enabled_hypervisors or opts.hvparams or - opts.beparams or opts.nicparams or opts.ndparams or + opts.beparams or opts.nicparams or + opts.ndparams or opts.diskparams or opts.candidate_pool_size is not None or opts.uid_pool is not None or opts.maintain_node_health is not None or @@ -887,7 +976,18 @@ def SetClusterParams(opts, args): opts.master_netdev is not None or opts.master_netmask is not None or opts.use_external_mip_script is not None or - opts.prealloc_wipe_disks is not None): + opts.prealloc_wipe_disks is not None or + opts.hv_state or + opts.enabled_storage_types or + opts.disk_state or + opts.ispecs_mem_size or + opts.ispecs_cpu_count or + opts.ispecs_disk_count or + opts.ispecs_disk_size or + opts.ispecs_nic_count or + opts.ipolicy_disk_templates is not None or + opts.ipolicy_vcpu_ratio is not None or + opts.ipolicy_spindle_ratio is not None): ToStderr("Please give at least one of the parameters.") return 1 @@ -911,11 +1011,20 @@ def SetClusterParams(opts, args): if hvlist is not None: hvlist = hvlist.split(",") + enabled_storage_types = opts.enabled_storage_types + if enabled_storage_types is not None: + enabled_storage_types = enabled_storage_types.split(",") + # a list of (name, dict) we can pass directly to dict() (or []) hvparams = dict(opts.hvparams) for hv_params in hvparams.values(): utils.ForceDictType(hv_params, constants.HVS_PARAMETER_TYPES) + diskparams = dict(opts.diskparams) + + for dt_params in diskparams.values(): + utils.ForceDictType(dt_params, constants.DISK_DT_TYPES) + beparams = opts.beparams utils.ForceDictType(beparams, constants.BES_PARAMETER_COMPAT) @@ -926,6 +1035,17 @@ def SetClusterParams(opts, args): if ndparams is not None: utils.ForceDictType(ndparams, constants.NDS_PARAMETER_TYPES) + ipolicy = CreateIPolicyFromOpts( + ispecs_mem_size=opts.ispecs_mem_size, + ispecs_cpu_count=opts.ispecs_cpu_count, + ispecs_disk_count=opts.ispecs_disk_count, + ispecs_disk_size=opts.ispecs_disk_size, + ispecs_nic_count=opts.ispecs_nic_count, + ipolicy_disk_templates=opts.ipolicy_disk_templates, + ipolicy_vcpu_ratio=opts.ipolicy_vcpu_ratio, + ipolicy_spindle_ratio=opts.ipolicy_spindle_ratio, + ) + mnh = opts.maintain_node_health uid_pool = opts.uid_pool @@ -955,27 +1075,40 @@ def SetClusterParams(opts, args): ext_ip_script = opts.use_external_mip_script - op = opcodes.OpClusterSetParams(vg_name=vg_name, - drbd_helper=drbd_helper, - enabled_hypervisors=hvlist, - hvparams=hvparams, - os_hvp=None, - beparams=beparams, - nicparams=nicparams, - ndparams=ndparams, - candidate_pool_size=opts.candidate_pool_size, - maintain_node_health=mnh, - uid_pool=uid_pool, - add_uids=add_uids, - remove_uids=remove_uids, - default_iallocator=opts.default_iallocator, - prealloc_wipe_disks=opts.prealloc_wipe_disks, - master_netdev=opts.master_netdev, - master_netmask=opts.master_netmask, - reserved_lvs=opts.reserved_lvs, - use_external_mip_script=ext_ip_script, - ) - SubmitOpCode(op, opts=opts) + if opts.disk_state: + disk_state = utils.FlatToDict(opts.disk_state) + else: + disk_state = {} + + hv_state = dict(opts.hv_state) + + op = opcodes.OpClusterSetParams( + vg_name=vg_name, + drbd_helper=drbd_helper, + enabled_hypervisors=hvlist, + hvparams=hvparams, + os_hvp=None, + beparams=beparams, + nicparams=nicparams, + ndparams=ndparams, + diskparams=diskparams, + ipolicy=ipolicy, + candidate_pool_size=opts.candidate_pool_size, + maintain_node_health=mnh, + uid_pool=uid_pool, + add_uids=add_uids, + remove_uids=remove_uids, + default_iallocator=opts.default_iallocator, + prealloc_wipe_disks=opts.prealloc_wipe_disks, + master_netdev=opts.master_netdev, + master_netmask=opts.master_netmask, + reserved_lvs=opts.reserved_lvs, + use_external_mip_script=ext_ip_script, + hv_state=hv_state, + disk_state=disk_state, + enabled_storage_types=enabled_storage_types, + ) + SubmitOrSend(op, opts) return 0 @@ -1087,12 +1220,13 @@ def _OobPower(opts, node_list, power): return True -def _InstanceStart(opts, inst_list, start): +def _InstanceStart(opts, inst_list, start, no_remember=False): """Puts the instances in the list to desired state. @param opts: The command line options selected by the user @param inst_list: The list of instances to operate on @param start: True if they should be started, False for shutdown + @param no_remember: If the instance state should be remembered @return: The success of the operation (none failed) """ @@ -1101,7 +1235,8 @@ def _InstanceStart(opts, inst_list, start): text_submit, text_success, text_failed = ("startup", "started", "starting") else: opcls = compat.partial(opcodes.OpInstanceShutdown, - timeout=opts.shutdown_timeout) + timeout=opts.shutdown_timeout, + no_remember=no_remember) text_submit, text_success, text_failed = ("shutdown", "stopped", "stopping") jex = JobExecutor(opts=opts) @@ -1281,7 +1416,7 @@ def _EpoOff(opts, node_list, inst_map): @return: The desired exit status """ - if not _InstanceStart(opts, inst_map.keys(), False): + if not _InstanceStart(opts, inst_map.keys(), False, no_remember=True): ToStderr("Please investigate and stop instances manually before continuing") return constants.EXIT_FAILURE @@ -1294,7 +1429,9 @@ def _EpoOff(opts, node_list, inst_map): return constants.EXIT_FAILURE -def Epo(opts, args): +def Epo(opts, args, cl=None, _on_fn=_EpoOn, _off_fn=_EpoOff, + _confirm_fn=ConfirmOperation, + _stdout_fn=ToStdout, _stderr_fn=ToStderr): """EPO operations. @param opts: the command line options selected by the user @@ -1305,32 +1442,29 @@ def Epo(opts, args): """ if opts.groups and opts.show_all: - ToStderr("Only one of --groups or --all are allowed") + _stderr_fn("Only one of --groups or --all are allowed") return constants.EXIT_FAILURE elif args and opts.show_all: - ToStderr("Arguments in combination with --all are not allowed") + _stderr_fn("Arguments in combination with --all are not allowed") return constants.EXIT_FAILURE - client = GetClient() + if cl is None: + cl = GetClient() if opts.groups: - node_query_list = itertools.chain(*client.QueryGroups(names=args, - fields=["node_list"], - use_locking=False)) + node_query_list = \ + itertools.chain(*cl.QueryGroups(args, ["node_list"], False)) else: node_query_list = args - result = client.QueryNodes(names=node_query_list, - fields=["name", "master", "pinst_list", - "sinst_list", "powered", "offline"], - use_locking=False) + result = cl.QueryNodes(node_query_list, ["name", "master", "pinst_list", + "sinst_list", "powered", "offline"], + False) + + all_nodes = map(compat.fst, result) node_list = [] inst_map = {} - for (idx, (node, master, pinsts, sinsts, powered, - offline)) in enumerate(result): - # Normalize the node_query_list as well - if not opts.show_all: - node_query_list[idx] = node + for (node, master, pinsts, sinsts, powered, offline) in result: if not offline: for inst in (pinsts + sinsts): if inst in inst_map: @@ -1346,25 +1480,25 @@ def Epo(opts, args): # already operating on the master at this point :) continue elif master and not opts.show_all: - ToStderr("%s is the master node, please do a master-failover to another" - " node not affected by the EPO or use --all if you intend to" - " shutdown the whole cluster", node) + _stderr_fn("%s is the master node, please do a master-failover to another" + " node not affected by the EPO or use --all if you intend to" + " shutdown the whole cluster", node) return constants.EXIT_FAILURE elif powered is None: - ToStdout("Node %s does not support out-of-band handling, it can not be" - " handled in a fully automated manner", node) + _stdout_fn("Node %s does not support out-of-band handling, it can not be" + " handled in a fully automated manner", node) elif powered == opts.on: - ToStdout("Node %s is already in desired power state, skipping", node) + _stdout_fn("Node %s is already in desired power state, skipping", node) elif not offline or (offline and powered): node_list.append(node) - if not opts.force and not ConfirmOperation(node_query_list, "nodes", "epo"): + if not (opts.force or _confirm_fn(all_nodes, "nodes", "epo")): return constants.EXIT_FAILURE if opts.on: - return _EpoOn(opts, node_query_list, node_list, inst_map) + return _on_fn(opts, all_nodes, node_list, inst_map) else: - return _EpoOff(opts, node_list, inst_map) + return _off_fn(opts, node_list, inst_map) commands = { @@ -1376,7 +1510,9 @@ commands = { NOMODIFY_SSH_SETUP_OPT, SECONDARY_IP_OPT, VG_NAME_OPT, MAINTAIN_NODE_HEALTH_OPT, UIDPOOL_OPT, DRBD_HELPER_OPT, NODRBD_STORAGE_OPT, DEFAULT_IALLOCATOR_OPT, PRIMARY_IP_VERSION_OPT, PREALLOC_WIPE_DISKS_OPT, - NODE_PARAMS_OPT, GLOBAL_SHARED_FILEDIR_OPT, USE_EXTERNAL_MIP_SCRIPT], + NODE_PARAMS_OPT, GLOBAL_SHARED_FILEDIR_OPT, USE_EXTERNAL_MIP_SCRIPT, + DISK_PARAMS_OPT, HV_STATE_OPT, DISK_STATE_OPT, ENABLED_STORAGE_TYPES_OPT] + + INSTANCE_POLICY_OPTS, "[opts...] ", "Initialises a new cluster configuration"), "destroy": ( DestroyCluster, ARGS_NONE, [YES_DOIT_OPT], @@ -1402,7 +1538,7 @@ commands = { RepairDiskSizes, ARGS_MANY_INSTANCES, [DRY_RUN_OPT, PRIORITY_OPT], "[instance...]", "Updates mismatches in recorded disk sizes"), "master-failover": ( - MasterFailover, ARGS_NONE, [NOVOTING_OPT], + MasterFailover, ARGS_NONE, [NOVOTING_OPT, FORCE_FAILOVER], "", "Makes the current node the master"), "master-ping": ( MasterPing, ARGS_NONE, [], @@ -1419,7 +1555,7 @@ commands = { "[-n node...] ", "Copies a file to all (or only some) nodes"), "command": ( RunClusterCommand, [ArgCommand(min=1)], - [NODE_LIST_OPT, NODEGROUP_OPT], + [NODE_LIST_OPT, NODEGROUP_OPT, SHOW_MACHINE_OPT, FAILURE_ONLY_OPT], "[-n node...] ", "Runs a command on all (or only some) nodes"), "info": ( ShowClusterConfig, ARGS_NONE, [ROMAN_OPT], @@ -1427,10 +1563,10 @@ commands = { "list-tags": ( ListTags, ARGS_NONE, [], "", "List the tags of the cluster"), "add-tags": ( - AddTags, [ArgUnknown()], [TAG_SRC_OPT, PRIORITY_OPT], + AddTags, [ArgUnknown()], [TAG_SRC_OPT, PRIORITY_OPT, SUBMIT_OPT], "tag...", "Add tags to the cluster"), "remove-tags": ( - RemoveTags, [ArgUnknown()], [TAG_SRC_OPT, PRIORITY_OPT], + RemoveTags, [ArgUnknown()], [TAG_SRC_OPT, PRIORITY_OPT, SUBMIT_OPT], "tag...", "Remove tags from the cluster"), "search-tags": ( SearchTags, [ArgUnknown(min=1, max=1)], [PRIORITY_OPT], "", @@ -1453,7 +1589,9 @@ commands = { MAINTAIN_NODE_HEALTH_OPT, UIDPOOL_OPT, ADD_UIDS_OPT, REMOVE_UIDS_OPT, DRBD_HELPER_OPT, NODRBD_STORAGE_OPT, DEFAULT_IALLOCATOR_OPT, RESERVED_LVS_OPT, DRY_RUN_OPT, PRIORITY_OPT, PREALLOC_WIPE_DISKS_OPT, - NODE_PARAMS_OPT, USE_EXTERNAL_MIP_SCRIPT], + NODE_PARAMS_OPT, USE_EXTERNAL_MIP_SCRIPT, DISK_PARAMS_OPT, HV_STATE_OPT, + DISK_STATE_OPT, SUBMIT_OPT, ENABLED_STORAGE_TYPES_OPT] + + INSTANCE_POLICY_OPTS, "[opts...]", "Alters the parameters of the cluster"), "renew-crypto": ( @@ -1481,6 +1619,7 @@ commands = { #: dictionary with aliases for commands aliases = { "masterfailover": "master-failover", + "show": "info", }