Add events
Change-Id: Ic5374b8d99890e804da340f8e90d7d81cb549197
This commit is contained in:
committed by
Vincent Fournier
parent
3c0ac12ebb
commit
cc2df796e2
@@ -1,44 +0,0 @@
|
||||
# Copyright 2014 - Savoir-Faire Linux inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import pecan
|
||||
from pecan import rest
|
||||
|
||||
|
||||
from surveil.api.controllers.v2.logs import acknowledgements
|
||||
from surveil.api.controllers.v2.logs import comments
|
||||
from surveil.api.controllers.v2.logs import downtimes
|
||||
from surveil.api.controllers.v2.logs import notifications
|
||||
from surveil.common import util
|
||||
|
||||
|
||||
class LogsController(rest.RestController):
|
||||
acknowledgements = acknowledgements.AcknowledgementsController()
|
||||
comments = comments.CommentsController()
|
||||
downtimes = downtimes.DowntimesController()
|
||||
notifications = notifications.NotificationsController()
|
||||
|
||||
# @wsme_pecan.wsexpose([Host])
|
||||
@util.policy_enforce(['authenticated'])
|
||||
@pecan.expose()
|
||||
def get_all(self):
|
||||
"""Returns all events from a specific host."""
|
||||
host_name = pecan.request.context.get("host_name")
|
||||
if host_name is not None:
|
||||
return "All events for %s" % host_name
|
||||
return "ALLL Events"
|
||||
|
||||
# @pecan.expose()
|
||||
# def _lookup(self, host_name, *remainder):
|
||||
# return EventController(host_name), remainder
|
||||
@@ -1,29 +0,0 @@
|
||||
# Copyright 2014 - Savoir-Faire Linux inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import pecan
|
||||
from pecan import rest
|
||||
|
||||
from surveil.common import util
|
||||
|
||||
|
||||
class AcknowledgementsController(rest.RestController):
|
||||
|
||||
# curl -X GET http://127.0.0.1:8080/v2/titilambert/myproject/builds/
|
||||
# @wsme_pecan.wsexpose([Host])
|
||||
@util.policy_enforce(['authenticated'])
|
||||
@pecan.expose()
|
||||
def get_all(self):
|
||||
"""Returns all acks from a specific host."""
|
||||
return "ALLL ACK"
|
||||
@@ -1,29 +0,0 @@
|
||||
# Copyright 2014 - Savoir-Faire Linux inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import pecan
|
||||
from pecan import rest
|
||||
|
||||
from surveil.common import util
|
||||
|
||||
|
||||
class CommentsController(rest.RestController):
|
||||
|
||||
# curl -X GET http://127.0.0.1:8080/v2/titilambert/myproject/builds/
|
||||
# @wsme_pecan.wsexpose([Host])
|
||||
@util.policy_enforce(['authenticated'])
|
||||
@pecan.expose()
|
||||
def get_all(self):
|
||||
"""Returns all comments from a specific host."""
|
||||
return "ALLL Comments"
|
||||
@@ -1,29 +0,0 @@
|
||||
# Copyright 2014 - Savoir-Faire Linux inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import pecan
|
||||
from pecan import rest
|
||||
|
||||
from surveil.common import util
|
||||
|
||||
|
||||
class DowntimesController(rest.RestController):
|
||||
|
||||
# curl -X GET http://127.0.0.1:8080/v2/titilambert/myproject/builds/
|
||||
# @wsme_pecan.wsexpose([Host])
|
||||
@util.policy_enforce(['authenticated'])
|
||||
@pecan.expose()
|
||||
def get_all(self):
|
||||
"""Returns all downtimes from a specific host."""
|
||||
return "ALLL DT"
|
||||
@@ -1,29 +0,0 @@
|
||||
# Copyright 2014 - Savoir-Faire Linux inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import pecan
|
||||
from pecan import rest
|
||||
|
||||
from surveil.common import util
|
||||
|
||||
|
||||
class NotificationsController(rest.RestController):
|
||||
|
||||
# curl -X GET http://127.0.0.1:8080/v2/titilambert/myproject/builds/
|
||||
# @wsme_pecan.wsexpose([Host])
|
||||
@util.policy_enforce(['authenticated'])
|
||||
@pecan.expose()
|
||||
def get_all(self):
|
||||
"""Returns all notifications from a specific host."""
|
||||
return "ALLL notifs"
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
from pecan import rest
|
||||
|
||||
from surveil.api.controllers.v2.status import events as v2_events
|
||||
from surveil.api.controllers.v2.status import hosts as v2_hosts
|
||||
from surveil.api.controllers.v2.status import services as v2_services
|
||||
|
||||
@@ -22,3 +23,4 @@ class StatusController(rest.RestController):
|
||||
# events = EventsController()
|
||||
hosts = v2_hosts.HostsController()
|
||||
services = v2_services.ServicesController()
|
||||
events = v2_events.EventsController()
|
||||
|
||||
42
surveil/api/controllers/v2/status/events.py
Normal file
42
surveil/api/controllers/v2/status/events.py
Normal file
@@ -0,0 +1,42 @@
|
||||
# Copyright 2014 - Savoir-Faire Linux inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import pecan
|
||||
from pecan import rest
|
||||
import wsmeext.pecan as wsme_pecan
|
||||
|
||||
|
||||
from surveil.api.datamodel.status import event
|
||||
from surveil.api.datamodel.status import live_query
|
||||
from surveil.api.handlers.status import event_handler
|
||||
from surveil.common import util
|
||||
|
||||
|
||||
class EventsController(rest.RestController):
|
||||
|
||||
@util.policy_enforce(['authenticated'])
|
||||
@wsme_pecan.wsexpose([event.Event])
|
||||
def get_all(self):
|
||||
"""Returns all events."""
|
||||
handler = event_handler.EventHandler(pecan.request)
|
||||
events = handler.get_all()
|
||||
return events
|
||||
|
||||
@util.policy_enforce(['authenticated'])
|
||||
@wsme_pecan.wsexpose([event.Event], body=live_query.LiveQuery)
|
||||
def post(self, query):
|
||||
"""Given a LiveQuery, returns all matching events."""
|
||||
handler = event_handler.EventHandler(pecan.request)
|
||||
events = handler.get_all(live_query=query)
|
||||
return events
|
||||
@@ -17,7 +17,7 @@ from pecan import rest
|
||||
import requests
|
||||
import wsmeext.pecan as wsme_pecan
|
||||
|
||||
from surveil.api.controllers.v2 import logs
|
||||
from surveil.api.controllers.v2.status import events
|
||||
from surveil.api.datamodel import checkresult
|
||||
from surveil.api.datamodel.status import live_host
|
||||
from surveil.api.datamodel.status import live_query
|
||||
@@ -241,7 +241,7 @@ class HostController(rest.RestController):
|
||||
# See init for controller creation. We need host_name to instanciate it
|
||||
# externalcommands = ExternalCommandsController()
|
||||
# config = config.ConfigController()
|
||||
events = logs.LogsController()
|
||||
events = events.EventsController()
|
||||
metrics = HostMetricsController()
|
||||
results = HostCheckResultsSubController()
|
||||
|
||||
|
||||
@@ -18,8 +18,8 @@ from surveil.api.controllers.v2 import auth as v2_auth
|
||||
from surveil.api.controllers.v2 import bansho as v2_bansho
|
||||
from surveil.api.controllers.v2 import config as v2_config
|
||||
from surveil.api.controllers.v2 import hello as v2_hello
|
||||
from surveil.api.controllers.v2 import logs as v2_logs
|
||||
from surveil.api.controllers.v2 import status as v2_status
|
||||
from surveil.api.controllers.v2.status import events as v2_event
|
||||
|
||||
|
||||
class V2Controller(object):
|
||||
@@ -30,5 +30,5 @@ class V2Controller(object):
|
||||
status = v2_status.StatusController()
|
||||
surveil = v2_admin.AdminController()
|
||||
auth = v2_auth.AuthController()
|
||||
logs = v2_logs.LogsController()
|
||||
bansho = v2_bansho.BanshoController()
|
||||
events = v2_event.EventsController()
|
||||
bansho = v2_bansho.BanshoController()
|
||||
|
||||
80
surveil/api/datamodel/status/event.py
Normal file
80
surveil/api/datamodel/status/event.py
Normal file
@@ -0,0 +1,80 @@
|
||||
# Copyright 2015 - Savoir-Faire Linux inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import wsme
|
||||
import wsme.types as wtypes
|
||||
|
||||
from surveil.api.datamodel import types
|
||||
|
||||
|
||||
class Event(types.Base):
|
||||
|
||||
time = wsme.wsattr(wtypes.text, mandatory=True)
|
||||
"""Timestamp of the alert"""
|
||||
|
||||
event_type = wsme.wsattr(wtypes.text, mandatory=True)
|
||||
"""Type of event. This is only ALERT"""
|
||||
|
||||
host_name = wsme.wsattr(wtypes.text, mandatory=False)
|
||||
"""Host which the alert is from."""
|
||||
|
||||
service_description = wsme.wsattr(wtypes.text, mandatory=False)
|
||||
"""Service which raised the alert"""
|
||||
|
||||
state = wsme.wsattr(wtypes.text, mandatory=False)
|
||||
"""State of the service or host who raised the alert"""
|
||||
|
||||
# Alerts
|
||||
state_type = wsme.wsattr(wtypes.text, mandatory=False)
|
||||
"""Confirmness level of the state [SOFT|HARD]"""
|
||||
|
||||
attempts = wsme.wsattr(int, mandatory=False)
|
||||
"""Number of attempts to confirm state"""
|
||||
|
||||
# Downtime
|
||||
downtime_type = wsme.wsattr(wtypes.text, mandatory=False)
|
||||
"""Type of alert. This is only HOST or SERVICE"""
|
||||
|
||||
# Notifications
|
||||
notification_type = wsme.wsattr(wtypes.text, mandatory=False)
|
||||
|
||||
notification_method = wsme.wsattr(wtypes.text, mandatory=False)
|
||||
|
||||
contact = wsme.wsattr(wtypes.text, mandatory=False)
|
||||
|
||||
acknowledgement = wsme.wsattr(wtypes.text, mandatory=False)
|
||||
|
||||
# Alert, Flapping
|
||||
alert_type = wsme.wsattr(wtypes.text, mandatory=False)
|
||||
"""Type of alert. This is only HOST or SERVICE"""
|
||||
|
||||
# Alerts, Downtime, Flapping
|
||||
output = wsme.wsattr(wtypes.text, mandatory=False)
|
||||
"""Additional output of the alert."""
|
||||
|
||||
@classmethod
|
||||
def sample(cls):
|
||||
return cls(
|
||||
time='2015-06-04T18:55:12Z',
|
||||
event_type='ALERT',
|
||||
alert_type='SERVICE',
|
||||
host_name='CoolHost',
|
||||
service_description='Apache Service',
|
||||
state='CRITICAL',
|
||||
state_type='HARD',
|
||||
attempts=4,
|
||||
output='WARNING - load average: 5.04, 4.67, 5.04',
|
||||
notification_method='notify-service-by-email',
|
||||
notification_type=''
|
||||
)
|
||||
65
surveil/api/handlers/status/event_handler.py
Normal file
65
surveil/api/handlers/status/event_handler.py
Normal file
@@ -0,0 +1,65 @@
|
||||
# Copyright 2015 - Savoir-Faire Linux inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from surveil.api.datamodel.status import event
|
||||
from surveil.api.handlers import handler
|
||||
from surveil.api.handlers.status import influxdb_query
|
||||
|
||||
|
||||
class EventHandler(handler.Handler):
|
||||
"""Fulfills a request on the events resource."""
|
||||
|
||||
def get_all(self, live_query=None):
|
||||
"""Return all logs."""
|
||||
influx_client = self.request.influxdb_client
|
||||
query = influxdb_query.build_influxdb_query(live_query, "EVENT")
|
||||
response = influx_client.query(query)
|
||||
|
||||
events = []
|
||||
|
||||
for item in response.items():
|
||||
tags = item[0][1]
|
||||
for point in response.get_points(tags=tags):
|
||||
point.update(tags)
|
||||
event_dict = self._event_dict_from_influx_item(point)
|
||||
events.append(event.Event(**event_dict))
|
||||
|
||||
return events
|
||||
|
||||
def _event_dict_from_influx_item(self, item):
|
||||
mappings = [
|
||||
'time',
|
||||
'event_type',
|
||||
'host_name',
|
||||
'service_description',
|
||||
'state',
|
||||
'state_type',
|
||||
'attempts',
|
||||
'downtime_type',
|
||||
'notification_type',
|
||||
'notification_method',
|
||||
'contact',
|
||||
'alert_type',
|
||||
'output',
|
||||
'acknowledgement'
|
||||
]
|
||||
|
||||
event_dict = {}
|
||||
|
||||
for field in mappings:
|
||||
value = item.get(field, None)
|
||||
if value is not None and value != "":
|
||||
event_dict[field] = value
|
||||
|
||||
return event_dict
|
||||
@@ -17,16 +17,18 @@ import json
|
||||
|
||||
def build_influxdb_query(live_query,
|
||||
measurement,
|
||||
time_delta=None,
|
||||
group_by=[],
|
||||
order_by=[],
|
||||
limit=None):
|
||||
|
||||
query = ['SELECT * FROM', measurement]
|
||||
|
||||
if live_query:
|
||||
filters = {}
|
||||
if live_query and live_query.filters:
|
||||
filters = json.loads(live_query.filters)
|
||||
if filters:
|
||||
query.append(_build_where_clause(filters))
|
||||
|
||||
query += _build_where_clause(filters, time_delta)
|
||||
|
||||
if group_by:
|
||||
query.append('GROUP BY')
|
||||
@@ -42,7 +44,7 @@ def build_influxdb_query(live_query,
|
||||
return ' '.join(query)
|
||||
|
||||
|
||||
def _build_where_clause(filters):
|
||||
def _build_where_clause(filters, time_delta=None):
|
||||
filters_conversion = {
|
||||
'is': '=',
|
||||
'isnot': '!='
|
||||
@@ -50,6 +52,14 @@ def _build_where_clause(filters):
|
||||
clause = []
|
||||
first = True
|
||||
|
||||
if time_delta:
|
||||
clause.append('WHERE')
|
||||
first = False
|
||||
|
||||
begin = time_delta.begin
|
||||
end = time_delta.end
|
||||
clause.append("time >= '%s' AND time <= '%s'" % (begin, end))
|
||||
|
||||
for filter_name, filter_data in sorted(filters.items()):
|
||||
for field, values in sorted(filter_data.items()):
|
||||
for value in values:
|
||||
@@ -69,4 +79,4 @@ def _build_where_clause(filters):
|
||||
value))
|
||||
first = False
|
||||
|
||||
return ' '.join(clause)
|
||||
return clause
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
# Copyright 2014 - Savoir-Faire Linux inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
def build_influxdb_query(metric_name,
|
||||
time_delta,
|
||||
host_name=None,
|
||||
service_description=None
|
||||
):
|
||||
group_by = []
|
||||
query = ['SELECT * FROM metric_%s'
|
||||
% metric_name]
|
||||
begin = time_delta.begin
|
||||
end = time_delta.end
|
||||
query.append("WHERE time >= '%s' AND time <= '%s'" % (begin, end))
|
||||
|
||||
if host_name is None:
|
||||
group_by.append('host_name')
|
||||
else:
|
||||
query.append("AND host_name ='%s'" % host_name)
|
||||
|
||||
if service_description is None:
|
||||
group_by.append('service_description')
|
||||
else:
|
||||
query.append("AND service_description ='%s'" % service_description)
|
||||
|
||||
if len(group_by) != 0:
|
||||
query.append('GROUP BY')
|
||||
query.append(', '.join(group_by))
|
||||
|
||||
query.append('ORDER BY time DESC')
|
||||
return ' '.join(query)
|
||||
@@ -11,11 +11,12 @@
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
import json
|
||||
|
||||
|
||||
from surveil.api.datamodel.status import live_query
|
||||
from surveil.api.datamodel.status.metrics import live_metric
|
||||
from surveil.api.handlers import handler
|
||||
from surveil.api.handlers.status.metrics import influxdb_time_query
|
||||
from surveil.api.handlers.status import influxdb_query
|
||||
|
||||
|
||||
class MetricHandler(handler.Handler):
|
||||
@@ -75,16 +76,29 @@ class MetricHandler(handler.Handler):
|
||||
|
||||
return metrics
|
||||
|
||||
def get_all(self, metric_name, time_delta, host_name=None,
|
||||
def get_all(self, metric_name, time_delta, host_name,
|
||||
service_description=None):
|
||||
"""Return all metrics."""
|
||||
filters = {
|
||||
"is": {
|
||||
"host_name": [host_name]
|
||||
}
|
||||
}
|
||||
|
||||
if service_description:
|
||||
filters["is"]["service_description"] = [service_description]
|
||||
|
||||
query = live_query.LiveQuery(
|
||||
filters=json.dumps(filters)
|
||||
)
|
||||
order_by = ["time desc"]
|
||||
|
||||
cli = self.request.influxdb_client
|
||||
query = influxdb_time_query.build_influxdb_query(
|
||||
metric_name,
|
||||
time_delta,
|
||||
host_name,
|
||||
service_description
|
||||
query = influxdb_query.build_influxdb_query(
|
||||
query,
|
||||
"metric_" + metric_name,
|
||||
time_delta=time_delta,
|
||||
order_by=order_by
|
||||
)
|
||||
response = cli.query(query)
|
||||
|
||||
@@ -127,4 +141,15 @@ class MetricHandler(handler.Handler):
|
||||
else:
|
||||
metric_dict[field[0]] = field[1](value)
|
||||
|
||||
return metric_dict
|
||||
return metric_dict
|
||||
|
||||
def _metrics_name_from_influx_item(self, item):
|
||||
|
||||
metric_name = {}
|
||||
mappings = [('metric_name', 'name', str), ]
|
||||
for field in mappings:
|
||||
value = item.get(field[1], None)
|
||||
if value is not None:
|
||||
metric_name[field[0]] = field[2](value)
|
||||
|
||||
return metric_name
|
||||
|
||||
Reference in New Issue
Block a user