From 7341571946d86252eb3f43c0f9957e1ba4d92336 Mon Sep 17 00:00:00 2001 From: Iustin Pop <iustin@google.com> Date: Sat, 3 Nov 2007 06:55:50 +0000 Subject: [PATCH] Implement tag searching This patch adds a search command for locating tags on all objects of the cluster using a regex pattern. Reviewed-by: aat --- lib/cmdlib.py | 36 ++++++++++++++++++++++++++++++++++++ lib/mcpu.py | 1 + lib/opcodes.py | 6 ++++++ man/gnt-cluster.sgml | 36 ++++++++++++++++++++++++++++++++++++ scripts/gnt-cluster | 17 +++++++++++++++++ 5 files changed, 96 insertions(+) diff --git a/lib/cmdlib.py b/lib/cmdlib.py index 829c01913..5864ee1cf 100644 --- a/lib/cmdlib.py +++ b/lib/cmdlib.py @@ -4141,6 +4141,42 @@ class LUGetTags(TagsLU): return self.target.GetTags() +class LUSearchTags(NoHooksLU): + """Searches the tags for a given pattern. + + """ + _OP_REQP = ["pattern"] + + def CheckPrereq(self): + """Check prerequisites. + + This checks the pattern passed for validity by compiling it. + + """ + try: + self.re = re.compile(self.op.pattern) + except re.error, err: + raise errors.OpPrereqError("Invalid search pattern '%s': %s" % + (self.op.pattern, err)) + + def Exec(self, feedback_fn): + """Returns the tag list. + + """ + cfg = self.cfg + tgts = [("/cluster", cfg.GetClusterInfo())] + ilist = [cfg.GetInstanceInfo(name) for name in cfg.GetInstanceList()] + tgts.extend([("/instances/%s" % i.name, i) for i in ilist]) + nlist = [cfg.GetNodeInfo(name) for name in cfg.GetNodeList()] + tgts.extend([("/nodes/%s" % n.name, n) for n in nlist]) + results = [] + for path, target in tgts: + for tag in target.GetTags(): + if self.re.search(tag): + results.append((path, tag)) + return results + + class LUAddTags(TagsLU): """Sets a tag on a given object. diff --git a/lib/mcpu.py b/lib/mcpu.py index 139a3bd68..5226fd7ff 100644 --- a/lib/mcpu.py +++ b/lib/mcpu.py @@ -80,6 +80,7 @@ class Processor(object): opcodes.OpExportInstance: cmdlib.LUExportInstance, # tags lu opcodes.OpGetTags: cmdlib.LUGetTags, + opcodes.OpSearchTags: cmdlib.LUSearchTags, opcodes.OpAddTags: cmdlib.LUAddTags, opcodes.OpDelTags: cmdlib.LUDelTags, } diff --git a/lib/opcodes.py b/lib/opcodes.py index 43cefaeea..99f44392c 100644 --- a/lib/opcodes.py +++ b/lib/opcodes.py @@ -263,6 +263,12 @@ class OpGetTags(OpCode): __slots__ = ["kind", "name"] +class OpSearchTags(OpCode): + """Searches the tags in the cluster for a given pattern.""" + OP_ID = "OP_TAGS_SEARCH" + __slots__ = ["pattern"] + + class OpAddTags(OpCode): """Add a list of tags on a given object.""" OP_ID = "OP_TAGS_SET" diff --git a/man/gnt-cluster.sgml b/man/gnt-cluster.sgml index 5781c0949..4f5560297 100644 --- a/man/gnt-cluster.sgml +++ b/man/gnt-cluster.sgml @@ -301,6 +301,42 @@ </para> </refsect2> + <refsect2> + <title>SEARCH-TAGS</title> + + <cmdsynopsis> + <command>search-tags</command> + <arg choice="req"><replaceable>pattern</replaceable></arg> + </cmdsynopsis> + + <para> + Searches the tags on all objects in the cluster (the cluster + itself, the nodes and the instances) for a given pattern. The + pattern is interpreted as a regular expression and a search + will be done on it (i.e. the given pattern is not anchored to + the beggining of the string; if you want that, prefix the + pattern with <literal>^</literal>). + </para> + + <para> + If no tags are matching the pattern, the exit code of the + command will be one. If there is at least one match, the exit + code will be zero. Each match is listed on one line, the + object and the tag separated by a space. The cluster will be + listed as <filename>/cluster</filename>, a node will be listed + as + <filename>/nodes/<replaceable>name</replaceable></filename>, + and an instance as + <filename>/instances/<replaceable>name</replaceable></filename>. + Example: + </para> +<screen> +# gnt-cluster search time +/cluster ctime:2007-09-01 +/nodes/node1.example.com mtime:2007-10-04 +</screen> + </refsect2> + <refsect2> <title>VERIFY</title> diff --git a/scripts/gnt-cluster b/scripts/gnt-cluster index 9be9904a8..42451a59f 100755 --- a/scripts/gnt-cluster +++ b/scripts/gnt-cluster @@ -193,6 +193,20 @@ def MasterFailover(opts, args): SubmitOpCode(op) +def SearchTags(opts, args): + """Searches the tags on all the cluster. + + """ + op = opcodes.OpSearchTags(pattern=args[0]) + result = SubmitOpCode(op) + if not result: + return 1 + result = list(result) + result.sort() + for path, tag in result: + print "%s %s" % (path, tag) + + # this is an option common to more than one command, so we declare # it here and reuse it node_option = make_option("-n", "--node", action="append", dest="nodes", @@ -269,6 +283,9 @@ commands = { "tag...", "Add tags to the cluster"), 'remove-tags': (RemoveTags, ARGS_ANY, [DEBUG_OPT, TAG_SRC_OPT], "tag...", "Remove tags from the cluster"), + 'search-tags': (SearchTags, ARGS_ONE, + [DEBUG_OPT], "", "Searches the tags on all objects on" + " the cluster for a given pattern (regex)"), } if __name__ == '__main__': -- GitLab