@cryptotaxi247 / netdata-1 / commits / 02386eb55

First commit new Samba python plugin for smb2 uses smbd -P 1 profiling

Christopher Cox committed Apr 16, 2017 at 15:32 UTC 02386eb5518e9045da22eb4bf5a59c455b842f9c
1 file changed +200
python.d/Samba.chart.py new
+200
@@ -0,0 +1,200 @@
1 +# -*- coding: utf-8 -*-
2 +# Description: samba netdata python.d module
3 +# Author: Christopher Cox <chris_cox@endlessnow.com>
4 +#
5 +# The netdata user needs to be able to be able to sudo the smbstatus program without password
6 +# netdata ALL=(ALL) NOPASSWD: /usr/bin/smbstatus -P
7 +#
8 +# This makes calls to smbstatus -P (note smbd needs to be run with the -P 1 option) a lot.
9 +#
10 +# Right now this just looks for the smb2_ counters, but adjust the regex to get what you need.
11 +#
12 +# The first chart makes a bad assumption that somehow readout/readin and writeout/writein
13 +# have something to do with actual reads and writes. While it seems to be mostly true for reads,
14 +# I am not sure what the write values are. Perhaps they shouldn't be paired?
15 +#
16 +# create and close are paired, maybe they shouldn't be?
17 +#
18 +# getinfo and setinfo are paired, maybe they shouldn't be?
19 +#
20 +# The Other Smb2 chart is merely a display of current counter values. They didn't seem to change
21 +# much to me. However, if you notice something changing a lot there, bring one or more out into its own
22 +# chart and make it incremental (like find and notify... good examples).
23 +
24 +
25 +from base import SimpleService
26 +from re import compile
27 +from subprocess import Popen, PIPE
28 +
29 +# default module values (can be overridden per job in `config`)
30 +# update_every = 2
31 +priority = 60000
32 +retries = 60
33 +
34 +ORDER = ['smb2_rw','smb2_create_close','smb2_info','smb2_find','smb2_notify','smb2_sm_count']
35 +
36 +# The weird dummy1, etc. is for color selection.
37 +
38 +CHARTS = {
39 + 'smb2_rw': {
40 + 'lines': [
41 + ['smb2_read_outbytes', 'readout', 'incremental', 1, 1024],
42 + ['smb2_write_inbytes', 'writein', 'incremental', -1, 1024],
43 + ['smb2_read_inbytes', 'readin', 'incremental', 1, 1024],
44 + ['smb2_write_outbytes', 'writeout', 'incremental', -1, 1024]
45 + ],
46 + 'options': [None, 'R/Ws', 'kilobytes/s', 'Smb2', 'smb2.readwrite', 'area']
47 + },
48 + 'smb2_create_close': {
49 + 'lines': [
50 + ['dummy1', ' ', 'incremental', 1, 1],
51 + ['dummy2', ' ', 'incremental', 1, 1],
52 + ['smb2_create_count', 'create', 'incremental', 1, 1],
53 + ['smb2_close_count', 'close', 'incremental', -1, 1]
54 + ],
55 + 'options': [None, 'Create/Close', 'operations/s', 'Smb2', 'smb2.create_close', 'area']
56 + },
57 + 'smb2_info': {
58 + 'lines': [
59 + ['dummy1', ' ', 'incremental', 1, 1],
60 + ['dummy2', ' ', 'incremental', 1, 1],
61 + ['dummy3', ' ', 'incremental', 1, 1],
62 + ['dummy4', ' ', 'incremental', 1, 1],
63 + ['smb2_getinfo_count', 'getinfo', 'incremental', 1, 1],
64 + ['smb2_setinfo_count', 'setinfo', 'incremental', -1, 1]
65 + ],
66 + 'options': [None, 'Info', 'operations/s', 'Smb2', 'smb2.get_set_info', 'area']
67 + },
68 + 'smb2_find': {
69 + 'lines': [
70 + ['dummy1', ' ', 'incremental', 1, 1],
71 + ['dummy2', ' ', 'incremental', 1, 1],
72 + ['dummy3', ' ', 'incremental', 1, 1],
73 + ['dummy4', ' ', 'incremental', 1, 1],
74 + ['dummy5', ' ', 'incremental', 1, 1],
75 + ['dummy6', ' ', 'incremental', 1, 1],
76 + ['smb2_find_count', 'find', 'incremental', 1, 1]
77 + ],
78 + 'options': [None, 'Find', 'operations/s', 'Smb2', 'smb2.find', 'area']
79 + },
80 + 'smb2_notify': {
81 + 'lines': [
82 + ['dummy1', ' ', 'incremental', 1, 1],
83 + ['dummy2', ' ', 'incremental', 1, 1],
84 + ['dummy3', ' ', 'incremental', 1, 1],
85 + ['dummy4', ' ', 'incremental', 1, 1],
86 + ['dummy5', ' ', 'incremental', 1, 1],
87 + ['dummy6', ' ', 'incremental', 1, 1],
88 + ['dummy7', ' ', 'incremental', 1, 1],
89 + ['smb2_notify_count', 'notify', 'incremental', 1, 1]
90 + ],
91 + 'options': [None, 'Notify', 'operations/s', 'Smb2', 'smb2.notify', 'area']
92 + },
93 + 'smb2_sm_count': {
94 + 'lines': [
95 + ['smb2_tcon_count', 'tcon', 'absolute', 1, 1],
96 + ['smb2_negprot_count', 'negprot', 'absolute', 1, 1],
97 + ['smb2_tdis_count', 'tdis', 'absolute', 1, 1],
98 + ['smb2_cancel_count', 'cancel', 'absolute', 1, 1],
99 + ['smb2_logoff_count', 'logoff', 'absolute', 1, 1],
100 + ['smb2_flush_count', 'flush', 'absolute', 1, 1],
101 + ['smb2_lock_count', 'lock', 'absolute', 1, 1],
102 + ['smb2_keepalive_count', 'keepalive', 'absolute', 1, 1],
103 + ['smb2_break_count', 'break', 'absolute', 1, 1],
104 + ['smb2_sessetup_count', 'sessetup', 'absolute', 1, 1]
105 + ],
106 + 'options': [None, 'Lesser Ops', 'count', 'Other Smb2', 'smb2.sm_counters', 'stacked']
107 + }
108 + }
109 +
110 +
111 +class Service(SimpleService):
112 + def __init__(self, configuration=None, name=None):
113 + SimpleService.__init__(self, configuration=configuration, name=name)
114 + self.smbstatus = self.find_binary('smbstatus')
115 + self.rgx_smb2 = compile(r'(smb2_[^:]+):\s+(\d+)')
116 + self.cache_prev = list()
117 +
118 + def check(self):
119 + # Cant start without 'smbstatus' command
120 + if not self.smbstatus:
121 + self.error('Can\'t locate \'smbstatus\' binary or binary is not executable by netdata')
122 + return False
123 +
124 + # If command is present and we can execute it we need to make sure..
125 + # 1. STDOUT is not empty
126 + reply = self._get_raw_data()
127 + if not reply:
128 + self.error('No output from \'smbstatus\' (not enough privileges?)')
129 + return False
130 + self.error(reply)
131 +
132 + # 2. Output is parsable (list is not empty after regex findall)
133 + is_parsable = self.rgx_smb2.findall(reply)
134 + if not is_parsable:
135 + self.error('Cant parse output...')
136 + return False
137 +
138 + # We are about to start!
139 + self.create_charts()
140 +
141 + self.info('Plugin was started successfully')
142 + return True
143 +
144 + def _get_raw_data(self):
145 + try:
146 + reply = Popen(['/usr/bin/sudo', self.smbstatus, '-P'], stdout=PIPE, stderr=PIPE, shell=False)
147 + except OSError:
148 + return None
149 +
150 + raw_data = reply.communicate()[0]
151 +
152 + if not raw_data:
153 + return None
154 +
155 + return raw_data.decode()
156 +
157 + def _get_data(self):
158 + """
159 + Format data received from shell command
160 + :return: dict
161 + """
162 + raw_data = self._get_raw_data()
163 + data_all = self.rgx_smb2.findall(raw_data)
164 +
165 + if not data_all:
166 + return None
167 +
168 + # 1. ALL data from 'smbstatus -P'.
169 + to_netdata = dict([(k, int(v)) for k, v in data_all])
170 + # Add dummy values that are always zero (forcing color selection in charts)
171 + to_netdata['dummy1'] = 0
172 + to_netdata['dummy2'] = 0
173 + to_netdata['dummy3'] = 0
174 + to_netdata['dummy4'] = 0
175 + to_netdata['dummy5'] = 0
176 + to_netdata['dummy6'] = 0
177 + to_netdata['dummy7'] = 0
178 + to_netdata['dummy8'] = 0
179 +
180 + # Ready steady go!
181 + return to_netdata
182 +
183 + def create_charts(self):
184 + # If 'all_charts' is true...ALL charts are displayed. If no only default + 'extra_charts'
185 + #if self.configuration.get('all_charts'):
186 + # self.order = EXTRA_ORDER
187 + #else:
188 + # try:
189 + # extra_charts = list(filter(lambda chart: chart in EXTRA_ORDER, self.extra_charts.split()))
190 + # except (AttributeError, NameError, ValueError):
191 + # self.error('Extra charts disabled.')
192 + # extra_charts = []
193 +
194 + self.order = ORDER[:]
195 + #self.order.extend(extra_charts)
196 +
197 + # Create static charts
198 + #self.definitions = {chart: values for chart, values in CHARTS.items() if chart in self.order}
199 + self.definitions = CHARTS
200 +