Skip to content
Permalink
Browse files

Refactor host / service reschedule action

* Use our standard AJAX mechanism (on JS and python side)
* Fix previously broken transport of data between Python and JS

Change-Id: I907c13551a295cd33f037bf471bc60a624c58d94
  • Loading branch information
LarsMichelsen committed Mar 24, 2020
1 parent de5226d commit 774584049c7cb22801375898a24e803a462bfe5a
@@ -197,8 +197,8 @@ def render(self, what, row, tags, custom_vars):
icon = 'reload_cmk'
txt = _('Reschedule \'Check_MK\' service')

url = 'onclick:cmk.views.reschedule_check(this, \'%s\', \'%s\', \'%s\', \'%s\');' % \
(row["site"], row["host_name"], html.urlencode(servicedesc), html.urlencode(wait_svc))
url = 'onclick:cmk.views.reschedule_check(this, %s, %s, %s, %s);' % \
(json.dumps(row["site"]), json.dumps(row["host_name"]), json.dumps(servicedesc), json.dumps(wait_svc))
# _self is needed to prevent wrong linking when views are parts of dashlets
return icon, txt, (url, "_self")

@@ -2690,73 +2690,78 @@ def ajax_popup_action_menu():
# '----------------------------------------------------------------------'


@cmk.gui.pages.register("ajax_reschedule")
def ajax_reschedule():
try:
do_reschedule()
except Exception as e:
html.write("['ERROR', '%s']\n" % e)

@page_registry.register_page("ajax_reschedule")
class PageRescheduleCheck(AjaxPage):
"""Is called to trigger a host / service check"""
def page(self):
request = html.get_request()
return self._do_reschedule(request)

def do_reschedule():
if not config.user.may("action.reschedule"):
raise MKGeneralException("You are not allowed to reschedule checks.")
def _do_reschedule(self, request):
if not config.user.may("action.reschedule"):
raise MKGeneralException("You are not allowed to reschedule checks.")

site = html.request.var("site")
host = html.request.var("host", "")
if not host:
raise MKGeneralException("Action reschedule: missing host name")
site = request.get("site")
host = request.get("host")
if not host or not site:
raise MKGeneralException("Action reschedule: missing host name")

service = html.request.get_unicode_input("service", "")
wait_svc = html.request.get_unicode_input("wait_svc", "")
service = request.get("service", "")
wait_svc = request.get("wait_svc", "")

if service:
cmd = "SVC"
what = "service"
spec = "%s;%s" % (host, service)
if service:
cmd = "SVC"
what = "service"
spec = "%s;%s" % (host, service)

if wait_svc:
wait_spec = u'%s;%s' % (host, wait_svc)
add_filter = "Filter: service_description = %s\n" % livestatus.lqencode(wait_svc)
if wait_svc:
wait_spec = u'%s;%s' % (host, wait_svc)
add_filter = "Filter: service_description = %s\n" % livestatus.lqencode(wait_svc)
else:
wait_spec = spec
add_filter = "Filter: service_description = %s\n" % livestatus.lqencode(service)
else:
cmd = "HOST"
what = "host"
spec = host
wait_spec = spec
add_filter = "Filter: service_description = %s\n" % livestatus.lqencode(service)
else:
cmd = "HOST"
what = "host"
spec = host
wait_spec = spec
add_filter = ""
add_filter = ""

try:
now = int(time.time())
sites.live().command(
"[%d] SCHEDULE_FORCED_%s_CHECK;%s;%d" % (now, cmd, livestatus.lqencode(spec), now),
site)
sites.live().set_only_sites([site])
query = u"GET %ss\n" \
"WaitObject: %s\n" \
"WaitCondition: last_check >= %d\n" \
"WaitTimeout: %d\n" \
"WaitTrigger: check\n" \
"Columns: last_check state plugin_output\n" \
"Filter: host_name = %s\n%s" \
% (what, livestatus.lqencode(wait_spec), now, config.reschedule_timeout * 1000, livestatus.lqencode(host), add_filter)
row = sites.live().query_row(query)
sites.live().set_only_sites()

try:
sites.live().set_only_sites([site])
query = u"GET %ss\n" \
"WaitObject: %s\n" \
"WaitCondition: last_check >= %d\n" \
"WaitTimeout: %d\n" \
"WaitTrigger: check\n" \
"Columns: last_check state plugin_output\n" \
"Filter: host_name = %s\n%s" \
% (what, livestatus.lqencode(wait_spec), now, config.reschedule_timeout * 1000, livestatus.lqencode(host), add_filter)
row = sites.live().query_row(query)
finally:
sites.live().set_only_sites()

last_check = row[0]
if last_check < now:
html.write("['TIMEOUT', 'Check not executed within %d seconds']\n" %
(config.reschedule_timeout))
else:
if service == "Check_MK":
# Passive services triggered by Check_MK often are updated
# a few ms later. We introduce a small wait time in order
# to increase the chance for the passive services already
# updated also when we return.
time.sleep(0.7)
html.write("['OK', %d, %d, %r]\n" % (row[0], row[1], row[2]))

except Exception as e:
sites.live().set_only_sites()
raise MKGeneralException(_("Cannot reschedule check: %s") % e)
return {
"state": "TIMEOUT",
"message": _("Check not executed within %d seconds") % (config.reschedule_timeout),
}

if service == "Check_MK":
# Passive services triggered by Check_MK often are updated
# a few ms later. We introduce a small wait time in order
# to increase the chance for the passive services already
# updated also when we return.
time.sleep(0.7)

# Row is currently not used by the frontend, but may be useful for debugging
return {
"state": "OK",
"row": row,
}
@@ -144,46 +144,42 @@ export function reschedule_check(oLink, site, host, service, wait_svc) {
utils.remove_class(img, "reload_failed");
utils.add_class(img, "reloading");

ajax.get_url("ajax_reschedule.py" +
"?site=" + encodeURIComponent(site) +
"&host=" + encodeURIComponent(host) +
"&service=" + service + // Already URL-encoded!
"&wait_svc=" + wait_svc,
reschedule_check_response_handler, img); // eslint-disable-line indent
var post_data = "request=" + encodeURIComponent(JSON.stringify({
"site": site,
"host": host,
"service": service,
"wait_svc": wait_svc,
}));

ajax.call_ajax("ajax_reschedule.py", {
method: "POST",
post_data: post_data,
response_handler: reschedule_check_response_handler,
handler_data: {
img: img,
},
});
}

// Protocol is:
// For regular response:
// [ 'OK', 'last check', 'exit status plugin', 'output' ]
// For timeout:
// [ 'TIMEOUT', 'output' ]
// For error:
// [ 'ERROR', 'output' ]
// Everything else:
// <undefined> - Unknown format. Simply echo.
function reschedule_check_response_handler(img, code) {
var validResponse = true;
var response = null;

function reschedule_check_response_handler(handler_data, ajax_response) {
var img = handler_data.img;
utils.remove_class(img, "reloading");

try {
response = eval(code);
} catch(e) {
validResponse = false;
var response = JSON.parse(ajax_response);
if (response.result_code != 0) {
utils.add_class(img, "reload_failed");
img.title = "Error [" + response.result_code + "]: " + response.result; // eslint-disable-line
return;
}

if(validResponse && response[0] === "OK") {
if (response.result.state === "OK") {
window.location.reload();
} else if(validResponse && response[0] === "TIMEOUT") {
utils.add_class(img, "reload_failed");
img.title = "Timeout while performing action: " + response[1];
} else if(validResponse) {
} else if(response.result.state === "TIMEOUT") {
utils.add_class(img, "reload_failed");
img.title = "Problem while processing - Response: " + response.join(" ");
img.title = "Timeout while performing action: " + response.result.message;
} else {
utils.add_class(img, "reload_failed");
img.title = "Invalid response: " + response;
img.title = response.result.message;
}
}

@@ -650,7 +650,8 @@ img.icon.reloading {
@-webkit-keyframes spin { 100% { -webkit-transform: rotate(360deg); } }
@keyframes spin { 100% { -webkit-transform: rotate(360deg); transform:rotate(360deg); } }

img.iconbutton.reload_failed {
img.iconbutton.reload_failed,
img.icon.reload_failed {
-webkit-filter: sepia(100%);
filter: sepia(100%);
}
@@ -884,7 +884,8 @@ tr.groupheader {
}
}

img.iconbutton {
img.iconbutton,
img.icon {
width: 20px;
height: 20px;
padding: 0 2px;
@@ -907,7 +908,6 @@ img.iconbutton {
}

/* reschedule check icon */
/* TODO: Reproduce these reloading/reload html elements */
img.iconbutton.reloading,
img.icon.reloading {
animation: spin 1s linear infinite;

0 comments on commit 7745840

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