2015-11-03 20:24:06 +00:00
|
|
|
#!/usr/bin/env python
|
|
|
|
|
2016-05-13 02:47:02 +00:00
|
|
|
import json
|
2016-02-18 15:41:32 +00:00
|
|
|
import datetime
|
2015-11-03 20:24:06 +00:00
|
|
|
import logging
|
2016-02-18 15:41:32 +00:00
|
|
|
import os
|
2016-02-22 23:10:14 +00:00
|
|
|
import re
|
2015-11-03 20:24:06 +00:00
|
|
|
import smtplib
|
|
|
|
import socket
|
2016-02-18 15:41:32 +00:00
|
|
|
import sys
|
|
|
|
import threading
|
|
|
|
import time
|
|
|
|
from email.mime.multipart import MIMEMultipart
|
|
|
|
from email.mime.text import MIMEText
|
|
|
|
|
2015-11-03 20:24:06 +00:00
|
|
|
import jinja2
|
|
|
|
|
2016-02-18 15:41:32 +00:00
|
|
|
from alerta.alert import AlertDocument
|
|
|
|
from alerta.api import ApiClient
|
|
|
|
from alerta.heartbeat import Heartbeat
|
|
|
|
from kombu import Connection, Exchange, Queue
|
|
|
|
from kombu.mixins import ConsumerMixin
|
|
|
|
|
2016-01-11 05:09:35 +00:00
|
|
|
DNS_RESOLVER_AVAILABLE = False
|
2016-02-18 15:41:32 +00:00
|
|
|
|
2016-01-11 05:09:35 +00:00
|
|
|
try:
|
|
|
|
import dns.resolver
|
|
|
|
DNS_RESOLVER_AVAILABLE = True
|
|
|
|
except:
|
2016-02-18 15:41:32 +00:00
|
|
|
sys.stdout.write('Python dns.resolver unavailable. The skip_mta option will be forced to False') # nopep8
|
2016-01-11 05:09:35 +00:00
|
|
|
|
2015-11-03 20:24:06 +00:00
|
|
|
try:
|
|
|
|
import configparser
|
|
|
|
except ImportError:
|
|
|
|
import ConfigParser as configparser
|
|
|
|
|
|
|
|
|
2016-05-13 03:40:25 +00:00
|
|
|
logging.basicConfig(level=logging.DEBUG)
|
2015-11-03 20:24:06 +00:00
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
root = logging.getLogger()
|
|
|
|
|
2016-01-11 05:09:35 +00:00
|
|
|
DEFAULT_OPTIONS = {
|
2015-11-03 20:24:06 +00:00
|
|
|
'config_file': '~/.alerta.conf',
|
|
|
|
'profile': None,
|
|
|
|
'endpoint': 'http://localhost:8080',
|
|
|
|
'key': '',
|
|
|
|
'amqp_url': 'redis://localhost:6379/',
|
|
|
|
'amqp_topic': 'notify',
|
|
|
|
'smtp_host': 'smtp.gmail.com',
|
|
|
|
'smtp_port': 587,
|
|
|
|
'smtp_password': '', # application-specific password if gmail used
|
2016-02-18 15:41:32 +00:00
|
|
|
'smtp_starttls': True, # use the STARTTLS SMTP extension
|
2015-11-03 20:24:06 +00:00
|
|
|
'mail_from': '', # alerta@example.com
|
|
|
|
'mail_to': [], # devops@example.com, support@example.com
|
2016-02-18 15:41:32 +00:00
|
|
|
'mail_localhost': None, # fqdn to use in the HELO/EHLO command
|
2016-01-12 01:01:27 +00:00
|
|
|
'mail_template': os.path.dirname(__file__) + os.sep + 'email.tmpl',
|
2016-02-22 08:27:38 +00:00
|
|
|
'mail_template_html': os.path.dirname(__file__) + os.sep + 'email.html.tmpl', # nopep8
|
2016-01-12 01:01:27 +00:00
|
|
|
'mail_subject': ('[{{ alert.status|capitalize }}] {{ alert.environment }}: '
|
|
|
|
'{{ alert.severity|capitalize }} {{ alert.event }} on '
|
2016-02-18 15:41:32 +00:00
|
|
|
'{{ alert.service|join(\',\') }} {{ alert.resource }}'),
|
2015-11-03 20:24:06 +00:00
|
|
|
'dashboard_url': 'http://try.alerta.io',
|
2016-01-11 05:09:35 +00:00
|
|
|
'debug': False,
|
2016-02-22 08:27:38 +00:00
|
|
|
'skip_mta': False,
|
|
|
|
'email_type': 'text' # options are: text, html
|
2015-11-03 20:24:06 +00:00
|
|
|
}
|
|
|
|
|
2016-01-11 05:09:35 +00:00
|
|
|
OPTIONS = {}
|
|
|
|
|
2016-02-18 15:41:32 +00:00
|
|
|
# seconds (hold alert until sending, delete if cleared before end of hold time)
|
|
|
|
HOLD_TIME = 30
|
2015-11-03 20:24:06 +00:00
|
|
|
|
|
|
|
on_hold = dict()
|
|
|
|
|
|
|
|
|
|
|
|
class FanoutConsumer(ConsumerMixin):
|
|
|
|
|
|
|
|
def __init__(self, connection):
|
|
|
|
|
|
|
|
self.connection = connection
|
|
|
|
self.channel = self.connection.channel()
|
|
|
|
|
|
|
|
def get_consumers(self, Consumer, channel):
|
|
|
|
|
|
|
|
exchange = Exchange(
|
|
|
|
name=OPTIONS['amqp_topic'],
|
|
|
|
type='fanout',
|
|
|
|
channel=self.channel,
|
|
|
|
durable=True
|
|
|
|
)
|
|
|
|
|
|
|
|
queues = [
|
|
|
|
Queue(
|
|
|
|
name='',
|
|
|
|
exchange=exchange,
|
|
|
|
routing_key='',
|
|
|
|
channel=self.channel,
|
|
|
|
exclusive=True
|
|
|
|
)
|
|
|
|
]
|
|
|
|
|
|
|
|
return [
|
2016-02-18 15:41:32 +00:00
|
|
|
Consumer(queues=queues, accept=['json'],
|
|
|
|
callbacks=[self.on_message])
|
2015-11-03 20:24:06 +00:00
|
|
|
]
|
|
|
|
|
|
|
|
def on_message(self, body, message):
|
|
|
|
|
|
|
|
try:
|
2015-12-15 01:04:41 +00:00
|
|
|
alert = AlertDocument.parse_alert(body)
|
2015-11-03 20:24:06 +00:00
|
|
|
alertid = alert.get_id()
|
|
|
|
except Exception as e:
|
|
|
|
LOG.warn(e)
|
|
|
|
return
|
|
|
|
|
|
|
|
if alert.repeat:
|
|
|
|
message.ack()
|
|
|
|
return
|
|
|
|
|
|
|
|
if alert.status not in ['open', 'closed']:
|
|
|
|
message.ack()
|
|
|
|
return
|
|
|
|
|
2016-02-18 15:41:32 +00:00
|
|
|
if (
|
|
|
|
alert.severity not in ['critical', 'major'] and
|
|
|
|
alert.previous_severity not in ['critical', 'major']
|
|
|
|
):
|
2015-11-03 20:24:06 +00:00
|
|
|
message.ack()
|
|
|
|
return
|
|
|
|
|
|
|
|
if alertid in on_hold:
|
|
|
|
if alert.severity in ['normal', 'ok', 'cleared']:
|
|
|
|
try:
|
|
|
|
del on_hold[alertid]
|
|
|
|
except KeyError:
|
|
|
|
pass
|
|
|
|
message.ack()
|
|
|
|
else:
|
|
|
|
on_hold[alertid] = (alert, time.time() + HOLD_TIME)
|
|
|
|
message.ack()
|
|
|
|
else:
|
|
|
|
on_hold[alertid] = (alert, time.time() + HOLD_TIME)
|
|
|
|
message.ack()
|
|
|
|
|
|
|
|
|
|
|
|
class MailSender(threading.Thread):
|
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
|
|
|
|
self.should_stop = False
|
2016-02-18 15:41:32 +00:00
|
|
|
self._template_dir = os.path.dirname(
|
|
|
|
os.path.realpath(OPTIONS['mail_template']))
|
2016-01-12 01:01:27 +00:00
|
|
|
self._template_name = os.path.basename(OPTIONS['mail_template'])
|
|
|
|
self._subject_template = jinja2.Template(OPTIONS['mail_subject'])
|
|
|
|
self._template_env = jinja2.Environment(
|
|
|
|
loader=jinja2.FileSystemLoader(self._template_dir),
|
|
|
|
extensions=['jinja2.ext.autoescape'],
|
|
|
|
autoescape=True
|
|
|
|
)
|
2016-02-22 08:27:38 +00:00
|
|
|
if OPTIONS['mail_template_html']:
|
|
|
|
self._template_name_html = os.path.basename(
|
|
|
|
OPTIONS['mail_template_html'])
|
2016-01-12 01:01:27 +00:00
|
|
|
|
2015-11-03 20:24:06 +00:00
|
|
|
super(MailSender, self).__init__()
|
|
|
|
|
|
|
|
def run(self):
|
|
|
|
|
2016-01-11 05:09:35 +00:00
|
|
|
api = ApiClient(endpoint=OPTIONS['endpoint'], key=OPTIONS['key'])
|
2015-11-03 20:24:06 +00:00
|
|
|
keep_alive = 0
|
|
|
|
|
|
|
|
while not self.should_stop:
|
|
|
|
for alertid in on_hold.keys():
|
|
|
|
try:
|
|
|
|
(alert, hold_time) = on_hold[alertid]
|
|
|
|
except KeyError:
|
|
|
|
continue
|
|
|
|
if time.time() > hold_time:
|
|
|
|
self.send_email(alert)
|
|
|
|
try:
|
|
|
|
del on_hold[alertid]
|
|
|
|
except KeyError:
|
|
|
|
continue
|
2016-02-18 15:41:32 +00:00
|
|
|
|
2015-11-03 20:24:06 +00:00
|
|
|
if keep_alive >= 10:
|
2016-01-11 05:09:35 +00:00
|
|
|
tag = OPTIONS['smtp_host'] or 'alerta-mailer'
|
2016-01-12 01:01:27 +00:00
|
|
|
api.send(Heartbeat(tags=[tag]))
|
2015-11-03 20:24:06 +00:00
|
|
|
keep_alive = 0
|
|
|
|
keep_alive += 1
|
|
|
|
time.sleep(2)
|
|
|
|
|
|
|
|
def send_email(self, alert):
|
2016-01-12 01:01:27 +00:00
|
|
|
"""Attempt to send an email for the provided alert, compiling
|
|
|
|
the subject and text template and using all the other smtp settings
|
|
|
|
that were specified in the configuration file
|
|
|
|
"""
|
2016-05-13 02:47:02 +00:00
|
|
|
contacts = OPTIONS['mail_to']
|
|
|
|
LOG.debug('Initial contact list: %s', contacts)
|
2016-03-04 18:28:31 +00:00
|
|
|
if 'group_rules' in OPTIONS and len(OPTIONS['group_rules']) > 0:
|
|
|
|
LOG.debug('Checking %d group rules' % len(OPTIONS['group_rules']))
|
2016-05-13 02:47:02 +00:00
|
|
|
for rule in OPTIONS['group_rules']:
|
|
|
|
LOG.info('Evaluating rule %s', rule['name'])
|
|
|
|
is_matching = True
|
|
|
|
for field in rule['fields']:
|
|
|
|
LOG.debug('Matching regex %s to %s (%s)' % (field['regex'],
|
|
|
|
field['field'],
|
|
|
|
getattr(alert, field['field'], None)))
|
|
|
|
if re.match(field['regex'],
|
|
|
|
getattr(alert, field['field'], None)):
|
|
|
|
LOG.debug('Regex matched')
|
|
|
|
else:
|
|
|
|
LOG.debug('regex did not match')
|
|
|
|
is_matching = False
|
|
|
|
if is_matching:
|
2016-03-04 18:28:31 +00:00
|
|
|
# Add up any new contacts
|
2016-05-13 02:47:02 +00:00
|
|
|
new_contacts = [x.strip() for x in rule['contacts']
|
2016-03-04 18:28:31 +00:00
|
|
|
if x.strip() not in contacts]
|
|
|
|
if len(new_contacts) > 0:
|
|
|
|
LOG.debug('Extending contact to include %s' % (new_contacts))
|
|
|
|
contacts.extend(new_contacts)
|
|
|
|
|
2016-01-12 01:01:27 +00:00
|
|
|
template_vars = {
|
2015-11-03 20:24:06 +00:00
|
|
|
'alert': alert,
|
2016-03-04 18:28:31 +00:00
|
|
|
'mail_to': contacts,
|
2015-11-03 20:24:06 +00:00
|
|
|
'dashboard_url': OPTIONS['dashboard_url'],
|
|
|
|
'program': os.path.basename(sys.argv[0]),
|
|
|
|
'hostname': os.uname()[1],
|
|
|
|
'now': datetime.datetime.utcnow()
|
|
|
|
}
|
2016-01-12 01:01:27 +00:00
|
|
|
|
|
|
|
subject = self._subject_template.render(alert=alert)
|
2016-02-22 08:27:38 +00:00
|
|
|
text = self._template_env.get_template(
|
|
|
|
self._template_name).render(**template_vars)
|
2015-11-03 20:24:06 +00:00
|
|
|
|
2016-02-22 08:27:38 +00:00
|
|
|
if (
|
|
|
|
OPTIONS['email_type'] == 'html' and
|
|
|
|
self._template_name_html
|
|
|
|
):
|
|
|
|
html = self._template_env.get_template(
|
|
|
|
self._template_name_html).render(**template_vars)
|
|
|
|
else:
|
|
|
|
html = None
|
|
|
|
|
|
|
|
msg = MIMEMultipart('alternative')
|
2015-11-03 20:24:06 +00:00
|
|
|
msg['Subject'] = subject
|
|
|
|
msg['From'] = OPTIONS['mail_from']
|
2016-03-04 18:28:31 +00:00
|
|
|
msg['To'] = ", ".join(contacts)
|
2015-11-03 20:24:06 +00:00
|
|
|
msg.preamble = subject
|
|
|
|
|
2016-02-22 08:27:38 +00:00
|
|
|
# by default we are going to assume that the email is going to be text
|
2015-11-03 20:24:06 +00:00
|
|
|
msg_text = MIMEText(text, 'plain', 'utf-8')
|
2016-02-22 08:27:38 +00:00
|
|
|
if html:
|
|
|
|
msg_html = MIMEText(html, 'html', 'utf-8')
|
|
|
|
msg.attach(msg_html)
|
|
|
|
|
2015-11-03 20:24:06 +00:00
|
|
|
msg.attach(msg_text)
|
|
|
|
|
|
|
|
try:
|
2016-03-04 18:28:31 +00:00
|
|
|
self._send_email_message(msg, contacts)
|
2016-02-18 15:41:32 +00:00
|
|
|
LOG.debug('%s : Email sent to %s' % (alert.get_id(),
|
2016-03-04 18:28:31 +00:00
|
|
|
','.join(contacts)))
|
2015-11-03 20:24:06 +00:00
|
|
|
except (socket.error, socket.herror, socket.gaierror), e:
|
|
|
|
LOG.error('Mail server connection error: %s', e)
|
|
|
|
return
|
|
|
|
except smtplib.SMTPException, e:
|
|
|
|
LOG.error('Failed to send mail to %s on %s:%s : %s',
|
2016-03-04 18:28:31 +00:00
|
|
|
", ".join(contacts),
|
2016-02-18 15:41:32 +00:00
|
|
|
OPTIONS['smtp_host'], OPTIONS['smtp_port'], e)
|
2015-11-03 20:24:06 +00:00
|
|
|
except Exception as e:
|
2016-02-18 15:41:32 +00:00
|
|
|
LOG.error('Unexpected error while sending email: {}'.format(str(e))) # nopep8
|
2015-11-03 20:24:06 +00:00
|
|
|
|
2016-03-04 18:28:31 +00:00
|
|
|
def _send_email_message(self, msg, contacts):
|
2016-01-11 05:09:35 +00:00
|
|
|
if OPTIONS['skip_mta'] and DNS_RESOLVER_AVAILABLE:
|
2016-03-04 18:28:31 +00:00
|
|
|
for dest in contacts:
|
2016-01-11 05:09:35 +00:00
|
|
|
try:
|
|
|
|
(_, ehost) = dest.split('@')
|
|
|
|
dns_answers = dns.resolver.query(ehost, 'MX')
|
2016-02-18 15:41:32 +00:00
|
|
|
|
|
|
|
if len(dns_answers) <= 0:
|
|
|
|
raise Exception('Failed to find mail exchange for {}'.format(dest)) # nopep8
|
|
|
|
|
|
|
|
mxhost = reduce(lambda x, y: x if x.preference >= y.preference else y, dns_answers).exchange.to_text() # nopep8
|
2016-01-11 05:09:35 +00:00
|
|
|
msg['To'] = dest
|
2016-02-18 15:41:32 +00:00
|
|
|
mx = smtplib.SMTP(mxhost,
|
|
|
|
OPTIONS['smtp_port'],
|
|
|
|
local_hostname=OPTIONS['mail_localhost'])
|
2016-01-11 05:09:35 +00:00
|
|
|
if OPTIONS['debug']:
|
|
|
|
mx.set_debuglevel(True)
|
|
|
|
mx.sendmail(OPTIONS['mail_from'], dest, msg.as_string())
|
|
|
|
mx.close()
|
2016-02-18 15:41:32 +00:00
|
|
|
LOG.debug('Sent notification email to {} (mta={})'.format(dest, mxhost)) # nopep8
|
2016-01-11 05:09:35 +00:00
|
|
|
except Exception as e:
|
2016-02-18 15:41:32 +00:00
|
|
|
LOG.error('Failed to send email to address {} (mta={}): {}'.format(dest, mxhost, str(e))) # nopep8
|
2015-11-03 20:24:06 +00:00
|
|
|
|
2016-01-11 05:09:35 +00:00
|
|
|
else:
|
2016-02-18 15:41:32 +00:00
|
|
|
mx = smtplib.SMTP(OPTIONS['smtp_host'],
|
|
|
|
OPTIONS['smtp_port'],
|
|
|
|
local_hostname=OPTIONS['mail_localhost'])
|
2016-01-11 05:09:35 +00:00
|
|
|
if OPTIONS['debug']:
|
|
|
|
mx.set_debuglevel(True)
|
2016-02-18 15:41:32 +00:00
|
|
|
|
2016-01-11 05:09:35 +00:00
|
|
|
mx.ehlo()
|
2016-02-18 15:41:32 +00:00
|
|
|
|
2016-01-11 05:09:35 +00:00
|
|
|
if OPTIONS['smtp_starttls']:
|
|
|
|
mx.starttls()
|
2016-02-18 15:41:32 +00:00
|
|
|
|
2016-01-11 05:09:35 +00:00
|
|
|
if OPTIONS['smtp_password']:
|
|
|
|
mx.login(OPTIONS['mail_from'], OPTIONS['smtp_password'])
|
2016-02-18 15:41:32 +00:00
|
|
|
|
|
|
|
mx.sendmail(OPTIONS['mail_from'],
|
2016-03-04 18:28:31 +00:00
|
|
|
contacts,
|
2016-02-18 15:41:32 +00:00
|
|
|
msg.as_string())
|
2016-01-11 05:09:35 +00:00
|
|
|
mx.close()
|
2015-11-03 20:24:06 +00:00
|
|
|
|
|
|
|
|
2016-05-13 02:47:02 +00:00
|
|
|
def validate_rules(rules):
|
|
|
|
'''
|
|
|
|
Validates that rules are correct
|
|
|
|
'''
|
|
|
|
if not isinstance(rules, list):
|
|
|
|
LOG.warning('Invalid rules, must be list')
|
|
|
|
return
|
|
|
|
valid_rules = []
|
|
|
|
for rule in rules:
|
|
|
|
if not isinstance(rule, dict):
|
|
|
|
LOG.warning('Invalid rule %s, must be dict', rule)
|
|
|
|
continue
|
|
|
|
valid = True
|
|
|
|
# TODO: This could be optimized to use sets instead
|
|
|
|
for key in ['name', 'fields', 'contacts']:
|
|
|
|
if key not in rule:
|
|
|
|
LOG.warning('Invalid rule %s, must have %s', rule, key)
|
|
|
|
valid = False
|
|
|
|
break
|
|
|
|
if valid is False:
|
|
|
|
continue
|
2016-05-13 03:40:25 +00:00
|
|
|
if not isinstance(rule['fields'], list) or len(rule['fields']) == 0:
|
|
|
|
LOG.warning('Rule fields must be a list and not empty')
|
2016-05-13 02:47:02 +00:00
|
|
|
continue
|
|
|
|
for field in rule['fields']:
|
|
|
|
for key in ['regex', 'field']:
|
2016-05-13 03:40:25 +00:00
|
|
|
if key not in field:
|
2016-05-13 02:47:02 +00:00
|
|
|
LOG.warning('Invalid rule %s, must have %s on fields',
|
|
|
|
rule, key)
|
|
|
|
valid = False
|
|
|
|
break
|
2016-05-13 03:40:25 +00:00
|
|
|
if valid is False:
|
|
|
|
continue
|
2016-05-13 02:47:02 +00:00
|
|
|
|
|
|
|
LOG.info('Adding rule %s to list of rules to be evaluated', rule)
|
|
|
|
valid_rules.append(rule)
|
|
|
|
return valid_rules
|
|
|
|
|
|
|
|
|
|
|
|
def parse_group_rules(config_file):
|
|
|
|
rules_dir = "{}.rules.d".format(config_file)
|
|
|
|
LOG.debug('Looking for rules files in %s', rules_dir)
|
|
|
|
if os.path.exists(rules_dir):
|
|
|
|
rules_d = []
|
|
|
|
for files in os.walk(rules_dir):
|
2016-05-13 03:40:25 +00:00
|
|
|
for filename in files[2]:
|
|
|
|
LOG.debug('Parsing %s', filename)
|
|
|
|
try:
|
|
|
|
with open(os.path.join(files[0], filename), 'r') as f:
|
|
|
|
rules = validate_rules(json.load(f))
|
|
|
|
if rules is not None:
|
|
|
|
rules_d.extend(rules)
|
|
|
|
except:
|
|
|
|
LOG.exception('Could not parse file')
|
2016-05-13 02:47:02 +00:00
|
|
|
return rules_d
|
2016-02-22 23:10:14 +00:00
|
|
|
|
|
|
|
|
2016-01-11 05:09:35 +00:00
|
|
|
def main():
|
2016-01-11 21:14:23 +00:00
|
|
|
global OPTIONS
|
|
|
|
|
2016-01-11 05:09:35 +00:00
|
|
|
CONFIG_SECTION = 'alerta-mailer'
|
2016-02-18 15:41:32 +00:00
|
|
|
config_file = os.environ.get('ALERTA_CONF_FILE') or DEFAULT_OPTIONS['config_file'] # nopep8
|
2015-11-03 20:24:06 +00:00
|
|
|
|
2016-02-18 15:41:32 +00:00
|
|
|
# Convert default booleans to its string type, otherwise config.getboolean fails # nopep8
|
|
|
|
defopts = {k: str(v) if type(v) is bool else v for k, v in DEFAULT_OPTIONS.iteritems()} # nopep8
|
2016-01-11 05:09:35 +00:00
|
|
|
config = configparser.RawConfigParser(defaults=defopts)
|
2016-02-18 15:41:32 +00:00
|
|
|
|
2016-03-02 20:35:07 +00:00
|
|
|
if os.path.exists("{}.d".format(config_file)):
|
|
|
|
config_path = "{}.d".format(config_file)
|
|
|
|
config_list = []
|
|
|
|
for files in os.walk(config_path):
|
|
|
|
for filename in files[2]:
|
|
|
|
config_list.append("{}/{}".format(config_path, filename))
|
|
|
|
|
|
|
|
config_list.append(os.path.expanduser(config_file))
|
|
|
|
config_file = config_list
|
|
|
|
|
2015-11-03 20:24:06 +00:00
|
|
|
try:
|
2016-03-02 20:35:07 +00:00
|
|
|
config.read(config_file)
|
2015-11-03 20:24:06 +00:00
|
|
|
except Exception as e:
|
2016-02-18 15:41:32 +00:00
|
|
|
LOG.warning("Problem reading configuration file %s - is this an ini file?", config_file) # nopep8
|
2015-11-03 20:24:06 +00:00
|
|
|
sys.exit(1)
|
|
|
|
|
2016-01-11 05:09:35 +00:00
|
|
|
if config.has_section(CONFIG_SECTION):
|
|
|
|
from types import NoneType
|
|
|
|
config_getters = {
|
|
|
|
NoneType: config.get,
|
|
|
|
str: config.get,
|
|
|
|
int: config.getint,
|
|
|
|
float: config.getfloat,
|
|
|
|
bool: config.getboolean,
|
|
|
|
list: lambda s, o: [e.strip() for e in config.get(s, o).split(',')]
|
|
|
|
}
|
|
|
|
for opt in DEFAULT_OPTIONS:
|
|
|
|
# Convert the options to the expected type
|
2016-02-18 15:41:32 +00:00
|
|
|
OPTIONS[opt] = config_getters[type(DEFAULT_OPTIONS[opt])](CONFIG_SECTION, opt) # nopep8
|
2016-01-11 05:09:35 +00:00
|
|
|
else:
|
2016-02-18 15:41:32 +00:00
|
|
|
sys.stderr.write('Alerta configuration section not found in configuration file\n') # nopep8
|
2016-01-11 05:09:35 +00:00
|
|
|
OPTIONS = defopts.copy()
|
2015-11-03 20:24:06 +00:00
|
|
|
|
2016-02-18 15:41:32 +00:00
|
|
|
OPTIONS['endpoint'] = os.environ.get('ALERTA_ENDPOINT') or OPTIONS['endpoint'] # nopep8
|
2015-11-03 20:24:06 +00:00
|
|
|
OPTIONS['key'] = os.environ.get('ALERTA_API_KEY') or OPTIONS['key']
|
2016-02-18 15:41:32 +00:00
|
|
|
OPTIONS['smtp_password'] = os.environ.get('SMTP_PASSWORD') or OPTIONS['smtp_password'] # nopep8
|
2016-01-11 05:09:35 +00:00
|
|
|
if os.environ.get('DEBUG'):
|
|
|
|
OPTIONS['debug'] = True
|
2015-11-03 20:24:06 +00:00
|
|
|
|
2016-05-13 02:47:02 +00:00
|
|
|
group_rules = parse_group_rules(config_file)
|
|
|
|
if group_rules is not None:
|
|
|
|
OPTIONS['group_rules'] = group_rules
|
2016-02-22 23:10:14 +00:00
|
|
|
|
2015-11-03 20:24:06 +00:00
|
|
|
try:
|
|
|
|
mailer = MailSender()
|
|
|
|
mailer.start()
|
|
|
|
except (SystemExit, KeyboardInterrupt):
|
|
|
|
sys.exit(0)
|
|
|
|
except Exception as e:
|
|
|
|
print str(e)
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
from kombu.utils.debug import setup_logging
|
2016-02-18 15:41:32 +00:00
|
|
|
loginfo = 'DEBUG' if OPTIONS['debug'] else 'INFO'
|
|
|
|
setup_logging(loglevel=loginfo, loggers=[''])
|
2015-11-03 20:24:06 +00:00
|
|
|
|
|
|
|
with Connection(OPTIONS['amqp_url']) as conn:
|
|
|
|
try:
|
|
|
|
consumer = FanoutConsumer(connection=conn)
|
|
|
|
consumer.run()
|
|
|
|
except (SystemExit, KeyboardInterrupt):
|
|
|
|
mailer.should_stop = True
|
|
|
|
mailer.join()
|
|
|
|
sys.exit(0)
|
|
|
|
except Exception as e:
|
|
|
|
print str(e)
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
main()
|