-
Notifications
You must be signed in to change notification settings - Fork 8
/
ceph.py
140 lines (110 loc) · 4.04 KB
/
ceph.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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# ceph-collectd-plugin - ceph.py
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; only version 2 of the License is applicable.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# Authors:
# Christian Eichelmann <crapworks at gmx.net>
#
# About this plugin:
# This plugin uses collectd's Python plugin to record ceph performances
# data via the specified admin socket.
#
# collectd:
# http://collectd.org
# Redis:
# http://ceph.com
# collectd-python:
# http://collectd.org/documentation/manpages/collectd-python.5.shtml
import collectd
import socket
import struct
import json
import glob
import re
CEPH_ADMIN_SOCKET=''
# ceph asok format: /var/run/ceph/{cluser}-{id}.asok
ADMIN_SOCKET_REGEXP = '.*/(.+)\-(.+)\.asok$'
ADMIN_SOCKET_PATTERN = re.compile(ADMIN_SOCKET_REGEXP)
def get_cluster_name(admin_socket):
"""returns the cluster name part from admin socket"""
m = ADMIN_SOCKET_PATTERN.match(admin_socket)
name = None
if m:
name = m.group(1)
return name
def get_instance_name(admin_socket):
"""returns the component (osd, mon, rgw) name part from admin socket"""
m = ADMIN_SOCKET_PATTERN.match(admin_socket)
name = None
if m:
name = m.group(2)
return name
def query_admin_socket(admin_socket, cmd):
""" Talk to ceph's admin socket """
try:
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock.connect(admin_socket)
except socket.error, e:
collectd.error('ERROR: ceph plugin: Connecting to %s: - %r' % (admin_socket, e))
return None
sock.sendall(cmd)
try:
length = struct.unpack('>i', sock.recv(4))[0]
json_data = json.loads(sock.recv(length))
except Exception as err:
collectd.error('ERROR: ceph plugin: Unable to parse json: %r' % (err, ))
json_data = {}
finally:
sock.close()
return json_data
def configure_callback(conf):
""" Collectd configuration callback """
global CEPH_ADMIN_SOCKET
for node in conf.children:
if node.key == 'AdminSocket':
CEPH_ADMIN_SOCKET= node.values[0]
else:
collectd.warning('WARNING: ceph plugin: Unknown config key: %s.' % (node.key, ))
def dispatch_value(collectd_type, plugin_instance, values):
""" Dispatch wrapper for collectd """
cleaned_values = []
for value in values:
if isinstance(value, dict):
cleaned_values.append(value['avgcount'])
else:
cleaned_values.append(value)
val = collectd.Values(plugin='ceph')
val.type = collectd_type
val.plugin_instance = plugin_instance
val.values = cleaned_values
val.dispatch()
def read_callback():
for admin_socket in glob.glob(CEPH_ADMIN_SOCKET):
# extract instance name directly from admin_socket: /var/run/ceph/ceph-osd.25.asok -> osd.25
plugin_instance = get_instance_name(admin_socket)
if not plugin_instance:
collectd.error('ERROR: ceph plugin: No name found in asok: %s' % admin_socket)
return
# query 'perf dump'
perfdata = query_admin_socket(admin_socket, '{\"prefix\": \"perf dump\"}\0')
if not perfdata:
collectd.error('ERROR: ceph plugin: No perf data received from %s' % admin_socket)
return
for collectd_type, value in perfdata.iteritems():
if not value:
continue
dispatch_value(collectd_type, plugin_instance, value.values())
# register callbacks
collectd.register_config(configure_callback)
collectd.register_read(read_callback)