server.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. #!/usr/bin/env python
  2. import copy
  3. import datetime
  4. import errno
  5. import json
  6. import os
  7. from os import path
  8. import traceback
  9. import urlparse
  10. import warnings
  11. warnings.filterwarnings('ignore', 'libevent')
  12. import gevent.pywsgi
  13. import fileio
  14. import reloader
  15. DATA_DIR = path.expanduser('~/sysvitals_data')
  16. handlers = None
  17. def main():
  18. global handlers
  19. handlers = {
  20. 'data': get_data,
  21. 'datum': post_datum,
  22. }
  23. server = gevent.pywsgi.WSGIServer(('0.0.0.0', 8892), application)
  24. reloader.init(server)
  25. server.serve_forever()
  26. def application(environ, start_response):
  27. try:
  28. split = environ['PATH_INFO'][1:].split('/')
  29. qs = environ['QUERY_STRING']
  30. if qs:
  31. query = urlparse.parse_qs(qs, True, True)
  32. for k, v in query.items():
  33. if len(v) > 1:
  34. start_response('400 Bad Request', [('Content-type', 'text/plain')])
  35. return ['duplicate query parameter: ' + k]
  36. query[k] = v[0]
  37. else:
  38. query = {}
  39. if split[0] == 'v1':
  40. handler = handlers.get(split[2])
  41. if handler:
  42. body = json.dumps(handler(split, query, environ))
  43. start_response('200 OK', [('Content-type', 'application/json')])
  44. return [body]
  45. else:
  46. print 'no handler for', split
  47. else:
  48. print 'split was', split
  49. start_response('404 Not Found', [('Content-type', 'text/plain')])
  50. return ['404 Not Found']
  51. except:
  52. traceback.print_exc()
  53. start_response('500 Internal Server Error', [('Content-type', 'text/plain')])
  54. return ['ruh roh']
  55. def get_data(split, query, environ):
  56. group = int(split[1])
  57. server_id = int(split[3])
  58. start = datetime.datetime.strptime(query['start'], '%Y-%m-%d').date()
  59. end = datetime.datetime.strptime(query['end'], '%Y-%m-%d').date()
  60. server_dir = path.join(DATA_DIR, str(group), str(server_id))
  61. rval = {}
  62. c = start
  63. while c <= end:
  64. date_str = c.isoformat()
  65. with open(path.join(server_dir, date_str), 'r') as f:
  66. stats = fileio.read_stats(f)
  67. rval[date_str] = stats
  68. c += datetime.timedelta(days=1)
  69. return rval
  70. def post_datum(split, query, environ):
  71. group = int(split[1])
  72. server_id = int(split[3])
  73. body = json.load(environ['wsgi.input'])
  74. server_dir = path.join(DATA_DIR, str(group), str(server_id))
  75. try:
  76. os.makedirs(server_dir)
  77. except OSError as e:
  78. if e.errno != errno.EEXIST:
  79. raise
  80. # we floor to the minute, so this rounds to the nearest minute
  81. now = datetime.datetime.utcnow() + datetime.timedelta(seconds=29)
  82. data_path = path.join(server_dir, now.date().isoformat())
  83. try:
  84. with open(data_path, 'r') as f:
  85. stats = fileio.read_stats(f)
  86. except IOError as e:
  87. if e.errno != errno.ENOENT:
  88. raise
  89. stats = copy.deepcopy(fileio.TEMPLATE)
  90. index = now.hour * 60 + now.minute
  91. data = {}
  92. for field, subfields in stats.items():
  93. field_data = {}
  94. if field == 'disk':
  95. disk = stats['disk']
  96. for mountpoint, datum in body['disk'].items(): # iterate through body to get new mountpoints
  97. disk.setdefault(mountpoint, {'total': [-1] * 1440, 'used': [-1] * 1440})
  98. field_data[mountpoint] = {}
  99. for subfield, array in disk[mountpoint].items():
  100. array = list(array)
  101. array[index] = datum[subfield]
  102. field_data[mountpoint][subfield] = array
  103. else:
  104. for subfield, array in subfields.items():
  105. array = list(array)
  106. array[index] = body[field][subfield]
  107. field_data[subfield] = array
  108. data[field] = field_data
  109. with open(data_path, 'w') as f:
  110. fileio.write_datum(f, data)
  111. return {'status': 'ok'}
  112. main()