]>
Commit | Line | Data |
---|---|---|
ad51e17e | 1 | #!/usr/bin/python2 |
8861bf39 RM |
2 | # |
3 | # Authors: | |
4 | # rafael@E-MC2.NET / https://e-mc2.net/ | |
5 | # | |
6 | # Copyright (c) 2018 USIT-University of Oslo | |
7 | # | |
8 | # zabbix_get_rabbitmq_stats.py is free software: you can redistribute | |
9 | # it and/or modify it under the terms of the GNU General Public | |
10 | # License as published by the Free Software Foundation, either version | |
11 | # 3 of the License, or (at your option) any later version. | |
12 | # | |
13 | # zabbix_get_rabbitmq_stats.py is distributed in the hope that it will | |
14 | # be useful, but WITHOUT ANY WARRANTY; without even the implied | |
15 | # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | |
16 | # See the GNU General Public License for more details. | |
17 | # | |
18 | # You should have received a copy of the GNU General Public License | |
19 | # along with sms_send. If not, see <http://www.gnu.org/licenses/>. | |
20 | # | |
21 | ||
22 | import requests | |
23 | import json | |
24 | import sys | |
25 | import os | |
26 | import tempfile | |
27 | import socket | |
28 | import subprocess | |
29 | ||
30 | # Zabbix proxy | |
31 | zabbix_proxy = ['zabbix-proxy-prod03.uio.no','zabbix-proxy-prod04.uio.no'] | |
32 | ||
33 | # Path to zabbix_sender | |
34 | zabbix_sender = '/usr/bin/zabbix_sender' | |
35 | ||
36 | # RabbitMQ server domain | |
37 | domain = ".uio.no" | |
38 | ||
39 | # Authentication file with username / password used to access RabbitMQ | |
40 | # API. | |
41 | auth_file = "/var/lib/zabbix/.rabbitmq_auth" | |
42 | ||
43 | ||
44 | # ############################################ | |
45 | # get_auth_data() | |
46 | # ############################################ | |
47 | ||
48 | def get_auth_data(): | |
49 | ||
50 | try: | |
51 | ||
52 | username = "none" | |
53 | password = "none" | |
54 | ||
55 | if os.path.isfile(auth_file): | |
56 | ||
57 | with open(auth_file, 'r') as f: | |
58 | for line in f: | |
59 | (username, password) = line.split('::') | |
60 | ||
61 | password = password.replace('\n', '') | |
62 | ||
63 | return username,password | |
64 | ||
65 | except Exception as e: | |
66 | raise Exception("[ERROR]: %s\n" % e) | |
67 | ||
68 | ||
69 | # ############################################ | |
70 | # get_rabbitmq_data() | |
71 | # ############################################ | |
72 | ||
73 | def get_rabbitmq_data(component): | |
74 | ||
75 | try: | |
76 | (username,password) = get_auth_data() | |
77 | request_data = requests.get("http://127.0.0.1:15672/api/" + component ,auth=(username,password)) | |
78 | ||
79 | if request_data.status_code != 200: | |
d2217524 | 80 | raise Exception("[ERROR]: Problems connecting to rabbitMQ stats API\n") |
8861bf39 RM |
81 | |
82 | data = request_data.json() | |
83 | ||
84 | return data | |
85 | ||
86 | except Exception as e: | |
87 | raise Exception("[ERROR]: %s\n" % e) | |
88 | ||
89 | ||
90 | # ############################################ | |
91 | # generate_zabbix_autodiscovery() | |
92 | # ############################################ | |
93 | ||
94 | def generate_zabbix_sender_data(data,component): | |
95 | ||
96 | try: | |
97 | result = "" | |
98 | hostname = socket.gethostname() | |
99 | ||
100 | if component == "queues": | |
101 | ||
102 | for queue in data: | |
103 | if hostname.replace(domain,'') in queue['node']: | |
104 | ||
105 | result += hostname + " queue.consumers[" + queue['vhost'] + "," + queue['name'] + "] " + str(queue['consumers']) + "\n" | |
106 | ||
107 | # consumer_utilisation is defined as none when the | |
108 | # queue is not in use. | |
109 | ||
110 | if queue['consumer_utilisation'] == None: | |
111 | queue['consumer_utilisation'] = 0 | |
112 | ||
113 | result += hostname + " queue.consumer.utilisation[" + queue['vhost'] + "," + queue['name'] + "] " + str(queue['consumer_utilisation']) + "\n" | |
114 | result += hostname + " queue.memory[" + queue['vhost'] + "," + queue['name'] + "] " + str(queue['memory']) + "\n" | |
115 | result += hostname + " queue.messages[" + queue['vhost'] + "," + queue['name'] + "] " + str(queue['messages']) + "\n" | |
116 | result += hostname + " queue.message.bytes[" + queue['vhost'] + "," + queue['name'] + "] " + str(queue['message_bytes']) + "\n" | |
117 | ||
118 | # message_stats is not defined when the queue is | |
119 | # not in use. | |
120 | ||
121 | if 'message_stats' in queue: | |
122 | ||
123 | result += hostname + " queue.messages.deliver.get[" + queue['vhost'] + "," + queue['name'] + "] " + str(queue['message_stats']['deliver_get']) + "\n" | |
124 | result += hostname + " queue.messages.publish[" + queue['vhost'] + "," + queue['name'] + "] " + str(queue['message_stats']['publish']) + "\n" | |
125 | ||
126 | result += hostname + " queue.messages.ram[" + queue['vhost'] + "," + queue['name'] + "] " + str(queue['messages_ram']) + "\n" | |
127 | result += hostname + " queue.node[" + queue['vhost'] + "," + queue['name'] + "] " + str(queue['node']) + "\n" | |
128 | result += hostname + " queue.state[" + queue['vhost'] + "," + queue['name'] + "] " + str(queue['state']) + "\n" | |
129 | ||
130 | elif component == "nodes": | |
131 | ||
132 | for node in data: | |
133 | if hostname.replace(domain,'') in node['name']: | |
134 | ||
135 | result += hostname + " node.disk.free " + str(node['disk_free']) + "\n" | |
136 | result += hostname + " node.disk.free.alarm " + str(node['disk_free_alarm']) + "\n" | |
137 | result += hostname + " node.disk.free.limit " + str(node['disk_free_limit']) + "\n" | |
138 | result += hostname + " node.proc.total " + str(node['proc_total']) + "\n" | |
139 | result += hostname + " node.proc.used " + str(node['proc_used']) + "\n" | |
140 | result += hostname + " node.run.queue " + str(node['run_queue']) + "\n" | |
141 | result += hostname + " node.fd.total " + str(node['fd_total']) + "\n" | |
142 | result += hostname + " node.fd.used " + str(node['fd_used']) + "\n" | |
143 | result += hostname + " node.io.read.bytes " + str(node['io_read_bytes']) + "\n" | |
144 | result += hostname + " node.io.read.count " + str(node['io_read_count']) + "\n" | |
145 | result += hostname + " node.io.seek.count " + str(node['io_seek_count']) + "\n" | |
146 | result += hostname + " node.io.sync.count " + str(node['io_sync_count']) + "\n" | |
147 | result += hostname + " node.io.write.bytes " + str(node['io_write_bytes']) + "\n" | |
148 | result += hostname + " node.io.write.count " + str(node['io_write_count']) + "\n" | |
149 | result += hostname + " node.mem.used " + str(node['mem_used']) + "\n" | |
150 | result += hostname + " node.mem.alarm " + str(node['mem_alarm']) + "\n" | |
151 | result += hostname + " node.mem.limit " + str(node['mem_limit']) + "\n" | |
152 | result += hostname + " node.queue.index.journal.write.count " + str(node['queue_index_journal_write_count']) + "\n" | |
153 | result += hostname + " node.sockets.total " + str(node['sockets_total']) + "\n" | |
154 | result += hostname + " node.sockets.used " + str(node['sockets_used']) + "\n" | |
155 | result += hostname + " node.uptime " + str(node['uptime']) + "\n" | |
156 | ||
157 | elif component == "overview": | |
158 | ||
159 | result += hostname + " cluster.name " + str(data['cluster_name']) + "\n" | |
160 | result += hostname + " cluster.rabbitmq.version " + str(data['rabbitmq_version']) + "\n" | |
161 | result += hostname + " cluster.erlang.version " + str(data['erlang_version']) + "\n" | |
162 | result += hostname + " cluster.messages " + str(data['queue_totals']['messages']) + "\n" | |
163 | result += hostname + " cluster.messages.deliver.get " + str(data['message_stats']['deliver_get']) + "\n" | |
164 | result += hostname + " cluster.messages.publish " + str(data['message_stats']['publish']) + "\n" | |
165 | result += hostname + " cluster.total.channels " + str(data['object_totals']['channels']) + "\n" | |
166 | result += hostname + " cluster.total.connections " + str(data['object_totals']['connections']) + "\n" | |
167 | result += hostname + " cluster.total.consumers " + str(data['object_totals']['consumers']) + "\n" | |
168 | result += hostname + " cluster.total.exchanges " + str(data['object_totals']['exchanges']) + "\n" | |
169 | result += hostname + " cluster.total.queues " + str(data['object_totals']['queues']) + "\n" | |
170 | ||
171 | return result | |
172 | ||
173 | except Exception as e: | |
174 | raise Exception("[ERROR]: %s\n" % e) | |
175 | ||
176 | ||
177 | if __name__ == '__main__': | |
178 | ||
179 | try: | |
180 | ||
d2217524 RM |
181 | # |
182 | # We send data about queues, nodes and cluster to Zabbix | |
183 | # | |
184 | ||
8861bf39 RM |
185 | for component in ['queues','nodes','overview']: |
186 | ||
187 | # Temp file with full json output | |
188 | tmp_stat_file = tempfile.NamedTemporaryFile(delete=False,dir='/tmp') | |
189 | ||
190 | data = get_rabbitmq_data(component) | |
191 | result = generate_zabbix_sender_data(data,component) | |
192 | ||
193 | # | |
194 | # We create a file with the data that zabbix_sender will | |
195 | # send in a bulk execution. | |
196 | # | |
197 | ||
198 | with open(tmp_stat_file.name,'w') as f: | |
199 | f.write(result) | |
200 | ||
201 | # | |
202 | # The monitoring of this host can be done by any of the | |
d2217524 | 203 | # zabbix proxies defined in zabbix_proxy[]. We try all of |
8861bf39 RM |
204 | # them until one of them accepts our data |
205 | # | |
206 | ||
207 | for proxy in zabbix_proxy: | |
208 | ||
209 | command = zabbix_sender + ' -z ' + proxy + ' -i ' + tmp_stat_file.name + ' > /dev/null 2>&1' | |
210 | ||
d2217524 | 211 | proc = subprocess.Popen([command],shell=True) |
8861bf39 RM |
212 | proc.wait() |
213 | ||
214 | if proc.returncode == 0: | |
215 | break | |
216 | ||
217 | # Delete temp file with zabbix_sender data | |
218 | os.remove(tmp_stat_file.name) | |
219 | ||
220 | # Return value 0 = execution OK | |
221 | print("0") | |
222 | ||
223 | except Exception, e: | |
224 | print("1") | |
225 | sys.exit(1) |