Module: check_mk
Branch: master
Commit: a81bc2460034c6a2267cedad69f96cf1a32e0596
URL:
http://git.mathias-kettner.de/git/?p=check_mk.git;a=commit;h=a81bc2460034c6…
Author: Lars Michelsen <lm(a)mathias-kettner.de>
Date: Tue Jul 12 11:07:02 2016 +0200
host_inv_api: Can now handle multiple hosts; Can now be filtered by tree paths
---
.werks/3585 | 70 +++++++++++++++++++++++++++++++++++++++++++++++
web/htdocs/htmllib.py | 15 ++++++++++
web/htdocs/inventory.py | 69 ++++++++++++++++++++++++++++++++++++++++------
web/htdocs/webapi.py | 5 +---
4 files changed, 146 insertions(+), 13 deletions(-)
diff --git a/.werks/3585 b/.werks/3585
index 4e9b753..9d067b4 100644
--- a/.werks/3585
+++ b/.werks/3585
@@ -42,3 +42,73 @@ the <tt>result_code</tt> is set to 1 and the result
contains the error message:
C+:
{"result": "Found no inventory data for this host.",
"result_code": 1}
C+:
+
+
+You can also request data of multiple hosts at once. In this case, you need to specify
your request like this:
+
+<tt>http://[MONITORING-SERVER]/[SITE]/check_mk/host_inv_api.py?request={"hosts":
["host1", "host2"]}&output_format=json</tt>
+
+You will then get an answer that is similar to the answer above. With the difference that
the top level dictionary
+uses the host names as keys and the values are the inventory tree of this host.
+
+C+:
+{
+ "result": {
+ "gestern": {
+ "hardware": {
+ "memory": {
+ "total_ram_usable": 16697307136,
+ "total_swap": 17049841664,
+ "total_vmalloc": 35184372087808
+ }
+ },
+ "networking": {
+ "hostname": "Klappspaten"
+ }
+ },
+ "heute": {
+ "hardware": {
+ "memory": {
+ "total_ram_usable": 16697307136,
+ "total_swap": 17049841664,
+ "total_vmalloc": 35184372087808
+ }
+ },
+ "networking": {
+ "hostname": "Klappspaten"
+ }
+ },
+ "slave": {}
+ },
+ "result_code": 0
+}
+C-:
+
+Another difference in this mode: When a host has no inventory data, the host has an empty
dictionary as value
+instead of providing an error result.
+
+
+If you want to only have a subset of inventory data, you can specify a list of
<i>inventory paths</i> which are then
+used to filter the tree. Only hosts that have those paths will show the trees.
+
+For example, if you only want to see the total and swap memory information of a single
host, you can use the following URL:
+
+<tt>http://[MONITORING-SERVER]/[SITE]/check_mk/host_inv_api.py?host=[HOST]&request={"paths":
[".hardware.memory.total_ram_usable",
".hardware.memory.total_swap"]}&output_format=json</tt>
+
+You will get back only the requested data:
+
+C+:
+{
+ "result": {
+ "": {
+ "hardware": {
+ "memory": {
+ "total_ram_usable": 16697307136,
+ "total_swap": 17049841664
+ }
+ }
+ }
+ },
+ "result_code": 0
+}
+C-:
diff --git a/web/htdocs/htmllib.py b/web/htdocs/htmllib.py
index 4d96a06..8826bc5 100644
--- a/web/htdocs/htmllib.py
+++ b/web/htdocs/htmllib.py
@@ -1314,6 +1314,21 @@ class html(GUITester):
def unstash_vars(self):
self.vars = self.var_stash.pop()
+
+ # Returns a dictionary containing all parameters the user handed over to this
request.
+ # The concept is that the user can either provide the data in a single
"request" variable,
+ # which contains the request data encoded as JSON, or provide multiple GET/POST vars
which
+ # are then used as top level entries in the request object.
+ def get_request(self):
+ request = json.loads(self.var("request", "{}"))
+
+ for key, val in self.all_vars().items():
+ if key not in [ "request", "output_format" ]:
+ request[key] = val
+
+ return request
+
+
def render_javascript(self, code):
return "<script
language=\"javascript\">\n%s\n</script>\n" % code
diff --git a/web/htdocs/inventory.py b/web/htdocs/inventory.py
index 9b89d4b..5f9a6ba 100644
--- a/web/htdocs/inventory.py
+++ b/web/htdocs/inventory.py
@@ -34,7 +34,7 @@ except ImportError:
import config
import sites
-from lib import MKException, MKGeneralException, MKAuthException, lqencode
+from lib import MKException, MKGeneralException, MKAuthException, MKUserError, lqencode
# Load data of a host, cache it in the current HTTP request
def host(hostname):
@@ -303,16 +303,27 @@ def count_items(tree):
# In case of success this is a dictionary containing the host
inventory.
def page_host_inv_api():
try:
- host_name = html.var("host")
- if not may_see(host_name):
- raise MKAuthException(_("Sorry, you are not allowed to access this
host."))
+ request = html.get_request()
- host_inv = host(host_name)
+ # The user can either specify a single host or provide a list of host names. In
case
+ # multiple hosts are handled, there is a top level dict added with "host
> invdict" pairs
+ hosts = request.get("hosts")
+ if hosts:
+ result = {}
+ for host_name in hosts:
+ result[host_name] = inventory_of_host(host_name, request)
- if not host_inv and not has_inventory(host_name):
- raise MKGeneralException(_("Found no inventory data for this
host."))
+ else:
+ host_name = request.get("host")
+ if host_name == None:
+ raise MKUserError("host", _("You need to provide a
\"host\"."))
+
+ result = inventory_of_host(host_name, request)
+
+ if not result and not has_inventory(host_name):
+ raise MKGeneralException(_("Found no inventory data for this
host."))
- response = { "result_code": 0, "result": host_inv }
+ response = { "result_code": 0, "result": result }
except MKException, e:
response = { "result_code": 1, "result": "%s" % e
}
@@ -330,12 +341,52 @@ def page_host_inv_api():
write_python(response)
-def may_see(host_name):
+def inventory_of_host(host_name, request):
+ if not may_see(host_name, site=request.get("site")):
+ raise MKAuthException(_("Sorry, you are not allowed to access the host
%s.") % host_name)
+
+ host_inv = host(host_name)
+
+ if "paths" in request:
+ host_inv = filter_tree_by_paths(host_inv, request["paths"])
+
+ return host_inv
+
+
+def filter_tree_by_paths(tree, paths):
+ filtered = {}
+
+ for path in paths:
+ node = get(tree, path)
+
+ parts = path.split(".")
+ this_tree = filtered
+ while True:
+ key = parts.pop(0)
+ if parts:
+ this_tree = this_tree.setdefault(key, {})
+ else:
+ this_tree[key] = node
+ break
+
+ return filtered
+
+
+def may_see(host_name, site=None):
if config.may("general.see_all"):
return True
+
query = "GET hosts\nStats: state >= 0\nFilter: name = %s\n" %
lqencode(host_name)
+
+ if site:
+ sites.live().set_only_sites([site])
+
result = sites.live().query_summed_stats(query, "ColumnHeaders: off\n")
+
+ if site:
+ sites.live().set_only_sites()
+
if not result:
return False
else:
diff --git a/web/htdocs/webapi.py b/web/htdocs/webapi.py
index 422d321..5440e90 100644
--- a/web/htdocs/webapi.py
+++ b/web/htdocs/webapi.py
@@ -81,10 +81,7 @@ def page_api():
if api_actions[action].get("dont_eval_request"):
request_object = html.var("request")
else:
- request = html.var("request")
- request_object = json.loads(request)
- else:
- request_object = {}
+ request_object = html.get_request()
if api_actions[action].get("locking", True):
lock_exclusive() # unlock is done automatically