forked from Crapworks/ceph-dash
/
ceph-dash.py
executable file
·118 lines (91 loc) · 3.24 KB
/
ceph-dash.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
ceph-dash.py
~~~~~~~~~~~~
Flask based api / dashboard for viewing a ceph clusters overall health
status
:copyright: (c) 2014 by Christian Eichelmann
:license: BSD, see LICENSE for more details.
"""
import os
import json
from flask import Flask
from flask import request
from flask import render_template
from flask import abort
from flask import jsonify
from flask.views import MethodView
from rados import Rados
from rados import ObjectNotFound
from rados import PermissionError
from rados import Error as RadosError
from werkzeug.exceptions import default_exceptions
from werkzeug.exceptions import HTTPException
class CephApiConfig(dict):
""" loads the json configuration file """
def _string_decode_hook(self, data):
rv = {}
for key, value in data.iteritems():
if isinstance(key, unicode):
key = key.encode('utf-8')
if isinstance(value, unicode):
value = value.encode('utf-8')
rv[key] = value
return rv
def __init__(self):
dict.__init__(self)
configfile = os.path.join(os.path.dirname(__file__), 'config.json')
self.update(json.load(open(configfile), object_hook=self._string_decode_hook))
class CephStatusView(MethodView):
"""
Endpoint that shows overall cluster status
"""
def __init__(self):
MethodView.__init__(self)
self.config = CephApiConfig()
def get(self):
with Rados(conffile=self.config['ceph_config']) as cluster:
command = { 'prefix': 'status', 'format': 'json' }
ret, buf, err = cluster.mon_command(json.dumps(command), '', timeout=5)
if ret != 0:
abort(500, err)
if request.mimetype == 'application/json':
return jsonify(json.loads(buf))
else:
return render_template('status.html', data=json.loads(buf))
class CephAPI(Flask):
def __init__(self, name):
Flask.__init__(self, name)
status_view = CephStatusView.as_view('status')
self.add_url_rule('/', view_func=status_view)
# add custom error handler
for code in default_exceptions.iterkeys():
self.error_handler_spec[None][code] = self.make_json_error
def make_json_error(self, ex):
if isinstance(ex, HTTPException):
code = ex.code
message = ex.description
elif isinstance(ex, ObjectNotFound):
code = 404
message = "object not found: " + str(ex)
elif isinstance(ex, PermissionError):
code = 403
message = "permission error: " + str(ex)
elif isinstance(ex, RadosError):
code = 400
message = "rados error: " + str(ex)
else:
code = 500
message = str(ex)
# TODO: make it possible to use fancy gui errors here
response = jsonify(code=code, message=message)
response.status_code = code
if code == 401:
response.headers['WWW-Authenticate'] = 'Basic realm="Login Required"'
return response
def main():
app = CephAPI(__name__)
app.run(debug=False, host='0.0.0.0')
if __name__ == '__main__':
main()