def run(self): api = Client(endpoint=OPTIONS['endpoint'], key=OPTIONS['key']) 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 if keep_alive >= 10: tag = OPTIONS['smtp_host'] or 'alerta-mailer' try: api.heartbeat(tags=[tag]) except Exception as e: time.sleep(5) continue keep_alive = 0 keep_alive += 1 time.sleep(2)
def senddata(self, content): config_file = os.environ.get('ALERTA_CONF_FILE') or OPTIONS['config_file'] config = configparser.RawConfigParser(defaults=OPTIONS) try: config.read(os.path.expanduser(config_file)) except Exception: sys.exit("Problem reading configuration file %s - is this an ini file?" % config_file) want_profile = os.environ.get('ALERTA_DEFAULT_PROFILE') or config.defaults().get('profile') if want_profile and config.has_section('profile %s' % want_profile): for opt in OPTIONS: try: OPTIONS[opt] = config.getboolean('profile %s' % want_profile, opt) except (ValueError, AttributeError): OPTIONS[opt] = config.get('profile %s' % want_profile, opt) else: for opt in OPTIONS: try: OPTIONS[opt] = config.getboolean('DEFAULT', opt) except (ValueError, AttributeError): OPTIONS[opt] = config.get('DEFAULT', opt) try: LOG.debug("[alerta] sendto=%s ", OPTIONS.get("endpoint")) api = Client(endpoint=OPTIONS.get("endpoint"), key=OPTIONS.get("key"), ssl_verify=OPTIONS.get("sslverify")) api.send_alert(**content) except RequestException as e: raise EAException("send message has error: %s" % e) elastalert_logger.info("send msg success" )
def __init__(self): self.api = Client() LOG.info('Starting UDP listener...') # Set up syslog UDP listener try: self.udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.udp.bind(('', SYSLOG_UDP_PORT)) except socket.error as e: LOG.error('Syslog UDP error: %s', e) sys.exit(2) LOG.info('Listening on syslog port %s/udp' % SYSLOG_UDP_PORT) LOG.info('Starting TCP listener...') # Set up syslog TCP listener try: self.tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.tcp.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.tcp.bind(('', SYSLOG_TCP_PORT)) self.tcp.listen(5) except socket.error as e: LOG.error('Syslog TCP error: %s', e) sys.exit(2) LOG.info('Listening on syslog port %s/tcp' % SYSLOG_TCP_PORT) self.shuttingdown = False
def run(self): endpoint = os.environ.get('ALERTA_ENDPOINT', 'http://localhost:8080') key = os.environ.get('ALERTA_API_KEY', None) self.api = Client(endpoint=endpoint, key=key) data = sys.stdin.read() LOG.info('snmptrapd -> %r', data) data = unicode(data, 'utf-8', errors='ignore') LOG.debug('unicoded -> %s', data) snmptrapAlert = SnmpTrapHandler.parse_snmptrap(data) if snmptrapAlert: try: self.api.send(snmptrapAlert) except Exception as e: LOG.warning('Failed to send alert: %s', e) LOG.debug('Send heartbeat...') try: origin = '{}/{}'.format('snmptrap', platform.uname()[1]) self.api.heartbeat(origin, tags=[__version__]) except Exception as e: LOG.warning('Failed to send heartbeat: %s', e)
def run(self): api = Client(endpoint=OPTIONS['endpoint'], key=OPTIONS['key']) keep_alive = 0 while not self.should_stop: for alertid in list(on_hold.keys()): try: (alert, hold_time) = on_hold[alertid] except KeyError: continue if time.time() > hold_time: self.diagnose(alert) try: del on_hold[alertid] except KeyError: continue if keep_alive >= 10: try: origin = '{}'.format('alerta-trigger') api.heartbeat(origin, tags=[__version__]) except Exception as e: time.sleep(5) continue keep_alive = 0 keep_alive += 1 time.sleep(2)
def run(self): """Run the App main logic. This method should contain the core logic of the App. """ alerta_api_key = self.tcex.playbook.read(self.args.alerta_api_key) alerta_api_endpoint = self.tcex.playbook.read(self.args.alerta_api_endpoint) alert_id = self.tcex.playbook.read(self.args.alert_id) query = self.tcex.playbook.read(self.args.query, True) # initialize alerta client client = Client(endpoint=alerta_api_endpoint, key=alerta_api_key) if not alert_id and not query: self.tcex.log.info('Retrieving all alerts from {}'.format(alerta_api_endpoint)) alerts = client.get_alerts() elif alert_id: self.tcex.log.info('Retrieving alert with id "{}"'.format(alert_id)) alerts = [client.get_alert(alert_id)] elif query: raise NotImplementedError('The ability to search for a query is not implemented yet. If you need it, create an issue here: https://github.com/ThreatConnect-Inc/threatconnect-playbooks/issues') # TODO: the difficulty here is that the query should be a tuple (I think) and I'm not sure how to (elegantly) convert the incoming string to a tuple # self.tcex.log.info('Retrieving alerts matching the query: {}'.format(query)) # alerts = client.search(query) alerts_json = self.convert_to_json(alerts) self.tcex.playbook.create_output('alerta.alerts', alerts_json, 'StringArray') self.tcex.playbook.create_output('alerta.alerts.0', alerts_json[0], 'String') self.tcex.playbook.create_output('alerta.alertCount', len(alerts_json), 'String')
def run(self): api = Client(endpoint=OPTIONS['endpoint'], key=OPTIONS['key']) keep_alive = 0 while not self.should_stop: for alertid in list(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 if keep_alive >= 10: try: origin = '{}/{}'.format('alerta-mailer', OPTIONS['smtp_host']) api.heartbeat(origin, tags=[__version__]) except Exception as e: time.sleep(5) continue keep_alive = 0 keep_alive += 1 time.sleep(2)
class PingerDaemon(object): def __init__(self): self.shuttingdown = False def run(self): self.running = True # Create internal queue self.queue = Queue.Queue() self.api = Client() # Initialiase ping targets ping_list = init_targets() # Start worker threads LOG.debug('Starting %s worker threads...', SERVER_THREAD_COUNT) for i in range(SERVER_THREAD_COUNT): w = WorkerThread(self.api, self.queue) try: w.start() except Exception as e: LOG.error('Worker thread #%s did not start: %s', i, e) continue LOG.info('Started worker thread: %s', w.getName()) while not self.shuttingdown: try: for p in ping_list: if 'targets' in p and p['targets']: for target in p['targets']: environment = p['environment'] service = p['service'] retries = p.get('retries', PING_MAX_RETRIES) self.queue.put( (environment, service, target, retries, time.time())) LOG.debug('Send heartbeat...') try: origin = '{}/{}'.format('pinger', platform.uname()[1]) self.api.heartbeat(origin, tags=[__version__]) except Exception as e: LOG.warning('Failed to send heartbeat: %s', e) time.sleep(LOOP_EVERY) LOG.info('Ping queue length is %d', self.queue.qsize()) except (KeyboardInterrupt, SystemExit): self.shuttingdown = True LOG.info('Shutdown request received...') self.running = False for i in range(SERVER_THREAD_COUNT): self.queue.put(None) w.join()
class PingerDaemon(object): def __init__(self): self.shuttingdown = False def run(self): self.running = True # Create internal queue self.queue = Queue.Queue() self.api = Client() # Initialiase ping targets ping_list = init_targets() # Start worker threads LOG.debug('Starting %s worker threads...', SERVER_THREAD_COUNT) for i in range(SERVER_THREAD_COUNT): w = WorkerThread(self.api, self.queue) try: w.start() except Exception as e: LOG.error('Worker thread #%s did not start: %s', i, e) continue LOG.info('Started worker thread: %s', w.getName()) while not self.shuttingdown: try: for p in ping_list: if 'targets' in p and p['targets']: for target in p['targets']: environment = p['environment'] service = p['service'] retries = p.get('retries', PING_MAX_RETRIES) self.queue.put((environment, service, target, retries, time.time())) LOG.debug('Send heartbeat...') try: origin = '{}/{}'.format('pinger', platform.uname()[1]) self.api.heartbeat(origin, tags=[__version__]) except Exception as e: LOG.warning('Failed to send heartbeat: %s', e) time.sleep(LOOP_EVERY) LOG.info('Ping queue length is %d', self.queue.qsize()) except (KeyboardInterrupt, SystemExit): self.shuttingdown = True LOG.info('Shutdown request received...') self.running = False for i in range(SERVER_THREAD_COUNT): self.queue.put(None) w.join()
def __init__(self): default_url = "http://localhost:8080/api" self.endpoint = os.environ.get("ALERTA_ENDPOINT", default_url) self.key = os.environ.get("ALERTA_KEY", "") self.ssl_verify = os.environ.get("ALERTA_SSL_VERIFY", False) self.client = Client(endpoint=self.endpoint, key=self.key, ssl_verify=self.ssl_verify)
def main(): api = Client() listener = Listener() while True: listener.send_cmd('READY\n') headers, body = listener.wait() event = headers['eventname'] if event.startswith('TICK'): try: origin = '{}/{}'.format('supervisord', platform.uname()[1]) api.heartbeat(origin, tags=[headers['ver'], event]) except Exception as e: listener.log_stderr(e) listener.send_cmd('RESULT 4\nFAIL') else: listener.send_cmd('RESULT 2\nOK') else: if event.endswith('FATAL'): severity = 'critical' elif event.endswith('BACKOFF'): severity = 'warning' elif event.endswith('EXITED'): severity = 'minor' else: severity = 'normal' try: api.send_alert( resource='%s:%s' % (platform.uname()[1], body['processname']), environment='Production', service=['supervisord'], event=event, correlate=[ 'PROCESS_STATE_STARTING', 'PROCESS_STATE_RUNNING', 'PROCESS_STATE_BACKOFF', 'PROCESS_STATE_STOPPING', 'PROCESS_STATE_EXITED', 'PROCESS_STATE_STOPPED', 'PROCESS_STATE_FATAL', 'PROCESS_STATE_UNKNOWN' ], value='serial=%s' % headers['serial'], severity=severity, origin=headers['server'], text='State changed from %s to %s.' % (body['from_state'], event), raw_data='%s\n\n%s' % (json.dumps(headers), json.dumps(body)) ) except Exception as e: listener.log_stderr(e) listener.send_cmd('RESULT 4\nFAIL') else: listener.send_cmd('RESULT 2\nOK')
def post_receive(self, alert): client = Client(endpoint=FORWARD_URL) fw_count = alert.attributes.get('fw_count') or 0 fw_count = fw_count + 1 if fw_count >= FORWARD_MAX_LENGTH: LOG.debug('alert discarded by cycle overflow') return alert.attributes['fw_count'] = fw_count client.send_alert(**alert.serialize) return
class AlertTestCase(unittest.TestCase): def setUp(self): self.client = Client(endpoint='http://*****:*****@alerta.io') note = self.client.update_alert_note(alert_id, notes[0].id, text='updated note text') self.assertEqual(note.text, 'updated note text') self.client.delete_alert_note(alert_id, notes[0].id) notes = self.client.get_alert_notes(alert_id) self.assertEqual(notes, [])
def post_receive(self, alert): if not FORWARD_URL or not FORWARD_API_KEY: return client = Client(endpoint=FORWARD_URL, key=FORWARD_API_KEY) fw_count = alert.attributes.get('fw_count') or 0 fw_count = fw_count+1 if fw_count >= FORWARD_MAX_LENGTH: LOG.debug('alert discarded by cycle overflow') return alert.attributes['fw_count'] = fw_count client.send_alert( **alert.serialize ) return
def post_receive(self, alert): if not FORWARD_URL or not FORWARD_API_KEY: return client = Client(endpoint=FORWARD_URL, key=FORWARD_API_KEY) fw_count = alert.attributes.get('fw_count') or 0 fw_count = fw_count+1 if fw_count >= FORWARD_MAX_LENGTH: LOG.debug('alert discarded by cycle overflow') return alert.get('attributes')['fw_count'] = fw_count client.send_alert( **alert ) return
class UrlmonDaemon(object): def __init__(self): self.shuttingdown = False def run(self): self.running = True self.queue = queue.Queue() self.api = Client(endpoint=settings.ENDPOINT, key=settings.API_KEY) # Start worker threads LOG.debug('Starting %s worker threads...', SERVER_THREADS) for i in range(SERVER_THREADS): w = WorkerThread(self.queue, self.api) try: w.start() except Exception as e: LOG.error('Worker thread #%s did not start: %s', i, e) continue LOG.info('Started worker thread: %s', w.getName()) while not self.shuttingdown: try: for check in settings.checks: self.queue.put((check, time.time())) LOG.debug('Send heartbeat...') try: origin = '{}/{}'.format('urlmon', platform.uname()[1]) self.api.heartbeat(origin, tags=[__version__]) except Exception as e: LOG.warning('Failed to send heartbeat: %s', e) time.sleep(LOOP_EVERY) LOG.info('URL check queue length is %d', self.queue.qsize()) except (KeyboardInterrupt, SystemExit): self.shuttingdown = True LOG.info('Shutdown request received...') self.running = False for i in range(SERVER_THREADS): self.queue.put(None) w.join()
def test_env_vars(self): config = Config(config_file=None) self.assertEqual(config.options['config_file'], '~/.alerta.conf') with mod_env(ALERTA_CONF_FILE='~/.alerta.test.conf', ALERTA_DEFAULT_PROFILE='test-profile', ALERTA_ENDPOINT='http://foo/bar/baz', ALERTA_API_KEY='test-key', REQUESTS_CA_BUNDLE='', CLICOLOR='', DEBUG='1'): # conf file config = Config(config_file=None) self.assertEqual(config.options['config_file'], '~/.alerta.test.conf', os.environ) config = Config(config_file='/dev/null') self.assertEqual(config.options['config_file'], '/dev/null') # profile config = Config(config_file=None) config.get_config_for_profle() self.assertEqual(config.options['profile'], 'test-profile', os.environ) # endpoint self.client = Client() self.assertEqual(self.client.endpoint, 'http://foo/bar/baz') # api key self.assertEqual(config.options['key'], 'test-key')
def cli(ctx, config_file, profile, endpoint_url, output, color, debug): """ Alerta client unified command-line tool. """ config = Config(config_file) config.get_config_for_profle(profile) ctx.obj = dict() ctx.obj['timezone'] = config.options['timezone'] ctx.obj['output'] = output or config.options['output'] ctx.obj['color'] = color or os.environ.get('CLICOLOR', None) or config.options['color'] endpoint = endpoint_url or config.options['endpoint'] ctx.obj['provider'] = config.options['provider'] ctx.obj['client_id'] = config.options['client_id'] ctx.obj['github_url'] = config.options['github_url'] ctx.obj['gitlab_url'] = config.options['gitlab_url'] ctx.obj['client'] = Client( endpoint=endpoint, key=config.options['key'], token=get_token(endpoint), timeout=float(config.options['timeout']), ssl_verify=config.options['sslverify'], debug=debug or os.environ.get('DEBUG', None) or config.options['debug'] )
class ApiKeyTestCase(unittest.TestCase): def setUp(self): self.client = Client() self.key = """ { "data": { "count": 0, "customer": null, "expireTime": "2018-10-03T08:36:14.651Z", "href": "http://localhost:8080/key/BpSG0Ck5JCqk5TJiuBSLAWuTs03QKc_527T5cDtw", "id": "f4203347-d1b2-4f56-b5e9-6de97cf2d8ae", "key": "BpSG0Ck5JCqk5TJiuBSLAWuTs03QKc_527T5cDtw", "lastUsedTime": null, "scopes": [ "write:alerts", "admin:keys" ], "text": "Ops kAPI Key", "type": "read-write", "user": "******" }, "key": "BpSG0Ck5JCqk5TJiuBSLAWuTs03QKc_527T5cDtw", "status": "ok" } """ @requests_mock.mock() def test_key(self, m): m.post('http://*****:*****@example.com') self.assertEqual(sorted(api_key.scopes), sorted(['write:alerts', 'admin:keys']))
class GroupTestCase(unittest.TestCase): def setUp(self): self.client = Client() self.key = """ { "group": { "count": 0, "href": "http://localhost:8080/group/8ed5d256-4205-4dfc-b25d-185bd019cb21", "id": "8ed5d256-4205-4dfc-b25d-185bd019cb21", "name": "myGroup", "text": "test group" }, "id": "8ed5d256-4205-4dfc-b25d-185bd019cb21", "status": "ok" } """ @requests_mock.mock() def test_key(self, m): m.post('http://localhost:8080/group', text=self.key) group = self.client.create_group(name='myGroup', text='test group') self.assertEqual(group.name, 'myGroup') self.assertEqual(group.text, 'test group')
def setUp(self): self.client = Client() alarm_model = { 'name': 'Alerta 8.0.1', 'severity': { 'security': 0, 'critical': 1, 'major': 2, 'minor': 3, 'warning': 4, 'indeterminate': 5, 'informational': 6, 'normal': 7, 'ok': 7, 'cleared': 7, 'debug': 8, 'trace': 9, 'unknown': 10 }, 'defaults': { 'normal_severity': 'normal' } } config = Config(config_file=None, config_override={'alarm_model': alarm_model}) self.obj = config.options self.obj['client'] = self.client self.runner = CliRunner(echo_stdin=True)
def cli(ctx, config_file, profile, endpoint_url, output, color, debug): """ Alerta client unified command-line tool. """ config = Config(config_file) config.get_config_for_profle(profile) config.get_remote_config(endpoint_url) ctx.obj = config.options # override current options with command-line options or environment variables ctx.obj['output'] = output or config.options['output'] ctx.obj['color'] = color or os.environ.get('CLICOLOR', None) or config.options['color'] endpoint = endpoint_url or config.options['endpoint'] ctx.obj['client'] = Client(endpoint=endpoint, key=config.options['key'], token=get_token(endpoint), username=config.options.get('username', None), password=config.options.get('password', None), timeout=float(config.options['timeout']), ssl_verify=config.options['sslverify'], debug=debug or os.environ.get('DEBUG', None) or config.options['debug'])
class PermissionTestCase(unittest.TestCase): def setUp(self): self.client = Client() self.perm = """ { "id": "584f38f4-b44e-4d87-9b61-c106d21bcc7a", "permission": { "href": "http://localhost:8080/perm/584f38f4-b44e-4d87-9b61-c106d21bcc7a", "id": "584f38f4-b44e-4d87-9b61-c106d21bcc7a", "match": "websys", "scopes": [ "admin:users", "admin:keys", "write" ] }, "status": "ok" } """ @requests_mock.mock() def test_permission(self, m): m.post('http://localhost:8080/perm', text=self.perm) perm = self.client.create_perm(role='websys', scopes=['admin:users', 'admin:keys', 'write']) self.assertEqual(perm.match, 'websys') self.assertEqual(sorted(perm.scopes), sorted(['admin:users', 'admin:keys', 'write']))
def setUp(self): self.client = Client() config = Config(config_file=None) self.obj = config.options self.obj['client'] = self.client self.runner = CliRunner(echo_stdin=True)
def run(self): self.running = True self.queue = queue.Queue() self.api = Client(endpoint=settings.ENDPOINT, key=settings.API_KEY) # Start worker threads LOG.debug('Starting %s worker threads...', SERVER_THREADS) for i in range(SERVER_THREADS): w = WorkerThread(self.queue, self.api) try: w.start() except Exception as e: LOG.error('Worker thread #%s did not start: %s', i, e) continue LOG.info('Started worker thread: %s', w.getName()) while not self.shuttingdown: try: for check in settings.checks: self.queue.put((check, time.time())) LOG.debug('Send heartbeat...') try: origin = '{}/{}'.format('urlmon', platform.uname()[1]) self.api.heartbeat(origin, tags=[__version__], timeout=3600) except Exception as e: LOG.warning('Failed to send heartbeat: %s', e) time.sleep(LOOP_EVERY) LOG.info('URL check queue length is %d', self.queue.qsize()) if self.queue.qsize() > 100: severity = 'warning' else: severity = 'ok' try: self.api.send_alert( resource=origin, event='big queue for http checks', value=self.queue.qsize(), severity=severity, text='URL check queue length is %d', self.queue.qsize(), event_type='serviceAlert', ) except Exception as e: LOG.warning('Failed to send alert: %s', e) except (KeyboardInterrupt, SystemExit): self.shuttingdown = True LOG.info('Shutdown request received...') self.running = False for i in range(SERVER_THREADS): self.queue.put(None) w.join()
class AlertTestCase(unittest.TestCase): def setUp(self): self.client = Client(endpoint='http://api:8080', key='demo-key') def test_customer(self): customer = self.client.create_customer(customer='ACME Corp.', match='example.com') customer_id = customer.id self.assertEqual(customer.customer, 'ACME Corp.') self.assertEqual(customer.match, 'example.com') customer = self.client.update_customer(customer_id, customer='Foo Corp.', match='foo.com') self.assertEqual(customer.customer, 'Foo Corp.') self.assertEqual(customer.match, 'foo.com') customer = self.client.create_customer(customer='Quetzal Inc.', match='quetzal.io') customers = self.client.get_customers() self.assertEqual(len(customers), 2) self.client.delete_customer(customer_id) customers = self.client.get_customers() self.assertEqual(len(customers), 1)
class AlertTestCase(unittest.TestCase): def setUp(self): self.client = Client(endpoint='http://api:8080', key='demo-key') def test_group(self): group = self.client.create_group(name='myGroup', text='test group') group_id = group.id self.assertEqual(group.name, 'myGroup') self.assertEqual(group.text, 'test group') group = self.client.update_group(group_id, name='newGroup', text='updated group text') self.assertEqual(group.name, 'newGroup') self.assertEqual(group.text, 'updated group text') group = self.client.create_group(name='myGroup2', text='test group2') groups = self.client.get_users_groups() self.assertEqual(len(groups), 2, groups) self.client.delete_group(group_id) groups = self.client.get_users_groups() self.assertEqual(len(groups), 1)
def alerta(self): """Return alerta instance, create new if missing""" if self._alerta is None: LOGGER.warning('No alerta exist. Create client.') self._alerta = Client(endpoint=self.alerta_config.alerta_endpoint, debug=self.alerta_config.alerta_debug, timeout=self.alerta_config.alerta_timeout, key=self.alerta_api_key) return self._alerta
class BlackoutTestCase(unittest.TestCase): def setUp(self): self.client = Client() self.blackout = """ { "blackout": { "createTime": "2021-04-14T20:36:06.453Z", "customer": null, "duration": 3600, "endTime": "2021-04-14T21:36:06.453Z", "environment": "Production", "event": "node_down", "group": "Network", "href": "http://local.alerta.io:8080/blackout/5ed223a3-27dc-4c4c-97d1-504f107d8a1a", "id": "5ed223a3-27dc-4c4c-97d1-504f107d8a1a", "origin": "foo/xyz", "priority": 8, "remaining": 3600, "resource": "web01", "service": [ "Web", "App" ], "startTime": "2021-04-14T20:36:06.453Z", "status": "active", "tags": [ "london", "linux" ], "text": "Network outage in Bracknell", "user": "******" }, "id": "5ed223a3-27dc-4c4c-97d1-504f107d8a1a", "status": "ok" } """ @requests_mock.mock() def test_blackout(self, m): m.post('http://*****:*****@alerta.dev')
class AlertaClient(object): def __init__(self): default_url = "http://localhost:8080/api" self.endpoint = os.environ.get("ALERTA_ENDPOINT", default_url) self.key = os.environ.get("ALERTA_KEY", "") self.ssl_verify = os.environ.get("ALERTA_SSL_VERIFY", False) self.client = Client(endpoint=self.endpoint, key=self.key, ssl_verify=self.ssl_verify) def send_event(self, **event_params): """ Object constructor expects nine arguments. :param resource: resource under alarm, deliberately not host-centric :param event: event name eg. NodeDown :param environment: effected environment, development, \ staging or production :param service: list of effected services :param text: freeform text description :param value: event value eg. 100%, Down, PingFail, 55ms, ORA-1664 :param severity: severity of alert (default normal) :param timeout: number of seconds before alert is considered stale :param raw_data: log event or the steps to resolve """ if len(event_params) >= 8: try: self.client.send_alert( resource=event_params.get("resource"), event=event_params.get("event"), environment=event_params.get("environment"), service=event_params.get("service", None), text=event_params.get("text"), value=event_params.get("value"), severity=event_params.get("severity"), timeout=event_params.get("timeout", 86400), raw_data=event_params.get("raw_data"), ) except Exception: logging.error("Could not send events to alerta service", exc_info=True)
class AlertTestCase(unittest.TestCase): def setUp(self): self.client = Client(endpoint='http://*****:*****@alerta.io') self.assertEqual(sorted(users[0].roles), sorted(['admin'])) self.assertEqual(users[0].status, 'active')
class AlertTestCase(unittest.TestCase): def setUp(self): self.client = Client(endpoint='http://api:8080', key='demo-key') def test_permission(self): perm = self.client.create_perm( role='websys', scopes=['admin:users', 'admin:keys', 'write']) self.assertEqual(perm.match, 'websys') self.assertEqual(sorted(perm.scopes), sorted(['admin:users', 'admin:keys', 'write']))
def run(self): endpoint = os.environ.get('ALERTA_ENDPOINT', 'http://localhost:8080') key = os.environ.get('ALERTA_API_KEY', None) self.api = Client(endpoint=endpoint, key=key) data = sys.stdin.read() LOG.info('snmptrapd -> %r', data) try: data = unicode(data, 'utf-8', errors='ignore') # python 2 except NameError: pass LOG.debug('unicoded -> %s', data) try: resource, event, correlate, trap_version, trapvars = self.parse_snmptrap(data) if resource and event: self.api.send_alert( resource=resource, event=event, correlate=correlate, group='SNMP', value=trapvars['$w'], severity='indeterminate', environment='Production', service=['Network'], text=trapvars['$W'], event_type='snmptrapAlert', attributes={'trapvars': {k.replace('$', '_'): v for k, v in trapvars.items()}}, tags=[trap_version], create_time=datetime.datetime.strptime('%sT%s.000Z' % (trapvars['$x'], trapvars['$X']), '%Y-%m-%dT%H:%M:%S.%fZ'), raw_data=data ) except Exception as e: LOG.warning('Failed to send alert: %s', e) LOG.debug('Send heartbeat...') try: origin = '{}/{}'.format('snmptrap', platform.uname()[1]) self.api.heartbeat(origin, tags=[__version__]) except Exception as e: LOG.warning('Failed to send heartbeat: %s', e)
class AlertTestCase(unittest.TestCase): def setUp(self): self.client = Client(endpoint='http://api:8080', key='demo-key') def test_heartbeat(self): hb = self.client.heartbeat(origin='app/web01', timeout=10, tags=['london', 'linux']) self.assertEqual(hb.origin, 'app/web01') self.assertEqual(hb.event_type, 'Heartbeat') self.assertEqual(hb.timeout, 10) self.assertIn('linux', hb.tags)
class AlertTestCase(unittest.TestCase): def setUp(self): self.client = Client(endpoint='http://api:8080', key='demo-key') def test_alert(self): id, alert, message = self.client.send_alert( environment='Production', resource='net03', event='node_down', correlated=['node_up', 'node_down', 'node_marginal'], service=['Network', 'Core'], severity='critical', tags=['newyork', 'linux'], value=4) id, alert, message = self.client.send_alert( environment='Production', resource='net03', event='node_marginal', correlated=['node_up', 'node_down', 'node_marginal'], service=['Network', 'Core'], severity='minor', tags=['newyork', 'linux'], value=1) self.assertEqual(alert.value, '1') # values cast to string self.assertEqual(alert.timeout, 86400) # timeout returned as int self.assertIn('newyork', alert.tags) def test_history(self): hist = self.client.get_history(query=[('resource', 'net03')]) self.assertEqual(hist[0].environment, 'Production') self.assertEqual(hist[0].service, ['Network', 'Core']) self.assertEqual(hist[0].resource, 'net03') self.assertIn('newyork', hist[0].tags) self.assertEqual(hist[0].change_type, 'new') self.assertEqual(hist[1].environment, 'Production') self.assertEqual(hist[1].service, ['Network', 'Core']) self.assertEqual(hist[1].resource, 'net03') self.assertIn('newyork', hist[1].tags) self.assertEqual(hist[1].change_type, 'new')
class AlertTestCase(unittest.TestCase): def setUp(self): self.client = Client(endpoint='http://*****:*****@alerta.io') self.assertEqual(sorted(api_key.scopes), sorted(['write:alerts', 'admin:keys'])) api_key = self.client.update_key(api_key_id, scopes=[ Scope.write_alerts, Scope.write_heartbeats, Scope.admin_keys ], text='Updated Ops API Key') self.assertEqual( sorted(api_key.scopes), sorted( [Scope.write_alerts, Scope.write_heartbeats, Scope.admin_keys])) self.assertEqual(api_key.text, 'Updated Ops API Key') api_key = self.client.create_key(username='******', scopes=[Scope.admin], text='Admin API Key', key='admin-key') self.assertEqual(api_key.key, 'admin-key') api_keys = self.client.get_keys(query=[('user', '*****@*****.**')]) self.assertEqual(len(api_keys), 2) api_keys = self.client.delete_key(api_key_id) self.assertEqual(len(api_keys), 1)
class HistoryTestCase(unittest.TestCase): def setUp(self): self.client = Client() self.history = """ { "history": [ { "attributes": { "ip": "127.0.0.1", "notify": false }, "customer": null, "environment": "Production", "event": "node_down", "group": "Misc", "href": "http://localhost:8080/alert/e7020428-5dad-4a41-9bfe-78e9d55cda06", "id": "e7020428-5dad-4a41-9bfe-78e9d55cda06", "origin": "alertad/fdaa33ca.local", "resource": "web01", "service": [ "Web", "App" ], "severity": "critical", "tags": [ "london", "linux" ], "text": "", "type": "severity", "updateTime": "2017-10-03T09:12:27.283Z", "value": "4" } ], "status": "ok", "total": 1 } """ @requests_mock.mock() def test_history(self, m): m.get('http://localhost:8080/alerts/history', text=self.history) hist = self.client.get_history() self.assertEqual(hist[0].environment, 'Production') self.assertEqual(hist[0].service, ['Web', 'App']) self.assertEqual(hist[0].resource, 'web01') self.assertIn('london', hist[0].tags) self.assertEqual(hist[0].change_type, 'severity')
class NotesTestCase(unittest.TestCase): def setUp(self): self.client = Client() self.key = """ { "status": "ok" } """ @requests_mock.mock() def test_add_note(self, m): m.put('http://localhost:8080/alert/e7020428-5dad-4a41-9bfe-78e9d55cda06/note', text=self.key) r = self.client.add_note(id='e7020428-5dad-4a41-9bfe-78e9d55cda06', note='this is a test note') self.assertEqual(r['status'], 'ok')
class UserTestCase(unittest.TestCase): def setUp(self): self.client = Client() self.user = """ { "domains": [ "alerta.io", "gmail.com", "foo.com" ], "status": "ok", "total": 1, "users": [ { "attributes": {}, "createTime": "2017-10-01T15:45:32.671Z", "domain": "alerta.io", "email": "*****@*****.**", "email_verified": false, "href": "http://localhost:8080/user/107dcbe2-e5a9-4f6a-8c23-ce9379288bf5", "id": "107dcbe2-e5a9-4f6a-8c23-ce9379288bf5", "lastLogin": "******", "name": "Admin", "provider": "basic", "roles": [ "admin" ], "status": "active", "text": "", "updateTime": "2017-10-03T09:21:20.888Z" } ] } """ @requests_mock.mock() def test_user(self, m): m.get('http://localhost:8080/users', text=self.user) users = self.client.get_users() self.assertEqual(users[0].name, 'Admin') self.assertEqual(sorted(users[0].roles), sorted(['admin'])) self.assertEqual(users[0].status, 'active')
class HeartbeatTestCase(unittest.TestCase): def setUp(self): self.client = Client() self.heartbeat = """ { "heartbeat": { "createTime": "2017-10-02T23:54:05.214Z", "customer": null, "href": "http://localhost:8080/heartbeat/4a0b87cd-9786-48f8-9994-59a9209ff0b2", "id": "4a0b87cd-9786-48f8-9994-59a9209ff0b2", "latency": 0.0, "origin": "app/web01", "receiveTime": "2017-10-02T23:54:05.214Z", "since": 0, "status": "ok", "tags": [ "london", "linux" ], "timeout": 10, "type": "Heartbeat" }, "id": "4a0b87cd-9786-48f8-9994-59a9209ff0b2", "status": "ok" } """ @requests_mock.mock() def test_heartbeat(self, m): m.post('http://localhost:8080/heartbeat', text=self.heartbeat) hb = self.client.heartbeat(origin='app/web01', timeout=10, tags=['london', 'linux']) self.assertEqual(hb.origin, 'app/web01') self.assertEqual(hb.event_type, 'Heartbeat') self.assertEqual(hb.timeout, 10) self.assertIn('linux', hb.tags)
class SyslogDaemon(object): def __init__(self): self.api = Client() LOG.info('Starting UDP listener...') # Set up syslog UDP listener try: self.udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.udp.bind(('', SYSLOG_UDP_PORT)) except socket.error as e: LOG.error('Syslog UDP error: %s', e) sys.exit(2) LOG.info('Listening on syslog port %s/udp' % SYSLOG_UDP_PORT) LOG.info('Starting TCP listener...') # Set up syslog TCP listener try: self.tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.tcp.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.tcp.bind(('', SYSLOG_TCP_PORT)) self.tcp.listen(5) except socket.error as e: LOG.error('Syslog TCP error: %s', e) sys.exit(2) LOG.info('Listening on syslog port %s/tcp' % SYSLOG_TCP_PORT) self.shuttingdown = False def run(self): count = 0 while not self.shuttingdown: try: LOG.debug('Waiting for syslog messages...') ip, op, rdy = select.select([self.udp, self.tcp], [], [], LOOP_EVERY) if ip: for i in ip: if i == self.udp: data, addr = self.udp.recvfrom(4096) data = unicode(data, 'utf-8', errors='ignore') LOG.debug('Syslog UDP data received from %s: %s', addr, data) if i == self.tcp: client, addr = self.tcp.accept() data = client.recv(4096) data = unicode(data, 'utf-8', errors='ignore') client.close() LOG.debug('Syslog TCP data received from %s: %s', addr, data) alerts = self.parse_syslog(ip=addr[0], data=data) for alert in alerts: try: self.api.send_alert(**alert) except Exception as e: LOG.warning('Failed to send alert: %s', e) count += 1 if not ip or count % 5 == 0: LOG.debug('Send heartbeat...') try: origin = '{}/{}'.format('syslog', platform.uname()[1]) self.api.heartbeat(origin, tags=[__version__]) except Exception as e: LOG.warning('Failed to send heartbeat: %s', e) except (KeyboardInterrupt, SystemExit): self.shuttingdown = True LOG.info('Shutdown request received...') def parse_syslog(self, ip, data): LOG.debug('Parsing syslog message...') syslogAlerts = list() event = None resource = None for msg in data.split('\n'): if not msg or 'last message repeated' in msg: continue if re.match('<\d+>1', msg): # Parse RFC 5424 compliant message m = re.match(r'<(\d+)>1 (\S+) (\S+) (\S+) (\S+) (\S+) (.*)', msg) if m: PRI = int(m.group(1)) ISOTIMESTAMP = m.group(2) HOSTNAME = m.group(3) APPNAME = m.group(4) PROCID = m.group(5) MSGID = m.group(6) TAG = '%s[%s] %s' % (APPNAME, PROCID, MSGID) MSG = m.group(7) LOG.info("Parsed RFC 5424 message OK") else: LOG.error("Could not parse RFC 5424 syslog message: %s", msg) continue elif re.match(r'<(\d{1,3})>\S{3}\s', msg): # Parse RFC 3164 compliant message m = re.match(r'<(\d{1,3})>\S{3}\s{1,2}\d?\d \d{2}:\d{2}:\d{2} (\S+)( (\S+):)? (.*)', msg) if m: PRI = int(m.group(1)) HOSTNAME = m.group(2) TAG = m.group(4) MSG = m.group(5) LOG.info("Parsed RFC 3164 message OK") else: LOG.error("Could not parse RFC 3164 syslog message: %s", msg) continue elif re.match('<\d+>.*%[A-Z0-9_-]+', msg): # Parse Cisco Syslog message m = re.match('<(\d+)>.*(%([A-Z0-9_-]+)):? (.*)', msg) if m: LOG.debug(m.groups()) PRI = int(m.group(1)) CISCO_SYSLOG = m.group(2) try: CISCO_FACILITY, CISCO_SEVERITY, CISCO_MNEMONIC = m.group(3).split('-') except ValueError as e: LOG.error('Could not parse Cisco syslog - %s: %s', e, m.group(3)) CISCO_FACILITY = CISCO_SEVERITY = CISCO_MNEMONIC = 'na' TAG = CISCO_MNEMONIC MSG = m.group(4) event = CISCO_SYSLOG # replace IP address with a hostname, if necessary try: socket.inet_aton(ip) (resource, _, _) = socket.gethostbyaddr(ip) except (socket.error, socket.herror): resource = ip resource = '%s:%s' % (resource, CISCO_FACILITY) else: LOG.error("Could not parse Cisco syslog message: %s", msg) continue facility, level = decode_priority(PRI) # Defaults event = event or '%s%s' % (facility.capitalize(), level.capitalize()) resource = resource or '%s%s' % (HOSTNAME, ':' + TAG if TAG else '') severity = priority_to_code(level) group = 'Syslog' value = level text = MSG environment = 'Production' service = ['Platform'] tags = ['%s.%s' % (facility, level)] correlate = ['%s%s' % (facility.capitalize(), s.capitalize()) for s in SYSLOG_SEVERITY_NAMES] raw_data = msg syslogAlert = { 'resource': resource, 'event': event, 'environment': environment, 'severity': severity, 'correlate':correlate, 'service': service, 'group': group, 'value': value, 'text': text, 'tags': tags, 'event_type': 'syslogAlert', 'raw_data': raw_data } syslogAlerts.append(syslogAlert) return syslogAlerts
def setUp(self): self.client = Client() self.heartbeat = """
def setUp(self): self.client = Client() self.key = """
def setUp(self): self.client = Client() self.history = """
def run(self): while True: LOG.debug('Waiting on input queue...') try: check, queue_time = self.queue.get() except TypeError: LOG.info('%s is shutting down.', self.getName()) break if time.time() - queue_time > LOOP_EVERY: LOG.warning('URL request for %s to %s expired after %d seconds.', check['resource'], check['url'], int(time.time() - queue_time)) self.queue.task_done() continue resource = check['resource'] LOG.info('%s polling %s...', self.getName(), resource) status, reason, body, rtt = self.urlmon(check) status_regex = check.get('status_regex', None) search_string = check.get('search', None) rule = check.get('rule', None) warn_thold = check.get('warning', SLOW_WARNING_THRESHOLD) crit_thold = check.get('critical', SLOW_CRITICAL_THRESHOLD) checker_api = check.get('api_endpoint', None) checker_apikey = check.get('api_key', None) check_ssl = check.get('check_ssl') if (checker_api and checker_apikey): local_api = Client(endpoint=checker_api, key=checker_apikey) else: local_api = self.api try: description = HTTP_RESPONSES[status] except KeyError: description = 'undefined' if not status: event = 'HttpConnectionError' severity = 'major' value = reason text = 'Error during connection or data transfer (timeout=%d).' % MAX_TIMEOUT elif status_regex: if re.search(status_regex, str(status)): event = 'HttpResponseRegexOK' severity = 'normal' value = '%s (%d)' % (description, status) text = 'HTTP server responded with status code %d that matched "%s" in %dms' % (status, status_regex, rtt) else: event = 'HttpResponseRegexError' severity = 'major' value = '%s (%d)' % (description, status) text = 'HTTP server responded with status code %d that failed to match "%s"' % (status, status_regex) elif 100 <= status <= 199: event = 'HttpInformational' severity = 'normal' value = '%s (%d)' % (description, status) text = 'HTTP server responded with status code %d in %dms' % (status, rtt) elif 200 <= status <= 299: event = 'HttpResponseOK' severity = 'normal' value = '%s (%d)' % (description, status) text = 'HTTP server responded with status code %d in %dms' % (status, rtt) elif 300 <= status <= 399: event = 'HttpRedirection' severity = 'minor' value = '%s (%d)' % (description, status) text = 'HTTP server responded with status code %d in %dms' % (status, rtt) elif 400 <= status <= 499: event = 'HttpClientError' severity = 'minor' value = '%s (%d)' % (description, status) text = 'HTTP server responded with status code %d in %dms' % (status, rtt) elif 500 <= status <= 599: event = 'HttpServerError' severity = 'major' value = '%s (%d)' % (description, status) text = 'HTTP server responded with status code %d in %dms' % (status, rtt) else: event = 'HttpUnknownError' severity = 'warning' value = 'UNKNOWN' text = 'HTTP request resulted in an unhandled error.' if event in ['HttpResponseOK', 'HttpResponseRegexOK']: if rtt > crit_thold: event = 'HttpResponseSlow' severity = 'critical' value = '%dms' % rtt text = 'Website available but exceeding critical RT thresholds of %dms' % crit_thold elif rtt > warn_thold: event = 'HttpResponseSlow' severity = 'warning' value = '%dms' % rtt text = 'Website available but exceeding warning RT thresholds of %dms' % warn_thold if search_string and body: LOG.debug('Searching for %s', search_string) found = False for line in body.split('\n'): m = re.search(search_string, line) if m: found = True LOG.debug("Regex: Found %s in %s", search_string, line) break if not found: event = 'HttpContentError' severity = 'minor' value = 'Search failed' text = 'Website available but pattern "%s" not found' % search_string elif rule and body: LOG.debug('Evaluating rule %s', rule) headers = check.get('headers', {}) if 'Content-type' in headers and headers['Content-type'] == 'application/json': try: body = json.loads(body) except ValueError as e: LOG.error('Could not evaluate rule %s: %s', rule, e) try: eval(rule) # NOTE: assumes request body in variable called 'body' except (SyntaxError, NameError, ZeroDivisionError) as e: LOG.error('Could not evaluate rule %s: %s', rule, e) except Exception as e: LOG.error('Could not evaluate rule %s: %s', rule, e) else: if not eval(rule): event = 'HttpContentError' severity = 'minor' value = 'Rule failed' text = 'Website available but rule evaluation failed (%s)' % rule LOG.debug("URL: %s, Status: %s (%s), Round-Trip Time: %dms -> %s", check['url'], description, status, rtt, event) resource = check['resource'] correlate = _HTTP_ALERTS group = 'Web' environment = check['environment'] service = check['service'] text = text tags = check.get('tags', list()) threshold_info = "%s : RT > %d RT > %d x %s" % (check['url'], warn_thold, crit_thold, check.get('count', 1)) try: local_api.send_alert( resource=resource, event=event, correlate=correlate, group=group, value=value, severity=severity, environment=environment, service=service, text=text, event_type='serviceAlert', tags=tags, attributes={ 'thresholdInfo': threshold_info } ) except Exception as e: LOG.warning('Failed to send alert: %s', e) if check_ssl: ssl_date_fmt = r'%b %d %H:%M:%S %Y %Z' context = ssl.create_default_context() domain = '{uri.netloc}'.format(uri=urllib.parse.urlparse(check.get('url'))) port = urllib.parse.urlparse(check.get('url')).port or 443 conn = context.wrap_socket( socket.socket(socket.AF_INET), server_hostname=domain ) conn.settimeout(3.0) conn.connect((domain, port)) ssl_info = conn.getpeercert() days_left = datetime.datetime.strptime(ssl_info['notAfter'], ssl_date_fmt) - datetime.datetime.utcnow() if days_left < datetime.timedelta(days=0): text = 'HTTPS cert for %s expired' % check['resource'] severity = 'critical' elif days_left < datetime.timedelta(days=SSL_DAYS) and days_left > datetime.timedelta(days=SSL_DAYS_PANIC): text = 'HTTPS cert for %s will expire at %s' % (check['resource'], days_left) severity = 'major' elif days_left <= datetime.timedelta(days=SSL_DAYS_PANIC): text = 'HTTPS cert for %s will expire at %s' % (check['resource'], days_left) severity = 'critical' else: severity = 'normal' try: local_api.send_alert( resource=resource, event='HttpSSLChecker', correlate=correlate, group=group, value='0', severity=severity, environment=environment, service=service, text=text, event_type='serviceAlert', tags=tags, attributes={ 'thresholdInfo': threshold_info } ) except Exception as e: LOG.warning('Failed to send ssl alert: %s', e) self.queue.task_done() LOG.info('%s check complete.', self.getName()) self.queue.task_done()
class FormatsTestCase(unittest.TestCase): def setUp(self): self.client = Client() self.alert = """ { "alert": { "attributes": { "ip": "127.0.0.1" }, "correlate": [], "createTime": "2018-04-08T19:01:44.979Z", "customer": null, "duplicateCount": 0, "environment": "Development", "event": "foo", "group": "Misc", "history": [ { "event": "foo", "href": "https://alerta-api.herokuapp.com/alert/d1bb37cf-e976-429e-96f5-82b2a48aa50b", "id": "d1bb37cf-e976-429e-96f5-82b2a48aa50b", "severity": null, "status": "shelved", "text": "shelved by Test90", "type": "status", "updateTime": "2018-04-09T09:11:43.502Z", "value": null }, { "event": "foo", "href": "https://alerta-api.herokuapp.com/alert/d1bb37cf-e976-429e-96f5-82b2a48aa50b", "id": "d1bb37cf-e976-429e-96f5-82b2a48aa50b", "severity": null, "status": "open", "text": "bulk status change via console by test", "type": "status", "updateTime": "2018-04-24T17:52:40.088Z", "value": null }, { "event": "foo", "href": "https://alerta-api.herokuapp.com/alert/d1bb37cf-e976-429e-96f5-82b2a48aa50b", "id": "d1bb37cf-e976-429e-96f5-82b2a48aa50b", "severity": "minor", "status": "shelved", "text": "status change via console by Scott Wenzel", "type": "action", "updateTime": "2018-05-18T03:38:50.333Z", "value": null } ], "href": "https://alerta-api.herokuapp.com/alert/d1bb37cf-e976-429e-96f5-82b2a48aa50b", "id": "d1bb37cf-e976-429e-96f5-82b2a48aa50b", "lastReceiveId": "d1bb37cf-e976-429e-96f5-82b2a48aa50b", "lastReceiveTime": "2018-04-08T19:01:46.090Z", "origin": "alertad/fdaa33ca.lan", "previousSeverity": "indeterminate", "rawData": null, "receiveTime": "2018-04-08T19:01:46.090Z", "repeat": false, "resource": "quux", "service": [ "Bar" ], "severity": "minor", "status": "shelved", "tags": [ "watch:Scott Wenzel" ], "text": "", "timeout": 3600, "trendIndication": "moreSevere", "type": "exceptionAlert", "value": null } } """ @requests_mock.mock() def test_alert(self, m): m.post('http://localhost:8080/alert', text=self.alert) msg = {'event': 'foo', 'service': ['Bar']} id, alert, message = self.client.send_alert( environment='Production', resource='quux', **msg ) alert_summary = alert.tabular(fields='summary', timezone='UTC') self.assertEqual(alert_summary['id'], 'd1bb37cf') alert_summary = alert.tabular(fields='details', timezone='UTC') self.assertEqual(alert_summary['severity'], 'indeterminate -> minor') alert_summary = alert.tabular(fields='all', timezone='UTC') self.assertEqual(alert_summary['history'][0]['status'], 'shelved')
def setUp(self): self.client = Client() self.user = """
def setUp(self): self.client = Client() self.alert = """
def test_action(self, trapper, endpoint, key=None): hosts = self.zapi.host.get() zabbix_server_id = [h for h in hosts if h['name'] == 'Zabbix server'][0]['hostid'] # enable zabbix server monitoring self.zapi.host.update(hostid=zabbix_server_id, status=ENABLED) description = 'Test trigger event on {HOST.NAME}' try: response = self.zapi.item.create( name='Test Zabbix-Alerta Integration', type=ZABBIX_TRAPPER, key_='test.alerta', value_type=TEXT, hostid=zabbix_server_id, status=ENABLED ) self.item_id = response['itemids'][0] response = self.zapi.trigger.create( hostid=zabbix_server_id, description=description, expression='{Zabbix server:test.alerta.diff()}>0', type=GENERATE_MULTIPLE_EVENTS, priority=INFORMATION, status=ENABLED, manual_close=ALLOW_MANUAL_CLOSE ) self.trigger_id = response['triggerids'][0] except ZabbixAPIException: triggers = self.zapi.trigger.get(hostids=zabbix_server_id) self.trigger_id = [t for t in triggers if t['description'] == description][0]['triggerid'] self.item_id = self.zapi.item.get(triggerids=self.trigger_id)[0]['itemid'] def zabbix_send(value): cfg = protobix.ZabbixAgentConfig() cfg.server_active = trapper zbx = protobix.DataContainer(cfg) zbx.data_type = 'items' zbx.add_item(host='Zabbix server', key='test.alerta', value=value) response = zbx.send() print(response) print('sending test items') now = int(time.time()) zabbix_send('OK') print('wait for items to be received') count = 0 while True: count += 1 response = self.zapi.history.get(itemids=[self.item_id], history=TEXT, time_from=now, output='extend', sortfield='clock', sortorder='DESC', limit=10) zabbix_send('RETRY%s' % count) if len(response) > 1: break print('waiting 5 seconds...') time.sleep(5) print('sent items received by zabbix') print(response) from_date = datetime.utcnow().replace(microsecond=0).isoformat() + ".000Z" print('wait for triggered event') while True: response = self.zapi.event.get(objectids=self.trigger_id, time_from=now, output='extend', sortfield=['clock', 'eventid'], sortorder='DESC') if len(response) > 0 and 'eventid' in response[0]: event_id = response[0]['eventid'] break print('waiting 2 seconds...') time.sleep(2) print('event triggered') print(response[0]) print('wait for alert') while True: response = self.zapi.alert.get(eventid=event_id, time_from=now, output='extend',) if len(response) > 0: break print('waiting 2 seconds...') time.sleep(2) print('alert triggered by event') print(response[0]) api = Client(endpoint, key) print('check alert received by Alerta') while True: try: response = api.get_alerts(query=[('event', 'test.alerta'), ('from-date', from_date)]) except Exception as e: sys.exit(e) if len(response) > 0: break time.sleep(5) print(response[0].last_receive_id) print('success!')
def main(): config_file = os.environ.get('ALERTA_CONF_FILE') or OPTIONS['config_file'] config = configparser.RawConfigParser(defaults=OPTIONS) try: config.read(os.path.expanduser(config_file)) except Exception: sys.exit("Problem reading configuration file %s - is this an ini file?" % config_file) parser = argparse.ArgumentParser( prog='zabbix-alerta', usage='zabbix-alerta SENDTO SUMMARY BODY', description='Zabbix-to-Alerta integration script', epilog=epilog, formatter_class=argparse.RawTextHelpFormatter ) parser.add_argument( 'sendto', help='config profile or alerta API endpoint and key' ) parser.add_argument( 'summary', help='alert summary' ) parser.add_argument( 'body', help='alert body (see format below)' ) args, left = parser.parse_known_args() # sendto=apiUrl[;key] if args.sendto.startswith('http://') or args.sendto.startswith('https://'): want_profile = None try: OPTIONS['endpoint'], OPTIONS['key'] = args.sendto.split(';', 1) except ValueError: OPTIONS['endpoint'] = args.sendto # sendto=profile else: want_profile = args.sendto or os.environ.get('ALERTA_DEFAULT_PROFILE') or config.defaults().get('profile') if want_profile and config.has_section('profile %s' % want_profile): for opt in OPTIONS: try: OPTIONS[opt] = config.getboolean('profile %s' % want_profile, opt) except (ValueError, AttributeError): OPTIONS[opt] = config.get('profile %s' % want_profile, opt) else: for opt in OPTIONS: try: OPTIONS[opt] = config.getboolean('DEFAULT', opt) except (ValueError, AttributeError): OPTIONS[opt] = config.get('DEFAULT', opt) parser.set_defaults(**OPTIONS) args = parser.parse_args() if args.debug or not os.path.isdir('/var/log/zabbix'): LOG.basicConfig(stream=sys.stderr, format=LOG_FORMAT, datefmt=LOG_DATE_FMT, level=LOG.DEBUG) else: LOG.basicConfig(filename=LOG_FILE, format=LOG_FORMAT, datefmt=LOG_DATE_FMT, level=LOG.INFO) LOG.info("[alerta] endpoint=%s key=%s", args.endpoint, args.key) api = Client(endpoint=args.endpoint, key=args.key, ssl_verify=args.sslverify) LOG.debug("[alerta] sendto=%s, summary=%s, body=%s", args.sendto, args.summary, args.body) try: alert = parse_zabbix(args.summary, args.body) api.send_alert(**alert) except (SystemExit, KeyboardInterrupt): LOG.warning("Exiting zabbix-alerta.") sys.exit(0) except Exception as e: LOG.error(e, exc_info=1) sys.exit(1)
class SnmpTrapHandler(object): def __init__(self): self.api = None def run(self): endpoint = os.environ.get('ALERTA_ENDPOINT', 'http://localhost:8080') key = os.environ.get('ALERTA_API_KEY', None) self.api = Client(endpoint=endpoint, key=key) data = sys.stdin.read() LOG.info('snmptrapd -> %r', data) try: data = unicode(data, 'utf-8', errors='ignore') # python 2 except NameError: pass LOG.debug('unicoded -> %s', data) try: resource, event, correlate, trap_version, trapvars = self.parse_snmptrap(data) if resource and event: self.api.send_alert( resource=resource, event=event, correlate=correlate, group='SNMP', value=trapvars['$w'], severity='indeterminate', environment='Production', service=['Network'], text=trapvars['$W'], event_type='snmptrapAlert', attributes={'trapvars': {k.replace('$', '_'): v for k, v in trapvars.items()}}, tags=[trap_version], create_time=datetime.datetime.strptime('%sT%s.000Z' % (trapvars['$x'], trapvars['$X']), '%Y-%m-%dT%H:%M:%S.%fZ'), raw_data=data ) except Exception as e: LOG.warning('Failed to send alert: %s', e) LOG.debug('Send heartbeat...') try: origin = '{}/{}'.format('snmptrap', platform.uname()[1]) self.api.heartbeat(origin, tags=[__version__]) except Exception as e: LOG.warning('Failed to send heartbeat: %s', e) def parse_snmptrap(self, data): pdu_data = data.splitlines() varbind_list = pdu_data[:] trapvars = dict() for line in pdu_data: if line.startswith('$'): special, value = line.split(None, 1) trapvars[special] = value varbind_list.pop(0) if '$s' in trapvars: if trapvars['$s'] == '0': trap_version = 'SNMPv1' elif trapvars['$s'] == '1': trap_version = 'SNMPv2c' elif trapvars['$s'] == '2': trap_version = 'SNMPv2u' # not supported else: trap_version = 'SNMPv3' trapvars['$s'] = trap_version else: LOG.warning('Failed to parse unknown trap type.') return # Get varbinds varbinds = dict() idx = 0 for varbind in '\n'.join(varbind_list).split('~%~'): if varbind == '': break idx += 1 try: oid, value = varbind.split(None, 1) except ValueError: oid = varbind value = '' varbinds[oid] = value trapvars['$' + str(idx)] = value # $n LOG.debug('$%s %s', str(idx), value) trapvars['$q'] = trapvars['$q'].lstrip('.') # if numeric, remove leading '.' trapvars['$#'] = str(idx) LOG.debug('varbinds = %s', varbinds) correlate = list() if trap_version == 'SNMPv1': if trapvars['$w'] == '0': trapvars['$O'] = 'coldStart' correlate = ['coldStart', 'warmStart'] elif trapvars['$w'] == '1': trapvars['$O'] = 'warmStart' correlate = ['coldStart', 'warmStart'] elif trapvars['$w'] == '2': trapvars['$O'] = 'linkDown' correlate = ['linkUp', 'linkDown'] elif trapvars['$w'] == '3': trapvars['$O'] = 'linkUp' correlate = ['linkUp', 'linkDown'] elif trapvars['$w'] == '4': trapvars['$O'] = 'authenticationFailure' elif trapvars['$w'] == '5': trapvars['$O'] = 'egpNeighborLoss' elif trapvars['$w'] == '6': # enterpriseSpecific(6) if trapvars['$q'].isdigit(): # XXX - specific trap number was not decoded trapvars['$O'] = '%s.0.%s' % (trapvars['$N'], trapvars['$q']) else: trapvars['$O'] = trapvars['$q'] elif trap_version == 'SNMPv2c': if 'coldStart' in trapvars['$2']: trapvars['$w'] = '0' trapvars['$W'] = 'Cold Start' elif 'warmStart' in trapvars['$2']: trapvars['$w'] = '1' trapvars['$W'] = 'Warm Start' elif 'linkDown' in trapvars['$2']: trapvars['$w'] = '2' trapvars['$W'] = 'Link Down' elif 'linkUp' in trapvars['$2']: trapvars['$w'] = '3' trapvars['$W'] = 'Link Up' elif 'authenticationFailure' in trapvars['$2']: trapvars['$w'] = '4' trapvars['$W'] = 'Authentication Failure' elif 'egpNeighborLoss' in trapvars['$2']: trapvars['$w'] = '5' trapvars['$W'] = 'EGP Neighbor Loss' else: trapvars['$w'] = '6' trapvars['$W'] = 'Enterprise Specific' trapvars['$O'] = trapvars['$2'] # SNMPv2-MIB::snmpTrapOID.0 LOG.debug('trapvars = %s', trapvars) LOG.info('%s-Trap-PDU %s from %s at %s %s', trap_version, trapvars['$O'], trapvars['$B'], trapvars['$x'], trapvars['$X']) if trapvars['$B'] != '<UNKNOWN>': resource = trapvars['$B'] elif trapvars['$A'] != '0.0.0.0': resource = trapvars['$A'] else: m = re.match(r'UDP: \[(\d+\.\d+\.\d+\.\d+)\]', trapvars['$b']) if m: resource = m.group(1) else: resource = '<NONE>' return resource, trapvars['$O'], correlate, trap_version, trapvars
class AlertTestCase(unittest.TestCase): def setUp(self): self.client = Client() self.alert = """ { "alert": { "attributes": { "ip": "127.0.0.1", "notify": false }, "correlate": [], "createTime": "2017-10-03T09:12:27.283Z", "customer": null, "duplicateCount": 4, "environment": "Production", "event": "node_down", "group": "Misc", "history": [], "href": "http://localhost:8080/alert/e7020428-5dad-4a41-9bfe-78e9d55cda06", "id": "e7020428-5dad-4a41-9bfe-78e9d55cda06", "lastReceiveId": "534ced13-ddb0-435e-8f94-a38691719683", "lastReceiveTime": "2017-10-03T09:15:06.156Z", "origin": "alertad/fdaa33ca.local", "previousSeverity": "indeterminate", "rawData": null, "receiveTime": "2017-10-03T09:12:27.289Z", "repeat": true, "resource": "web01", "service": [ "Web", "App" ], "severity": "critical", "status": "open", "tags": [ "london", "linux" ], "text": "", "timeout": 86400, "trendIndication": "moreSevere", "type": "exceptionAlert", "value": "4" }, "id": "e7020428-5dad-4a41-9bfe-78e9d55cda06", "status": "ok" } """ @requests_mock.mock() def test_alert(self, m): m.post('http://localhost:8080/alert', text=self.alert) id, alert, message = self.client.send_alert( environment='Production', resource='web01', event='node_down', correlated=['node_up', 'node_down'], service=['Web', 'App'], severity='critical', tags=['london', 'linux'], value=4 ) self.assertEqual(alert.value, '4') # values cast to string self.assertEqual(alert.timeout, 86400) # timeout returned as int self.assertIn('london', alert.tags)