diff --git a/Dockerfile b/Dockerfile index 49787cd..4795752 100644 --- a/Dockerfile +++ b/Dockerfile @@ -37,7 +37,7 @@ RUN apt-get install -y wget curl RUN wget http://s3.amazonaws.com/influxdb/influxdb_latest_amd64.deb RUN useradd influxdb # We should remove this when issue is fixed (https://github.com/influxdb/influxdb/issues/670) RUN dpkg -i influxdb_latest_amd64.deb -RUN service influxdb start && sleep 10 && curl -X POST 'http://localhost:8086/db?u=root&p=root' -d '{"name": "grafana"}' && curl -X POST 'http://localhost:8086/db?u=root&p=root' -d '{"name": "db"}' # We should remove the sleep when this issue is fixed: https://github.com/influxdb/influxdb/issues/805 +RUN service influxdb start && until curl -X POST 'http://localhost:8086/db?u=root&p=root' -d '{"name": "grafana"}'; do echo "Try again"; sleep 2; done && curl -X POST 'http://localhost:8086/db?u=root&p=root' -d '{"name": "db"}' # We should remove the sleep when this issue is fixed: https://github.com/influxdb/influxdb/issues/805 ### Riemann RUN wget http://aphyr.com/riemann/riemann_0.2.6_all.deb @@ -62,6 +62,11 @@ ADD tools/docker/etc/apache2/conf-enabled/influxdb.conf /etc/apache2/conf-enable RUN apt-get install -y mongodb ADD tools/docker/etc/mongodb.conf /etc/mongodb.conf +## Import sample config +## TODO: Use the python client or curl instead. +ADD tools/docker/mongoimport /mongoimport +RUN service mongodb start && until mongoimport --db shinken --host localhost --collection hosts < /mongoimport/hosts.json; do echo "Try again"; sleep 2; done && mongoimport --db shinken --host localhost --collection services < /mongoimport/services.json && service mongodb stop + ### Surveil ## Copy files ADD surveil /surveil/surveil diff --git a/doc/source/webapi/v1.rst b/doc/source/webapi/v1.rst index 5115a1c..1f63bc6 100644 --- a/doc/source/webapi/v1.rst +++ b/doc/source/webapi/v1.rst @@ -22,6 +22,12 @@ Hosts .. rest-controller:: surveil.api.controllers.v1.hosts:HostServicesSubController :webprefix: /v1/hosts/(host_name)/services +.. rest-controller:: surveil.api.controllers.v1.hosts:HostCheckResultsSubController + :webprefix: /v1/hosts/(host_name)/results + +.. autotype:: surveil.api.controllers.v1.datamodel.checkresult.CheckResult + :members: + .. autotype:: surveil.api.controllers.v1.datamodel.host.Host :members: diff --git a/requirements.txt b/requirements.txt index ef21ca6..92e26b8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,5 @@ pecan>=0.5.0 pymongo>=2.7.2 -wsme \ No newline at end of file +wsme +requests + diff --git a/surveil/api/config.py b/surveil/api/config.py index a2b57ef..e529965 100644 --- a/surveil/api/config.py +++ b/surveil/api/config.py @@ -24,7 +24,8 @@ server = { app_hooks = [ hooks.DBHook( - pymongo.MongoClient('127.0.0.1', 27017) + pymongo.MongoClient('127.0.0.1', 27017), + "http://127.0.0.1:7760" ) ] diff --git a/surveil/api/controllers/v1/datamodel/checkresult.py b/surveil/api/controllers/v1/datamodel/checkresult.py new file mode 100644 index 0000000..77f7db5 --- /dev/null +++ b/surveil/api/controllers/v1/datamodel/checkresult.py @@ -0,0 +1,41 @@ +# 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 time + +import wsme +import wsme.types as wtypes + +from surveil.api.controllers.v1.datamodel import types + + +class CheckResult(types.Base): + time_stamp = wsme.wsattr(wtypes.text, + mandatory=False, + default=str(int(time.time()))) + """The time the check was executed. Defaults to now.""" + + return_code = wsme.wsattr(wtypes.text, mandatory=True) + """The return code of the check.""" + + output = wsme.wsattr(wtypes.text, mandatory=True) + """The output of the check.""" + + @classmethod + def sample(cls): + return cls( + time_stamp="1409087486", + return_code="0", + output="CPU Usage 98%|c[cpu]=98%;80;95;0;100" + ) diff --git a/surveil/api/controllers/v1/hosts.py b/surveil/api/controllers/v1/hosts.py index 27ce777..f7d3b3b 100644 --- a/surveil/api/controllers/v1/hosts.py +++ b/surveil/api/controllers/v1/hosts.py @@ -14,8 +14,10 @@ import pecan from pecan import rest +import requests import wsmeext.pecan as wsme_pecan +from surveil.api.controllers.v1.datamodel import checkresult from surveil.api.controllers.v1.datamodel import host from surveil.api.controllers.v1.datamodel import service @@ -37,8 +39,26 @@ class HostServicesSubController(rest.RestController): return services +class HostCheckResultsSubController(rest.RestController): + + @wsme_pecan.wsexpose(body=checkresult.CheckResult, status_code=204) + def post(self, data): + """Submit a new check result. + + :param data: a check result within the request body. + """ + result = data.as_dict() + result['host_name'] = pecan.request.context['host_name'] + + requests.post( + pecan.request.ws_arbiter_url + "/push_check_result", + data=result + ) + + class HostSubController(rest.RestController): services = HostServicesSubController() + results = HostCheckResultsSubController() class HostController(rest.RestController): diff --git a/surveil/api/hooks.py b/surveil/api/hooks.py index 1aad2ac..ed42c99 100644 --- a/surveil/api/hooks.py +++ b/surveil/api/hooks.py @@ -17,8 +17,10 @@ from pecan import hooks class DBHook(hooks.PecanHook): - def __init__(self, mongo_connection): + def __init__(self, mongo_connection, ws_arbiter_url): self.mongo_connection = mongo_connection + self.ws_arbiter_url = ws_arbiter_url def before(self, state): state.request.mongo_connection = self.mongo_connection + state.request.ws_arbiter_url = self.ws_arbiter_url diff --git a/surveil/tests/api/controllers/v1/test_hosts.py b/surveil/tests/api/controllers/v1/test_hosts.py index 6dd2fe6..8e14aec 100644 --- a/surveil/tests/api/controllers/v1/test_hosts.py +++ b/surveil/tests/api/controllers/v1/test_hosts.py @@ -15,6 +15,8 @@ import copy import json +import httpretty + from surveil.api.controllers.v1.datamodel import host from surveil.tests.api import functionalTest @@ -143,3 +145,28 @@ class TestHostController(functionalTest.FunctionalTest): services, json.loads(response.body.decode()) ) + + @httpretty.activate + def test_submit_result(self): + httpretty.register_uri(httpretty.POST, + self.ws_arbiter_url + "/push_check_result") + + check_result = { + "return_code": "0", + "output": "TEST OUTPUT", + "time_stamp": "1409149234" + } + + response = self.app.post_json("/v1/hosts/bogus-router/results", + params=check_result) + + self.assertEqual(response.status_int, 204) + self.assertEqual( + httpretty.last_request().parsed_body, + { + u'output': [u'TEST OUTPUT'], + u'return_code': [u'0'], + u'host_name': [u'bogus-router'], + u'time_stamp': [u'1409149234'] + } + ) diff --git a/surveil/tests/api/functionalTest.py b/surveil/tests/api/functionalTest.py index 0910f32..a054db2 100644 --- a/surveil/tests/api/functionalTest.py +++ b/surveil/tests/api/functionalTest.py @@ -33,10 +33,12 @@ class FunctionalTest(base.BaseTestCase): def setUp(self): self.mongoconnection = mongomock.Connection() + self.ws_arbiter_url = "http://localhost:7760" app_hooks = [ hooks.DBHook( - self.mongoconnection + self.mongoconnection, + self.ws_arbiter_url ) ] diff --git a/test-requirements.txt b/test-requirements.txt index 28a0f59..258b182 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -4,4 +4,5 @@ sphinxcontrib-pecanwsme>=0.8 sphinxcontrib-httpdomain oslosphinx testrepository>=0.0.18 -mongomock \ No newline at end of file +mongomock +httpretty \ No newline at end of file diff --git a/tools/docker/etc/shinken/modules/ws_arbiter.cfg b/tools/docker/etc/shinken/modules/ws_arbiter.cfg index 0cd4ef8..2df29b3 100644 --- a/tools/docker/etc/shinken/modules/ws_arbiter.cfg +++ b/tools/docker/etc/shinken/modules/ws_arbiter.cfg @@ -7,7 +7,7 @@ define module { module_type ws_arbiter host 0.0.0.0 port 7760 - username admin ; If you want auth, set username and password. - password admin +# username admin ; If you want auth, set username and password. +# password admin } diff --git a/tools/docker/mongoimport/hosts.json b/tools/docker/mongoimport/hosts.json new file mode 100644 index 0000000..ee03040 --- /dev/null +++ b/tools/docker/mongoimport/hosts.json @@ -0,0 +1 @@ +{"use": "generic-host", "contact_groups": "admins", "host_name": "surveil", "address": "localhost"} diff --git a/tools/docker/mongoimport/services.json b/tools/docker/mongoimport/services.json new file mode 100644 index 0000000..37d55cb --- /dev/null +++ b/tools/docker/mongoimport/services.json @@ -0,0 +1 @@ +{ "check_command": "check_tcp!8080", "check_interval": "5", "check_period": "24x7", "contact_groups": "admins", "contacts": "admin", "host_name": "surveil", "max_check_attempts": "5", "notification_interval": "30", "notification_period": "24x7", "retry_interval": "3", "service_description": "check-surveil-api" }