#!/usr/bin/env python import warnings warnings.filterwarnings('ignore', 'libevent') import gevent.monkey gevent.monkey.patch_all(thread=False) import copy import datetime import errno import json import os from os import path import traceback import urlparse import gevent.pywsgi import fileio import reloader DATA_DIR = path.expanduser('~/sysvitals_data') handlers = None def main(): global handlers handlers = { 'data': get_data, 'datum': post_datum, } server = gevent.pywsgi.WSGIServer(('0.0.0.0', 8892), application) reloader.init(server) server.serve_forever() def application(environ, start_response): try: split = environ['PATH_INFO'][1:].split('/') qs = environ['QUERY_STRING'] if qs: query = urlparse.parse_qs(qs, True, True) for k, v in query.items(): if len(v) > 1: start_response('400 Bad Request', [('Content-type', 'text/plain')]) return ['duplicate query parameter: ' + k] query[k] = v[0] else: query = {} if split[0] == 'v1': handler = handlers.get(split[2]) if handler: body = json.dumps(handler(split, query, environ)) start_response('200 OK', [('Content-type', 'application/json')]) return [body] else: print 'no handler for', split else: print 'split was', split start_response('404 Not Found', [('Content-type', 'text/plain')]) return ['404 Not Found'] except: traceback.print_exc() start_response('500 Internal Server Error', [('Content-type', 'text/plain')]) return ['ruh roh'] def get_data(split, query, environ): group = int(split[1]) server_id = int(split[3]) start = datetime.datetime.strptime(query['start'], '%Y-%m-%d').date() end = datetime.datetime.strptime(query['end'], '%Y-%m-%d').date() server_dir = path.join(DATA_DIR, str(group), str(server_id)) rval = {} c = start while c <= end: date_str = c.isoformat() with open(path.join(server_dir, date_str), 'r') as f: stats = fileio.read_stats(f) rval[date_str] = stats c += datetime.timedelta(days=1) return rval def post_datum(split, query, environ): group = int(split[1]) server_id = int(split[3]) body = json.load(environ['wsgi.input']) server_dir = path.join(DATA_DIR, str(group), str(server_id)) try: os.makedirs(server_dir) except OSError as e: if e.errno != errno.EEXIST: raise # we floor to the minute, so this rounds to the nearest minute now = datetime.datetime.utcnow() + datetime.timedelta(seconds=29) data_path = path.join(server_dir, now.date().isoformat()) try: with open(data_path, 'r') as f: stats = fileio.read_stats(f) except IOError as e: if e.errno != errno.ENOENT: raise stats = copy.deepcopy(fileio.TEMPLATE) index = now.hour * 60 + now.minute data = {} for field, subfields in stats.items(): field_data = {} if field == 'disk': disk = stats['disk'] for mountpoint, datum in body['disk'].items(): # iterate through body to get new mountpoints disk.setdefault(mountpoint, {'total': [-1] * 1440, 'used': [-1] * 1440}) field_data[mountpoint] = {} for subfield, array in disk[mountpoint].items(): array = list(array) array[index] = datum[subfield] field_data[mountpoint][subfield] = array else: for subfield, array in subfields.items(): array = list(array) array[index] = body[field][subfield] field_data[subfield] = array data[field] = field_data with open(data_path, 'w') as f: fileio.write_datum(f, data) return {'status': 'ok'} main()