diff --git a/cachet_url_monitor/configuration.py b/cachet_url_monitor/configuration.py index 551f74f..622fa5e 100644 --- a/cachet_url_monitor/configuration.py +++ b/cachet_url_monitor/configuration.py @@ -1,10 +1,15 @@ +#!/usr/bin/env python import abc +import logging import requests import timeit from yaml import load class Configuration(object): + """Represents a configuration file, but it also includes the functionality + of assessing the API and pushing the results to cachet. + """ def __init__(self, config_file): #TODO(mtakaki|2016-04-26): Needs validation if the config is correct. self.config_file = config_file @@ -13,22 +18,50 @@ class Configuration(object): in self.data['endpoint']['expectation']] def evaluate(self): - self.request = requests.request(self.data['endpoint']['method'], - self.data['endpoint']['url']) - self.status = True + #TODO(mtakaki|2016-04-27): Add support to configurable timeout. + try: + self.request = requests.request(self.data['endpoint']['method'], + self.data['endpoint']['url']) + except requests.ConnectionError: + logging.warning('The URL is unreachable: %s %s' % + (self.data['endpoint']['method'], + self.data['endpoint']['url'])) + self.status = 3 + return + except requests.HTTPError: + logging.exception('Unexpected HTTP response') + self.status = 3 + return + except requests.Timeout: + logging.warning('Request timed out') + self.status = 3 + return + + # We, by default, assume the API is healthy. + self.status = 1 self.message = '' for expectation in self.expectations: - status = expectation.is_healthy(self.request) - self.status = self.status and status + status = expectation.get_status(self.request) + + # The greater the status is, the worse the state of the API is. + if status > self.status: + self.status = status def push_status_and_metrics(self): - if not self.status: - params = {'id': self.data['cachet']['component_id'], 'status': 0} - headers = {'X-Cachet-Token': self.data['cachet']['token']} - incident_request = requests.post('%s/api/v1/components/%d' % - (self.data['cachet']['api_url'], - self.data['cachet']['component_id']), - params=params, headers=headers) + params = {'id': self.data['cachet']['component_id'], 'status': + self.status} + headers = {'X-Cachet-Token': self.data['cachet']['token']} + component_request = requests.put('%s/components/%d' % + (self.data['cachet']['api_url'], + self.data['cachet']['component_id']), + params=params, headers=headers) + if component_request.status_code == 200: + # Successful update + logging.info('Component update: status [%d]' % (self.status,)) + else: + # Failed to update the API status + logging.warning('Component update failed with status [%d]: API' + ' status: [%d]' % (component_request.status_code, self.status)) class Expectaction(object): @staticmethod @@ -40,8 +73,10 @@ class Expectaction(object): return expectations.get(configuration['type'])(configuration) @abc.abstractmethod - def is_healthy(self, response): - """Returns true if the endpoint is healthy and false if otherwise.""" + def get_status(self, response): + """Returns the status of the API, following cachet's component status + documentation: https://docs.cachethq.io/docs/component-statuses + """ @abc.abstractmethod def get_message(self, response): @@ -52,8 +87,11 @@ class HttpStatus(Expectaction): def __init__(self, configuration): self.status = configuration['status'] - def is_healthy(self, response): - return response.status_code == self.status + def get_status(self, response): + if response.status_code == self.status: + return 1 + else: + return 3 def get_message(self, response): return 'Unexpected HTTP status (%s)' % (response.status_code,) @@ -63,9 +101,11 @@ class Latency(Expectaction): def __init__(self, configuration): self.threshold = configuration['threshold'] - def is_healthy(self, response): - return response.elapsed.total_seconds() <= self.threshold + def get_status(self, response): + if response.elapsed.total_seconds() <= self.threshold: + return 1 + else: + return 2 def get_message(self, response): - return 'Latency above threshold: %d' % - (response.elapsed.total_seconds(),) + return 'Latency above threshold: %d' % (response.elapsed.total_seconds(),) diff --git a/cachet_url_monitor/scheduler.py b/cachet_url_monitor/scheduler.py new file mode 100644 index 0000000..122604e --- /dev/null +++ b/cachet_url_monitor/scheduler.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python +from threading import Timer +import configuration + + +class Agent(object): + def __init__(self, configuration): + self.configuration = configuration + + diff --git a/config.yml b/config.yml index 44bd3e4..edd6ae6 100644 --- a/config.yml +++ b/config.yml @@ -5,7 +5,7 @@ endpoint: - type: HTTP_STATUS status: 200 - type: LATENCY - threshold: 80 + threshold: 1 cachet: api_url: http://status.cachethq.io/api/v1/ token: my_token