]>
Commit | Line | Data |
---|---|---|
bfda2ced MO |
1 | #!/usr/bin/env python |
2 | # | |
3 | # Authors: | |
4 | # Mustafa Ocak | |
5 | # muo@uio.no | |
6 | # | |
7 | # Copyright (c) 2016 USIT-University of Oslo | |
8 | # | |
9 | # zabbix_elk_container.py: Used by zabbix_agent to pull kibana and logstash | |
10 | # service information from consul key-value db. | |
11 | # Service information from consul is used to low-level discovery of logstash | |
12 | # instanses and building url of kibana instanses. | |
13 | # Logstash instanses are monitored by net.tcp.service and Kibana web services | |
14 | # are monitored by this script. | |
15 | # | |
16 | # zabbix_elk_container.py is free software: you can | |
17 | # redistribute it and/or modify it under the terms of the GNU General | |
18 | # Public License as published by the Free Software Foundation, either | |
19 | # version 3 of the License, or (at your option) any later version. | |
20 | # | |
21 | # zabbix_elk_container.py is distributed in the hope | |
22 | # that it will be useful, but WITHOUT ANY WARRANTY; without even the | |
23 | # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR | |
24 | # PURPOSE. See the GNU General Public License for more details. | |
25 | # | |
26 | # You should have received a copy of the GNU General Public License | |
27 | # along with sms_send. If not, see <http://www.gnu.org/licenses/>. | |
28 | # | |
29 | ||
30 | import requests | |
31 | import re | |
32 | import json | |
33 | import socket | |
34 | import sys | |
35 | ||
36 | ||
37 | ||
38 | # ########################################################## | |
39 | # Getting the list of all the services registred in consul. | |
40 | # ########################################################## | |
41 | ||
42 | def get_services(consul_catalog_url): | |
43 | ||
44 | # list of all the registred services in consul | |
45 | servicefqdnlist=[] | |
46 | ||
47 | try: | |
48 | response = requests.get(consul_catalog_url) | |
49 | ||
50 | if (response.status_code == 200): | |
51 | jsonout=response.json() | |
52 | for servicename_fqdn in jsonout: | |
53 | ||
54 | # finding all the logstash service fqdn entries. | |
55 | matchobj = re.search(r'logstash',servicename_fqdn,re.IGNORECASE) | |
56 | if (matchobj): | |
57 | servicefqdnlist.append(servicename_fqdn) | |
58 | return servicefqdnlist | |
59 | except Exception as e: | |
60 | print e | |
61 | sys.exit(1) | |
62 | ||
63 | # ########################################################## | |
64 | # Getting the list of all the logowners registred in consul. | |
65 | # ########################################################## | |
66 | ||
67 | def get_logowners (consul_kv_url,servicetype): | |
68 | ''' | |
69 | Get logowners from consul. Consul url structure is as follows: | |
70 | http://localhost:8500/v1/kv/uio-elk/services/<servicetype>/<logowner> | |
71 | ''' | |
72 | logowners=[] | |
73 | try: | |
74 | response = requests.get(consul_kv_url+servicetype+'?recurse') | |
75 | if (response.status_code == 200): | |
76 | jsonout = response.json() | |
77 | for jsonelement in jsonout: | |
78 | ||
79 | # jsonelement['Key']= "uio-elk/services/kibana/usit-gid/host" | |
80 | # value[3]="usit-gid" | |
81 | value = jsonelement['Key'].split("/") | |
82 | if value[3] not in logowners: | |
83 | logowners.append(value[3]) | |
84 | return logowners | |
85 | except Exception as e: | |
86 | print e | |
87 | sys.exit(1) | |
88 | ||
89 | # ###################################################################### | |
90 | # Get list of all logstash instanses for low-level discovery in zabbix. | |
91 | # ###################################################################### | |
92 | ||
93 | def get_logstash_instanses (consul_kv_url,servicetype,servicefqdnlist,logowners): | |
94 | ''' | |
95 | Pipelines for windows logs are as follows | |
96 | ||
97 | --> |nxlog-server|--> |logstash-instanse| --> |ELK| | |
98 | or | |
99 | --> |logstash-instanse| --> |ELK| | |
100 | ||
101 | This function finds whether there is a nxlog-server or not in front of logstash-instanse | |
102 | and builds a list of dictionary | |
103 | ||
104 | logstash_instanse = { | |
105 | 'logowner':.., | |
106 | 'type':.., | |
107 | 'service':.., | |
108 | 'port':.., | |
109 | 'host':.., | |
110 | 'nxlog':true|false | |
111 | } | |
112 | logstash_service_list = [ logstash_instanse,...] | |
113 | ''' | |
114 | ||
115 | serviceadded=[] | |
116 | logstash_lld=[] | |
117 | ||
118 | try: | |
119 | ||
120 | for logowner in logowners: | |
121 | response = requests.get(consul_kv_url+servicetype+'/'+logowner+'?recurse') | |
122 | nxlog = "false" | |
123 | ||
124 | if response.status_code == 200: | |
125 | jsonout = response.json() | |
126 | for jsonelement in jsonout: | |
127 | templist=[] | |
128 | ||
129 | # uio-elk/services/logstash/usit-gsd/tcp/host | |
130 | # value[4] = "tcp" | |
131 | ||
132 | value = jsonelement['Key'].split("/") | |
133 | host = requests.get(consul_kv_url+servicetype+'/'+logowner+'/'+value[4]+'/host?raw') | |
134 | port = requests.get(consul_kv_url+servicetype+'/'+logowner+'/'+value[4]+'/port?raw') | |
135 | ||
136 | # | |
137 | # Find out logstash instanses which has a nxlog-server in front. | |
138 | # nxlog=true if not false. | |
139 | # | |
140 | ||
141 | for servicefqdn in servicefqdnlist: | |
142 | matchobj = re.search(value[3]+'-nxlog-tcp',servicefqdn,re.IGNORECASE) | |
143 | if matchobj: | |
144 | nxlog="true" | |
145 | fqdn=servicefqdn+".service.consul" | |
146 | templist.append(fqdn) | |
147 | fqdn = host.text+"-"+value[3]+"-"+value[4]+".service.consul" | |
148 | if fqdn not in serviceadded: | |
149 | templist.append(fqdn) | |
150 | ||
151 | logstash_instanse = {'logowner':value[3],'type':value[4],'service':templist,'port':port.text,'host':host.text,'nxlog':nxlog} | |
152 | logstash_lld.append(logstash_instanse) | |
153 | serviceadded = serviceadded+templist | |
154 | templist=[] | |
155 | nxlog="false" | |
156 | ||
157 | return logstash_lld | |
158 | ||
159 | except Exception as e: | |
160 | print e | |
161 | sys.exit(1) | |
162 | ||
163 | # ######################### | |
164 | # Monitor kibana instanses | |
165 | # ######################### | |
166 | ||
167 | def monitor_kibana_instanse(kibanaurl): | |
168 | ''' | |
169 | If http response status code is 200 and responce content have | |
170 | key words like "Username" and "Password" then the web service is | |
171 | considered up. | |
172 | status | |
173 | 0 for UP | |
174 | 1 for DOWN | |
175 | is returned. | |
176 | ''' | |
177 | status=1 | |
178 | try: | |
179 | response = requests.get(kibanaurl) | |
180 | if (response.status_code == 200): | |
181 | if (re.search("username",response.content,re.IGNORECASE)): | |
182 | if (re.search("password",response.content,re.IGNORECASE)): | |
183 | status = 0 | |
184 | else: | |
185 | status = 1 | |
186 | else: | |
187 | status = 1 | |
188 | else: | |
189 | status = 1 | |
190 | return status | |
191 | except Exception as e: | |
192 | print e | |
193 | sys.exit(1) | |
194 | ||
195 | def print_usage(): | |
196 | print "Error: Wrong number of parameters" | |
197 | print 'Format: ' + sys.argv[0] + ' logstashlld' | |
198 | print 'Format: ' + sys.argv[0] + ' kibanalld' | |
199 | print 'Format: ' + sys.argv[0] + ' <kibana_url> monitorkibana' | |
200 | ||
201 | def print_zabbix_lld_json(lld_data): | |
202 | ''' | |
203 | Print low level discovery json for Zabbix | |
204 | ''' | |
205 | ||
206 | zabbixstr = { "data":lld_data} | |
207 | ||
208 | zabbixjson = json.dumps(zabbixstr, indent=4, sort_keys=True) | |
209 | print zabbixjson | |
210 | ||
211 | ||
212 | # ############################################ | |
213 | # Main | |
214 | # ############################################ | |
215 | ||
216 | if __name__ == '__main__': | |
217 | ||
218 | consul_catalog_url="http://localhost:8500/v1/catalog/services?recurse" | |
219 | consul_kv_url="http://localhost:8500/v1/kv/uio-elk/services/" | |
220 | ||
221 | lld_data=[] | |
222 | ||
223 | # | |
224 | # find which machine the script is running on | |
225 | # | |
226 | ||
227 | machine = socket.gethostname() | |
228 | machinename = machine.split(".")[0] | |
229 | ||
230 | if len(sys.argv) == 2: | |
231 | ||
232 | # ############################### | |
233 | # Logstash low level discovery | |
234 | # ############################### | |
235 | ||
236 | if sys.argv[1] == "logstashlld": | |
237 | servicetype = "logstash" | |
238 | servicefqdnlist = get_services(consul_catalog_url) | |
239 | logowners = get_logowners(consul_kv_url,servicetype) | |
240 | logstash_lld = get_logstash_instanses (consul_kv_url,servicetype,servicefqdnlist,logowners) | |
241 | for logstashinstanse in logstash_lld: | |
242 | ||
243 | if logstashinstanse['nxlog'] == "true": | |
244 | for k in logstashinstanse['service']: | |
245 | matchobj = re.search('nxlog',k,re.IGNORECASE) | |
246 | if matchobj: | |
247 | containerfqdn = k | |
248 | containerport = logstashinstanse['port'] | |
249 | else: | |
250 | containerfqdn = logstashinstanse['service'][0] | |
251 | containerport = logstashinstanse['port'] | |
252 | ||
253 | # ############################################################## | |
254 | # Get only the containers running on the machine where this | |
255 | # script is run. | |
256 | # ############################################################## | |
257 | ||
258 | matchobj = re.search(machinename,containerfqdn,re.IGNORECASE) | |
259 | if matchobj: | |
260 | containerdic = {"{#CONTAINER}":containerfqdn,"{#CONTAINER_PORT}":containerport} | |
261 | lld_data.append(containerdic) | |
262 | ||
263 | print_zabbix_lld_json(lld_data) | |
264 | ||
265 | # ############################### | |
266 | # Kibana low level discovery | |
267 | # ############################### | |
268 | ||
269 | elif sys.argv[1] == "kibanalld": | |
270 | ||
271 | servicetype = "kibana" | |
272 | logowners = get_logowners(consul_kv_url,servicetype) | |
273 | for logowner in logowners: | |
274 | ||
275 | host = requests.get(consul_kv_url+servicetype+'/'+logowner+'/host?raw') | |
276 | ||
277 | # ############################################################## | |
278 | # Get only the kibana containers running on the machine | |
279 | # where this script is run. | |
280 | # ############################################################## | |
281 | ||
282 | if (host.text.lower() == machinename.lower()): | |
283 | kibanaurl = "https://"+logowner+".logs.uio.no" | |
284 | kibanadic = {"{#KIBANAURL}":kibanaurl} | |
285 | lld_data.append(kibanadic) | |
286 | ||
287 | print_zabbix_lld_json(lld_data) | |
288 | else: | |
289 | print_usage() | |
290 | ||
291 | # ############################### | |
292 | # Kibana monitoring | |
293 | # ############################### | |
294 | ||
295 | elif len(sys.argv) == 3: | |
296 | if sys.argv[2] == "monitorkibana": | |
297 | kibanaurl = sys.argv[1] | |
298 | status=monitor_kibana_instanse(kibanaurl) | |
299 | print status | |
300 | else: | |
301 | print_usage() | |
302 | ||
303 | else: | |
304 | print_usage() |