Commit 846baef9 authored by Iustin Pop's avatar Iustin Pop

Implement command-line tags support

This patch adds generic functions for tag manipulations to cli.py and
modifies gnt-{cluster,node,instance} to export {list,add,remove}-tags
commands that use those.

Reviewed-by: imsnah
parent f27302fa
......@@ -32,6 +32,7 @@ from ganeti import logger
from ganeti import errors
from ganeti import mcpu
from ganeti import constants
from ganeti import opcodes
from optparse import (OptionParser, make_option, TitledHelpFormatter,
Option, OptionValueError, SUPPRESS_HELP)
......@@ -39,7 +40,81 @@ from optparse import (OptionParser, make_option, TitledHelpFormatter,
__all__ = ["DEBUG_OPT", "NOHDR_OPT", "SEP_OPT", "GenericMain", "SubmitOpCode",
"cli_option", "GenerateTable", "AskUser",
"ARGS_NONE", "ARGS_FIXED", "ARGS_ATLEAST", "ARGS_ANY", "ARGS_ONE",
"USEUNITS_OPT", "FIELDS_OPT", "FORCE_OPT"]
"USEUNITS_OPT", "FIELDS_OPT", "FORCE_OPT",
"ListTags", "AddTags", "RemoveTags",
]
def _ExtractTagsObject(opts, args):
"""Extract the tag type object.
Note that this function will modify its args parameter.
"""
if not hasattr(opts, "tag_type"):
raise errors.ProgrammerError("tag_type not passed to _ExtractTagsObject")
kind = opts.tag_type
if kind == constants.TAG_CLUSTER:
retval = kind, kind
elif kind == constants.TAG_NODE or kind == constants.TAG_INSTANCE:
if not args:
raise errors.OpPrereq("no arguments passed to the command")
name = args.pop(0)
retval = kind, name
else:
raise errors.ProgrammerError("Unhandled tag type '%s'" % kind)
return retval
def ListTags(opts, args):
"""List the tags on a given object.
This is a generic implementation that knows how to deal with all
three cases of tag objects (cluster, node, instance). The opts
argument is expected to contain a tag_type field denoting what
object type we work on.
"""
kind, name = _ExtractTagsObject(opts, args)
op = opcodes.OpGetTags(kind=kind, name=name)
result = SubmitOpCode(op)
result = list(result)
result.sort()
for tag in result:
print tag
def AddTags(opts, args):
"""Add tags on a given object.
This is a generic implementation that knows how to deal with all
three cases of tag objects (cluster, node, instance). The opts
argument is expected to contain a tag_type field denoting what
object type we work on.
"""
kind, name = _ExtractTagsObject(opts, args)
if not args:
raise errors.OpPrereqError("No tags to be added")
op = opcodes.OpAddTags(kind=kind, name=name, tags=args)
SubmitOpCode(op)
def RemoveTags(opts, args):
"""Remove tags from a given object.
This is a generic implementation that knows how to deal with all
three cases of tag objects (cluster, node, instance). The opts
argument is expected to contain a tag_type field denoting what
object type we work on.
"""
kind, name = _ExtractTagsObject(opts, args)
if not args:
raise errors.OpPrereqError("No tags to be removed")
op = opcodes.OpDelTags(kind=kind, name=name, tags=args)
SubmitOpCode(op)
DEBUG_OPT = make_option("-d", "--debug", default=False,
action="store_true",
......@@ -68,7 +143,6 @@ FORCE_OPT = make_option("-f", "--force", dest="force", action="store_true",
_LOCK_OPT = make_option("--lock-retries", default=None,
type="int", help=SUPPRESS_HELP)
def ARGS_FIXED(val):
"""Macro-like function denoting a fixed number of arguments"""
return -val
......
......@@ -263,7 +263,13 @@ commands = {
"Runs a command on all (or only some) nodes"),
'info': (ShowClusterConfig, ARGS_NONE, [DEBUG_OPT],
"", "Show cluster configuration"),
'list-tags': (ListTags, ARGS_NONE,
[DEBUG_OPT], "", "List the tags of the cluster"),
'add-tags': (AddTags, ARGS_ANY, [DEBUG_OPT],
"tag...", "Add tags to the cluster"),
'remove-tags': (RemoveTags, ARGS_ANY, [DEBUG_OPT],
"tag...", "Remove tags from the cluster"),
}
if __name__ == '__main__':
sys.exit(GenericMain(commands))
sys.exit(GenericMain(commands, override={"tag_type": constants.TAG_CLUSTER}))
......@@ -754,7 +754,14 @@ commands = {
'deactivate-disks': (DeactivateDisks, ARGS_ONE, [DEBUG_OPT],
"<instance>",
"Deactivate an instance's disks"),
'list-tags': (ListTags, ARGS_ONE, [DEBUG_OPT],
"<node_name>", "List the tags of the given instance"),
'add-tags': (AddTags, ARGS_ATLEAST(1), [DEBUG_OPT],
"<node_name> tag...", "Add tags to the given instance"),
'remove-tags': (RemoveTags, ARGS_ATLEAST(1), [DEBUG_OPT],
"<node_name> tag...", "Remove tags from given instance"),
}
if __name__ == '__main__':
sys.exit(GenericMain(commands))
sys.exit(GenericMain(commands,
override={"tag_type": constants.TAG_INSTANCE}))
......@@ -26,6 +26,7 @@ from ganeti.cli import *
from ganeti import opcodes
from ganeti import logger
from ganeti import utils
from ganeti import constants
def AddNode(opts, args):
......@@ -180,8 +181,14 @@ commands = {
'volumes': (ListVolumes, ARGS_ANY,
[DEBUG_OPT, NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT],
"[<node_name>...]", "List logical volumes on node(s)"),
'list-tags': (ListTags, ARGS_ONE, [DEBUG_OPT],
"<node_name>", "List the tags of the given node"),
'add-tags': (AddTags, ARGS_ATLEAST(1), [DEBUG_OPT],
"<node_name> tag...", "Add tags to the given node"),
'remove-tags': (RemoveTags, ARGS_ATLEAST(1), [DEBUG_OPT],
"<node_name> tag...", "Remove tags from the given node"),
}
if __name__ == '__main__':
sys.exit(GenericMain(commands))
sys.exit(GenericMain(commands, override={"tag_type": constants.TAG_NODE}))
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment