diff --git a/lib/cli.py b/lib/cli.py index 8065f3da76c8ff50eb6cca742b10b9867b7b118d..13c13801c88b536c819e72719cb89206f95601b8 100644 --- a/lib/cli.py +++ b/lib/cli.py @@ -46,7 +46,6 @@ __all__ = ["DEBUG_OPT", "NOHDR_OPT", "SEP_OPT", "GenericMain", "SubmitOpCode", "GetClient", "cli_option", "GenerateTable", "AskUser", - "ARGS_NONE", "ARGS_FIXED", "ARGS_ATLEAST", "ARGS_ANY", "ARGS_ONE", "USEUNITS_OPT", "FIELDS_OPT", "FORCE_OPT", "SUBMIT_OPT", "ListTags", "AddTags", "RemoveTags", "TAG_SRC_OPT", "FormatError", "SplitNodeOption", "SubmitOrSend", @@ -279,21 +278,6 @@ _DRY_RUN_OPT = make_option("--dry-run", default=False, " check steps and verify it it could be executed") -def ARGS_FIXED(val): - """Macro-like function denoting a fixed number of arguments""" - return -val - - -def ARGS_ATLEAST(val): - """Macro-like function denoting a minimum number of arguments""" - return val - - -ARGS_NONE = None -ARGS_ONE = ARGS_FIXED(1) -ARGS_ANY = ARGS_ATLEAST(0) - - def check_unit(option, opt, value): """OptParsers custom converter for units. @@ -464,27 +448,91 @@ def _ParseArgs(argv, commands, aliases): cmd = aliases[cmd] - func, nargs, parser_opts, usage, description = commands[cmd] + func, args_def, parser_opts, usage, description = commands[cmd] parser = OptionParser(option_list=parser_opts + [_DRY_RUN_OPT], description=description, formatter=TitledHelpFormatter(), usage="%%prog %s %s" % (cmd, usage)) parser.disable_interspersed_args() options, args = parser.parse_args() - if nargs is None: - if len(args) != 0: - ToStderr("Error: Command %s expects no arguments", cmd) - return None, None, None - elif nargs < 0 and len(args) != -nargs: - ToStderr("Error: Command %s expects %d argument(s)", cmd, -nargs) - return None, None, None - elif nargs >= 0 and len(args) < nargs: - ToStderr("Error: Command %s expects at least %d argument(s)", cmd, nargs) + + if not _CheckArguments(cmd, args_def, args): return None, None, None return func, options, args +def _CheckArguments(cmd, args_def, args): + """Verifies the arguments using the argument definition. + + Algorithm: + + 1. Abort with error if values specified by user but none expected. + + 1. For each argument in definition + + 1. Keep running count of minimum number of values (min_count) + 1. Keep running count of maximum number of values (max_count) + 1. If it has an unlimited number of values + + 1. Abort with error if it's not the last argument in the definition + + 1. If last argument has limited number of values + + 1. Abort with error if number of values doesn't match or is too large + + 1. Abort with error if user didn't pass enough values (min_count) + + """ + if args and not args_def: + ToStderr("Error: Command %s expects no arguments", cmd) + return False + + min_count = None + max_count = None + check_max = None + + last_idx = len(args_def) - 1 + + for idx, arg in enumerate(args_def): + if min_count is None: + min_count = arg.min + elif arg.min is not None: + min_count += arg.min + + if max_count is None: + max_count = arg.max + elif arg.max is not None: + max_count += arg.max + + if idx == last_idx: + check_max = (arg.max is not None) + + elif arg.max is None: + raise errors.ProgrammerError("Only the last argument can have max=None") + + if check_max: + # Command with exact number of arguments + if (min_count is not None and max_count is not None and + min_count == max_count and len(args) != min_count): + ToStderr("Error: Command %s expects %d argument(s)", cmd, min_count) + return False + + # Command with limited number of arguments + if max_count is not None and len(args) > max_count: + ToStderr("Error: Command %s expects only %d argument(s)", + cmd, max_count) + return False + + # Command with some required arguments + if min_count is not None and len(args) < min_count: + ToStderr("Error: Command %s expects at least %d argument(s)", + cmd, min_count) + return False + + return True + + def SplitNodeOption(value): """Splits the value of a --node option. diff --git a/scripts/gnt-backup b/scripts/gnt-backup index e005d914758f88797df431434ce683e46f8319f8..cb06160aa9474b29883c88444113d211bd3307f1 100755 --- a/scripts/gnt-backup +++ b/scripts/gnt-backup @@ -35,6 +35,7 @@ from ganeti import utils _VALUE_TRUE = "true" + def PrintExportList(opts, args): """Prints a list of all the exported system images. @@ -259,14 +260,14 @@ import_opts = [ ] commands = { - 'list': (PrintExportList, ARGS_NONE, + 'list': (PrintExportList, [], [DEBUG_OPT, make_option("--node", dest="nodes", default=[], action="append", help="List only backups stored on this node" " (can be used multiple times)"), ], "", "Lists instance exports available in the ganeti cluster"), - 'export': (ExportInstance, ARGS_ONE, + 'export': (ExportInstance, [ArgInstance(min=1, max=1)], [DEBUG_OPT, FORCE_OPT, make_option("-n", "--node", dest="node", help="Target node", metavar="<node>"), @@ -275,15 +276,16 @@ commands = { help="Don't shutdown the instance (unsafe)"), ], "-n <target_node> [opts...] <name>", "Exports an instance to an image"), - 'import': (ImportInstance, ARGS_ONE, import_opts, + 'import': (ImportInstance, [ArgInstance(min=1, max=1)], import_opts, ("[...] -t disk-type -n node[:secondary-node]" " <name>"), "Imports an instance from an exported image"), - 'remove': (RemoveExport, ARGS_ONE, + 'remove': (RemoveExport, [ArgUnknown(min=1, max=1)], [DEBUG_OPT], "<name>", "Remove exports of named instance from the filesystem."), } + if __name__ == '__main__': sys.exit(GenericMain(commands)) diff --git a/scripts/gnt-cluster b/scripts/gnt-cluster index 60f7a4a4dc2858be8fcc1c2996dd0dcd49c57b36..5a68f7a74f8323c919673d34b725b145b8ae03f8 100755 --- a/scripts/gnt-cluster +++ b/scripts/gnt-cluster @@ -542,7 +542,7 @@ node_option = make_option("-n", "--node", action="append", dest="nodes", metavar="<node>", default=[]) commands = { - 'init': (InitCluster, ARGS_ONE, + 'init': (InitCluster, [ArgUnknown(min=1, max=1)], [DEBUG_OPT, make_option("-s", "--secondary-ip", dest="secondary_ip", help="Specify the secondary ip for this node;" @@ -603,62 +603,66 @@ commands = { ], "[opts...] <cluster_name>", "Initialises a new cluster configuration"), - 'destroy': (DestroyCluster, ARGS_NONE, + 'destroy': (DestroyCluster, [], [DEBUG_OPT, make_option("--yes-do-it", dest="yes_do_it", help="Destroy cluster", action="store_true"), ], "", "Destroy cluster"), - 'rename': (RenameCluster, ARGS_ONE, [DEBUG_OPT, FORCE_OPT], - "<new_name>", - "Renames the cluster"), - 'redist-conf': (RedistributeConfig, ARGS_NONE, [DEBUG_OPT, SUBMIT_OPT], + 'rename': (RenameCluster, [ArgUnknown(min=1, max=1)], + [DEBUG_OPT, FORCE_OPT], + "<new_name>", + "Renames the cluster"), + 'redist-conf': (RedistributeConfig, [], [DEBUG_OPT, SUBMIT_OPT], "", "Forces a push of the configuration file and ssconf files" " to the nodes in the cluster"), - 'verify': (VerifyCluster, ARGS_NONE, [DEBUG_OPT, + 'verify': (VerifyCluster, [], [DEBUG_OPT, make_option("--no-nplus1-mem", dest="skip_nplusone_mem", help="Skip N+1 memory redundancy tests", action="store_true", default=False,), ], "", "Does a check on the cluster configuration"), - 'verify-disks': (VerifyDisks, ARGS_NONE, [DEBUG_OPT], + 'verify-disks': (VerifyDisks, [], [DEBUG_OPT], "", "Does a check on the cluster disk status"), - 'repair-disk-sizes': (RepairDiskSizes, ARGS_ANY, [DEBUG_OPT], + 'repair-disk-sizes': (RepairDiskSizes, [ArgInstance()], [DEBUG_OPT], "", "Updates mismatches in recorded disk sizes"), - 'masterfailover': (MasterFailover, ARGS_NONE, [DEBUG_OPT, + 'masterfailover': (MasterFailover, [], [DEBUG_OPT, make_option("--no-voting", dest="no_voting", help="Skip node agreement check (dangerous)", action="store_true", default=False,), ], "", "Makes the current node the master"), - 'version': (ShowClusterVersion, ARGS_NONE, [DEBUG_OPT], + 'version': (ShowClusterVersion, [], [DEBUG_OPT], "", "Shows the cluster version"), - 'getmaster': (ShowClusterMaster, ARGS_NONE, [DEBUG_OPT], + 'getmaster': (ShowClusterMaster, [], [DEBUG_OPT], "", "Shows the cluster master"), - 'copyfile': (ClusterCopyFile, ARGS_ONE, [DEBUG_OPT, node_option], + 'copyfile': (ClusterCopyFile, [ArgFile(min=1, max=1)], + [DEBUG_OPT, node_option], "[-n node...] <filename>", "Copies a file to all (or only some) nodes"), - 'command': (RunClusterCommand, ARGS_ATLEAST(1), [DEBUG_OPT, node_option], + 'command': (RunClusterCommand, [ArgCommand(min=1)], [DEBUG_OPT, node_option], "[-n node...] <command>", "Runs a command on all (or only some) nodes"), - 'info': (ShowClusterConfig, ARGS_NONE, [DEBUG_OPT], - "", "Show cluster configuration"), - 'list-tags': (ListTags, ARGS_NONE, + 'info': (ShowClusterConfig, [], [DEBUG_OPT], + "", "Show cluster configuration"), + 'list-tags': (ListTags, [], [DEBUG_OPT], "", "List the tags of the cluster"), - 'add-tags': (AddTags, ARGS_ANY, [DEBUG_OPT, TAG_SRC_OPT], + 'add-tags': (AddTags, [ArgUnknown()], [DEBUG_OPT, TAG_SRC_OPT], "tag...", "Add tags to the cluster"), - 'remove-tags': (RemoveTags, ARGS_ANY, [DEBUG_OPT, TAG_SRC_OPT], + 'remove-tags': (RemoveTags, [ArgUnknown()], [DEBUG_OPT, TAG_SRC_OPT], "tag...", "Remove tags from the cluster"), - 'search-tags': (SearchTags, ARGS_ONE, + 'search-tags': (SearchTags, [ArgUnknown(min=1, max=1)], [DEBUG_OPT], "", "Searches the tags on all objects on" " the cluster for a given pattern (regex)"), - 'queue': (QueueOps, ARGS_ONE, [DEBUG_OPT], + 'queue': (QueueOps, + [ArgChoice(min=1, max=1, choices=["drain", "undrain", "info"])], + [DEBUG_OPT], "drain|undrain|info", "Change queue properties"), - 'modify': (SetClusterParams, ARGS_NONE, + 'modify': (SetClusterParams, [], [DEBUG_OPT, make_option("-g", "--vg-name", dest="vg_name", help="Specify the volume group name " diff --git a/scripts/gnt-debug b/scripts/gnt-debug index 3a12b2b7aaa9c1ec111a6d0f00c7ec081706243f..91f2e102cdc0bd0ab79ea01fee4ef09c3dc13a71 100755 --- a/scripts/gnt-debug +++ b/scripts/gnt-debug @@ -131,7 +131,7 @@ def TestAllocator(opts, args): commands = { - 'delay': (Delay, ARGS_ONE, + 'delay': (Delay, [ArgUnknown(min=1, max=1)], [DEBUG_OPT, make_option("--no-master", dest="on_master", default=True, action="store_false", @@ -141,12 +141,10 @@ commands = { help="Select nodes to sleep on"), ], "[opts...] <duration>", "Executes a TestDelay OpCode"), - 'submit-job': (GenericOpCodes, ARGS_ATLEAST(1), - [DEBUG_OPT, - ], + 'submit-job': (GenericOpCodes, [ArgFile(min=1)], [DEBUG_OPT], "<op_list_file...>", "Submits jobs built from json files" " containing a list of serialized opcodes"), - 'allocator': (TestAllocator, ARGS_ONE, + 'allocator': (TestAllocator, [ArgInstance(min=1, max=1)], [DEBUG_OPT, make_option("--dir", dest="direction", default="in", choices=["in", "out"], diff --git a/scripts/gnt-instance b/scripts/gnt-instance index 2d0fe8c4ce0cd5d2ae344603da290b7a95eb402b..5484ff2e62bc2b8bca0b38ca7eb88a5bc4da06a5 100755 --- a/scripts/gnt-instance +++ b/scripts/gnt-instance @@ -1417,21 +1417,21 @@ add_opts = [ ] commands = { - 'add': (AddInstance, ARGS_ONE, add_opts, + 'add': (AddInstance, [ArgUnknown(min=1, max=1)], add_opts, "[...] -t disk-type -n node[:secondary-node] -o os-type <name>", "Creates and adds a new instance to the cluster"), - 'batch-create': (BatchCreate, ARGS_ONE, + 'batch-create': (BatchCreate, [ArgFile(min=1, max=1)], [DEBUG_OPT], "<instances_file.json>", "Create a bunch of instances based on specs in the file."), - 'console': (ConnectToInstanceConsole, ARGS_ONE, + 'console': (ConnectToInstanceConsole, [ArgInstance(min=1, max=1)], [DEBUG_OPT, make_option("--show-cmd", dest="show_command", action="store_true", default=False, help=("Show command instead of executing it"))], "[--show-cmd] <instance>", "Opens a console on the specified instance"), - 'failover': (FailoverInstance, ARGS_ONE, + 'failover': (FailoverInstance, [ArgInstance(min=1, max=1)], [DEBUG_OPT, FORCE_OPT, make_option("--ignore-consistency", dest="ignore_consistency", action="store_true", default=False, @@ -1442,7 +1442,7 @@ commands = { "[-f] <instance>", "Stops the instance and starts it on the backup node, using" " the remote mirror (only for instances of type drbd)"), - 'migrate': (MigrateInstance, ARGS_ONE, + 'migrate': (MigrateInstance, [ArgInstance(min=1, max=1)], [DEBUG_OPT, FORCE_OPT, make_option("--non-live", dest="live", default=True, action="store_false", @@ -1462,7 +1462,7 @@ commands = { "[-f] <instance>", "Migrate instance to its secondary node" " (only for instances of type drbd)"), - 'move': (MoveInstance, ARGS_ONE, + 'move': (MoveInstance, [ArgInstance(min=1, max=1)], [DEBUG_OPT, FORCE_OPT, SUBMIT_OPT, make_option("-n", "--new-node", dest="target_node", help="Destinattion node", metavar="NODE", @@ -1471,7 +1471,7 @@ commands = { "[-f] <instance>", "Move instance to an arbitrary node" " (only for instances of type file and lv)"), - 'info': (ShowInstanceConfig, ARGS_ANY, + 'info': (ShowInstanceConfig, [ArgInstance()], [DEBUG_OPT, make_option("-s", "--static", dest="static", action="store_true", default=False, @@ -1482,7 +1482,7 @@ commands = { " This can take a long time to run, use wisely."), ], "[-s] {--all | <instance>...}", "Show information on the specified instance(s)"), - 'list': (ListInstances, ARGS_ANY, + 'list': (ListInstances, [ArgInstance()], [DEBUG_OPT, NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT, SYNC_OPT], "[<instance>...]", "Lists the instances and their status. The available fields are" @@ -1493,7 +1493,7 @@ commands = { " The default field" " list is (in order): %s." % ", ".join(_LIST_DEF_FIELDS), ), - 'reinstall': (ReinstallInstance, ARGS_ANY, + 'reinstall': (ReinstallInstance, [ArgInstance(min=1)], [DEBUG_OPT, FORCE_OPT, os_opt, m_force_multi, m_node_opt, m_pri_node_opt, m_sec_node_opt, @@ -1505,7 +1505,7 @@ commands = { SUBMIT_OPT, ], "[-f] <instance>", "Reinstall a stopped instance"), - 'remove': (RemoveInstance, ARGS_ONE, + 'remove': (RemoveInstance, [ArgInstance(min=1, max=1)], [DEBUG_OPT, FORCE_OPT, make_option("--ignore-failures", dest="ignore_failures", action="store_true", default=False, @@ -1515,7 +1515,8 @@ commands = { SUBMIT_OPT, ], "[-f] <instance>", "Shuts down the instance and removes it"), - 'rename': (RenameInstance, ARGS_FIXED(2), + 'rename': (RenameInstance, + [ArgInstance(min=1, max=1), ArgUnknown(min=1, max=1)], [DEBUG_OPT, make_option("--no-ip-check", dest="ignore_ip", help="Do not check that the IP of the new name" @@ -1524,7 +1525,7 @@ commands = { SUBMIT_OPT, ], "<instance> <new_name>", "Rename the instance"), - 'replace-disks': (ReplaceDisks, ARGS_ONE, + 'replace-disks': (ReplaceDisks, [ArgInstance(min=1, max=1)], [DEBUG_OPT, make_option("-n", "--new-secondary", dest="new_secondary", help=("New secondary node (for secondary" @@ -1556,7 +1557,7 @@ commands = { ], "[-s|-p|-n NODE|-I NAME] <instance>", "Replaces all disks for the instance"), - 'modify': (SetInstanceParams, ARGS_ONE, + 'modify': (SetInstanceParams, [ArgInstance(min=1, max=1)], [DEBUG_OPT, FORCE_OPT, cli_option("-H", "--hypervisor", type="keyval", default={}, dest="hypervisor", @@ -1575,13 +1576,13 @@ commands = { SUBMIT_OPT, ], "<instance>", "Alters the parameters of an instance"), - 'shutdown': (ShutdownInstance, ARGS_ANY, + 'shutdown': (ShutdownInstance, [ArgInstance(min=1)], [DEBUG_OPT, m_node_opt, m_pri_node_opt, m_sec_node_opt, m_clust_opt, m_inst_opt, m_force_multi, SUBMIT_OPT, ], "<instance>", "Stops an instance"), - 'startup': (StartupInstance, ARGS_ANY, + 'startup': (StartupInstance, [ArgInstance(min=1)], [DEBUG_OPT, FORCE_OPT, m_force_multi, m_node_opt, m_pri_node_opt, m_sec_node_opt, m_clust_opt, m_inst_opt, @@ -1594,8 +1595,7 @@ commands = { help="Temporary backend parameters"), ], "<instance>", "Starts an instance"), - - 'reboot': (RebootInstance, ARGS_ANY, + 'reboot': (RebootInstance, [ArgInstance(min=1)], [DEBUG_OPT, m_force_multi, make_option("-t", "--type", dest="reboot_type", help="Type of reboot: soft/hard/full", @@ -1609,7 +1609,7 @@ commands = { SUBMIT_OPT, ], "<instance>", "Reboots an instance"), - 'activate-disks': (ActivateDisks, ARGS_ONE, + 'activate-disks': (ActivateDisks, [ArgInstance(min=1, max=1)], [DEBUG_OPT, SUBMIT_OPT, make_option("--ignore-size", dest="ignore_size", default=False, action="store_true", @@ -1619,10 +1619,11 @@ commands = { ], "<instance>", "Activate an instance's disks"), - 'deactivate-disks': (DeactivateDisks, ARGS_ONE, [DEBUG_OPT, SUBMIT_OPT], + 'deactivate-disks': (DeactivateDisks, [ArgInstance(min=1, max=1)], + [DEBUG_OPT, SUBMIT_OPT], "<instance>", "Deactivate an instance's disks"), - 'recreate-disks': (RecreateDisks, ARGS_ONE, + 'recreate-disks': (RecreateDisks, [ArgInstance(min=1, max=1)], [DEBUG_OPT, SUBMIT_OPT, make_option("--disks", dest="disks", default=None, help="Comma-separated list of disks" @@ -1631,7 +1632,9 @@ commands = { ], "<instance>", "Recreate an instance's disks"), - 'grow-disk': (GrowDisk, ARGS_FIXED(3), + 'grow-disk': (GrowDisk, + [ArgInstance(min=1, max=1), ArgUnknown(min=1, max=1), + ArgUnknown(min=1, max=1)], [DEBUG_OPT, SUBMIT_OPT, make_option("--no-wait-for-sync", dest="wait_for_sync", default=True, @@ -1639,11 +1642,13 @@ commands = { help="Don't wait for sync (DANGEROUS!)"), ], "<instance> <disk> <size>", "Grow an instance's disk"), - 'list-tags': (ListTags, ARGS_ONE, [DEBUG_OPT], + 'list-tags': (ListTags, [ArgInstance(min=1, max=1)], [DEBUG_OPT], "<instance_name>", "List the tags of the given instance"), - 'add-tags': (AddTags, ARGS_ATLEAST(1), [DEBUG_OPT, TAG_SRC_OPT], + 'add-tags': (AddTags, [ArgInstance(min=1, max=1), ArgUnknown()], + [DEBUG_OPT, TAG_SRC_OPT], "<instance_name> tag...", "Add tags to the given instance"), - 'remove-tags': (RemoveTags, ARGS_ATLEAST(1), [DEBUG_OPT, TAG_SRC_OPT], + 'remove-tags': (RemoveTags, [ArgInstance(min=1, max=1), ArgUnknown()], + [DEBUG_OPT, TAG_SRC_OPT], "<instance_name> tag...", "Remove tags from given instance"), } @@ -1655,6 +1660,7 @@ aliases = { 'stop': 'shutdown', } + if __name__ == '__main__': sys.exit(GenericMain(commands, aliases=aliases, override={"tag_type": constants.TAG_INSTANCE})) diff --git a/scripts/gnt-job b/scripts/gnt-job index 1402583e6ae8ba80c3d628aaac0ed2cb7730a7b5..89f246766fecc203ae5d30b5b6736629a5d8542c 100755 --- a/scripts/gnt-job +++ b/scripts/gnt-job @@ -340,32 +340,31 @@ def WatchJob(opts, args): commands = { - 'list': (ListJobs, ARGS_ANY, - [DEBUG_OPT, NOHDR_OPT, SEP_OPT, FIELDS_OPT], - "[job_id ...]", + 'list': (ListJobs, [ArgJobId()], + [DEBUG_OPT, NOHDR_OPT, SEP_OPT, FIELDS_OPT], + "[job_id ...]", "List the jobs and their status. The available fields are" " (see the man page for details): id, status, op_list," " op_status, op_result." " The default field" " list is (in order): %s." % ", ".join(_LIST_DEF_FIELDS)), - 'archive': (ArchiveJobs, ARGS_ANY, - [DEBUG_OPT], + 'archive': (ArchiveJobs, [ArgJobId(min=1)], [DEBUG_OPT], "<job-id> [<job-id> ...]", "Archive specified jobs"), - 'autoarchive': (AutoArchiveJobs, ARGS_ONE, - [DEBUG_OPT], - "<age>", - "Auto archive jobs older than the given age"), - 'cancel': (CancelJobs, ARGS_ANY, - [DEBUG_OPT], + 'autoarchive': (AutoArchiveJobs, + [ArgSuggest(min=1, max=1, choices=["1d", "1w", "4w"])], + [DEBUG_OPT], + "<age>", + "Auto archive jobs older than the given age"), + 'cancel': (CancelJobs, [ArgJobId(min=1)], [DEBUG_OPT], "<job-id> [<job-id> ...]", "Cancel specified jobs"), - 'info': (ShowJobs, ARGS_ANY, [DEBUG_OPT], + 'info': (ShowJobs, [ArgJobId(min=1)], [DEBUG_OPT], "<job-id> [<job-id> ...]", "Show detailed information about the specified jobs"), - 'watch': (WatchJob, ARGS_ONE, [DEBUG_OPT], - "<job-id>", - "Follows a job and prints its output as it arrives"), + 'watch': (WatchJob, [ArgJobId(min=1, max=1)], [DEBUG_OPT], + "<job-id>", + "Follows a job and prints its output as it arrives"), } diff --git a/scripts/gnt-node b/scripts/gnt-node index 29c9a1e05706605a702ac3dc3cfdef4506e7cb9c..00c2d3899aa6818065377559d8e5f8facfbeec63 100755 --- a/scripts/gnt-node +++ b/scripts/gnt-node @@ -67,6 +67,21 @@ _USER_STORAGE_TYPE = { constants.ST_LVM_VG: "lvm-vg", } +_STORAGE_TYPE_OPT = \ + cli_option("--storage-type", + dest="user_storage_type", + choices=_USER_STORAGE_TYPE.keys(), + default=None, + metavar="STORAGE_TYPE", + help=("Storage type (%s)" % + utils.CommaJoin(_USER_STORAGE_TYPE.keys()))) + +_REPAIRABLE_STORAGE_TYPES = \ + [st for st, so in constants.VALID_STORAGE_OPERATIONS.iteritems() + if constants.SO_FIX_CONSISTENCY in so] + +_MODIFIABLE_STORAGE_TYPES = constants.MODIFIABLE_STORAGE_FIELDS.keys() + def ConvertStorageType(user_storage_type): """Converts a user storage type to its internal name. @@ -608,7 +623,7 @@ def SetNodeParams(opts, args): commands = { - 'add': (AddNode, ARGS_ONE, + 'add': (AddNode, [ArgUnknown(min=1, max=1)], [DEBUG_OPT, make_option("-s", "--secondary-ip", dest="secondary_ip", help="Specify the secondary ip for the node", @@ -622,7 +637,7 @@ commands = { ], "[-s ip] [--readd] [--no-ssh-key-check] <node_name>", "Add a node to the cluster"), - 'evacuate': (EvacuateNode, ARGS_ONE, + 'evacuate': (EvacuateNode, [ArgNode(min=1, max=1)], [DEBUG_OPT, FORCE_OPT, make_option("-n", "--new-secondary", dest="dst_node", help="New secondary node", metavar="NODE", @@ -636,7 +651,7 @@ commands = { "[-f] {-I <iallocator> | -n <dst>} <node>", "Relocate the secondary instances from a node" " to other nodes (only for instances with drbd disk template)"), - 'failover': (FailoverNode, ARGS_ONE, + 'failover': (FailoverNode, [ArgNode(min=1, max=1)], [DEBUG_OPT, FORCE_OPT, make_option("--ignore-consistency", dest="ignore_consistency", action="store_true", default=False, @@ -646,7 +661,7 @@ commands = { "[-f] <node>", "Stops the primary instances on a node and start them on their" " secondary node (only for instances with drbd disk template)"), - 'migrate': (MigrateNode, ARGS_ONE, + 'migrate': (MigrateNode, [ArgNode(min=1, max=1)], [DEBUG_OPT, FORCE_OPT, make_option("--non-live", dest="live", default=True, action="store_false", @@ -658,16 +673,16 @@ commands = { "[-f] <node>", "Migrate all the primary instance on a node away from it" " (only for instances of type drbd)"), - 'info': (ShowNodeConfig, ARGS_ANY, [DEBUG_OPT], + 'info': (ShowNodeConfig, [ArgNode()], [DEBUG_OPT], "[<node_name>...]", "Show information about the node(s)"), - 'list': (ListNodes, ARGS_ANY, + 'list': (ListNodes, [ArgNode()], [DEBUG_OPT, NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT, SYNC_OPT], "[nodes...]", "Lists the nodes in the cluster. The available fields" " are (see the man page for details): %s" " The default field list is (in order): %s." % (", ".join(_LIST_HEADERS), ", ".join(_LIST_DEF_FIELDS))), - 'modify': (SetNodeParams, ARGS_ONE, + 'modify': (SetNodeParams, [ArgNode(min=1, max=1)], [DEBUG_OPT, FORCE_OPT, SUBMIT_OPT, make_option("-C", "--master-candidate", dest="master_candidate", @@ -681,28 +696,25 @@ commands = { choices=('yes', 'no'), default=None, help="Set the drained flag on the node"), ], - "<instance>", "Alters the parameters of an instance"), - 'powercycle': (PowercycleNode, ARGS_ONE, [DEBUG_OPT, FORCE_OPT, CONFIRM_OPT], + "<node>", "Alters the parameters of a node"), + 'powercycle': (PowercycleNode, [ArgNode(min=1, max=1)], + [DEBUG_OPT, FORCE_OPT, CONFIRM_OPT], "<node_name>", "Tries to forcefully powercycle a node"), - 'remove': (RemoveNode, ARGS_ONE, [DEBUG_OPT], + 'remove': (RemoveNode, [ArgNode(min=1, max=1)], [DEBUG_OPT], "<node_name>", "Removes a node from the cluster"), - 'volumes': (ListVolumes, ARGS_ANY, + 'volumes': (ListVolumes, [ArgNode()], [DEBUG_OPT, NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT], "[<node_name>...]", "List logical volumes on node(s)"), - 'physical-volumes': (ListPhysicalVolumes, ARGS_ANY, + 'physical-volumes': (ListPhysicalVolumes, [ArgNode()], [DEBUG_OPT, NOHDR_OPT, SEP_OPT, USEUNITS_OPT, - FIELDS_OPT, - make_option("--storage-type", - dest="user_storage_type", - choices=_USER_STORAGE_TYPE.keys(), - default=None, - metavar="STORAGE_TYPE", - help=("Storage type (%s)" % - utils.CommaJoin(_USER_STORAGE_TYPE.keys()))), - ], + FIELDS_OPT, _STORAGE_TYPE_OPT], "[<node_name>...]", "List physical volumes on node(s)"), - 'modify-volume': (ModifyVolume, ARGS_FIXED(3), + 'modify-volume': (ModifyVolume, + [ArgNode(min=1, max=1), + ArgChoice(min=1, max=1, + choices=_MODIFIABLE_STORAGE_TYPES), + ArgFile(min=1, max=1)], [DEBUG_OPT, make_option("--allocatable", dest="allocatable", choices=["yes", "no"], default=None, @@ -711,15 +723,21 @@ commands = { ], "<node_name> <storage_type> <name>", "Modify storage volume on a node"), - 'repair-volume': (RepairVolume, ARGS_FIXED(3), + 'repair-volume': (RepairVolume, + [ArgNode(min=1, max=1), + ArgChoice(min=1, max=1, + choices=_REPAIRABLE_STORAGE_TYPES), + ArgFile(min=1, max=1)], [DEBUG_OPT], "<node_name> <storage_type> <name>", "Repairs a storage volume on a node"), - 'list-tags': (ListTags, ARGS_ONE, [DEBUG_OPT], + 'list-tags': (ListTags, [ArgNode(min=1, max=1)], [DEBUG_OPT], "<node_name>", "List the tags of the given node"), - 'add-tags': (AddTags, ARGS_ATLEAST(1), [DEBUG_OPT, TAG_SRC_OPT], + 'add-tags': (AddTags, [ArgNode(min=1, max=1), ArgUnknown()], + [DEBUG_OPT, TAG_SRC_OPT], "<node_name> tag...", "Add tags to the given node"), - 'remove-tags': (RemoveTags, ARGS_ATLEAST(1), [DEBUG_OPT, TAG_SRC_OPT], + 'remove-tags': (RemoveTags, [ArgNode(min=1, max=1), ArgUnknown()], + [DEBUG_OPT, TAG_SRC_OPT], "<node_name> tag...", "Remove tags from the given node"), } diff --git a/scripts/gnt-os b/scripts/gnt-os index 4cfa07bf0e307fd0feaa366df6bdfe77aedd9d4e..41d3dca4df4c51fdf7e2cd556c97792eeaf3688c 100755 --- a/scripts/gnt-os +++ b/scripts/gnt-os @@ -146,9 +146,9 @@ def DiagnoseOS(opts, args): commands = { - 'list': (ListOS, ARGS_NONE, [DEBUG_OPT, NOHDR_OPT], "", + 'list': (ListOS, [], [DEBUG_OPT, NOHDR_OPT], "", "Lists all valid OSes on the master"), - 'diagnose': (DiagnoseOS, ARGS_NONE, [DEBUG_OPT], "", + 'diagnose': (DiagnoseOS, [], [DEBUG_OPT], "", "Diagnose all OSes"), }