*clean: basemodule.Module renamed to basemodule.BaseModule.
[shinken.git] / shinken / modules / nsca_arbiter.py
blob2a64dbb98e8eac90020c9495df6c1b9e8b9a2626
1 #!/usr/bin/python
2 #Copyright (C) 2009 Gabes Jean, naparuba@gmail.com
4 #This file is part of Shinken.
6 #Shinken is free software: you can redistribute it and/or modify
7 #it under the terms of the GNU Affero General Public License as published by
8 #the Free Software Foundation, either version 3 of the License, or
9 #(at your option) any later version.
11 #Shinken is distributed in the hope that it will be useful,
12 #but WITHOUT ANY WARRANTY; without even the implied warranty of
13 #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 #GNU Affero General Public License for more details.
16 #You should have received a copy of the GNU Affero General Public License
17 #along with Shinken. If not, see <http://www.gnu.org/licenses/>.
20 #This Class is an example of an Arbiter module
21 #Here for the configuration phase AND running one
24 #This text is print at the import
25 print "Detected module : NSCA module for Arbiter"
28 import time
29 import select
30 import socket
31 import struct
32 from ctypes import create_string_buffer
33 import random
35 from shinken.basemodule import BaseModule
36 from shinken.external_command import ExternalCommand
38 properties = {
39 'type' : 'nsca_server',
40 'external' : True,
41 'phases' : ['running'],
44 def decrypt_xor(data, key):
45 keylen = len(key)
46 crypted = [chr(ord(data[i]) ^ ord(key[i % keylen])) for i in xrange(len(data))]
47 return ''.join(crypted)
49 #called by the plugin manager to get a broker
50 def get_instance(plugin):
51 print "Get a NSCA arbiter module for plugin %s" % plugin.get_name()
53 if hasattr(plugin, 'host'):
54 if plugin.host == '*':
55 host = ''
56 else:
57 host = plugin.host
58 else:
59 host = '127.0.0.1'
60 if hasattr(plugin, 'port'):
61 port = int(plugin.port)
62 else:
63 port = 5667
64 if hasattr(plugin, 'encryption_method'):
65 encryption_method = int(plugin.encryption_method)
66 else:
67 encryption_method = 0
68 if hasattr(plugin, 'password'):
69 password = plugin.password
70 else:
71 password = ""
73 instance = NSCA_arbiter(plugin, host, port, encryption_method, password)
74 return instance
77 #Just print some stuff
78 class NSCA_arbiter(BaseModule):
79 def __init__(self, modconf, host, port, encryption_method, password):
80 BaseModule.__init__(self, modconf)
81 self.host = host
82 self.port = port
83 self.encryption_method = encryption_method
84 self.password = password
85 self.rng = random.Random(password)
88 #Ok, main function that is called in the CONFIGURATION phase
89 def get_objects(self):
90 print "[Dummy] ask me for objects to return"
91 r = {'hosts' : []}
92 h = {'name' : 'dummy host from dummy arbiter module',
93 'register' : '0',
96 r['hosts'].append(h)
97 print "[Dummy] Returning to Arbiter the hosts:", r
98 return r
100 def send_init_packet(self, socket):
102 Build an init packet
103 00-127 : IV
104 128-131 : unix timestamp
106 init_packet=create_string_buffer(132)
107 iv = ''.join([chr(self.rng.randrange(256)) for i in xrange(128)])
108 init_packet.raw=struct.pack("!128sI",iv,int(time.mktime(time.gmtime())))
109 socket.send(init_packet)
110 return iv
112 def read_check_result(self, data, iv):
114 Read the check result
115 00-01 : Version
116 02-05 : CRC32
117 06-09 : Timestamp
118 10-11 : Return code
119 12-75 : hostname
120 76-203 : service
121 204-715 : output of the plugin
122 716-720 : padding
124 if len(data) != 720:
125 return None
127 if self.encryption_method == 1:
128 data = decrypt_xor(data,self.password)
129 data = decrypt_xor(data,iv)
131 (version, pad1, crc32, timestamp, rc, hostname_dirty, service_dirty, output_dirty, pad2) = struct.unpack("!hhIIh64s128s512sh",data)
132 hostname, sep, dish = hostname_dirty.partition("\0")
133 service, sep, dish = service_dirty.partition("\0")
134 output, sep, dish = output_dirty.partition("\0")
135 return (timestamp, rc, hostname, service, output)
137 def post_command(self, timestamp, rc, hostname, service, output):
139 Send a check result command to the arbiter
141 if len(service) == 0:
142 extcmd = "[%lu] PROCESS_HOST_CHECK_RESULT;%s;%d;%s\n" % (timestamp,hostname,rc,output)
143 else:
144 extcmd = "[%lu] PROCESS_SERVICE_CHECK_RESULT;%s;%s;%d;%s\n" % (timestamp,hostname,service,rc,output)
146 e = ExternalCommand(extcmd)
147 self.from_q.put(e)
150 # When you are in "external" mode, that is the main loop of your process
151 def main(self):
152 self.set_exit_handler()
153 backlog = 5
154 size = 8192
155 server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
156 server.setblocking(0)
157 server.bind((self.host, self.port))
158 server.listen(backlog)
159 input = [server]
160 databuffer = {}
161 IVs = {}
163 while not self.interrupted:
164 inputready,outputready,exceptready = select.select(input,[],[], 1)
166 for s in inputready:
167 if s == server:
168 # handle the server socket
169 client, address = server.accept()
170 iv = self.send_init_packet(client)
171 IVs[client] = iv
172 input.append(client)
173 else:
174 # handle all other sockets
175 data = s.recv(size)
176 if s in databuffer:
177 databuffer[s] += data
178 else:
179 databuffer[s] = data
180 if len(databuffer[s]) == 720:
181 # end-of-transmission or an empty line was received
182 (timestamp, rc, hostname, service, output)=self.read_check_result(databuffer[s],IVs[s])
183 del databuffer[s]
184 del IVs[s]
185 self.post_command(timestamp,rc,hostname,service,output)
186 try:
187 s.shutdown(2)
188 except Exception , exp:
189 print exp
190 s.close()
191 input.remove(s)