From d11d24b59448d282f3df55c7ecf14b73e60e7dd0 Mon Sep 17 00:00:00 2001 From: Camilo Nova Date: Thu, 11 Aug 2016 16:34:55 -0500 Subject: [PATCH 1/5] Use a ini file for settings --- README.md | 4 +- config.ini | 12 +++++ cron.py | 6 --- update_status.py | 121 ++++++++++++++++++++++------------------------- 4 files changed, 70 insertions(+), 73 deletions(-) create mode 100644 config.ini delete mode 100644 cron.py diff --git a/README.md b/README.md index 1e1cbee..360b453 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ MONITOR_LIST = { Register a cron that runs `cron.py` every 5 minutes. -```bash +```bash # Open cron file to edit. crontab -e ``` @@ -57,7 +57,7 @@ You can also update your Cachet data manually by running this: ```python from update_status import Monitor -# Create a monitor instance +# Create a monitor instance m = Monitor() # Gets uptime data from UptimeRobot and send to Cachet. diff --git a/config.ini b/config.ini new file mode 100644 index 0000000..9305009 --- /dev/null +++ b/config.ini @@ -0,0 +1,12 @@ +[uptimeRobot] +UptimeRobotMainApiKey = abcd + +[url.in.uptime.robot.com] +CachetApiKey = cachet-api-key +CachetUrl = https://status.mycompany.com +MetricId = 1 + +[another.url.in.uptime.robot.com] +CachetApiKey = another-cachet-api-key +CachetUrl = https://status.another.mycompany.com +MetricId = 3 diff --git a/cron.py b/cron.py deleted file mode 100644 index 281389e..0000000 --- a/cron.py +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env python3 -from update_status import Monitor - -# Update monitors. -m = Monitor() -m.update_all_monitors() diff --git a/update_status.py b/update_status.py index 2d627c8..d27130f 100644 --- a/update_status.py +++ b/update_status.py @@ -1,35 +1,16 @@ #!/usr/bin/env python3 - import json +import sys +import configparser from urllib import request from urllib import parse from datetime import datetime -# API Key from `https://uptimerobot.com/`. -UPTIME_ROBOT_API_KEY = '' - -# List of monitors to update. -# Each monitor must be an active UptimeRobot monitor and also -# there must be a Cachet metric and component for it. -MONITOR_LIST = { - 'https://mydomain.com': { - 'api_key': 'cachet-api-key', - 'status_url': 'https://your-status-page-url.com', - 'component_id': 1, - 'metric_id': 1, - } -} - -# Terminal colors. -GREEN = '\033[92m' -RED = '\033[91m' -ENDC = '\033[0m' - class UptimeRobot(object): """ Intermediate class for setting uptime stats. """ - def __init__(self, api_key=''): + def __init__(self, api_key): self.api_key = api_key self.base_url = 'https://api.uptimerobot.com/' @@ -83,9 +64,9 @@ class CachetHq(object): CACHET_SEEMS_DOWN = 3 CACHET_DOWN = 4 - def __init__(self, api_key='', base_url=''): - self.api_key = api_key - self.base_url = base_url + def __init__(self, cachet_api_key, cachet_url): + self.cachet_api_key = cachet_api_key + self.cachet_url = cachet_url def update_component(self, id_component=1, status=None): component_status = None @@ -104,7 +85,7 @@ def update_component(self, id_component=1, status=None): if component_status: url = '{0}/{1}/{2}/'.format( - self.base_url, + self.cachet_url, 'components', id_component ) @@ -115,16 +96,14 @@ def update_component(self, id_component=1, status=None): url=url, data=data, method='PUT', - headers={ - 'X-Cachet-Token': self.api_key, - } + headers={'X-Cachet-Token': self.cachet_api_key}, ) response = request.urlopen(req) content = response.read().decode('utf-8') return content def set_data_metrics(self, value, timestamp, id_metric=1): - url = '{0}/metrics/{1}/points/'.format(self.base_url, id_metric) + url = '{0}/metrics/{1}/points/'.format(self.cachet_url, id_metric) data = parse.urlencode({ 'value': value, 'timestamp': timestamp, @@ -133,21 +112,19 @@ def set_data_metrics(self, value, timestamp, id_metric=1): url=url, data=data, method='POST', - headers={ - 'X-Cachet-Token': self.api_key, - } + headers={'X-Cachet-Token': self.cachet_api_key}, ) response = request.urlopen(req) - content = response.read().decode('utf-8') - return json.loads(content) + + return json.loads(response.read().decode('utf-8')) def get_last_metric_point(self, id_metric): - url = '{0}/metrics/{1}/points/'.format(self.base_url, id_metric) + url = '{0}/metrics/{1}/points/'.format(self.cachet_url, id_metric) req = request.Request( url=url, method='GET', headers={ - 'X-Cachet-Token': self.api_key, + 'X-Cachet-Token': self.cachet_api_key, } ) response = request.urlopen(req) @@ -158,7 +135,7 @@ def get_last_metric_point(self, id_metric): ).get('meta').get('pagination').get('total_pages') url = '{0}/metrics/{1}/points?page={2}'.format( - self.base_url, + self.cachet_url, id_metric, last_page ) @@ -166,32 +143,36 @@ def get_last_metric_point(self, id_metric): req = request.Request( url=url, method='GET', - headers={ - 'X-Cachet-Token': self.api_key, - } + headers={'X-Cachet-Token': self.cachet_api_key}, ) response = request.urlopen(req) content = response.read().decode('utf-8') if json.loads(content).get('data'): - return json.loads(content).get('data')[0] + data = json.loads(content).get('data')[0] else: - return { + data = { 'created_at': datetime.now().date().strftime( '%Y-%m-%d %H:%M:%S' ) } + return data + class Monitor(object): + def __init__(self, monitor_list, api_key): + self.monitor_list = monitor_list + self.api_key = api_key + def send_data_to_catchet(self, monitor): """ Posts data to Cachet API. Data sent is the value of last `Uptime`. """ - website_config = MONITOR_LIST[monitor.get('url')] + website_config = self.monitor_list[monitor.get('url')] cachet = CachetHq( - website_config['api_key'], - website_config['status_url'] + api_key=website_config['api_key'], + base_url=website_config['status_url'], ) cachet.update_component( @@ -215,35 +196,45 @@ def send_data_to_catchet(self, monitor): int(point_datetime.strftime('%s')), website_config['metric_id'] ) - print( - '{0}Created metric with id {1}{2}:'.format( - GREEN, - metric['data']['id'], - ENDC, - ) - ) - print(metric) + print('Metric created: {0}'.format(metric)) - def update_all_monitors(self): + def update(self): """ Update all monitors uptime and status. """ - uptime_robot = UptimeRobot(UPTIME_ROBOT_API_KEY) + uptime_robot = UptimeRobot(self.api_key) success, response = uptime_robot.get_monitors(response_times=1) if success: monitors = response.get('monitors').get('monitor') for monitor in monitors: - print('{0}Updating monitor {1}: URL: {2} - id: {3}{4}'.format( - GREEN, + print('Updating monitor {0}. URL: {1}. ID: {2}'.format( monitor['friendlyname'], monitor['url'], monitor['id'], - ENDC, )) self.send_data_to_catchet(monitor) else: - print( - '{0}No data was returned from UptimeMonitor {1}'.format( - RED, - ENDC - ) - ) + print('ERROR: No data was returned from UptimeMonitor') + +if __name__ == "__main__": + config = configparser.ConfigParser() + config.read(sys.argv[1]) + sections = config.sections() + + if not sections: + print('File path is not valid') + sys.exit(1) + + uptime_robot_api_key = None + monitor_dict = {} + for element in sections: + if element == 'uptimeRobot': + uptime_robot_api_key = config[element]['UptimeRobotMainApiKey'] + else: + monitor_dict[element] = { + 'cachet_api_key': config[element]['CachetApiKey'], + 'cachet_url': config[element]['CachetUrl'], + 'metric_id': config[element]['MetricId'], + } + + monitor = Monitor(monitor_list=monitor_dict, api_key=uptime_robot_api_key) + monitor.update() From 4aa1858d63bb904c8acbc066a5a21327df6c7f35 Mon Sep 17 00:00:00 2001 From: Felipe Gonzalez Date: Thu, 11 Aug 2016 17:06:26 -0500 Subject: [PATCH 2/5] :bug: Improve code base --- update_status.py | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/update_status.py b/update_status.py index d27130f..6b5bd81 100644 --- a/update_status.py +++ b/update_status.py @@ -169,10 +169,15 @@ def send_data_to_catchet(self, monitor): """ Posts data to Cachet API. Data sent is the value of last `Uptime`. """ - website_config = self.monitor_list[monitor.get('url')] + try: + website_config = self.monitor_list[monitor.get('url')] + except KeyError: + print('ERROR: monitor is not valid') + sys.exit(1) + cachet = CachetHq( - api_key=website_config['api_key'], - base_url=website_config['status_url'], + cachet_api_key=website_config['api_key'], + cachet_url=website_config['status_url'], ) cachet.update_component( @@ -215,26 +220,27 @@ def update(self): else: print('ERROR: No data was returned from UptimeMonitor') + if __name__ == "__main__": - config = configparser.ConfigParser() - config.read(sys.argv[1]) - sections = config.sections() + CONFIG = configparser.ConfigParser() + CONFIG.read(sys.argv[1]) + SECTIONS = CONFIG.sections() - if not sections: - print('File path is not valid') + if not SECTIONS: + print('ERROR: File path is not valid') sys.exit(1) - uptime_robot_api_key = None - monitor_dict = {} - for element in sections: + UPTIME_ROBOT_API_KEY = None + MONITOR_DICT = {} + for element in SECTIONS: if element == 'uptimeRobot': - uptime_robot_api_key = config[element]['UptimeRobotMainApiKey'] + uptime_robot_api_key = CONFIG[element]['UptimeRobotMainApiKey'] else: - monitor_dict[element] = { - 'cachet_api_key': config[element]['CachetApiKey'], - 'cachet_url': config[element]['CachetUrl'], - 'metric_id': config[element]['MetricId'], + MONITOR_DICT[element] = { + 'cachet_api_key': CONFIG[element]['CachetApiKey'], + 'cachet_url': CONFIG[element]['CachetUrl'], + 'metric_id': CONFIG[element]['MetricId'], } - monitor = Monitor(monitor_list=monitor_dict, api_key=uptime_robot_api_key) - monitor.update() + MONITOR = Monitor(monitor_list=MONITOR_DICT, api_key=uptime_robot_api_key) + MONITOR.update() From fab071f488be8914b42f091961cf47e306c1d212 Mon Sep 17 00:00:00 2001 From: Pablo Vallejo Date: Fri, 12 Aug 2016 08:31:07 -0500 Subject: [PATCH 3/5] :sunny: :lollipop: Update metrics to represent server availability --- config.ini | 8 ++----- update_status.py | 57 +++++++++++++++++++++++++----------------------- 2 files changed, 32 insertions(+), 33 deletions(-) diff --git a/config.ini b/config.ini index 9305009..c603b35 100644 --- a/config.ini +++ b/config.ini @@ -1,12 +1,8 @@ [uptimeRobot] UptimeRobotMainApiKey = abcd -[url.in.uptime.robot.com] +[https://url.in.uptime.robot.com] CachetApiKey = cachet-api-key CachetUrl = https://status.mycompany.com MetricId = 1 - -[another.url.in.uptime.robot.com] -CachetApiKey = another-cachet-api-key -CachetUrl = https://status.another.mycompany.com -MetricId = 3 +ComponentId = 1 diff --git a/update_status.py b/update_status.py index 6b5bd81..cefd73c 100644 --- a/update_status.py +++ b/update_status.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 import json import sys +import time import configparser from urllib import request from urllib import parse @@ -84,7 +85,7 @@ def update_component(self, id_component=1, status=None): component_status = self.CACHET_DOWN if component_status: - url = '{0}/{1}/{2}/'.format( + url = '{0}/api/v1/{1}/{2}/'.format( self.cachet_url, 'components', id_component @@ -103,7 +104,11 @@ def update_component(self, id_component=1, status=None): return content def set_data_metrics(self, value, timestamp, id_metric=1): - url = '{0}/metrics/{1}/points/'.format(self.cachet_url, id_metric) + url = '{0}/api/v1/metrics/{1}/points/'.format( + self.cachet_url, + id_metric + ) + data = parse.urlencode({ 'value': value, 'timestamp': timestamp, @@ -119,7 +124,11 @@ def set_data_metrics(self, value, timestamp, id_metric=1): return json.loads(response.read().decode('utf-8')) def get_last_metric_point(self, id_metric): - url = '{0}/metrics/{1}/points/'.format(self.cachet_url, id_metric) + url = '{0}/api/v1/metrics/{1}/points/'.format( + self.cachet_url, + id_metric + ) + req = request.Request( url=url, method='GET', @@ -134,7 +143,7 @@ def get_last_metric_point(self, id_metric): content ).get('meta').get('pagination').get('total_pages') - url = '{0}/metrics/{1}/points?page={2}'.format( + url = '{0}/api/v1/metrics/{1}/points?page={2}'.format( self.cachet_url, id_metric, last_page @@ -176,32 +185,22 @@ def send_data_to_catchet(self, monitor): sys.exit(1) cachet = CachetHq( - cachet_api_key=website_config['api_key'], - cachet_url=website_config['status_url'], + cachet_api_key=website_config['cachet_api_key'], + cachet_url=website_config['cachet_url'], ) - cachet.update_component( - website_config['component_id'], - monitor.get('status') - ) - - last_date_metric_point = datetime.strptime( - cachet.get_last_metric_point( - website_config['metric_id'] - ).get('created_at'), '%Y-%m-%d %H:%M:%S') - - for point in reversed(monitor.get('responsetime')): - point_datetime = datetime.strptime( - point.get('datetime'), - '%m/%d/%Y %H:%M:%S' + if 'component_id' in website_config: + cachet.update_component( + website_config['component_id'], + monitor.get('status') ) - if point_datetime > last_date_metric_point: - metric = cachet.set_data_metrics( - point.get('value'), - int(point_datetime.strftime('%s')), - website_config['metric_id'] - ) - print('Metric created: {0}'.format(metric)) + + metric = cachet.set_data_metrics( + monitor.get('alltimeuptimeratio'), + int(time.time()), + website_config['metric_id'] + ) + print('Metric created: {0}'.format(metric)) def update(self): """ Update all monitors uptime and status. @@ -241,6 +240,10 @@ def update(self): 'cachet_url': CONFIG[element]['CachetUrl'], 'metric_id': CONFIG[element]['MetricId'], } + if 'ComponentId' in CONFIG[element]: + MONITOR_DICT[element].update({ + 'component_id': CONFIG[element]['ComponentId'], + }) MONITOR = Monitor(monitor_list=MONITOR_DICT, api_key=uptime_robot_api_key) MONITOR.update() From 76fa89ae223b17f7a337712506fd7dd8ad43f8c7 Mon Sep 17 00:00:00 2001 From: Pablo Vallejo Date: Fri, 12 Aug 2016 08:44:28 -0500 Subject: [PATCH 4/5] :memo: Update docs --- README.md | 50 ++++++++++++++++++-------------------------------- 1 file changed, 18 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 360b453..b88b0bd 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Cachet Uptime Robot -Cachet is an open source status page system, this repository is a Python script that does two things, **first**, it reads the status of a page in UptimeRobot and updates a cachet component based on that status and **second**, it updates a metric with the historic uptime data from Uptime Robot. +Cachet is an open source status page system, this repository is a Python script that does two things, **first**, it reads the status of a page in UptimeRobot and updates a cachet component based on that status and **second**, it updates a metric with the historic uptime ratio from Uptime Robot. **Component status: Uptime Robot (left), Cachet (right)** @@ -11,28 +11,22 @@ Cachet is an open source status page system, this repository is a Python script ### Getting started -To get started, you have to specify your Cachet settings and UptimeRobot api key. -```python -UPTIME_ROBOT_API_KEY = 'your-api-key' -``` +To get started, you have to specify your Cachet and UptimeRobot settings and in **config.ini**. +```ini +[uptimeRobot] +UptimeRobotMainApiKey = your-api-key -In the `MONITOR_LIST` variable you have to specify some settings for each monitor. - -```python -MONITOR_LIST = { - 'https://mydomain.com': { - 'api_key': 'cachet-api-key', - 'status_url': 'https://your-status-page-url.com/api/v1', - 'component_id': 1, - 'metric_id': 1, - } -} +[https://url.in.uptime.robot.com] +CachetApiKey = cachet-api-key +CachetUrl = https://status.mycompany.com +MetricId = 1 +ComponentId = 1 ``` -* `api_key`: Global Cachet API key -* `status_url`: URL of the API of the status page you want to show the uptime in. -* `component_id`: Id of the Cachet component with site status -* `metric_id`: Id of the metric where you want to show the uptime graph. +* `CachetApiKey`: Cachet API key. +* `CachetUrl`: URL of the API of the status page you want to show the site availability in. +* `MetricId`: Id of the Cachet metric with site availability. +* `ComponentId`: (Optional) Id of the component you want to update on each check. ### Usage @@ -45,7 +39,7 @@ crontab -e Edit the crontab file and add this line: ```bash -*/5 * * * * python3 ~/cachet-uptime-robot/cron.py +*/5 * * * * python3 ~/path/update_status.py ~/path/config.ini ``` _Note that the path of cron.py may vary depending on the location you cloned the repository_ @@ -55,16 +49,8 @@ _Note that the path of cron.py may vary depending on the location you cloned the You can also update your Cachet data manually by running this: ```python -from update_status import Monitor - -# Create a monitor instance -m = Monitor() - -# Gets uptime data from UptimeRobot and send to Cachet. -m.update_all_monitors() +python3 update_status.py config.ini ->>> Updating monitor MyDomain: URL: https://mydomain.com - id: 12345678 ->>> Created metric with id 27: ->>> {'data': {'id': 27, 'calculated_value': 7872, 'value': 328, 'updated_at': '2016-08-11 08:35:32', 'created_at': '2016-08-11 09:59:59', 'counter': 24, 'metric_id': 1}} ->>> ... +>>> Updating monitor MySite. URL: http://mysite.co. ID: 12345678 +>>> Metric created: {'data': {'calculated_value': 99.99, 'counter': 1, 'metric_id': 4, 'value': 99.99, 'created_at': '2016-08-12 08:23:10', 'updated_at': '2016-08-12 08:23:10', 'id': 99}} ``` From adab3fdb16d3465f2563ccf6a2f1759302ae87e4 Mon Sep 17 00:00:00 2001 From: Pablo Vallejo Date: Fri, 12 Aug 2016 08:56:29 -0500 Subject: [PATCH 5/5] :bug: FIx wrong variable type --- update_status.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/update_status.py b/update_status.py index cefd73c..296879f 100644 --- a/update_status.py +++ b/update_status.py @@ -192,7 +192,7 @@ def send_data_to_catchet(self, monitor): if 'component_id' in website_config: cachet.update_component( website_config['component_id'], - monitor.get('status') + int(monitor.get('status')) ) metric = cachet.set_data_metrics(