-
Notifications
You must be signed in to change notification settings - Fork 20
/
Copy pathpython_zabbix_assistant.py
90 lines (81 loc) · 3.75 KB
/
python_zabbix_assistant.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
#! /usr/bin/python
import os, json, socket, struct, logging, time, urllib2, platform, threading
# Some day this will use "real" Zabbix auth and become more complicated.
ZABBIX_API_SERVER = 'zabbix-api.example.com'
ZABBIX_KEY = 'xyzzy-plugh-plover'
class ZabbixActiveSender(object):
'''This will send values to Zabbix via the same mechanism zabbix_sender uses.
'''
def __init__(self, zabbixserver=None, prefix = None, no_send=False, clienthost=platform.node()):
self.lock = threading.Lock()
self.zabbixserver = zabbixserver
self.clienthost = clienthost # This better be the FQDN
logging.debug('ZAS.__init__: clienthost="%s"', self.clienthost)
self.prefix = prefix
self.no_send = no_send
self.check_for_proxy()
self.clear()
logging.debug('ZAS.__init__: zabbixserver="%s"', str(self.zabbixserver))
if os.environ.has_key('http_proxy'):
del os.environ['http_proxy']
logging.debug('ZAS.__init__: removed http_proxy from the environment')
return
def check_for_proxy(self):
'''If the zabbixserver was specified, we trust that (e.g. for
zabbix-stage.llnw.net). Otherwise, we go looking for the proxy
that owns us.
'''
if self.zabbixserver: return
postdata = {
"key": ZABBIX_KEY,
"method": "proxymap.get",
"params": {
"hostnames": [ os.uname()[1] ],
"output": "json"
}
}
data = urllib2.urlopen('http://'+ZABBIX_API_SERVER+'/llnw/api_jsonrpc.php',json.dumps(postdata))
self.zabbixserver = json.load(data)['result'][0]['proxy']
return
def __call__(self, key, value):
'''Load up our dictionary with data preparatory to sending it on to Zabbix.
If we're debugging, we'll immediately send each value, which makes it a
*lot* easier to figure out where we've got problems.'''
logging.debug('ZAS.__call__: %30s\t%s', key, value)
if self.prefix: key = self.prefix+key
self.lock.acquire()
self.data.append({"key":key, "value":value, "host":self.clienthost, "clock":int(time.time())})
self.lock.release()
if logging.root.level < logging.INFO: self.send()
return
def send(self):
'''Ship the data to Zabbix. Call as often as you like, though of course
it's more efficient to call it just once after you've accumulated
all of the data you'd like to send.
The magic in here with structs is required to format everything for
Zabbix' wire protocol. If this breaks, it's time to dive into the
Zabbix internals again.
'''
self.lock.acquire()
if not self.data:
self.lock.release()
return # Nothing to send!
if not self.no_send:
response = {"request":"agent data", "clock":int(time.time()), "data":self.data}
string = json.dumps(response)
logging.debug(string)
string_to_send = 'ZBXD\x01%s%s' % (struct.pack('<q', len(string)), string)
s = socket.create_connection((self.zabbixserver, 10051))
s.sendall(string_to_send)
s.shutdown(socket.SHUT_WR)
try:
retstring = s.recv(5) # Header, don't care: 'ZBXD\01'
datalen = struct.unpack('<q',s.recv(8))[0] # Length of data being returned
retstring = s.recv(datalen) # Actual return string
logging.debug(retstring)
except Exception as e:
logging.debug('ZAS.send: Failed to get a proper response: %s (%s)', retstring, e)
self.clear()
self.lock.release()
return
def clear(self): self.data = []