This relies on the ReqConfigQuery and takes several RFC6901 paths and
will return a table of the keys and values. The data accessible is the
same as in config.data (typically found at /var/lib/ganeti/config.data).

Signed-off-by: Aaron Karper <[email protected]>
---
 tools/query-config | 148 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 148 insertions(+)
 create mode 100755 tools/query-config

diff --git a/tools/query-config b/tools/query-config
new file mode 100755
index 0000000..37505f1
--- /dev/null
+++ b/tools/query-config
@@ -0,0 +1,148 @@
+#!/usr/bin/python
+#
+
+# Copyright (C) 2014 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
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+
+
+"""Tool to query the cluster configuration over RConfD
+
+"""
+
+# functions in this module need to have a given name structure, so:
+# pylint: disable=C0103
+
+
+import optparse
+import sys
+import logging
+
+from ganeti import constants
+from ganeti import cli
+from ganeti import utils
+from ganeti import pathutils
+
+from ganeti.confd import client as confd_client
+
+USAGE = ("\tquery-config [--addr=host] [--hmac=key] QUERY [QUERY...]")
+
+OPTIONS = [
+  cli.cli_option("--hmac", dest="hmac", default=None,
+                 help="Specify HMAC key instead of reading"
+                 " it from the filesystem",
+                 metavar="<KEY>"),
+  cli.cli_option("-a", "--address", dest="mc", default="127.0.0.1",
+                 help="Server IP to query (default: 127.0.0.1)",
+                 metavar="<ADDRESS>"),
+  cli.cli_option("-r", "--requests", dest="requests", default=100,
+                 help="Number of requests for the timing tests",
+                 type="int", metavar="<REQUESTS>"),
+  ]
+logging.basicConfig()
+log = logging.getLogger()
+log.setLevel(logging.INFO)
+
+def Err(msg, exit_code=1):
+  """Simple error logging that prints to stderr.
+
+  """
+  sys.stderr.write(msg + "\n")
+  sys.stderr.flush()
+  sys.exit(exit_code)
+
+
+def Usage():
+  """Shows program usage information and exits the program."""
+
+  print >> sys.stderr, "Usage:"
+  print >> sys.stderr, USAGE
+  sys.exit(2)
+
+class QueryClient(object):
+  """Confd client for querying the configuration JSON."""
+  def __init__(self):
+    """Constructor."""
+    self.opts = None
+    self.cluster_master = None
+    self.instance_ips = None
+    self.is_timing = False
+    self.ParseOptions()
+
+  def ParseOptions(self):
+    """Parses the command line options.
+
+    In case of command line errors, it will show the usage and exit the
+    program.
+
+    @return: a tuple (options, args), as returned by OptionParser.parse_args
+
+    """
+    parser = optparse.OptionParser(usage="\n%s" % USAGE,
+                                  version=("%%prog (ganeti) %s" %
+                                            constants.RELEASE_VERSION),
+                                  option_list=OPTIONS)
+
+    options, args = parser.parse_args()
+    if args == []:
+      Usage()
+
+    self.paths = args
+
+    if options.hmac is None:
+      options.hmac = utils.ReadFile(pathutils.CONFD_HMAC_KEY)
+
+    self.hmac_key = options.hmac
+
+    self.mc_list = [options.mc]
+
+    self.opts = options
+
+  def Run(self):
+    self.store_callback = confd_client.StoreResultCallback()
+
+    self.confd_client = confd_client.ConfdClient(self.hmac_key,
+                                      self.mc_list,
+                                      self.store_callback)
+
+    responses = []
+    for path in self.paths:
+      log.info('request %s' % path)
+      req = confd_client.ConfdClientRequest(
+        type=constants.CONFD_REQ_CONFIG_QUERY, query=path)
+      _, response = self.DoConfdRequestReply(req)
+      responses.append(str(response.server_reply.answer))
+    table = zip(self.paths, responses)
+    longest_path = max(len(p) for p in self.paths)
+    for p, a in table:
+      print "%s\t%s" % (p.ljust(longest_path), a)
+
+  def DoConfdRequestReply(self, req):
+    """Send request to Confd and await all responses."""
+    self.confd_client.SendRequest(req, async=False)
+    if not self.confd_client.ReceiveReply():
+      Err("Did not receive all expected confd replies")
+    return self.store_callback.GetResponse(req.rsalt)
+
+def main():
+  """Application entry point.
+
+  """
+  QueryClient().Run()
+
+
+if __name__ == "__main__":
+  main()
-- 
2.0.0.526.g5318336

Reply via email to