Skip to content

Commit

Permalink
Merge pull request #5 from mtakaki/mtakaki_validate_configuration
Browse files Browse the repository at this point in the history
Validate configuration
  • Loading branch information
mtakaki committed May 4, 2016
2 parents 47ff348 + 6f70206 commit e0418e7
Showing 1 changed file with 55 additions and 2 deletions.
57 changes: 55 additions & 2 deletions cachet_url_monitor/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,66 @@
from yaml import load


# This is the mandatory fields that must be in the configuration file in this
# same exact structure.
configuration_mandatory_fields = {
'endpoint': ['url', 'method', 'timeout', 'expectation'],
'cachet': ['api_url', 'token', 'component_id'],
'frequency': []}


class ConfigurationValidationError(Exception):
"""Exception raised when there's a validation error."""
def __init__(self, value):
self.value = value

def __str__(self):
return repr(self.value)


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.
#TODO(mtakaki|2016-04-28): Accept overriding settings using environment
#TODO(mtakaki#1|2016-04-28): Accept overriding settings using environment
# variables so we have a more docker-friendly approach.
self.logger = logging.getLogger('cachet_url_monitor.configuration.Configuration')
self.config_file = config_file
self.data = load(file(self.config_file, 'r'))

self.validate()

self.logger.info('Monitoring URL: %s %s' %
(self.data['endpoint']['method'], self.data['endpoint']['url']))
self.expectations = [Expectaction.create(expectation) for expectation
in self.data['endpoint']['expectation']]
for expectation in self.expectations:
self.logger.info('Registered expectation: %s' % (expectation,))
self.headers = {'X-Cachet-Token': self.data['cachet']['token']}

def validate(self):
configuration_errors = []
for key, sub_entries in configuration_mandatory_fields.iteritems():
if key not in self.data:
configuration_errors.append(key)

for sub_key in sub_entries:
if sub_key not in self.data[key]:
configuration_errors.append('%s.%s' % (key, sub_key))

if ('endpoint' in self.data and 'expectation' in
self.data['endpoint']):
if (not isinstance(self.data['endpoint']['expectation'], list) or
(isinstance(self.data['endpoint']['expectation'], list) and
len(self.data['endpoint']['expectation']) == 0)):
configuration_errors.append('endpoint.expectation')

if len(configuration_errors) > 0:
raise ConfigurationValidationError(('Config file [%s] failed '
'validation. Missing keys: %s') % (self.config_file,
', '.join(configuration_errors)))

def evaluate(self):
"""Sends the request to the URL set in the configuration and executes
each one of the expectations, one by one. The status will be updated
Expand Down Expand Up @@ -132,6 +175,9 @@ def get_status(self, response):
def get_message(self, response):
return 'Unexpected HTTP status (%s)' % (response.status_code,)

def __str__(self):
return repr('HTTP status: %s' % (self.status,))


class Latency(Expectaction):
def __init__(self, configuration):
Expand All @@ -146,9 +192,13 @@ def get_status(self, response):
def get_message(self, response):
return 'Latency above threshold: %.4f' % (response.elapsed.total_seconds(),)

def __str__(self):
return repr('Latency threshold: %.4f' % (self.threshold,))


class Regex(Expectaction):
def __init__(self, configuration):
self.regex_string = configuration['regex']
self.regex = re.compile(configuration['regex'])

def get_status(self, response):
Expand All @@ -159,3 +209,6 @@ def get_status(self, response):

def get_message(self, response):
return 'Regex did not match anything in the body'

def __str__(self):
return repr('Regex: %s' % (self.regex_string,))

0 comments on commit e0418e7

Please sign in to comment.