Fix poll returning earlier than it should.
[supybot_NagiosLogger.git] / plugin.py
blob2453919e2fdacc8abc22003b5b61c02dc24fd8d4
1 ###
2 # Copyright (c) 2010, Thomas Guyot-Sionnest
3 # All rights reserved.
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions are met:
8 # * Redistributions of source code must retain the above copyright notice,
9 # this list of conditions, and the following disclaimer.
10 # * Redistributions in binary form must reproduce the above copyright notice,
11 # this list of conditions, and the following disclaimer in the
12 # documentation and/or other materials provided with the distribution.
13 # * Neither the name of the author of this software nor the name of
14 # contributors to this software may be used to endorse or promote products
15 # derived from this software without specific prior written consent.
17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 # POSSIBILITY OF SUCH DAMAGE.
29 ###
31 import zmq
32 import threading
33 import supybot.utils as utils
34 import supybot.world as world
35 from supybot.commands import *
36 import supybot.ircmsgs as ircmsgs
37 import supybot.plugins as plugins
38 import supybot.ircutils as ircutils
39 import supybot.callbacks as callbacks
42 class NagiosLogger(callbacks.Plugin):
43 """This plugin receives alert notifications from Nagios and show them in
44 channel. The only configuration needed is running the client on a Nagios
45 server. See the client script for more details."""
46 threaded = False
48 # Some colormaps
50 # Notification type map
51 notype_cmap = {
52 'PROBLEM': 'orange',
53 'RECOVERY': 'green',
54 'ACKNOWLEDGEMENT': 'blue',
55 'FLAPPINGSTART': 'orange',
56 'FLAPPINGSTOP': 'green',
57 'FLAPPINGDISABLED': 'orange',
58 'DOWNTIMESTART': 'dark grey',
59 'DOWNTIMEEND': 'dark grey',
60 'DOWNTIMECANCELLED': 'orange',
63 # Alert type map
64 state_cmap = {
65 'UP': 'green',
66 'DOWN': 'red',
67 'UNREACHABLE': 'orange',
68 'OK': 'green',
69 'WARNING': 'yellow',
70 'UNKNOWN': 'orange',
71 'CRITICAL': 'red',
74 def __init__(self, irc):
75 self.__parent = super(NagiosLogger, self)
76 self.__parent.__init__(irc)
78 self.tp = threading.Thread(target=self.listener)
79 self.tp.setDaemon(True)
80 self.tp.start()
82 def _get_irc(self, network):
83 for irc in world.ircs:
84 if irc.network == network:
85 return irc
87 def _get_person_or_channel(self, irc, personorchannel):
88 if personorchannel.startswith('#'):
89 for channel in irc.state.channels:
90 if channel == personorchannel:
91 return channel
92 else:
93 return personorchannel
95 def _get_irc_and_target(self, network, personorchannel):
96 target_irc = self._get_irc(network)
97 if target_irc is None:
98 raise Exception('Not on Network: %s' % network)
99 target = self._get_person_or_channel(target_irc, personorchannel)
100 if target is None:
101 raise Exception('Not on Channel: %s' % personorchannel)
102 return target_irc, target
104 def listener(self):
105 ctx = zmq.Context(1, 1)
106 socket = zmq.Socket(ctx, zmq.REP)
107 #socket.bind(self.registryValue('ZmqURL')) # TODO: Doesn't work, help!
108 socket.bind('tcp://0.0.0.0:12543')
110 while True:
112 msg = socket.recv()
113 socket.send('Ack!')
115 # Format is:
116 # server(str)[Tab]notifi_type(str)[Tab]stateid(int)[Tab]host(str)
117 # [Tab]service(str)[Tab]message(str)
118 try:
119 msgarray = msg.split('\t', 5)
120 server = msgarray[0]
121 notype = msgarray[1]
122 stateid = int(msgarray[2])
123 hostname = msgarray[3]
124 service = msgarray[4]
125 message = msgarray[5]
126 except ValueError:
127 self.log.error('NagiosLogger: Received message is invalid')
128 except IndexError:
129 self.log.error('NagiosLogger: Received message is invalid '
130 'or incomplete')
132 self.logEvent(server, notype, stateid,
133 hostname, service, message)
136 def logEvent(self, server, notype, stateid, hostname, service, message):
137 # Get the IRC object and target
138 # TODO: Queue up messages if not on channel yet?
139 try:
140 # TODO: add channel parameter
141 (irc, tgt) = self._get_irc_and_target('NETWORK', '#CHANNEL')
142 except Exception, e:
143 # Likely cause is not being on channel yet
144 self.log.error('NagiosLogger: Getting context failed: %s' % (str(e),))
145 return
147 # TODO: Wrap around color map, allowing unknown types
148 try:
149 if service is not '':
150 statemap = {0: 'OK', 1: 'WARNING', 2: 'CRITICAL', 3: 'UNKNOWN'}
151 msg = format('%s %s %s %s %s %s',
152 ircutils.mircColor(server, fg='light grey'),
153 ircutils.mircColor(ircutils.bold(notype + ':'),
154 fg=NagiosLogger.notype_cmap[notype]),
155 ircutils.mircColor(hostname, fg='dark grey'),
156 ircutils.mircColor(ircutils.underline(service),
157 fg='purple'),
158 ircutils.mircColor(ircutils.bold(statemap[stateid] + ':'),
159 fg=NagiosLogger.state_cmap[statemap[stateid]]),
160 ircutils.mircColor(ircutils.underline(message), fg='teal')
162 else:
163 statemap = {0: 'UP', 1: 'DOWN', 2: 'UNREACHABLE'}
164 msg = format('%s %s %s %s %s',
165 ircutils.mircColor(server, fg='light grey'),
166 ircutils.mircColor(ircutils.bold(notype + ':'),
167 fg=NagiosLogger.notype_cmap[notype]),
168 ircutils.mircColor(hostname, fg='dark grey'),
169 ircutils.mircColor(ircutils.bold(statemap[stateid] + ':'),
170 fg=NagiosLogger.state_cmap[statemap[stateid]]),
171 ircutils.mircColor(ircutils.underline(message), fg='teal')
173 except KeyError:
174 self.log.error('NagiosLogger: Message contain invalid fields')
175 return
177 # TODO: Split lines and send multiple messages if necessary
178 try:
179 tgt_msg = ircmsgs.privmsg(tgt, msg)
180 irc.queueMsg(tgt_msg)
181 except AssertionError:
182 self.log.error('NagiosLogger: Sending message failed, this may '
183 'be caused by invalid characters in it')
186 Class = NagiosLogger
189 # vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: