@cryptotaxi247 / netdata-1 / commits / 19a9841f3

Add ceph plugin

Luis Eduardo committed Dec 21, 2017 at 17:54 UTC 19a9841f394ae88b5971ce26fab94364e7a2858d
2 files changed +188
conf.d/python.d/ceph.conf new
+5
@@ -0,0 +1,5 @@
1 +update_every : 10
2 +local:
3 + config_file: '/etc/ceph/ceph.conf'
4 + keyring_file: '/etc/ceph/ceph.client.admin.keyring'
5 + presentation_data: 'KB'
\ No newline at end of file
python.d/ceph.chart.py new
+183
@@ -0,0 +1,183 @@
1 +# -*- coding: utf-8 -*-
2 +# Description: ceph netdata python.d module
3 +# Author: Luis Eduardo (lets00)
4 +
5 +import rados
6 +import json
7 +from bases.FrameworkServices.SimpleService import SimpleService
8 +
9 +ORDER = ['general', 'pool_usage', 'pool_objects', 'osd_usage']
10 +
11 +CHARTS = {
12 + 'general': {
13 + 'options': [None, 'Ceph General Options', 'usage', 'general', 'ceph.general', 'line'],
14 + 'lines': []
15 + },
16 + 'pool_usage': {
17 + 'options': [None, 'Ceph Pools', 'usage', 'pool usage', 'ceph.pool_usage', 'line'],
18 + 'lines': []
19 + },
20 + 'pool_objects': {
21 + 'options': [None, 'Ceph Pools', 'objects', 'number of objects', 'ceph.pool_objects', 'line'],
22 + 'lines': []
23 + },
24 + 'osd_usage': {
25 + 'options': [None, 'Ceph OSDs', 'usage', 'osd usage', 'ceph.osd_usage', 'line'],
26 + 'lines': []
27 + }
28 +}
29 +
30 +PRESENTATION_MAP = {
31 + 'KB': 1,
32 + 'MB': 1024,
33 + 'GB': 1024**2,
34 + 'TB': 1024**3
35 +}
36 +
37 +
38 +class Service(SimpleService):
39 + def __init__(self, configuration=None, name=None):
40 + SimpleService.__init__(self, configuration=configuration, name=name)
41 + self.order = ORDER
42 + self.definitions = CHARTS
43 + self.config_file = self.configuration.get('config_file')
44 + self.keyring_file = self.configuration.get('keyring_file')
45 + self.presentation_data = self.configuration.get('presentation_data')
46 + self.presentation_value = None
47 + self.cluster = rados.Rados(conffile=self.config_file,
48 + conf=dict(keyring=self.keyring_file))
49 +
50 + def check(self):
51 + """
52 + Checks module
53 + :return:
54 + """
55 + if not (self.config_file and self.keyring_file):
56 + self.error('config_file and/or keyring_file is not defined')
57 + return False
58 +
59 + # Set default presentation_data to GB if it does not defined and declare
60 + # presentation_value with PRESENTATION_MAP value.
61 + if not self.presentation_data:
62 + self.presentation_data = 'GB'
63 + self.presentation_value = PRESENTATION_MAP[self.presentation_data]
64 + try:
65 + self.cluster.connect()
66 + except Exception as error:
67 + self.error(error)
68 + return False
69 + self.create_definitions()
70 + return True
71 +
72 + def create_definitions(self):
73 + """
74 + Create dynamically charts options, add presentation data/value
75 + set on YAML file
76 + :return: None
77 + """
78 + # Options
79 + self.definitions['general']['options'] = [None, 'Ceph General Options',
80 + 'usage ({})'.format(self.presentation_data),
81 + 'general', 'ceph.general', 'areastack']
82 + self.definitions['pool_usage']['options'] = [None, 'Ceph Pools',
83 + 'usage ({})'.format(self.presentation_data),
84 + 'pool usage', 'ceph.pool_usage', 'line']
85 + self.definitions['osd_usage']['options'] = [None, 'Ceph OSDs',
86 + 'usage ({})'.format(self.presentation_data),
87 + 'osd usage', 'ceph.osd_usage', 'line']
88 +
89 + # Lines
90 + self.definitions['general']['lines'].append(['general_total', 'Total',
91 + 'absolute', 1, self.presentation_value])
92 + self.definitions['general']['lines'].append(['general_usage', 'Usage',
93 + 'absolute', 1, self.presentation_value])
94 + self.definitions['general']['lines'].append(['general_available', 'Available',
95 + 'absolute', 1, self.presentation_value])
96 +
97 + for pool in self.cluster.list_pools():
98 + self.definitions['pool_usage']['lines'].append([pool, pool,
99 + 'absolute', 1, self.presentation_value])
100 + self.definitions['pool_objects']['lines'].append(["obj_{}".format(pool), pool,
101 + 'absolute'])
102 +
103 + for osd in self._get_osds_df()['nodes']:
104 + self.definitions['osd_usage']['lines'].append([osd['name'], osd['name'],
105 + 'absolute', 1, self.presentation_value])
106 +
107 + def get_data(self):
108 + """
109 + Catch all ceph data
110 + :return: dict
111 + """
112 + try:
113 + data = {}
114 + data.update(self._get_general())
115 + data.update(self._get_pool_usage())
116 + data.update(self._get_pool_objects())
117 + data.update(self._get_osd_usage())
118 + return data
119 + except (ValueError, AttributeError):
120 + return None
121 +
122 + def _get_general(self):
123 + """
124 + Get ceph's general usage
125 + :return: dict
126 + """
127 + info = self.cluster.get_cluster_stats()
128 + # Values are get in bytes, convert it
129 + return {'general_total': float(info['kb']),
130 + 'general_usage': float(info['kb_used']),
131 + 'general_available': float(info['kb_avail'])
132 + }
133 +
134 + def _get_pool_usage(self):
135 + """
136 + Process raw data into pool usage dict information
137 + :return: A pool dict with pool name's key and usage bytes' value
138 + """
139 + pool_usage = {}
140 + for df in self._get_df()['pools']:
141 + pool_usage[df['name']] = df['stats']['bytes_used']
142 + return pool_usage
143 +
144 + def _get_pool_objects(self):
145 + """
146 + Process raw data into pool usage dict information
147 + :return: A pool dict with pool name's key and object numbers
148 + """
149 + pool_objects = {}
150 + for df in self._get_df()['pools']:
151 + pool_objects["obj_{}".format(df['name'])] = df['stats']['objects']
152 + return pool_objects
153 +
154 + def _get_osd_usage(self):
155 + # TODO: FIX ME
156 + """
157 + Process raw data into osd dict information to get osd usage
158 + :return: A osd dict with osd name's key and usage bytes' value
159 + """
160 + osd_usage = {}
161 + for osd in self._get_osds_df()['nodes']:
162 + osd_usage[osd['name']] = float(osd['kb_used'])
163 + return osd_usage
164 +
165 + def _get_df(self):
166 + """
167 + Get ceph df output
168 + :return: ceph df --format json
169 + """
170 + return json.loads(self.cluster.mon_command(json.dumps({
171 + 'prefix': 'df',
172 + 'format': 'json'
173 + }), '')[1])
174 +
175 + def _get_osds_df(self):
176 + """
177 + Get ceph osd df output
178 + :return: ceph osd df --format json
179 + """
180 + return json.loads(self.cluster.mon_command(json.dumps({
181 + 'prefix': 'osd df',
182 + 'format': 'json'
183 + }), '')[1])