Skip to content
Permalink
Browse files

Forecast Graphs

New graph class with live editor
Refactor and module split
Report element

CMK-2440

Change-Id: Iedcb01be3c3d5c3424a470ee141eaefc419980bb
  • Loading branch information...
Titan-C authored and LarsMichelsen committed Jul 29, 2019
1 parent 148fa0a commit c8d6c7394cc74cc4eea45ce45b107ab075b154cc
@@ -914,7 +914,7 @@ def page_host_service_graph_popup():

# TODO: Refactor this to some OO based approach
if cmk_graphs_possible(site_id):
import cmk.gui.cee.plugins.metrics.graphs as graphs
import cmk.gui.cee.plugins.metrics.html_render as graphs
graphs.host_service_graph_popup_cmk(site_id, host_name, service_description)
else:
host_service_graph_popup_pnp(site_id, host_name, service_description)
@@ -962,7 +962,7 @@ def page_graph_dashlet():

# TODO: Refactor this to some OO based approach
if cmk_graphs_possible():
import cmk.gui.cee.plugins.metrics.graphs as graphs
import cmk.gui.cee.plugins.metrics.html_render as graphs
graphs.host_service_graph_dashlet_cmk(graph_identification, custom_graph_render_options)
elif graph_identification[0] == "template":
host_service_graph_dashlet_pnp(graph_identification)
@@ -1010,10 +1010,10 @@ def render_metrics_table(translated_metrics, host_name, service_description):
output += "<td>"
output += html.render_popup_trigger(
html.render_icon("custom_graph",
title=_("Add this metric to a custom graph"),
title=_("Add this metric to dedicated graph"),
cssclass="iconbutton"),
ident="add_metric_to_graph_" + host_name + ";" + service_description,
what="add_metric_to_custom_graph",
what="add_metric_to_graph",
url_vars=[
("host", host_name),
("service", service_description),
@@ -112,11 +112,13 @@ def _parameter_elements(cls):

import cmk.gui.metrics as metrics
if metrics.cmk_graphs_possible():
import cmk.gui.cee.plugins.metrics.graphs as graphs
from cmk.gui.cee.plugins.metrics.html_render import default_dashlet_graph_render_options
from cmk.gui.cee.plugins.metrics.valuespecs import vs_graph_render_options

elements += [
("graph_render_options",
graphs.vs_graph_render_options(
default_values=graphs.default_dashlet_graph_render_options,
vs_graph_render_options(
default_values=default_dashlet_graph_render_options,
exclude=[
"show_time_range_previews",
],
@@ -298,26 +298,31 @@ def perfvar_translation(perfvar_name, check_command):
}


def scalar_bounds(perfvar_bounds, scale):
"""rescale "warn, crit, min, max" PERFVAR_BOUNDS values
Return "None" entries if no performance data and hence no scalars are available
"""

scalars = {}
for name, value in zip(("warn", "crit", "min", "max"), perfvar_bounds):
if value is not None:
scalars[name] = float(value) * scale
return scalars


def normalize_perf_data(perf_data, check_command):
translation_entry = perfvar_translation(perf_data[0], check_command)

new_entry = {
"orig_name": perf_data[0],
"value": perf_data[1] * translation_entry["scale"],
"scalar": {},
"scalar": scalar_bounds(perf_data[3:], translation_entry["scale"]),
"scale": translation_entry["scale"], # needed for graph recipes
# Do not create graphs for ungraphed metrics if listed here
"auto_graph": translation_entry["auto_graph"],
}

# Add warn, crit, min, max
for perf_value, name in zip(perf_data[3:], ["warn", "crit", "min", "max"]):
if perf_value is not None:
try:
new_entry["scalar"][name] = float(perf_value) * translation_entry["scale"]
except Exception as exc:
if config.debug:
raise exc
return translation_entry["name"], new_entry


@@ -360,10 +365,6 @@ def translate_metrics(perf_data, check_command):
new_entry["unit"] = unit_info[new_entry["unit"]]

translated_metrics[metric_name] = new_entry
# TODO: warn, crit, min, max
# if entry[2]:
# # TODO: lower and upper levels
# translated_metrics[metric_name]["warn"] = float(entry[2])
return translated_metrics


@@ -433,6 +433,8 @@ def page_list(what,
html.context_button(_("Graph collections"), "graph_collections.py", "graph_collection")
if pagetypes.has_page_type("custom_graph"):
html.context_button(_("Custom graphs"), "custom_graphs.py", "custom_graph")
if pagetypes.has_page_type("forecast_graph"):
html.context_button(_("Forecast Graphs"), "forecast_graphs.py", "forecast_graph")
if pagetypes.has_page_type("graph_tuning"):
html.context_button(_("Graph tunings"), "graph_tunings.py", "graph_tuning")
if pagetypes.has_page_type("sla_configuration"):
@@ -28,6 +28,7 @@
import json
import time

import six
# suppress "Cannot find module" error from mypy
import livestatus # type: ignore
from livestatus import MKLivestatusNotFoundError
@@ -67,12 +68,25 @@ class TimeSeries(object):
which means they are at the end of the interval.
- The Series describes the interval [start; end[
- Start has no associated value to it.
args:
data : List
Includes [start, end, step, *values]
timewindow: tuple
describes (start, end, step), in this case data has only values
"""
def __init__(self, data):
self.start = data[0]
self.end = data[1]
self.step = data[2]
self.values = data[3:]
def __init__(self, data, timewindow=None):
if timewindow:
self.start = timewindow[0]
self.end = timewindow[1]
self.step = timewindow[2]
self.values = data
else:
self.start = data[0]
self.end = data[1]
self.step = data[2]
self.values = data[3:]

@property
def twindow(self):
@@ -110,6 +124,40 @@ def __eq__(self, other):

return self.start == other.start and self.end == other.end and self.step == other.step and self.values == other.values

def __getitem__(self, i):
return self.values[i]

def __len__(self):
return len(self.values)


def lq_logic(filter_condition, values, join):
"""JOIN with (Or, And) FILTER_CONDITION the VALUES for a livestatus query"""
if isinstance(values, six.string_types):
values = [values]
conds = ["%s %s" % (filter_condition, livestatus.lqencode(x)) for x in values]
if len(conds) > 1:
return "\n".join(conds) + "\n%s: %d\n" % (join, len(conds))
if conds:
return conds[0] + '\n'
return ""


def livestatus_lql(host_names, columns, service_descriptions=None):
if isinstance(columns, list):
columns = " ".join(columns)

query_filter = "Columns: %s\n" % columns
query_filter += lq_logic("Filter: host_name =", host_names, "Or")

if service_descriptions == "_HOST_" or service_descriptions is None:
what = 'host'
else:
what = 'service'
query_filter += lq_logic("Filter: service_description =", service_descriptions, "Or")

return "GET %ss\n%s" % (what, query_filter)


def get_rrd_data(hostname, service_description, varname, cf, fromtime, untiltime, max_entries=400):
"""Fetch RRD historic metrics data of a specific service, within the specified time range
@@ -136,14 +184,11 @@ def get_rrd_data(hostname, service_description, varname, cf, fromtime, untiltime

step = 1
rpn = "%s.%s" % (varname, cf.lower()) # "MAX" -> "max"
point_range = ":".join(
livestatus.lqencode(str(x)) for x in (fromtime, untiltime, step, max_entries))
column = "rrddata:m1:%s:%s" % (rpn, point_range)

lql = "GET services\n" \
"Columns: rrddata:m1:%s:%s:%s:%s:%s\n" \
"OutputFormat: python\n" \
"Filter: host_name = %s\n" \
"Filter: description = %s\n" % tuple(map(livestatus.lqencode,
map(str, (rpn, fromtime, untiltime, step, max_entries,
hostname, service_description))))
lql = livestatus_lql(hostname, column, service_description) + "OutputFormat: python\n"

try:
connection = livestatus.SingleSiteConnection("unix:%s" %
@@ -61,6 +61,7 @@ def test_registered_permission_sections():
('nagvis', (50, u'NagVis', False)),
('view', (50, u'Views', True)),
('icons_and_actions', (50, u'Icons', True)),
('forecast_graph', (50, u'Forecast Graphs', True)),
]

section_names = permission_section_registry.keys()
@@ -105,6 +106,7 @@ def test_registered_permissions():
'general.delete_foreign_custom_graph',
'general.delete_foreign_custom_snapin',
'general.delete_foreign_dashboards',
'general.delete_foreign_forecast_graph',
'general.delete_foreign_graph_collection',
'general.delete_foreign_graph_tuning',
'general.delete_foreign_reports',
@@ -117,10 +119,12 @@ def test_registered_permissions():
'general.edit_custom_graph',
'general.edit_custom_snapin',
'general.edit_dashboards',
'general.edit_forecast_graph',
'general.edit_foreign_bookmark_list',
'general.edit_foreign_custom_graph',
'general.edit_foreign_custom_snapin',
'general.edit_foreign_dashboards',
'general.edit_foreign_forecast_graph',
'general.edit_foreign_graph_collection',
'general.edit_foreign_graph_tuning',
'general.edit_foreign_reports',
@@ -138,6 +142,7 @@ def test_registered_permissions():
'general.force_custom_graph',
'general.force_custom_snapin',
'general.force_dashboards',
'general.force_forecast_graph',
'general.force_graph_collection',
'general.force_graph_tuning',
'general.force_reports',
@@ -157,6 +162,7 @@ def test_registered_permissions():
'general.publish_to_foreign_groups_custom_snapin',
'general.publish_dashboards',
'general.publish_dashboards_to_foreign_groups',
'general.publish_forecast_graph',
'general.publish_graph_collection',
'general.publish_to_foreign_groups_graph_collection',
'general.publish_graph_tuning',
@@ -166,6 +172,7 @@ def test_registered_permissions():
'general.publish_sla_configuration',
'general.publish_to_foreign_groups_sla_configuration',
'general.publish_stored_report',
'general.publish_to_foreign_groups_forecast_graph',
'general.publish_views',
'general.publish_views_to_foreign_groups',
'general.reporting',
@@ -182,6 +189,7 @@ def test_registered_permissions():
'general.see_user_custom_graph',
'general.see_user_custom_snapin',
'general.see_user_dashboards',
'general.see_user_forecast_graph',
'general.see_user_graph_collection',
'general.see_user_graph_tuning',
'general.see_user_reports',
@@ -23,7 +23,7 @@ def test_registered_pages():
'ajax_nagvis_maps_snapin',
'ajax_pagetype_add_element',
'ajax_popup_action_menu',
'ajax_popup_add_metric_to_custom_graph',
'ajax_popup_add_metric_to_graph',
'ajax_popup_add_visual',
'ajax_popup_icon_selector',
'ajax_popup_move_to_folder',
@@ -85,6 +85,7 @@ def test_registered_pages():
'edit_dashboard',
'edit_dashboards',
'edit_dashlet',
'edit_forecast_graph',
'edit_graph_collection',
'edit_graph_tuning',
'edit_report',
@@ -97,6 +98,9 @@ def test_registered_pages():
'edit_views',
'export_views',
'fetch_agent_output',
'forecast_editor',
'forecast_graph',
'forecast_graphs',
'graph_collection',
'graph_collections',
'graph_dashlet',
Binary file not shown.
Binary file not shown.

0 comments on commit c8d6c73

Please sign in to comment.
You can’t perform that action at this time.