diff --git a/doc/source/webapi/v2/status.rst b/doc/source/webapi/v2/status.rst index 6822ca4..6953658 100644 --- a/doc/source/webapi/v2/status.rst +++ b/doc/source/webapi/v2/status.rst @@ -23,9 +23,21 @@ Hosts .. rest-controller:: surveil.api.controllers.v2.status.hosts:HostCheckResultsSubController :webprefix: /v2/status/hosts/(host_name)/results +.. rest-controller:: surveil.api.controllers.v2.status.hosts:HostMetricsController + :webprefix: /v2/status/hosts/(host_name)/metrics + +.. rest-controller:: surveil.api.controllers.v2.status.hosts:HostMetricController + :webprefix: /v2/status/hosts/(host_name)/metrics + .. rest-controller:: surveil.api.controllers.v2.status.hosts:ServiceCheckResultsSubController :webprefix: /v2/status/hosts/(host_name)/services/(service_description)/results +.. rest-controller:: surveil.api.controllers.v2.status.hosts:HostServiceMetricsController + :webprefix: /v2/status/hosts/(host_name)/services/(service_description)/metrics + +.. rest-controller:: surveil.api.controllers.v2.status.hosts:HostServiceMetricController + :webprefix: /v2/status/hosts/(host_name)/services/(service_description)/metrics + .. rest-controller:: surveil.api.controllers.v2.logs:LogsController :webprefix: /v2/status/hosts/(host_name)/events @@ -59,3 +71,9 @@ types documentation .. autotype:: surveil.api.datamodel.status.live_query.LiveQuery :members: + +.. autotype:: surveil.api.datamodel.status.metrics.live_metric.LiveMetric + :members: + +.. autotype:: surveil.api.datamodel.status.metrics.time_delta.TimeDelta + :members: \ No newline at end of file diff --git a/surveil/api/controllers/v2/status/__init__.py b/surveil/api/controllers/v2/status/__init__.py index 10ae8a4..5dd3c25 100644 --- a/surveil/api/controllers/v2/status/__init__.py +++ b/surveil/api/controllers/v2/status/__init__.py @@ -21,4 +21,4 @@ from surveil.api.controllers.v2.status import services as v2_services class StatusController(rest.RestController): # events = EventsController() hosts = v2_hosts.HostsController() - services = v2_services.ServicesController() \ No newline at end of file + services = v2_services.ServicesController() diff --git a/surveil/api/controllers/v2/status/hosts.py b/surveil/api/controllers/v2/status/hosts.py index e2f6a7e..8e1dea3 100644 --- a/surveil/api/controllers/v2/status/hosts.py +++ b/surveil/api/controllers/v2/status/hosts.py @@ -76,9 +76,9 @@ class HostServiceMetricsController(rest.RestController): def get(self): """Returns all metrics name for a host with a service.""" handler = live_metric_handler.MetricHandler(pecan.request) - metrics_name = handler.get_metric( + metrics_name = handler.get( pecan.request.context['host_name'], - pecan.request.context['service_name'] + service_description=pecan.request.context['service_name'] ) return metrics_name @@ -94,7 +94,7 @@ class HostMetricsController(rest.RestController): def get(self): """Returns all metrics name for a host.""" handler = live_metric_handler.MetricHandler(pecan.request) - metrics_name = handler.get_metric(pecan.request.context['host_name']) + metrics_name = handler.get(pecan.request.context['host_name']) return metrics_name @pecan.expose() @@ -178,8 +178,8 @@ class HostServiceMetricController(rest.RestController): """ handler = live_metric_handler.MetricHandler(pecan.request) metric = handler.get( - self.metric_name, pecan.request.context['host_name'], + self.metric_name, pecan.request.context['service_name'] ) return metric @@ -187,7 +187,10 @@ class HostServiceMetricController(rest.RestController): @util.policy_enforce(['authenticated']) @wsme_pecan.wsexpose([live_metric.LiveMetric], body=time_delta.TimeDelta) def post(self, time): - """Given a LiveQuery, returns all matching s.""" + """Returns all matching metrics. + + :param time: a time delta within the request body. + """ handler = live_metric_handler.MetricHandler(pecan.request) metrics = handler.get_all(time_delta=time, metric_name=self.metric_name, @@ -212,15 +215,18 @@ class HostMetricController(rest.RestController): """ handler = live_metric_handler.MetricHandler(pecan.request) metric = handler.get( - self.metric_name, - pecan.request.context['host_name'] + pecan.request.context['host_name'], + self.metric_name ) return metric @util.policy_enforce(['authenticated']) @wsme_pecan.wsexpose([live_metric.LiveMetric], body=time_delta.TimeDelta) def post(self, time): - """Given a LiveQuery, returns all matching s.""" + """Given a time delta, returns all matching metrics. + + :param time: a time delta within the request body. + """ handler = live_metric_handler.MetricHandler(pecan.request) metrics = handler.get_all(time_delta=time, metric_name=self.metric_name, diff --git a/surveil/api/controllers/v2/v2.py b/surveil/api/controllers/v2/v2.py index 41f4810..d9ebc9d 100644 --- a/surveil/api/controllers/v2/v2.py +++ b/surveil/api/controllers/v2/v2.py @@ -31,4 +31,4 @@ class V2Controller(object): surveil = v2_admin.AdminController() auth = v2_auth.AuthController() logs = v2_logs.LogsController() - bansho = v2_bansho.BanshoController() + bansho = v2_bansho.BanshoController() \ No newline at end of file diff --git a/surveil/api/datamodel/status/live_service.py b/surveil/api/datamodel/status/live_service.py index 53bb15b..8fb5fa7 100644 --- a/surveil/api/datamodel/status/live_service.py +++ b/surveil/api/datamodel/status/live_service.py @@ -37,7 +37,7 @@ class LiveService(types.Base): last_check = wsme.wsattr(int, mandatory=False) """The last time the service was checked""" - last_state_change = wsme.wsattr(int, mandatory=False) + last_state_change = wsme.wsattr(float, mandatory=False) """The last time the state has changed""" plugin_output = wsme.wsattr(wtypes.text, mandatory=False) @@ -54,7 +54,7 @@ class LiveService(types.Base): description='Serves Stuff', state='OK', last_check=1429220785, - last_state_change=1429220785, + last_state_change=1429220785.481679, plugin_output='HTTP OK - GOT NICE RESPONSE', acknowledged=True, long_output='Serves /var/www/\nServes /home/webserver/www/' diff --git a/surveil/api/handlers/status/live_service_handler.py b/surveil/api/handlers/status/live_service_handler.py index 51641ba..39e1e8c 100644 --- a/surveil/api/handlers/status/live_service_handler.py +++ b/surveil/api/handlers/status/live_service_handler.py @@ -102,7 +102,7 @@ def _service_dict_from_mongo_item(mongo_item): mappings = [ ('last_chk', 'last_check', int), - ('last_state_change', 'last_state_change', int), + ('last_state_change', 'last_state_change', float), ('output', 'plugin_output', str), ('problem_has_been_acknowledged', 'acknowledged', bool), ] diff --git a/surveil/api/handlers/status/metrics/live_metric_handler.py b/surveil/api/handlers/status/metrics/live_metric_handler.py index e396a0a..952f131 100644 --- a/surveil/api/handlers/status/metrics/live_metric_handler.py +++ b/surveil/api/handlers/status/metrics/live_metric_handler.py @@ -21,58 +21,60 @@ from surveil.api.handlers.status.metrics import influxdb_time_query class MetricHandler(handler.Handler): """Fulfills a request on the metrics.""" - def get_metric(self, host_name, service_description=None): - """Return all metrics name for a given host.""" + def get(self, host_name, metric_name=None, service_description=None): + """Return metrics name if param metric_name is null, + else , return the last metric. + """ + metrics = [] cli = self.request.influxdb_client - - if service_description is None: - query = "SHOW measurements WHERE host_name='%s'" % host_name + if metric_name is None: + if service_description is None: + query = ("SHOW measurements WHERE host_name='%s' " + "AND service_description=''" + % host_name) + else: + query = ("SHOW measurements WHERE host_name='%s' " + "AND service_description='%s'" + % (host_name, service_description)) else: - query = ("SHOW measurements WHERE host_name='%s' " - "AND service_description='%s'" - % (host_name, service_description)) + if service_description is None: + query = ("SELECT * FROM metric_%s " + "WHERE host_name= '%s' " + "GROUP BY service_description " + "ORDER BY time DESC " + "LIMIT 1" + % (metric_name, host_name)) + else: + query = ("SELECT * FROM metric_%s " + "WHERE host_name= '%s' " + "AND service_description= '%s'" + "ORDER BY time DESC " + "LIMIT 1" + % (metric_name, host_name, service_description)) response = cli.query(query) - metric_name_dicts = [] + if metric_name is None: + metric_dicts = [] - for item in response[None]: - metric_name_dict = self._metrics_name_from_influx_item(item) - metric_name_dicts.append(metric_name_dict) + for item in response[None]: + metric_dict = self._metric_dict_from_influx_item(item) + if metric_dict is not None: + metric_dicts.append(metric_dict) - metrics = [] - for metric_dict in metric_name_dicts: - metric = live_metric.LiveMetric(**metric_dict) - metrics.append(metric) + for metric_dict in metric_dicts: + metric = live_metric.LiveMetric(**metric_dict) + metrics.append(metric) + + else: + metrics = live_metric.LiveMetric(**self. + _metric_dict_from_influx_item( + next(response.items()[0][1]), + metric_name)) return metrics - def get(self, metric_name, host_name, service_description=None): - """Return a metric.""" - - cli = self.request.influxdb_client - if service_description is None: - query = ("SELECT * FROM metric_%s " - "WHERE host_name= '%s' " - "GROUP BY service_description " - "ORDER BY time DESC " - "LIMIT 1" % (metric_name, host_name)) - else: - query = ("SELECT * FROM metric_%s " - "WHERE host_name= '%s' " - "AND service_description= '%s'" - "ORDER BY time DESC " - "LIMIT 1" % (metric_name, host_name, service_description)) - - response = cli.query(query) - metric = live_metric.LiveMetric( - **self._metric_dict_from_influx_item(next(response.items()[0][1]), - metric_name) - ) - - return metric - def get_all(self, metric_name, time_delta, host_name=None, service_description=None): """Return all metrics.""" @@ -99,33 +101,30 @@ class MetricHandler(handler.Handler): return metrics - def _metric_dict_from_influx_item(self, item, metric_name): + def _metric_dict_from_influx_item(self, item, metric_name=None): - metric_dict = {"metric_name": str(metric_name)} - - mappings = [ - ('min', str), - ('max', str), - ('critical', str), - ('warning', str), - ('value', str), - ('unit', str), - ] + if metric_name is None: + metric_dict = None + mappings = [('name', 'metric_name', str), ] + else: + metric_dict = {"metric_name": str(metric_name)} + mappings = [ + ('min', str), + ('max', str), + ('critical', str), + ('warning', str), + ('value', str), + ('unit', str), + ] for field in mappings: value = item.get(field[0], None) if value is not None: - metric_dict[field[0]] = field[1](value) + if field[0] == 'name': + if value.startswith('metric_'): + metric_dict = {} + metric_dict[field[1]] = field[2](value[7:]) + else: + metric_dict[field[0]] = field[1](value) - 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 \ No newline at end of file + return metric_dict \ No newline at end of file diff --git a/surveil/tests/api/controllers/v2/status/test_hosts_metric.py b/surveil/tests/api/controllers/v2/status/test_hosts_metric.py index abb48eb..1e0664d 100644 --- a/surveil/tests/api/controllers/v2/status/test_hosts_metric.py +++ b/surveil/tests/api/controllers/v2/status/test_hosts_metric.py @@ -187,12 +187,8 @@ class TestHostMetric(functionalTest.FunctionalTest): "name": "measurements", "columns": ["name"], "values": [ - ["ALERT"], - ["HOST_STATE"], - ["metric_pl"], - ["metric_rta"], - ["metric_rtmax"], - ["metric_rtmin"] + ["metric_rtmin"], + ["ALERT"] ] } ] @@ -205,23 +201,18 @@ class TestHostMetric(functionalTest.FunctionalTest): text=self.influxdb_response) response = self.get( - "/v2/status/hosts/localhost/metrics" + "/v2/status/hosts/ws-arbiter/metrics" ) - expected = [{"metric_name": "ALERT"}, - {"metric_name": "HOST_STATE"}, - {"metric_name": "metric_pl"}, - {"metric_name": "metric_rta"}, - {"metric_name": "metric_rtmax"}, - {"metric_name": "metric_rtmin"}, - ] + expected = [{"metric_name": "rtmin"}, ] self.assert_count_equal_backport( json.loads(response.body.decode()), expected) self.assertEqual( m.last_request.qs['q'], - ["show measurements where host_name='localhost'"] + ["show measurements where host_name='ws-arbiter' " + "and service_description=''"] ) def test_metric_names_services(self): @@ -233,7 +224,8 @@ class TestHostMetric(functionalTest.FunctionalTest): "name": "measurements", "columns": ["name"], "values": [ - ["SERVICE_STATE"] + ["metric_rtmin"], + ["ALERT"] ] } ] @@ -249,7 +241,7 @@ class TestHostMetric(functionalTest.FunctionalTest): "/v2/status/hosts/localhost/services/load/metrics" ) - expected = [{"metric_name": "SERVICE_STATE"}, ] + expected = [{"metric_name": "rtmin"}, ] self.assert_count_equal_backport( json.loads(response.body.decode()),