]>
Commit | Line | Data |
---|---|---|
02673eb0 ER |
1 | #!/usr/bin/python -u |
2 | # arekm@pld-linux.org, 2006-01 | |
3 | # glen@pld-linux.org, 2006-03-14 | |
ad7ac473 | 4 | # glen@pld-linux.org,arekm@pld-linux.org, 2006-10-30 - added ssl support (for gmail.com) |
8a0d8b38 | 5 | # glen@pld-linux.org 2006-11-03 - made it work with jabber.pld-linux.org again |
20bb0aca | 6 | # glen@pld-linux.org,arekm@pld-linux.org, 2006-11-13 - added config file support |
ebbef88a | 7 | # glen@pld-linux.org, 2006-12-07 - added html messages support (-x), thx goes to to jajcus |
071905aa | 8 | # luzik@pld-linux.org, 2007-03 - added digest auth method(jabber.gda.pl) |
b6621e54 | 9 | # arekm@pld-linux.org, 2009-07 - added fallback accounts support |
02673eb0 | 10 | # usage: |
b262787e | 11 | # jabber.alert [-x] [-c config] [-a account_id][,otheraccount_id] [-t timeout ] [-J from_jid -P password] to_jid1 to_jid2 to_jid3 |
02673eb0 ER |
12 | |
13 | import os | |
257cdecd | 14 | import hashlib |
02673eb0 ER |
15 | import re |
16 | import sys | |
17 | import getopt | |
eca05a2f | 18 | import logging |
c49eec10 | 19 | import socket |
02673eb0 ER |
20 | import string |
21 | import time | |
ebbef88a | 22 | import libxml2 |
02673eb0 ER |
23 | |
24 | from pyxmpp.jid import JID | |
25 | from pyxmpp.message import Message | |
26 | from pyxmpp.jabber.client import JabberClient | |
ad7ac473 | 27 | from pyxmpp.streamtls import TLSSettings |
02673eb0 ER |
28 | |
29 | try: | |
dcc2b4eb | 30 | opts, args = getopt.getopt(sys.argv[1:], "J:P:a:b:c:ds:t:x") |
02673eb0 | 31 | except getopt.GetoptError, e: |
2682443e AM |
32 | print >> sys.stderr, "%s: %s " % (sys.argv[0], e) |
33 | sys.exit(1) | |
02673eb0 | 34 | |
b6621e54 | 35 | jids = [] |
ebbef88a | 36 | html = False |
f985e683 | 37 | debug = False |
5cf88261 | 38 | timeout = 20 |
b262787e | 39 | cfg = "/etc/nagios/jabber-notify.ini" |
b6621e54 | 40 | tjid = None |
abcee6c0 | 41 | body = "" |
dcc2b4eb | 42 | subject = "Nagios alert" |
02673eb0 | 43 | for o, a in opts: |
abcee6c0 | 44 | if o == '-b': |
816fdfb4 | 45 | body += a |
2682443e AM |
46 | if o == '-c': |
47 | cfg = a | |
48 | if o == '-d': | |
49 | debug = True | |
50 | if o == '-t': | |
51 | timeout = float(a) | |
52 | if o == '-x': | |
53 | html = True | |
54 | if o == '-J': | |
55 | tjid = a | |
56 | if o == '-P': | |
57 | jids.append({ 'jid': tjid, 'password': a }) | |
dcc2b4eb AM |
58 | if o == '-s': |
59 | subject = a | |
2682443e AM |
60 | if o == '-a': |
61 | import ConfigParser | |
62 | ||
63 | config = ConfigParser.ConfigParser() | |
64 | config.read(cfg) | |
65 | ||
66 | for section in a.split(','): | |
67 | jids.append({ 'jid': config.get(section, 'jid'), 'password': config.get(section, 'password')}) | |
02673eb0 | 68 | |
5cf88261 AM |
69 | socket.setdefaulttimeout(timeout) |
70 | ||
02673eb0 ER |
71 | recpt = args |
72 | ||
b6621e54 | 73 | for section in jids: |
2682443e AM |
74 | if not section['jid'] or not section['password']: |
75 | print >> sys.stderr, "%s: jid (-J) and password (-P) are required for `%s'" % (sys.argv[0], section) | |
76 | sys.exit(1) | |
b6621e54 AM |
77 | |
78 | if not jids: | |
2682443e AM |
79 | print >> sys.stderr, "%s: no configured jid accounts found" % sys.argv[0] |
80 | sys.exit(1) | |
02673eb0 | 81 | |
b6621e54 | 82 | if not recpt: |
2682443e AM |
83 | print >> sys.stderr, "%s: recipient jids are required" % sys.argv[0] |
84 | sys.exit(1) | |
02673eb0 | 85 | |
f985e683 | 86 | if debug: |
2682443e AM |
87 | logger=logging.getLogger() |
88 | logger.addHandler(logging.StreamHandler()) | |
89 | logger.setLevel(logging.DEBUG) | |
02673eb0 | 90 | |
abcee6c0 AM |
91 | if not body: |
92 | stdin_body = "" | |
93 | for line in sys.stdin.readlines(): | |
94 | stdin_body += line | |
02673eb0 | 95 | |
abcee6c0 | 96 | body += stdin_body |
02673eb0 | 97 | |
8ccfe18b | 98 | if len(body.strip()) == 0: |
2682443e | 99 | body = "(nagios-jabber.alert warning: missing message body)"; |
8ccfe18b | 100 | |
02673eb0 ER |
101 | message_type = 'chat' |
102 | ||
257cdecd | 103 | class XMPPStreamError(Exception): |
2682443e AM |
104 | def __init__(self, msg): |
105 | self.msg = msg | |
106 | def __str__(self): | |
107 | return self.msg | |
257cdecd | 108 | |
02673eb0 | 109 | class Client(JabberClient): |
2682443e AM |
110 | def session_started(self): |
111 | if (html == True): | |
112 | import re | |
113 | message = re.sub('<.*?>', '', body) | |
114 | doc = libxml2.parseDoc('<body>' + body + '</body>') | |
115 | doc_element = doc.getRootElement().children | |
116 | else: | |
117 | message = body | |
118 | ||
119 | for r in recpt: | |
120 | jid_r = JID(r) | |
121 | msg = Message(to_jid = jid_r, body = message, subject = subject, | |
122 | stanza_type = message_type, thread = "Nagios") | |
123 | ||
124 | if (html == True): | |
125 | node = msg.add_new_content('http://jabber.org/protocol/xhtml-im', 'html') | |
126 | xbody = node.newChild(None, "body", None) | |
127 | html_ns = xbody.newNs('http://www.w3.org/1999/xhtml', None) | |
128 | xbody.setNs(html_ns) | |
129 | xbody.addChildList(doc_element.docCopyNodeList(xbody.doc)) | |
130 | ||
131 | self.stream.send(msg) | |
132 | self.disconnect() | |
133 | ||
134 | def stream_state_changed(self,state,arg): | |
135 | if debug: | |
136 | print "*** State changed: %s %r ***" % (state,arg) | |
137 | ||
138 | def stream_error(self,err): | |
139 | raise XMPPStreamError(err.get_message()) | |
257cdecd MM |
140 | |
141 | ||
b6621e54 AM |
142 | err = [] |
143 | for section in jids: | |
2682443e AM |
144 | for attempt in ('first', 'second'): |
145 | jid = JID(section['jid']) | |
146 | resource = "Nagios/" + hashlib.md5(''.join(recpt)).hexdigest()[:10] | |
147 | if attempt == 'second': | |
148 | # if something went wrong the second time around, it's | |
149 | # most likely a resource name conflict on login, so let's | |
150 | # wait a bit, randomize the resource name and try again | |
151 | resource = resource + '/' + repr(os.getpid()) | |
152 | time.sleep(0.8) | |
153 | if not jid.resource: | |
154 | jid = JID(jid.node, jid.domain, resource) | |
155 | ||
156 | c = Client(jid, section['password'], auth_methods = ['sasl:DIGEST-MD5', 'sasl:PLAIN', 'digest'], | |
157 | tls_settings = TLSSettings(require = False, verify_peer = False)) | |
158 | try: | |
159 | c.connect() | |
160 | try: | |
161 | c.loop(1) | |
162 | except XMPPStreamError, e: | |
163 | # Most likely a duplicate stream problem | |
164 | # don't log anything, just try again | |
165 | c.disconnect() | |
166 | continue | |
167 | except Exception, e: | |
168 | err.append("ERROR1: %s: %s" % (section['jid'], e)) | |
169 | c.disconnect() | |
170 | # don't try another attempt, jump straigt to | |
171 | # another section | |
172 | break | |
173 | c.disconnect() | |
174 | # stop after first successful attempt at sending the msg | |
175 | sys.exit(0) | |
176 | except Exception, e: | |
177 | err.append("ERROR2: %s: %s" % (section['jid'], e)) | |
b6621e54 AM |
178 | |
179 | print >> sys.stderr, "\n".join(err) | |
180 | sys.exit(1) |