Skip to content

Commit

Permalink
Enh: ability to delete a single downtime
Browse files Browse the repository at this point in the history
This patch bring the ability to delete a single downtime as opposed to
all the downtimes of an host or service in the current implementation,
and remains the default behavior.

This is done by simply providing the parameter `downtime_id` to the
`/downtime` endpoint when `action=delete`.

Also re-indented some code for better readability.
  • Loading branch information
geektophe committed May 11, 2021
1 parent a2b2315 commit 29d6ec3
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 90 deletions.
43 changes: 23 additions & 20 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
.. _ws_daemon_module:

===================
Web Service Module
Web Service Module
===================


The ws-arbiter module is an Arbiter (or Receiver) module to treat requests from remote hosts via HTTP(s).
The ws-arbiter module is an Arbiter (or Receiver) module to treat requests from remote hosts via HTTP(s).


Configuring the Web Service Module
Configuring the Web Service Module
===================================

The module configuration is made in the ws-arbiter.cfg file, in the modules configuration directory. To enable this module, simply add the module to your Arbiter or Receiver daemon configuration.
Expand All @@ -20,7 +20,7 @@ If data is POSTed to this page, it will validate the data to determine if it is
This module listens by default on all IP interfaces, TCP port 7760 and it supports anonymous or authenticated access. This configuration may be changed in the ws-arbiter.cfg file.


Using the Web Service Module
Using the Web Service Module
=============================


Expand All @@ -36,7 +36,7 @@ The web service listens for POSTs to:

- /reload
Makes Shinken reload configuration (/etc/init.d/shinken reload)

Command:
::
curl -u user:password -d '' http://shinken-srv:7760/reload
Expand All @@ -49,15 +49,15 @@ The web service listens for POSTs to:
- action: (default = add)
add, to add an acknowledge for an host/service
delete, to remove current acknowledges on host/service

- host_name:
Host name

- service_description: (default = '' for host acknowledge only)
Service description

- time_stamp: (default = current time)

- sticky: (default = 1)

- notify: (default = 0)
Expand All @@ -68,7 +68,7 @@ The web service listens for POSTs to:

- comment: (default = 'No comment')


Command:
::
curl -u user:password -d "&host_name=host-ack&service_description=service-ack&author=Me&comment=Ack problem" http://shinken-srv:7760/acknowledge
Expand All @@ -81,19 +81,22 @@ The web service listens for POSTs to:
- action: (default = add)
add, to add an acknowledge for an host/service
delete, to remove current downtimes on host/service

- host_name:
Host name

- service_description: (default = '' for host acknowledge only)
Service description


- downtime_id: (default = '')
The downtime id to delete (all downtimes are deleted if missing)

- time_stamp: (default = current time)

- start_time: (default = current time)

- end_time: (default = current time)

- fixed: (default = 1)

- duration: (default = 86400 seconds)
Expand All @@ -104,7 +107,7 @@ The web service listens for POSTs to:

- comment: (default = 'No comment')


Command:
::
curl -u user:password -d "&host_name=host-ack&author=Me&comment=Downtime host" http://shinken-srv:7760/downtime
Expand All @@ -117,11 +120,11 @@ The web service listens for POSTs to:
curl -u user:password -d "time_stamp=$(date +%s)&host_name=host-checked&service_description=service-checked&return_code=0" --data-urlencode "output=Everything OK" http://shinken-srv:7760/push_check_result

Example with more readability:

::

curl
-u user:password
curl
-u user:password
-d "time_stamp=$(date +%s)
&host_name=host-checked
&service_description=service-checked
Expand Down
186 changes: 117 additions & 69 deletions module/module.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@
from shinken.external_command import ExternalCommand
from shinken.log import logger

from shinken.webui.bottlewebui import Bottle, run, static_file, view, route, request, response, abort, parse_auth
from shinken.webui.bottlewebui import Bottle, run, static_file, view, route
from shinken.webui.bottlewebui import request, response, abort, parse_auth

properties = {
'daemons': ['arbiter', 'receiver'],
Expand Down Expand Up @@ -95,9 +96,13 @@ def _compose_command(t, h, s, r, o):
"""Simple function to create a command from the inputs"""
cmd = ""
if not s or s == "":
cmd = '[%s] PROCESS_HOST_CHECK_RESULT;%s;%s;%s' % (t if t is not None else current_time_stamp, h, r, o)
cmd = '[%s] PROCESS_HOST_CHECK_RESULT;%s;%s;%s' % (
t if t is not None else current_time_stamp, h, r, o
)
else:
cmd = '[%s] PROCESS_SERVICE_CHECK_RESULT;%s;%s;%s;%s' % (t if t is not None else current_time_stamp, h, s, r, o)
cmd = '[%s] PROCESS_SERVICE_CHECK_RESULT;%s;%s;%s;%s' % (
t if t is not None else current_time_stamp, h, s, r, o
)
logger.debug("[WS_Arbiter] CMD: %s" % (cmd))
commands.append(cmd)

Expand All @@ -108,7 +113,10 @@ def _compose_command(t, h, s, r, o):
# Sanity check: if we get N return codes, we must have N hosts.
# The other values could be None
if (len(return_codes) != len(hosts)):
logger.error("[WS_Arbiter] number of return codes (%d) does not match number of hosts (%d)" % (len(return_codes), len(hosts)))
logger.error(
"[WS_Arbiter] number of return codes (%d) does not match number "
"of hosts (%d)" % (len(return_codes), len(hosts))
)
abort(400, "number of return codes does not match number of hosts")

map(_compose_command, time_stamps, hosts, services, return_codes, outputs)
Expand All @@ -131,12 +139,21 @@ def get_page():
host_name_list = request.forms.getall(key='host_name')
logger.debug("[WS_Arbiter] host_name_list: %s" % (host_name_list))
service_description_list = request.forms.getall(key='service_description')
logger.debug("[WS_Arbiter] service_description_list: %s" % (service_description_list))
logger.debug(
"[WS_Arbiter] service_description_list: %s" %
(service_description_list)
)
return_code_list = request.forms.getall(key='return_code')
logger.debug("[WS_Arbiter] return_code_list: %s" % (return_code_list))
output_list = request.forms.getall(key='output')
logger.debug("[WS_Arbiter] output_list: %s" % (output_list))
commands_list = get_commands(time_stamp_list, host_name_list, service_description_list, return_code_list, output_list)
commands_list = get_commands(
time_stamp_list,
host_name_list,
service_description_list,
return_code_list,
output_list
)
except Exception, e:
logger.error("[WS_Arbiter] failed to get the lists: %s" % str(e))
commands_list = []
Expand Down Expand Up @@ -194,42 +211,51 @@ def do_acknowledge():
persistent = request.forms.get('persistent', '1')
author = request.forms.get('author', 'anonymous')
comment = request.forms.get('comment', 'No comment')
logger.debug("[WS_Arbiter] Acknowledge %s - host: '%s', service: '%s', comment: '%s'" % (action, host_name, service_description, comment))
logger.debug(
"[WS_Arbiter] Acknowledge %s - host: '%s', service: '%s', "
"comment: '%s'" % (action, host_name, service_description, comment)
)

if not host_name:
abort(400, 'Missing parameter host_name')

if action == 'add':
if service_description:
command = '[%s] ACKNOWLEDGE_SVC_PROBLEM;%s;%s;%s;%s;%s;%s;%s\n' % ( time_stamp,
host_name,
service_description,
sticky,
notify,
persistent,
author,
comment
)
command = '[%s] ACKNOWLEDGE_SVC_PROBLEM;%s;%s;%s;%s;%s;%s;%s\n' % (
time_stamp,
host_name,
service_description,
sticky,
notify,
persistent,
author,
comment
)
else:
command = '[%s] ACKNOWLEDGE_HOST_PROBLEM;%s;%s;%s;%s;%s;%s\n' % ( time_stamp,
host_name,
sticky,
notify,
persistent,
author,
comment
)
command = '[%s] ACKNOWLEDGE_HOST_PROBLEM;%s;%s;%s;%s;%s;%s\n' % (
time_stamp,
host_name,
sticky,
notify,
persistent,
author,
comment
)

if action == 'delete':
if service_description:
# REMOVE_SVC_ACKNOWLEDGEMENT;<host_name>;<service_description>
command = '[%s] REMOVE_SVC_ACKNOWLEDGEMENT;%s;%s\n' % ( time_stamp,
host_name,
service_description)
command = '[%s] REMOVE_SVC_ACKNOWLEDGEMENT;%s;%s\n' % (
time_stamp,
host_name,
service_description
)
else:
# REMOVE_HOST_ACKNOWLEDGEMENT;<host_name>
command = '[%s] REMOVE_HOST_ACKNOWLEDGEMENT;%s\n' % ( time_stamp,
host_name)
command = '[%s] REMOVE_HOST_ACKNOWLEDGEMENT;%s\n' % (
time_stamp,
host_name
)


# logger.warning("[WS_Arbiter] command: %s" % (command))
Expand Down Expand Up @@ -286,6 +312,7 @@ def do_downtime():
time_stamp = request.forms.get('time_stamp', int(time.time()))
host_name = request.forms.get('host_name', '')
service_description = request.forms.get('service_description', '')
downtime_id = request.forms.get('downtime_id', '')
start_time = request.forms.get('start_time', int(time.time()))
end_time = request.forms.get('end_time', int(time.time()))
# Fixed is 1 for a period between start and end time
Expand All @@ -295,59 +322,74 @@ def do_downtime():
trigger_id = request.forms.get('trigger_id', '0')
author = request.forms.get('author', 'anonymous')
comment = request.forms.get('comment', 'No comment')
logger.debug("[WS_Arbiter] Downtime %s - host: '%s', service: '%s', comment: '%s'" % (action, host_name, service_description, comment))
logger.debug(
"[WS_Arbiter] Downtime %s - host: '%s', service: '%s', comment: '%s'" %
(action, host_name, service_description, comment)
)

if not host_name:
abort(400, 'Missing parameter host_name')

if action == 'add':
if service_description:
# SCHEDULE_SVC_DOWNTIME;<host_name>;<service_description>;<start_time>;<end_time>;<fixed>;<trigger_id>;<duration>;<author>;<comment>
command = '[%s] SCHEDULE_SVC_DOWNTIME;%s;%s;%s;%s;%s;%s;%s;%s;%s\n' % ( time_stamp,
host_name,
service_description,
start_time,
end_time,
fixed,
trigger_id,
duration,
author,
comment
)
command = '[%s] SCHEDULE_SVC_DOWNTIME;%s;%s;%s;%s;%s;%s;%s;%s;%s\n' % (
time_stamp,
host_name,
service_description,
start_time,
end_time,
fixed,
trigger_id,
duration,
author,
comment
)
else:
# SCHEDULE_HOST_DOWNTIME;<host_name>;<start_time>;<end_time>;<fixed>;<trigger_id>;<duration>;<author>;<comment>
command = '[%s] SCHEDULE_HOST_DOWNTIME;%s;%s;%s;%s;%s;%s;%s;%s\n' % ( time_stamp,
host_name,
start_time,
end_time,
fixed,
trigger_id,
duration,
author,
comment
)
command = '[%s] SCHEDULE_HOST_DOWNTIME;%s;%s;%s;%s;%s;%s;%s;%s\n' % (
time_stamp,
host_name,
start_time,
end_time,
fixed,
trigger_id,
duration,
author,
comment
)

if action == 'delete':
if service_description:
# DEL_ALL_SVC_DOWNTIMES;<host_name>;<service_description>
command = '[%s] DEL_ALL_SVC_DOWNTIMES;%s;%s\n' % ( time_stamp,
host_name,
service_description)
if downtime_id:
# DEL_SVC_DOWNTIMES;<downtime_id>
command = '[%s] DEL_SVC_DOWNTIME;%s\n' % (
time_stamp,
downtime_id
)
else:
# DEL_ALL_SVC_DOWNTIMES;<host_name>;<service_description>
command = '[%s] DEL_ALL_SVC_DOWNTIMES;%s;%s\n' % (
time_stamp,
host_name,
service_description
)
else:
# DEL_ALL_SVC_DOWNTIMES;<host_name>
command = '[%s] DEL_ALL_HOST_DOWNTIMES;%s\n' % ( time_stamp,
host_name)

if downtime_id:
# DEL_HOST_DOWNTIMES;<downtime_id>
command = '[%s] DEL_HOST_DOWNTIME;%s\n' % (
time_stamp,
downtime_id
)
else:
# DEL_ALL_SVC_DOWNTIMES;<host_name>
command = '[%s] DEL_ALL_HOST_DOWNTIMES;%s\n' % (
time_stamp,
host_name
)

# We check for auth if it's not anonymously allowed
if app.username != 'anonymous':
basic = parse_auth(request.environ.get('HTTP_AUTHORIZATION', ''))
# Maybe the user not even ask for user/pass. If so, bail out
if not basic:
abort(401, 'Authentication required')
# Maybe he do not give the good credential?
if basic[0] != app.username or basic[1] != app.password:
abort(403, 'Authentication denied')
check_auth()

# Adding commands to the main queue()
logger.debug("[WS_Arbiter] command = %s" % command)
Expand All @@ -374,9 +416,15 @@ def __init__(self, modconf):
if self.routes is not None:
self.routes = self.routes.split(',')

logger.info("[WS_Arbiter] Configuration done, host: %s(%s), username: %s)" %(self.host, self.port, self.username))
logger.info(
"[WS_Arbiter] Configuration done, host: %s(%s), username: %s)" %
(self.host, self.port, self.username)
)
except AttributeError:
logger.error("[WS_Arbiter] The module is missing a property, check module declaration in shinken-specific.cfg")
logger.error(
"[WS_Arbiter] The module is missing a property, check module "
"declaration in shinken-specific.cfg"
)
raise
except Exception, e:
logger.error("[WS_Arbiter] Exception : %s" % str(e))
Expand Down
Loading

0 comments on commit 29d6ec3

Please sign in to comment.