def make_key(user, scopes=None, type=None, text=''): api_key = ApiKey( user=user, scopes=scopes, type=type, text=text ) return api_key.create().key
def make_key(user, scopes=None, type=None, text=''): api_key = ApiKey( user=user, scopes=scopes, type=type, text=text ) return api_key.create().key
def create_key(admin, key=None): key = ApiKey(user=admin, key=key, scopes=scopes, expire_time=expires, text=text, customer=customer) try: key = key.create() except Exception as e: click.echo('ERROR: {}'.format(e)) else: return key
def create_key(admin, key): key = ApiKey(user=admin, key=key, scopes=['admin', 'write', 'read'], text='Admin key created by alertad script', expire_time=None) try: db.get_db() # init db on global app context key = key.create() except Exception as e: click.echo('ERROR: {}'.format(e)) else: click.echo('{} {}'.format(key.key, key.user))
def create_key(admin): key = ApiKey( user=admin, scopes=['admin', 'write', 'read'], text='Admin key created by alertad script', expire_time=None ) try: db.get_db() # init db on global app context key = key.create() except Exception as e: click.echo('ERROR: {}'.format(e)) else: click.echo('{} {}'.format(key.key, key.user))
class AuthTestCase(unittest.TestCase): def setUp(self): test_config = { 'TESTING': True, 'AUTH_REQUIRED': True, 'CUSTOMER_VIEWS': True, 'ADMIN_USERS': ['*****@*****.**'], 'ALLOWED_EMAIL_DOMAINS': ['alerta.io', 'foo.com', 'bar.com'] } self.app = create_app(test_config) self.client = self.app.test_client() self.foo_alert = { 'event': 'foo1', 'resource': 'foo1', 'environment': 'Production', 'service': ['Web'] } self.bar_alert = { 'event': 'bar1', 'resource': 'bar1', 'environment': 'Production', 'service': ['Web'] } with self.app.test_request_context('/'): self.app.preprocess_request() self.api_key = ApiKey( user='******', scopes=[Scope.admin, Scope.read, Scope.write], text='admin-key') self.api_key.create() self.admin_headers = { 'Authorization': 'Key %s' % self.api_key.key, 'Content-type': 'application/json' } def tearDown(self): db.destroy() def test_customers(self): # add customer mappings payload = {'customer': 'Bar Corp', 'match': 'bar.com'} response = self.client.post('/customer', data=json.dumps(payload), content_type='application/json', headers=self.admin_headers) self.assertEqual(response.status_code, 201) payload = {'customer': 'Foo Bar Corp', 'match': '*****@*****.**'} response = self.client.post('/customer', data=json.dumps(payload), content_type='application/json', headers=self.admin_headers) self.assertEqual(response.status_code, 201) response = self.client.get('/customers', headers=self.admin_headers) self.assertEqual(response.status_code, 200) # create users payload = { 'name': 'Bar User', 'email': '*****@*****.**', 'password': '******', 'text': '' } response = self.client.post('/auth/signup', data=json.dumps(payload), content_type='application/json', headers=self.admin_headers) self.assertEqual(response.status_code, 200, response.data) data = json.loads(response.data.decode('utf-8')) self.assertIsNotNone(data, 'Failed to create user') self.bar_bearer_headers = { 'Authorization': 'Bearer %s' % data['token'], 'Content-type': 'application/json' } payload = { 'name': 'Foo Bar User', 'email': '*****@*****.**', 'password': '******', 'text': '' } response = self.client.post('/auth/signup', data=json.dumps(payload), content_type='application/json', headers=self.admin_headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertIsNotNone(data, 'Failed to create user') self.foobar_bearer_headers = { 'Authorization': 'Bearer %s' % data['token'], 'Content-type': 'application/json' } # create API key for [email protected] payload = { 'user': '******', 'scopes': ['read', 'write'], 'text': '' } response = self.client.post('/key', data=json.dumps(payload), content_type='application/json', headers=self.bar_bearer_headers) self.assertEqual(response.status_code, 201, response.data) data = json.loads(response.data.decode('utf-8')) self.assertIsNotNone(data['key'], 'Failed to create read-write key') self.bar_api_key_headers = { 'Authorization': 'Key %s' % data['key'], 'Content-type': 'application/json' } # create API keys for [email protected] payload = { 'user': '******', 'scopes': ['read', 'write'], 'text': '', 'customer': 'Foo Bar Corp' } response = self.client.post('/key', data=json.dumps(payload), content_type='application/json', headers=self.foobar_bearer_headers) self.assertEqual(response.status_code, 201, response.data) data = json.loads(response.data.decode('utf-8')) self.assertIsNotNone(data['key'], 'Failed to create read-write key') self.foobar_api_key_headers = { 'Authorization': 'Key %s' % data['key'], 'Content-type': 'application/json' } payload = { 'user': '******', 'scopes': ['read', 'write'], 'text': '', 'customer': 'Bar Corp' } response = self.client.post('/key', data=json.dumps(payload), content_type='application/json', headers=self.foobar_bearer_headers) self.assertEqual(response.status_code, 201, response.data) data = json.loads(response.data.decode('utf-8')) self.assertIsNotNone(data['key'], 'Failed to create read-write key') self.foobar_bar_only_api_key_headers = { 'Authorization': 'Key %s' % data['key'], 'Content-type': 'application/json' } # get list of customers for users response = self.client.get('/customers', headers=self.bar_api_key_headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual([c['customer'] for c in data['customers']], ['Bar Corp']) response = self.client.get('/customers', headers=self.foobar_api_key_headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual([c['customer'] for c in data['customers']], ['Foo Bar Corp']) # create alerts using API keys response = self.client.post('/alert', data=json.dumps(self.foo_alert), headers=self.bar_api_key_headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['customer'], 'Bar Corp') response = self.client.post('/alert', data=json.dumps(self.foo_alert), headers=self.foobar_api_key_headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['customer'], 'Foo Bar Corp') response = self.client.post( '/alert', data=json.dumps(self.foo_alert), headers=self.foobar_bar_only_api_key_headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['customer'], 'Bar Corp') response = self.client.post( '/alert', data=json.dumps(self.foo_alert), headers=self.foobar_bar_only_api_key_headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['customer'], 'Bar Corp') # create alerts using Bearer tokens response = self.client.post('/alert', data=json.dumps(self.foo_alert), headers=self.bar_bearer_headers) self.assertEqual(response.status_code, 201, response.data) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['customer'], 'Bar Corp') self.foo_alert['customer'] = 'Foo Bar Corp' response = self.client.post('/alert', data=json.dumps(self.foo_alert), headers=self.foobar_bearer_headers) self.assertEqual(response.status_code, 201, response.data) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['customer'], 'Foo Bar Corp') def test_blackouts(self): # add customer mappings payload = {'customer': 'Foo Corp', 'match': 'foo.com'} response = self.client.post('/customer', data=json.dumps(payload), content_type='application/json', headers=self.admin_headers) self.assertEqual(response.status_code, 201) payload = {'customer': 'Bar Corp', 'match': 'bar.com'} response = self.client.post('/customer', data=json.dumps(payload), content_type='application/json', headers=self.admin_headers) self.assertEqual(response.status_code, 201) # create users payload = { 'name': 'Foo User', 'email': '*****@*****.**', 'password': '******', 'text': '' } response = self.client.post('/auth/signup', data=json.dumps(payload), content_type='application/json', headers=self.admin_headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertIsNotNone(data, 'Failed to create user') foo_user_headers = { 'Authorization': 'Bearer %s' % data['token'], 'Content-type': 'application/json' } payload = { 'name': 'Bar User', 'email': '*****@*****.**', 'password': '******', 'text': '' } response = self.client.post('/auth/signup', data=json.dumps(payload), content_type='application/json', headers=self.admin_headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertIsNotNone(data, 'Failed to create user') bar_user_headers = { 'Authorization': 'Bearer %s' % data['token'], 'Content-type': 'application/json' } # create customer blackout by foo user response = self.client.post('/blackout', data=json.dumps( {'environment': 'Production'}), headers=foo_user_headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) blackout_id = data['id'] # new alert by foo user should be suppressed response = self.client.post('/alert', data=json.dumps(self.foo_alert), headers=foo_user_headers) self.assertEqual(response.status_code, 202) # new alert by bar user should not be suppressed response = self.client.post('/alert', data=json.dumps(self.bar_alert), headers=bar_user_headers) self.assertEqual(response.status_code, 201) # delete blackout by id response = self.client.delete('/blackout/' + blackout_id, headers=self.admin_headers) self.assertEqual(response.status_code, 200) # create global blackout by admin user response = self.client.post('/blackout', data=json.dumps( {'environment': 'Production'}), headers=self.admin_headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) blackout_id = data['id'] # new alert by foo user should be suppressed response = self.client.post('/alert', data=json.dumps(self.foo_alert), headers=foo_user_headers) self.assertEqual(response.status_code, 202) # new alert by bar user should be suppressed response = self.client.post('/alert', data=json.dumps(self.bar_alert), headers=bar_user_headers) self.assertEqual(response.status_code, 202) # delete blackout by id response = self.client.delete('/blackout/' + blackout_id, headers=self.admin_headers) self.assertEqual(response.status_code, 200) def test_assign_customer(self): with self.app.test_request_context('/'): self.app.preprocess_request() # nothing wanted, assign one g.customers = ['Customer1'] g.scopes = [] self.assertEqual(assign_customer(wanted=None), 'Customer1') # nothing wanted, but too many, throw error g.customers = ['Customer1', 'Customer2'] g.scopes = [] with self.assertRaises(ApiError) as e: assign_customer(wanted=None) exc = e.exception self.assertEqual( str(exc), 'must define customer as more than one possibility') # customer wanted, matches so allow g.customers = ['Customer1'] g.scopes = [] self.assertEqual(assign_customer(wanted='Customer1'), 'Customer1') # customer wanted, in list so allow g.customers = ['Customer1', 'Customer2'] g.scopes = [] self.assertEqual(assign_customer(wanted='Customer2'), 'Customer2') # customer wanted not in list, throw exception g.customers = ['Customer1', 'Customer2'] g.scopes = [] with self.assertRaises(ApiError) as e: assign_customer(wanted='Customer3') exc = e.exception self.assertEqual(str(exc), "not allowed to set customer to 'Customer3'") # no customers, admin scope so allow g.customers = [] g.scopes = ['admin'] self.assertEqual(assign_customer(wanted=None), None) self.assertEqual(assign_customer(wanted='Customer1'), 'Customer1') g.customers = ['Customer1', 'Customer2'] g.scopes = ['admin'] with self.assertRaises(ApiError) as e: assign_customer(wanted=None) exc = e.exception self.assertEqual( str(exc), 'must define customer as more than one possibility') self.assertEqual(assign_customer(wanted='Customer3'), 'Customer3') # wrong scope g.customers = ['Customer1'] g.scopes = ['read:keys', 'write:keys'] with self.assertRaises(ApiError) as e: assign_customer(wanted='Customer2', permission=Scope.admin_keys) exc = e.exception self.assertEqual(str(exc), "not allowed to set customer to 'Customer2'") # right scope g.customers = ['Customer1'] g.scopes = ['admin:keys', 'read:keys', 'write:keys'] self.assertEqual( assign_customer(wanted='Customer2', permission=Scope.admin_keys), 'Customer2') def test_invalid_customer(self): self.foo_alert['customer'] = '' response = self.client.post('/alert', data=json.dumps(self.foo_alert), headers=self.admin_headers) self.assertEqual(response.status_code, 400) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['message'], 'customer must not be an empty string') def test_edit_customer(self): # add customer mappings payload = {'customer': 'Foo Corp', 'match': 'foo.com'} response = self.client.post('/customer', data=json.dumps(payload), content_type='application/json', headers=self.admin_headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) customer_id = data['id'] # change customer name update = {'customer': 'Bar Corp'} response = self.client.put('/customer/' + customer_id, data=json.dumps(update), headers=self.admin_headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['status'], 'ok') # check updates worked and didn't change anything else response = self.client.get('/customer/' + customer_id, headers=self.admin_headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['customer']['customer'], 'Bar Corp') self.assertEqual(data['customer']['match'], 'foo.com') # change customer lookup update = {'match': 'bar.com'} response = self.client.put('/customer/' + customer_id, data=json.dumps(update), headers=self.admin_headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['status'], 'ok') # check updates worked and didn't change anything else response = self.client.get('/customer/' + customer_id, headers=self.admin_headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['customer']['customer'], 'Bar Corp') self.assertEqual(data['customer']['match'], 'bar.com')
class UserTestCase(unittest.TestCase): def setUp(self): test_config = { 'TESTING': True, 'AUTH_REQUIRED': True, 'ADMIN_USERS': ['*****@*****.**'], 'ALLOWED_EMAIL_DOMAINS': ['alerta.io', 'doe.com'] } self.app = create_app(test_config) self.client = self.app.test_client() self.alert = { 'event': 'Foo', 'resource': 'Bar', 'environment': 'Production', 'service': ['Quux'] } with self.app.test_request_context('/'): self.app.preprocess_request() self.api_key = ApiKey( user='******', scopes=[Scope.admin, Scope.read, Scope.write], text='demo-key') self.api_key.create() self.headers = { 'Authorization': 'Key %s' % self.api_key.key, 'Content-type': 'application/json' } def tearDown(self): db.destroy() def test_user(self): payload = { 'name': 'John Doe', 'email': '*****@*****.**', 'password': '******', 'roles': ['operator'], 'text': 'devops user' } # create user response = self.client.post('/user', data=json.dumps(payload), headers=self.headers) self.assertEqual(response.status_code, 201, response.data) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['user']['name'], 'John Doe') self.assertEqual(data['user']['email'], '*****@*****.**') self.assertEqual(data['user']['roles'], ['operator']) self.assertEqual(data['user']['email_verified'], False) user_id = data['id'] payload = {'role': 'devops'} # modify user (assign different role) response = self.client.put('/user/' + user_id, data=json.dumps(payload), headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) # get user response = self.client.get('/user/' + user_id, headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['user']['name'], 'John Doe') self.assertEqual(data['user']['email'], '*****@*****.**') self.assertEqual(data['user']['roles'], ['devops']) self.assertEqual(data['user']['email_verified'], False) payload = {'roles': ['devops', 'operator', 'user']} # modify user (assign multiple roles) response = self.client.put('/user/' + user_id, data=json.dumps(payload), headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) # get user response = self.client.get('/user/' + user_id, headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['user']['name'], 'John Doe') self.assertEqual(data['user']['email'], '*****@*****.**') self.assertEqual(data['user']['roles'], ['devops', 'operator', 'user']) self.assertEqual(data['user']['email_verified'], False) def test_user_attributes(self): payload = { 'name': 'John Doe', 'email': '*****@*****.**', 'password': '******', 'roles': ['operator'], 'text': 'devops user' } # create user response = self.client.post('/user', data=json.dumps(payload), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['user']['name'], 'John Doe') self.assertEqual(data['user']['email'], '*****@*****.**') self.assertEqual(data['user']['roles'], ['operator']) self.assertEqual(data['user']['email_verified'], False) payload = {'email': '*****@*****.**', 'password': '******'} # login using new user response = self.client.post('/auth/login', data=json.dumps(payload), content_type='application/json') # self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertIn('token', data) token = data['token'] headers = { 'Authorization': 'Bearer ' + token, 'Content-type': 'application/json' } payload = {'attributes': {'prefs': {'isDark': True}}} # set user attribute response = self.client.put('/user/me/attributes', data=json.dumps(payload), headers=headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) # get user attribute response = self.client.get('/user/me/attributes', data=json.dumps(payload), headers=headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['attributes']['prefs'], {'isDark': True}) payload = { 'attributes': { 'prefs': { 'isMute': False, 'refreshInterval': 5000 } } } # set user attribute response = self.client.put('/user/me/attributes', data=json.dumps(payload), headers=headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) # get user attribute response = self.client.get('/user/me/attributes', data=json.dumps(payload), headers=headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['attributes']['prefs'], { 'isDark': True, 'isMute': False, 'refreshInterval': 5000 }) payload = {'attributes': {'prefs': {'isMute': None}}} # unset user attribute response = self.client.put('/user/me/attributes', data=json.dumps(payload), headers=headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) # get user attribute response = self.client.get('/user/me/attributes', data=json.dumps(payload), headers=headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['attributes']['prefs'], { 'isDark': True, 'isMute': None, 'refreshInterval': 5000 })
class BlackoutsTestCase(unittest.TestCase): def setUp(self): test_config = { 'TESTING': True, 'AUTH_REQUIRED': True, 'CUSTOMER_VIEWS': True, 'PLUGINS': ['reject'] } self.app = create_app(test_config) self.client = self.app.test_client() self.alert = { 'resource': 'node404', 'event': 'node_marginal', 'environment': 'Production', 'severity': 'warning', 'correlate': ['node_down', 'node_marginal', 'node_up'], 'service': ['Core', 'Web', 'Network'], 'group': 'Network', 'tags': ['level=20', 'switch:off'] } with self.app.test_request_context('/'): self.app.preprocess_request() self.admin_api_key = ApiKey(user='******', scopes=['admin', 'read', 'write'], text='demo-key') self.customer_api_key = ApiKey(user='******', scopes=['admin', 'read', 'write'], text='demo-key', customer='Foo') self.admin_api_key.create() self.customer_api_key.create() def tearDown(self): db.destroy() def test_suppress_blackout(self): plugins.plugins['blackout'] = SuppressionBlackout() self.headers = { 'Authorization': 'Key %s' % self.admin_api_key.key, 'Content-type': 'application/json' } # create alert response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) # create blackout response = self.client.post('/blackout', data=json.dumps( {'environment': 'Production'}), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) blackout_id = data['id'] # suppress alert response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 202) self.headers = { 'Authorization': 'Key %s' % self.customer_api_key.key, 'Content-type': 'application/json' } # create alert response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 202) self.headers = { 'Authorization': 'Key %s' % self.admin_api_key.key, 'Content-type': 'application/json' } response = self.client.delete('/blackout/' + blackout_id, headers=self.headers) self.assertEqual(response.status_code, 200) def test_notification_blackout(self): plugins.plugins['blackout'] = NotificationBlackout() self.headers = { 'Authorization': 'Key %s' % self.admin_api_key.key, 'Content-type': 'application/json' } # create new blackout blackout = {'environment': 'Production', 'service': ['Core']} response = self.client.post('/blackout', data=json.dumps(blackout), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) blackout_id = data['id'] # new alert should be status=blackout response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'blackout') # duplicate alert should be status=blackout response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'blackout') # duplicate alert should be status=blackout (again) response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'blackout') # increase severity alert should be status=blackout self.alert['severity'] = 'major' response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'blackout') # increase severity alert should be status=blackout (again) self.alert['severity'] = 'critical' response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'blackout') # decrease severity alert should be status=blackout self.alert['severity'] = 'minor' response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'blackout') # decrease severity alert should be status=blackout (again) self.alert['severity'] = 'warning' response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'blackout') # normal severity alert should be status=closed self.alert['severity'] = 'ok' response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'closed') # normal severity alert should be status=closed (again) response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'closed') # non-normal severity alert should be status=blackout (again) self.alert['severity'] = 'major' response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'blackout') # decrease severity alert should be status=blackout self.alert['severity'] = 'minor' response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'blackout') # remove blackout response = self.client.delete('/blackout/' + blackout_id, headers=self.headers) self.assertEqual(response.status_code, 200) # non-normal severity alert should be status=open self.alert['severity'] = 'minor' response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'open') # normal severity alert should be status=closed self.alert['severity'] = 'ok' response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'closed') def test_combination_blackout(self): plugins.plugins['blackout'] = SuppressionBlackout() self.headers = { 'Authorization': 'Key %s' % self.admin_api_key.key, 'Content-type': 'application/json' } # create alert response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) # create blackout (only for services on a particular host) blackout = { 'environment': 'Production', 'resource': 'node404', 'service': ['Network', 'Web'] } response = self.client.post('/blackout', data=json.dumps(blackout), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) blackout_id = data['id'] # suppress alert response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 202) # remove blackout response = self.client.delete('/blackout/' + blackout_id, headers=self.headers) self.assertEqual(response.status_code, 200) # create alert response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) # create blackout (only for groups of alerts with particular tags) blackout = { 'environment': 'Production', 'group': 'Network', 'tags': ['system:web01', 'switch:off'] } response = self.client.post('/blackout', data=json.dumps(blackout), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) blackout_id = data['id'] # do not suppress alert response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) self.alert['tags'].append('system:web01') # suppress alert response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 202) # remove blackout response = self.client.delete('/blackout/' + blackout_id, headers=self.headers) self.assertEqual(response.status_code, 200) def test_user_info(self): self.headers = { 'Authorization': 'Key %s' % self.admin_api_key.key, 'Content-type': 'application/json' } # create new blackout response = self.client.post('/blackout', data=json.dumps({ 'environment': 'Production', 'service': ['Network'], 'text': 'administratively down' }), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['blackout']['user'], '*****@*****.**') self.assertIsInstance(DateTime.parse(data['blackout']['createTime']), datetime) self.assertEqual(data['blackout']['text'], 'administratively down')
class ShelvingTestCase(unittest.TestCase): def setUp(self): test_config = { 'TESTING': True, 'AUTH_REQUIRED': True, 'CUSTOMER_VIEWS': True, 'PLUGINS': ['reject'] } self.app = create_app(test_config) self.client = self.app.test_client() self.alert = { 'event': 'node_marginal', 'resource': 'node404', 'environment': 'Production', 'service': ['Network'], 'severity': 'warning', 'correlate': ['node_down', 'node_marginal', 'node_up'] } with self.app.test_request_context('/'): self.app.preprocess_request() self.admin_api_key = ApiKey(user='******', scopes=['admin', 'read', 'write'], text='demo-key') self.customer_api_key = ApiKey(user='******', scopes=['admin', 'read', 'write'], text='demo-key', customer='Foo') self.admin_api_key.create() self.customer_api_key.create() def tearDown(self): db.destroy() def test_alarm_shelving(self): self.headers = { 'Authorization': 'Key %s' % self.admin_api_key.key, 'Content-type': 'application/json' } # new alert should be status=open response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'open') alert_id = data['id'] # shelve alert response = self.client.put('/alert/' + alert_id + '/status', data=json.dumps({'status': 'shelved'}), headers=self.headers) self.assertEqual(response.status_code, 200) response = self.client.get('/alert/' + alert_id, headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'shelved') # duplicate alert should be status=shelved response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'shelved') # duplicate alert should be status=shelved (again) response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'shelved') # increase severity alert should be status=open self.alert['severity'] = 'major' response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'open') # shelve alert response = self.client.put('/alert/' + alert_id + '/status', data=json.dumps({'status': 'shelved'}), headers=self.headers) self.assertEqual(response.status_code, 200) response = self.client.get('/alert/' + alert_id, headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'shelved') # decrease severity alert should be status=shelved self.alert['severity'] = 'minor' response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'shelved') # decrease severity alert should be status=shelved (again) self.alert['severity'] = 'warning' response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'shelved') # normal severity alert should be status=closed self.alert['severity'] = 'ok' response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'closed') # normal severity alert should be status=closed (again) response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'closed') # normal severity alert should be status=closed response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'closed') ### # increase severity alert should be status=open self.alert['severity'] = 'critical' response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'open') # shelve alert response = self.client.put('/alert/' + alert_id + '/status', data=json.dumps({'status': 'shelved'}), headers=self.headers) self.assertEqual(response.status_code, 200) response = self.client.get('/alert/' + alert_id, headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'shelved') # duplicate alert should be status=shelved response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'shelved') # unshelve alert response = self.client.put('/alert/' + alert_id + '/status', data=json.dumps({'status': 'open'}), headers=self.headers) self.assertEqual(response.status_code, 200) response = self.client.get('/alert/' + alert_id, headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'open') # duplicate alert should be status=open response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'open')
class RoutingTestCase(unittest.TestCase): def setUp(self): # create dummy routing rules self.dist = pkg_resources.Distribution(__file__, project_name='alerta-routing', version='0.1') s = 'rules = tests.test_zrouting:rules' self.entry_point = pkg_resources.EntryPoint.parse(s, dist=self.dist) self.dist._ep_map = {'alerta.routing': {'rules': self.entry_point}} pkg_resources.working_set.add(self.dist) test_config = { 'TESTING': True, 'AUTH_REQUIRED': True, 'CUSTOMER_VIEWS': True, 'ADMIN_USERS': ['*****@*****.**'], 'ALLOWED_EMAIL_DOMAINS': ['alerta.io', 'foo.com', 'bar.com'], 'PD_API_KEYS': { 'Tyrell Corporation': 'tc-key', 'Cyberdyne Systems': 'cs-key', 'Weyland-Yutani': 'wy-key', 'Zorin Enterprises': 'ze-key' }, 'SLACK_API_KEYS': { 'Soylent Corporation': 'sc-key', 'Omni Consumer Products': 'ocp-key', 'Dolmansaxlil Shoe Corporation': 'dsc-key' }, 'API_KEY': 'default-key', 'HOOK': 'not-set' } self.app = create_app(test_config) self.client = self.app.test_client() self.tier1_tc_alert = { 'event': 'foo1', 'resource': 'foo1', 'environment': 'Production', 'service': ['Web'], 'customer': 'Tyrell Corporation' # tier 1 } self.tier1_wy_alert = { 'event': 'foo1', 'resource': 'foo1', 'environment': 'Production', 'service': ['Web'], 'customer': 'Weyland-Yutani' # tier 1 } self.tier2_sc_alert = { 'event': 'bar1', 'resource': 'bar1', 'environment': 'Production', 'service': ['Web'], 'customer': 'Soylent Corporation' # tier 2 } self.tier2_ocp_alert = { 'event': 'bar1', 'resource': 'bar1', 'environment': 'Production', 'service': ['Web'], 'customer': 'Omni Consumer Products' # tier 2 } self.tier2_dsc_alert = { 'event': 'bar1', 'resource': 'bar1', 'environment': 'Production', 'service': ['Web'], 'customer': 'Dolmansaxlil Shoe Corporation' # tier 2 } self.tier3_it_alert = { 'event': 'bar1', 'resource': 'bar1', 'environment': 'Production', 'service': ['Web'], 'customer': 'Initech' # tier 3 } with self.app.test_request_context('/'): self.app.preprocess_request() self.api_key = ApiKey( user='******', scopes=[Scope.admin, Scope.read, Scope.write], text='admin-key') self.api_key.create() self.headers = { 'Authorization': f'Key {self.api_key.key}', 'Content-type': 'application/json' } # create dummy plugins plugins.plugins['pagerduty'] = DummyPagerDutyPlugin() plugins.plugins['slack'] = DummySlackPlugin() plugins.plugins['config'] = DummyConfigPlugin() def tearDown(self): plugins.plugins.clear() self.dist._ep_map.clear() def test_config(self): os.environ['BOOL_ENVVAR'] = 'yes' os.environ['INT_ENVVAR'] = '2020' os.environ['FLOAT_ENVVAR'] = '0.99' os.environ['LIST_ENVVAR'] = 'up,down,left,right' os.environ['STR_ENVVAR'] = 'a string with spaces' os.environ['DICT_ENVVAR'] = '{"key":"value", "key2": "value2" }' self.app.config.update({ 'BOOL_SETTING': True, 'INT_SETTING': 1001, 'FLOAT_SETTING': 7.07, 'LIST_SETTING': ['a', 2, 'z'], 'STR_SETTING': ' long string with spaces', 'DICT_SETTING': { 'a': 'dict', 'with': 'three', 'keys': 3 }, }) # create alert response = self.client.post('/alert', data=json.dumps(self.tier1_tc_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['attributes']['env']['bool'], True) self.assertEqual(data['alert']['attributes']['env']['int'], 2020) self.assertEqual(data['alert']['attributes']['env']['float'], 0.99) self.assertEqual(data['alert']['attributes']['env']['list'], ['up', 'down', 'left', 'right']) self.assertEqual(data['alert']['attributes']['env']['str'], 'a string with spaces') self.assertEqual(data['alert']['attributes']['env']['dict'], dict(key='value', key2='value2')) self.assertEqual(data['alert']['attributes']['setting']['bool'], True) self.assertEqual(data['alert']['attributes']['setting']['int'], 1001) self.assertEqual(data['alert']['attributes']['setting']['float'], 7.07) self.assertEqual(data['alert']['attributes']['setting']['list'], ['a', 2, 'z']) self.assertEqual(data['alert']['attributes']['setting']['str'], ' long string with spaces') self.assertEqual(data['alert']['attributes']['setting']['dict'], { 'a': 'dict', 'with': 'three', 'keys': 3 }) self.assertEqual(data['alert']['attributes']['default']['bool'], False) self.assertEqual(data['alert']['attributes']['default']['int'], 999) self.assertEqual(data['alert']['attributes']['default']['float'], 5.55) self.assertEqual(data['alert']['attributes']['default']['list'], ['j', 'k']) self.assertEqual(data['alert']['attributes']['default']['str'], 'setting') self.assertEqual(data['alert']['attributes']['default']['dict'], dict(baz='quux')) def test_config_precedence(self): os.environ['var1'] = 'env1' self.app.config.update({'var1': 'setting1', 'var2': 'setting2'}) # create alert response = self.client.post('/alert', data=json.dumps(self.tier1_tc_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['attributes']['precedence']['var1'], 'env1') self.assertEqual(data['alert']['attributes']['precedence']['var2'], 'setting2') self.assertEqual(data['alert']['attributes']['precedence']['var3'], 'default3') def test_routing(self): # create alert (pagerduty key for Tyrell Corporation) response = self.client.post('/alert', data=json.dumps(self.tier1_tc_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['attributes']['NOTIFY'], 'pagerduty') self.assertEqual(data['alert']['attributes']['API_KEY'], 'tc-key') # create alert (pagerduty key for Weyland-Yutani) response = self.client.post('/alert', data=json.dumps(self.tier1_wy_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['attributes']['NOTIFY'], 'pagerduty') self.assertEqual(data['alert']['attributes']['API_KEY'], 'wy-key') # create alert (slack key for customer Soylent Corporation) response = self.client.post('/alert', data=json.dumps(self.tier2_sc_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['attributes']['NOTIFY'], 'slack') self.assertEqual(data['alert']['attributes']['API_KEY'], 'sc-key') # create alert (slack key for customer Omni Consumer Products) response = self.client.post('/alert', data=json.dumps(self.tier2_ocp_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['attributes']['NOTIFY'], 'slack') self.assertEqual(data['alert']['attributes']['API_KEY'], 'ocp-key') # create alert (use default slack key for Dolmansaxlil Shoe Corporation) response = self.client.post('/alert', data=json.dumps(self.tier2_dsc_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['attributes']['NOTIFY'], 'slack') self.assertEqual(data['alert']['attributes']['API_KEY'], 'dsc-key') # create alert (no key) response = self.client.post('/alert', data=json.dumps(self.tier3_it_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertNotIn('NOTIFY', data['alert']['attributes']) self.assertNotIn('API_KEY', data['alert']['attributes'])
class BlackoutsTestCase(unittest.TestCase): def setUp(self): test_config = { 'TESTING': True, 'AUTH_REQUIRED': True, 'CUSTOMER_VIEWS': True } self.app = create_app(test_config) self.client = self.app.test_client() self.alert = { 'event': 'node_marginal', 'resource': 'node404', 'environment': 'Production', 'service': ['Network'], 'severity': 'warning', 'correlate': ['node_down', 'node_marginal', 'node_up'] } with self.app.test_request_context('/'): self.app.preprocess_request() self.admin_api_key = ApiKey( user='******', scopes=['admin', 'read', 'write'], text='demo-key' ) self.customer_api_key = ApiKey( user='******', scopes=['admin', 'read', 'write'], text='demo-key', customer='Foo' ) self.admin_api_key.create() self.customer_api_key.create() def tearDown(self): db.destroy() def test_suppress_alerts(self): self.headers = { 'Authorization': 'Key %s' % self.admin_api_key.key, 'Content-type': 'application/json' } # create alert response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) # create blackout response = self.client.post('/blackout', data=json.dumps({"environment": "Production"}), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) blackout_id = data['id'] # suppress alert response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 202) self.headers = { 'Authorization': 'Key %s' % self.customer_api_key.key, 'Content-type': 'application/json' } # create alert response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 202) self.headers = { 'Authorization': 'Key %s' % self.admin_api_key.key, 'Content-type': 'application/json' } response = self.client.delete('/blackout/' + blackout_id, headers=self.headers) self.assertEqual(response.status_code, 200)
class AuthLdapTestCase(unittest.TestCase): class LDAPObjectMock: def __init__(self, user_to_login, pass_to_login, user_to_bind, pass_to_bind, search_results): self.user_to_login = user_to_login self.pass_to_login = pass_to_login self.user_to_bind = user_to_bind self.pass_to_bind = pass_to_bind self.search_results = search_results def simple_bind_s(self, who=None, cred=None, serverctrls=None, clientctrls=None): # raise Exception("{}-{}......{}-{}".format(who, cred, self.user_to_bind, self.pass_to_bind)) if not ((who == self.user_to_login and cred == self.pass_to_login) or (who == self.user_to_bind and cred == self.pass_to_bind)): raise ldap.INVALID_CREDENTIALS pass def search_s(self, base, scope, filterstr=None, attrlist=None, attrsonly=0): return self.search_results def setUp(self): test_config = { 'TESTING': True, 'DEBUG': True, 'AUTH_REQUIRED': True, 'AUTH_PROVIDER': 'ldap', 'CUSTOMER_VIEWS': True, 'ADMIN_USERS': ['*****@*****.**'], 'LDAP_URL': 'ldap://myldap.server', 'LDAP_BIND_USERNAME': '******', 'LDAP_BIND_PASSWORD': '******', 'LDAP_DOMAINS_SEARCH_QUERY': { 'debeauharnais.fr': 'sAMAccountName={username}' }, 'LDAP_DOMAINS_USER_BASEDN': { 'debeauharnais.fr': '' }, 'LDAP_DOMAINS': { 'debeauharnais.fr': 'DN=%s' } } self.app = create_app(test_config) self.client = self.app.test_client() with self.app.test_request_context('/'): self.app.preprocess_request() self.api_key = ApiKey( user='******', scopes=[Scope.admin, Scope.read, Scope.write], text='demo-key') self.api_key.create() self.headers = { 'Authorization': 'Key %s' % self.api_key.key, 'Content-type': 'application/json' } def tearDown(self): db.destroy() def test_401_error(self): response = self.client.get('/alerts') self.assertEqual(response.status_code, 401) def test_ldap_login_defined_dn(self): # Attemps to login with the defined DN instead of performing a search self.app.config['LDAP_DOMAINS_SEARCH_QUERY'] = {} mock_ldap = AuthLdapTestCase.LDAPObjectMock( 'DN=josephine', 'jojo', 'user_to_bind', 'password_to_bind', [('DN=josephine', { 'mail': [bytearray('*****@*****.**', 'utf-8')] })]) data = self.login_test(mock_ldap, 200) self.assertIn('token', data) def test_ldap_login_search(self): mock_ldap = AuthLdapTestCase.LDAPObjectMock( 'DN=josephine', 'jojo', 'user_to_bind', 'password_to_bind', [('DN=josephine', { 'mail': [bytearray('*****@*****.**', 'utf-8')] })]) data = self.login_test(mock_ldap, 200) self.assertIn('token', data) def test_ldap_login_wrong_password(self): mock_ldap = AuthLdapTestCase.LDAPObjectMock( 'DN=josephine', 'jojo_wrong', 'user_to_bind', 'password_to_bind', [('DN=josephine', { 'mail': [bytearray('*****@*****.**', 'utf-8')] })]) data = self.login_test(mock_ldap, 401) self.assertIn('message', data) self.assertEqual('invalid username or password', data.get('message')) def test_ldap_login_wrong_bind_password(self): mock_ldap = AuthLdapTestCase.LDAPObjectMock( 'DN=josephine', 'jojo', 'user_to_bind', 'password_to_bind_wrong', [('DN=josephine', { 'mail': [bytearray('*****@*****.**', 'utf-8')] })]) data = self.login_test(mock_ldap, 401) self.assertIn('message', data) self.assertEqual('invalid ldap bind username or password', data.get('message')) def login_test(self, mock_ldap, expected_response_code): # add customer mapping payload = { 'customer': 'Bonaparte Industries', 'match': 'debeauharnais.fr' } response = self.client.post('/customer', data=json.dumps(payload), content_type='application/json', headers=self.headers) self.assertEqual(response.status_code, 201) json.loads(response.data.decode('utf-8')) payload = {'email': '*****@*****.**', 'password': '******'} # login now that customer mapping exists with patch('ldap.initialize', return_value=mock_ldap): response = self.client.post('/auth/login', data=json.dumps(payload), content_type='application/json') self.assertEqual(response.status_code, expected_response_code) return json.loads(response.data.decode('utf-8'))
class ForwarderTestCase(unittest.TestCase): def setUp(self): test_config = { 'DEBUG': False, 'TESTING': True, 'AUTH_REQUIRED': True, 'BASE_URL': 'http://localhost:8080', 'PLUGINS': ['forwarder'] } HMAC_AUTH_CREDENTIALS = [ { # http://localhost:9001 'key': 'e3b8afc0-db18-4c51-865d-b95322742c5e', 'secret': 'MDhjZGMyYTRkY2YyNjk1MTEyMWFlNmM3Y2UxZDU1ZjIK', 'algorithm': 'sha256' }, ] FWD_DESTINATIONS = [ ('http://localhost:9000', { 'username': '******', 'password': '******', 'timeout': 10 }, ['alerts', 'actions']), # BasicAuth # ('https://httpbin.org/anything', dict(username='******', password='******', ssl_verify=False), ['*']), ('http://localhost:9001', { 'key': 'e3b8afc0-db18-4c51-865d-b95322742c5e', 'secret': 'MDhjZGMyYTRkY2YyNjk1MTEyMWFlNmM3Y2UxZDU1ZjIK' }, ['actions']), # Hawk HMAC ('http://localhost:9002', { 'key': 'demo-key' }, ['delete']), # API key ('http://localhost:9003', { 'token': 'bearer-token' }, ['*']), # Bearer token ] test_config['HMAC_AUTH_CREDENTIALS'] = HMAC_AUTH_CREDENTIALS test_config['FWD_DESTINATIONS'] = FWD_DESTINATIONS self.app = create_app(test_config) self.client = self.app.test_client() self.resource = str(uuid4()).upper()[:8] self.major_alert = { 'id': 'b528c6f7-0925-4f6d-b930-fa6c0bba51dc', 'event': 'node_marginal', 'resource': self.resource, 'environment': 'Production', 'service': ['Network'], 'severity': 'major', 'correlate': ['node_down', 'node_marginal', 'node_up'], 'timeout': 40 } self.repeated_major_alert = { 'id': '4ba2b0d6-ff4a-4fc0-8d93-45939c819465', 'event': 'node_marginal', 'resource': self.resource, 'environment': 'Production', 'service': ['Network'], 'severity': 'major', 'correlate': ['node_down', 'node_marginal', 'node_up'], 'timeout': 40 } self.warn_alert = { 'id': '67344228-bd03-4660-9c45-ff9c8f1d53d0', 'event': 'node_marginal', 'resource': self.resource, 'environment': 'Production', 'service': ['Network'], 'severity': 'warning', 'correlate': ['node_down', 'node_marginal', 'node_up'], 'timeout': 50 } self.normal_alert = { 'id': 'cb12250d-42ed-42cc-97ef-592f3a49618c', 'event': 'node_up', 'resource': self.resource, 'environment': 'Production', 'service': ['Network'], 'severity': 'normal', 'correlate': ['node_down', 'node_marginal', 'node_up'], 'timeout': 100 } with self.app.test_request_context('/'): self.app.preprocess_request() self.api_key = ApiKey( user='******', scopes=[Scope.admin, Scope.read, Scope.write], text='demo-key') self.api_key.create() def tearDown(self): plugins.plugins.clear() db.destroy() @requests_mock.mock() def test_forward_alert(self, m): ok_response = """ {"status": "ok"} """ m.post('http://localhost:9000/alert', text=ok_response) m.post('http://localhost:9001/alert', text=ok_response) m.post('http://localhost:9002/alert', text=ok_response) m.post('http://localhost:9003/alert', text=ok_response) headers = { 'Authorization': 'Key %s' % self.api_key.key, 'Content-type': 'application/json', 'Origin': 'http://localhost:5000', 'X-Alerta-Loop': 'http://localhost:5000', } response = self.client.post('/alert', data=json.dumps(self.major_alert), headers=headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['status'], 'ok') history = m.request_history self.assertEqual(history[0].port, 9000) self.assertEqual(history[1].port, 9003) @requests_mock.mock() def test_forward_action(self, m): ok_response = """ {"status": "ok"} """ m.post('http://localhost:9000/alert', text=ok_response) m.post('http://localhost:9003/alert', text=ok_response) # create alert headers = { 'Authorization': 'Key %s' % self.api_key.key, 'Content-type': 'application/json' } response = self.client.post('/alert', data=json.dumps(self.warn_alert), headers=headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'open') alert_id = data['id'] m.put('http://localhost:9000/alert/{}/action'.format(alert_id), text=ok_response) m.put('http://localhost:9001/alert/{}/action'.format(alert_id), text=ok_response) m.put('http://localhost:9002/alert/{}/action'.format(alert_id), text=ok_response) m.put('http://localhost:9003/alert/{}/action'.format(alert_id), text=ok_response) headers = { 'Authorization': 'Key %s' % self.api_key.key, 'Content-type': 'application/json', 'Origin': 'http://localhost:8000' } response = self.client.put('/alert/{}/action'.format(alert_id), data=json.dumps({'action': 'ack'}), headers=headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['status'], 'ok') history = m.request_history self.assertEqual(history[0].port, 9000) self.assertEqual(history[1].port, 9003) self.assertEqual(history[2].port, 9000) self.assertEqual(history[3].port, 9001) self.assertEqual(history[4].port, 9003) @requests_mock.mock() def test_forward_delete(self, m): ok_response = """ {"status": "ok"} """ m.post('http://localhost:9000/alert', text=ok_response) m.post('http://localhost:9003/alert', text=ok_response) # create alert headers = { 'Authorization': 'Key %s' % self.api_key.key, 'Content-type': 'application/json' } response = self.client.post('/alert', data=json.dumps(self.warn_alert), headers=headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'open') alert_id = data['id'] m.delete('http://localhost:9002/alert/{}'.format(alert_id), text=ok_response) m.delete('http://localhost:9003/alert/{}'.format(alert_id), text=ok_response) headers = { 'Authorization': 'Key %s' % self.api_key.key, 'Content-type': 'application/json', 'Origin': 'http://localhost:8000' } response = self.client.delete('/alert/{}'.format(alert_id), headers=headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['status'], 'ok') history = m.request_history self.assertEqual(history[0].port, 9000) self.assertEqual(history[1].port, 9003) self.assertEqual(history[2].port, 9002) self.assertEqual(history[3].port, 9003) @requests_mock.mock() def test_forward_heartbeat(self, m): # FIXME: currently not possible pass @requests_mock.mock() def test_already_processed(self, m): # Alert is not processed locally or forwarded when an Alerta server # receives an alert which it has already processed. This is # determined by checking to see if the BASE_URL of the server # is already in the X-Alerta-Loop header. A 202 is returned because # the alert was accepted, even though it wasn't processed. ok_response = """ {"status": "ok"} """ m.post('http://localhost:9000/alert', text=ok_response) m.post('http://localhost:9001/alert', text=ok_response) m.post('http://localhost:9002/alert', text=ok_response) m.post('http://localhost:9003/alert', text=ok_response) headers = { 'Authorization': 'Key %s' % self.api_key.key, 'Content-type': 'application/json', 'Origin': 'http://localhost:5000', 'X-Alerta-Loop': 'http://localhost:8080,http://localhost:5000', } response = self.client.post('/alert', data=json.dumps(self.major_alert), headers=headers) self.assertEqual(response.status_code, 202) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['status'], 'ok') self.assertEqual( data['message'], 'Alert forwarded by http://localhost:5000 already processed by http://localhost:8080' ) self.assertEqual(m.called, False) @requests_mock.mock() def test_forward_loop(self, m): # Alert is processed locally but not forwarded on to the remote # because it is already in the X-Alerta-Loop header. A 201 is # returned because the alert has been received and processed. ok_response = """ {"status": "ok"} """ m.post('http://localhost:9000/alert', text=ok_response) m.post('http://localhost:9001/alert', text=ok_response) m.post('http://localhost:9002/alert', text=ok_response) m.post('http://localhost:9003/alert', text=ok_response) headers = { 'Authorization': 'Key %s' % self.api_key.key, 'Content-type': 'application/json', 'X-Alerta-Loop': 'http://localhost:9000,http://localhost:9001,http://localhost:9002,http://localhost:9003', } response = self.client.post('/alert', data=json.dumps(self.warn_alert), headers=headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['status'], 'ok') self.assertEqual(m.called, False) def test_do_not_forward(self): # check forwarding rule for remote pass def test_base_url(self): with self.app.test_request_context('/'): self.assertEqual(base_url(), 'http://localhost:8080')
class BuiltinsTestCase(unittest.TestCase): def setUp(self): test_config = { 'TESTING': True, 'AUTH_REQUIRED': True, 'PLUGINS': [ 'remote_ip', 'reject', 'heartbeat', 'blackout', 'acked_by', 'forwarder' ] } os.environ['ALLOWED_ENVIRONMENTS'] = 'Production,Staging,Development' self.app = create_app(test_config) self.client = self.app.test_client() self.resource = str(uuid4()).upper()[:8] self.reject_alert = { 'event': 'node_marginal', 'resource': self.resource, 'environment': 'Production', 'service': [], # alert will be rejected because service not defined 'severity': 'warning', 'correlate': ['node_down', 'node_marginal', 'node_up'], 'tags': ['one', 'two'] } self.accept_alert = { 'event': 'node_marginal', 'resource': self.resource, 'environment': 'Production', 'service': ['Network'], # alert will be accepted because service defined 'severity': 'warning', 'correlate': ['node_down', 'node_marginal', 'node_up'], 'tags': ['three', 'four'] } self.critical_alert = { 'event': 'node_down', 'resource': self.resource, 'environment': 'Production', 'service': ['Network'], 'severity': 'critical', 'correlate': ['node_down', 'node_marginal', 'node_up'], 'tags': [] } self.ok_alert = { 'event': 'node_up', 'resource': self.resource, 'environment': 'Production', 'service': ['Network'], 'severity': 'ok', 'correlate': ['node_down', 'node_marginal', 'node_up'], 'tags': [] } with self.app.test_request_context('/'): self.app.preprocess_request() self.api_key = ApiKey( user='******', scopes=[Scope.admin, Scope.read, Scope.write], text='demo-key') self.api_key.create() self.headers = { 'Authorization': f'Key {self.api_key.key}', 'Content-type': 'application/json', 'X-Forwarded-For': '172.217.20.36' } def tearDown(self): plugins.plugins.clear() db.destroy() def test_remote_ip_alert(self): # create alert response = self.client.post('/alert', json=self.critical_alert, headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['attributes']['ip'], '172.217.20.36') def test_reject_alert(self): # create alert that will be rejected response = self.client.post('/alert', data=json.dumps(self.reject_alert), headers=self.headers) self.assertEqual(response.status_code, 403) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['status'], 'error') self.assertEqual(data['message'], '[POLICY] Alert must define a service') # create alert that will be accepted response = self.client.post('/alert', data=json.dumps(self.accept_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['status'], 'ok') self.assertRegex( data['id'], '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}') def test_heartbeat_alert(self): self.heartbeat_alert = { 'event': 'Heartbeat', 'resource': 'hb01', 'environment': 'Production', 'service': ['Svc1'], 'severity': 'informational', } # create alert response = self.client.post('/alert', json=self.heartbeat_alert, headers=self.headers) self.assertEqual(response.status_code, 202) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['message'], 'Alert converted to Heartbeat') # XXX - blackout plugin tested extensively in test_blackouts.py def test_acked_by_plugin(self): # create alert response = self.client.post('/alert', json=self.critical_alert, headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) alert_id = data['id'] # ack alert payload = {'action': 'ack', 'text': 'ack the alert'} response = self.client.put('/alert/' + alert_id + '/action', json=payload, headers=self.headers) self.assertEqual(response.status_code, 200) response = self.client.get('/alert/' + alert_id, headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['attributes']['acked-by'], '*****@*****.**') # clear alert response = self.client.post('/alert', json=self.ok_alert, headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['severity'], 'ok') self.assertEqual(data['alert']['status'], 'closed') self.assertEqual(data['alert']['attributes']['acked-by'], '*****@*****.**') # critical alert (unacked) response = self.client.post('/alert', json=self.critical_alert, headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['severity'], 'critical') self.assertEqual(data['alert']['status'], 'open') self.assertNotIn('acked-by', data['alert']['attributes']) # ack alert (again) payload = {'action': 'ack', 'text': 'ack the alert, again'} response = self.client.put('/alert/' + alert_id + '/action', json=payload, headers=self.headers) self.assertEqual(response.status_code, 200) response = self.client.get('/alert/' + alert_id, headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['attributes']['acked-by'], '*****@*****.**') # unack alert payload = {'action': 'unack', 'text': 'unack the alert'} response = self.client.put('/alert/' + alert_id + '/action', json=payload, headers=self.headers) self.assertEqual(response.status_code, 200) response = self.client.get('/alert/' + alert_id, headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertNotIn('acked-by', data['alert']['attributes'])
class ShelvingTestCase(unittest.TestCase): def setUp(self): test_config = { 'TESTING': True, 'AUTH_REQUIRED': True, 'CUSTOMER_VIEWS': True, 'PLUGINS': ['reject'] } self.app = create_app(test_config) self.client = self.app.test_client() self.alert = { 'event': 'node_marginal', 'resource': 'node404', 'environment': 'Production', 'service': ['Network'], 'severity': 'warning', 'correlate': ['node_down', 'node_marginal', 'node_up'] } with self.app.test_request_context('/'): self.app.preprocess_request() self.admin_api_key = ApiKey( user='******', scopes=['admin', 'read', 'write'], text='demo-key' ) self.customer_api_key = ApiKey( user='******', scopes=['admin', 'read', 'write'], text='demo-key', customer='Foo' ) self.admin_api_key.create() self.customer_api_key.create() def tearDown(self): db.destroy() def test_alarm_shelving(self): self.headers = { 'Authorization': 'Key %s' % self.admin_api_key.key, 'Content-type': 'application/json' } # new alert should be status=open response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'open') alert_id = data['id'] # shelve alert response = self.client.put('/alert/' + alert_id + '/status', data=json.dumps({'status': 'shelved'}), headers=self.headers) self.assertEqual(response.status_code, 200) response = self.client.get('/alert/' + alert_id, headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'shelved') # duplicate alert should be status=shelved response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'shelved') # duplicate alert should be status=shelved (again) response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'shelved') # increase severity alert should stay status=shelved self.alert['severity'] = 'major' response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'shelved') # shelve alert response = self.client.put('/alert/' + alert_id + '/status', data=json.dumps({'status': 'shelved'}), headers=self.headers) self.assertEqual(response.status_code, 200) response = self.client.get('/alert/' + alert_id, headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'shelved') # decrease severity alert should be status=shelved self.alert['severity'] = 'minor' response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'shelved') # decrease severity alert should be status=shelved (again) self.alert['severity'] = 'warning' response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'shelved') # normal severity alert should be status=closed self.alert['severity'] = 'ok' response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'closed') # normal severity alert should be status=closed (again) response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'closed') # normal severity alert should be status=closed response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'closed') ### # increase severity alert should be status=shelved self.alert['severity'] = 'critical' response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'shelved') # shelve alert response = self.client.put('/alert/' + alert_id + '/status', data=json.dumps({'status': 'shelved'}), headers=self.headers) self.assertEqual(response.status_code, 200) response = self.client.get('/alert/' + alert_id, headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'shelved') # duplicate alert should be status=shelved response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'shelved') # unshelve alert response = self.client.put('/alert/' + alert_id + '/status', data=json.dumps({'status': 'open'}), headers=self.headers) self.assertEqual(response.status_code, 200) response = self.client.get('/alert/' + alert_id, headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'open') # duplicate alert should be status=open response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'open')
class BlackoutsTestCase(unittest.TestCase): def setUp(self): test_config = { 'TESTING': True, 'AUTH_REQUIRED': True, 'CUSTOMER_VIEWS': True, 'PLUGINS': ['reject'] } self.app = create_app(test_config) self.client = self.app.test_client() self.prod_alert = { 'resource': 'node404', 'event': 'node_down', 'environment': 'Production', 'severity': 'major', 'correlate': ['node_down', 'node_marginal', 'node_up'], 'service': ['Core', 'Web', 'Network'], 'group': 'Network', 'tags': ['level=20', 'switch:off'] } self.dev_alert = { 'resource': 'node404', 'event': 'node_marginal', 'environment': 'Development', 'severity': 'warning', 'correlate': ['node_down', 'node_marginal', 'node_up'], 'service': ['Core', 'Web', 'Network'], 'group': 'Network', 'tags': ['level=20', 'switch:off'] } self.fatal_alert = { 'event': 'node_down', 'resource': 'net01', 'environment': 'Production', 'service': ['Network'], 'severity': 'critical', 'correlate': ['node_down', 'node_marginal', 'node_up'], 'tags': ['foo'], 'attributes': {'foo': 'abc def', 'bar': 1234, 'baz': False}, } self.critical_alert = { 'event': 'node_marginal', 'resource': 'net02', 'environment': 'Production', 'service': ['Network'], 'severity': 'critical', 'correlate': ['node_down', 'node_marginal', 'node_up'], 'timeout': 30 } self.major_alert = { 'event': 'node_marginal', 'resource': 'net03', 'environment': 'Production', 'service': ['Network'], 'severity': 'major', 'correlate': ['node_down', 'node_marginal', 'node_up'], 'timeout': 40 } self.normal_alert = { 'event': 'node_up', 'resource': 'net03', 'environment': 'Production', 'service': ['Network'], 'severity': 'normal', 'correlate': ['node_down', 'node_marginal', 'node_up'], 'timeout': 100 } self.minor_alert = { 'event': 'node_marginal', 'resource': 'net04', 'environment': 'Production', 'service': ['Network'], 'severity': 'minor', 'correlate': ['node_down', 'node_marginal', 'node_up'], 'timeout': 40 } self.ok_alert = { 'event': 'node_up', 'resource': 'net04', 'environment': 'Production', 'service': ['Network'], 'severity': 'ok', 'correlate': ['node_down', 'node_marginal', 'node_up'], 'timeout': 100 } self.warn_alert = { 'event': 'node_marginal', 'resource': 'net05', 'environment': 'Production', 'service': ['Network'], 'severity': 'warning', 'correlate': ['node_down', 'node_marginal', 'node_up'], 'timeout': 50 } with self.app.test_request_context('/'): self.app.preprocess_request() self.admin_api_key = ApiKey( user='******', scopes=['admin', 'read', 'write'], text='demo-key' ) self.customer_api_key = ApiKey( user='******', scopes=['admin', 'read', 'write'], text='demo-key', customer='Foo' ) self.admin_api_key.create() self.customer_api_key.create() def tearDown(self): db.destroy() def test_suppress_blackout(self): os.environ['NOTIFICATION_BLACKOUT'] = 'False' plugins.plugins['blackout'] = Blackout() self.headers = { 'Authorization': 'Key %s' % self.admin_api_key.key, 'Content-type': 'application/json' } # create alert response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 201) # create blackout response = self.client.post('/blackout', data=json.dumps({'environment': 'Production'}), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) blackout_id = data['id'] # suppress alert response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 202) self.headers = { 'Authorization': 'Key %s' % self.customer_api_key.key, 'Content-type': 'application/json' } # create alert response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 202) self.headers = { 'Authorization': 'Key %s' % self.admin_api_key.key, 'Content-type': 'application/json' } response = self.client.delete('/blackout/' + blackout_id, headers=self.headers) self.assertEqual(response.status_code, 200) def test_notification_blackout(self): os.environ['NOTIFICATION_BLACKOUT'] = 'True' plugins.plugins['blackout'] = Blackout() self.headers = { 'Authorization': 'Key %s' % self.admin_api_key.key, 'Content-type': 'application/json' } # create new blackout blackout = { 'environment': 'Production', 'service': ['Core'] } response = self.client.post('/blackout', data=json.dumps(blackout), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) blackout_id = data['id'] # new alert should be status=blackout response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'blackout') # duplicate alert should be status=blackout response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'blackout') # duplicate alert should be status=blackout (again) response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'blackout') # increase severity alert should be status=blackout self.prod_alert['severity'] = 'major' response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'blackout') # increase severity alert should be status=blackout (again) self.prod_alert['severity'] = 'critical' response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'blackout') # decrease severity alert should be status=blackout self.prod_alert['severity'] = 'minor' response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'blackout') # decrease severity alert should be status=blackout (again) self.prod_alert['severity'] = 'warning' response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'blackout') # normal severity alert should be status=closed self.prod_alert['severity'] = 'ok' response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'closed') # normal severity alert should be status=closed (again) response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'closed') # non-normal severity alert should be status=blackout (again) self.prod_alert['severity'] = 'major' response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'blackout') # decrease severity alert should be status=blackout self.prod_alert['severity'] = 'minor' response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'blackout') # remove blackout response = self.client.delete('/blackout/' + blackout_id, headers=self.headers) self.assertEqual(response.status_code, 200) # non-normal severity alert should be status=open self.prod_alert['severity'] = 'minor' response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'open') # normal severity alert should be status=closed self.prod_alert['severity'] = 'ok' response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'closed') def test_previous_status(self): self.headers = { 'Authorization': 'Key %s' % self.admin_api_key.key, 'Content-type': 'application/json' } # create an alert => critical, open response = self.client.post('/alert', data=json.dumps(self.fatal_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['severity'], 'critical') self.assertEqual(data['alert']['status'], 'open') alert_id_1 = data['id'] # ack the alert => critical, ack response = self.client.put('/alert/' + alert_id_1 + '/action', data=json.dumps({'action': 'ack'}), headers=self.headers) self.assertEqual(response.status_code, 200) response = self.client.get('/alert/' + alert_id_1, headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['severity'], 'critical') self.assertEqual(data['alert']['status'], 'ack') # create 2nd alert => critical, open response = self.client.post('/alert', data=json.dumps(self.critical_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['severity'], 'critical') self.assertEqual(data['alert']['status'], 'open') alert_id_2 = data['id'] # shelve 2nd alert => critical, shelved response = self.client.put('/alert/' + alert_id_2 + '/action', data=json.dumps({'action': 'shelve'}), headers=self.headers) self.assertEqual(response.status_code, 200) response = self.client.get('/alert/' + alert_id_2, headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['severity'], 'critical') self.assertEqual(data['alert']['status'], 'shelved') # create a blackout os.environ['NOTIFICATION_BLACKOUT'] = 'yes' plugins.plugins['blackout'] = Blackout() blackout = { 'environment': 'Production', 'service': ['Network'] } response = self.client.post('/blackout', data=json.dumps(blackout), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) blackout_id = data['id'] # update 1st alert => critical, blackout response = self.client.post('/alert', data=json.dumps(self.fatal_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['severity'], 'critical') self.assertEqual(data['alert']['status'], 'blackout') # create 3rd alert => major, blackout response = self.client.post('/alert', data=json.dumps(self.major_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['severity'], 'major') self.assertEqual(data['alert']['status'], 'blackout') # clear 3rd alert => normal, closed response = self.client.post('/alert', data=json.dumps(self.normal_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['severity'], 'normal') self.assertEqual(data['alert']['status'], 'closed') # create 4th alert => minor, blackout response = self.client.post('/alert', data=json.dumps(self.minor_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['severity'], 'minor') self.assertEqual(data['alert']['status'], 'blackout') # clear 4th alert => ok, closed response = self.client.post('/alert', data=json.dumps(self.ok_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['severity'], 'ok') self.assertEqual(data['alert']['status'], 'closed') # create 5th alert => warning, blackout response = self.client.post('/alert', data=json.dumps(self.warn_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['severity'], 'warning') self.assertEqual(data['alert']['status'], 'blackout') # remove blackout response = self.client.delete('/blackout/' + blackout_id, headers=self.headers) self.assertEqual(response.status_code, 200) # update 1st alert => critical, ack response = self.client.post('/alert', data=json.dumps(self.fatal_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['severity'], 'critical') self.assertEqual(data['alert']['status'], 'ack') # update 2nd alert => critical, shelved response = self.client.post('/alert', data=json.dumps(self.critical_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['severity'], 'critical') self.assertEqual(data['alert']['status'], 'shelved') # update 3rd alert => normal, closed response = self.client.post('/alert', data=json.dumps(self.normal_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['severity'], 'normal') self.assertEqual(data['alert']['status'], 'closed') # update 4th alert => minor, open response = self.client.post('/alert', data=json.dumps(self.minor_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['severity'], 'minor') self.assertEqual(data['alert']['status'], 'open') # update 5th alert => warning, open response = self.client.post('/alert', data=json.dumps(self.warn_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['severity'], 'warning') self.assertEqual(data['alert']['status'], 'open') def test_whole_environment_blackout(self): os.environ['NOTIFICATION_BLACKOUT'] = 'False' plugins.plugins['blackout'] = Blackout() self.headers = { 'Authorization': 'Key %s' % self.admin_api_key.key, 'Content-type': 'application/json' } # create alert response = self.client.post('/alert', data=json.dumps(self.dev_alert), headers=self.headers) self.assertEqual(response.status_code, 201) # create blackout (for whole development environment) blackout = { 'environment': 'Development' } response = self.client.post('/blackout', data=json.dumps(blackout), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) blackout_id = data['id'] # do not suppress production alert response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 201) # suppress development alert response = self.client.post('/alert', data=json.dumps(self.dev_alert), headers=self.headers) self.assertEqual(response.status_code, 202) # remove blackout response = self.client.delete('/blackout/' + blackout_id, headers=self.headers) self.assertEqual(response.status_code, 200) # do not suppress any alerts response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 201) response = self.client.post('/alert', data=json.dumps(self.dev_alert), headers=self.headers) self.assertEqual(response.status_code, 201) def test_combination_blackout(self): os.environ['NOTIFICATION_BLACKOUT'] = 'False' plugins.plugins['blackout'] = Blackout() self.headers = { 'Authorization': 'Key %s' % self.admin_api_key.key, 'Content-type': 'application/json' } # create alert response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 201) # create blackout (only for services on a particular host) blackout = { 'environment': 'Production', 'resource': 'node404', 'service': ['Network', 'Web'] } response = self.client.post('/blackout', data=json.dumps(blackout), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) blackout_id = data['id'] # suppress alert response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 202) # remove blackout response = self.client.delete('/blackout/' + blackout_id, headers=self.headers) self.assertEqual(response.status_code, 200) # create alert response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 201) # create blackout (only for groups of alerts with particular tags) blackout = { 'environment': 'Production', 'group': 'Network', 'tags': ['system:web01', 'switch:off'] } response = self.client.post('/blackout', data=json.dumps(blackout), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) blackout_id = data['id'] # do not suppress alert response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 201) self.prod_alert['tags'].append('system:web01') # suppress alert response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 202) # remove blackout response = self.client.delete('/blackout/' + blackout_id, headers=self.headers) self.assertEqual(response.status_code, 200) def test_edit_blackout(self): # create new blackout os.environ['NOTIFICATION_BLACKOUT'] = 'False' plugins.plugins['blackout'] = Blackout() self.headers = { 'Authorization': 'Key %s' % self.admin_api_key.key, 'Content-type': 'application/json' } # create alert response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 201) # create blackout (only for services on a particular host) blackout = { 'environment': 'Production', 'resource': 'node404', 'service': ['Network', 'Web'], 'startTime': '2019-01-01T00:00:00.000Z', 'endTime': '2019-12-31T23:59:59.999Z' } response = self.client.post('/blackout', data=json.dumps(blackout), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) blackout_id = data['id'] # extend blackout period & change environment update = { 'environment': 'Development', 'endTime': '2020-12-31T23:59:59.999Z' } response = self.client.put('/blackout/' + blackout_id, data=json.dumps(update), headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['status'], 'ok') # check updates worked and didn't change anything else response = self.client.get('/blackout/' + blackout_id, headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['blackout']['environment'], 'Development') self.assertEqual(data['blackout']['resource'], 'node404') self.assertEqual(data['blackout']['service'], ['Network', 'Web']) self.assertEqual(data['blackout']['group'], None) self.assertEqual(data['blackout']['startTime'], '2019-01-01T00:00:00.000Z') self.assertEqual(data['blackout']['endTime'], '2020-12-31T23:59:59.999Z') def test_user_info(self): self.headers = { 'Authorization': 'Key %s' % self.admin_api_key.key, 'Content-type': 'application/json' } # create new blackout response = self.client.post('/blackout', data=json.dumps({'environment': 'Production', 'service': [ 'Network'], 'text': 'administratively down'}), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['blackout']['user'], '*****@*****.**') self.assertIsInstance(DateTime.parse(data['blackout']['createTime']), datetime) self.assertEqual(data['blackout']['text'], 'administratively down')
class RoutingTestCase(unittest.TestCase): def setUp(self): # create dummy routing rules self.dist = pkg_resources.Distribution(__file__, project_name='alerta-routing', version='0.1') s = 'rules = tests.test_routing:rules' self.entry_point = pkg_resources.EntryPoint.parse(s, dist=self.dist) self.dist._ep_map = {'alerta.routing': {'rules': self.entry_point}} pkg_resources.working_set.add(self.dist) test_config = { 'TESTING': True, 'AUTH_REQUIRED': True, 'CUSTOMER_VIEWS': True, 'ADMIN_USERS': ['*****@*****.**'], 'ALLOWED_EMAIL_DOMAINS': ['alerta.io', 'foo.com', 'bar.com'], 'PD_API_KEYS': { 'Tyrell Corporation': 'tc-key', 'Cyberdyne Systems': 'cs-key', 'Weyland-Yutani': 'wy-key', 'Zorin Enterprises': 'ze-key' }, 'SLACK_API_KEYS': { 'Soylent Corporation': 'sc-key', 'Omni Consumer Products': 'ocp-key', # 'Dolmansaxlil Shoe Corporation': 'dsc-key' # use default key }, 'API_KEY': 'default-key' } self.app = create_app(test_config) self.client = self.app.test_client() self.tier1_tc_alert = { 'event': 'foo1', 'resource': 'foo1', 'environment': 'Production', 'service': ['Web'], 'customer': 'Tyrell Corporation' # tier 1 } self.tier1_wy_alert = { 'event': 'foo1', 'resource': 'foo1', 'environment': 'Production', 'service': ['Web'], 'customer': 'Weyland-Yutani' # tier 1 } self.tier2_sc_alert = { 'event': 'bar1', 'resource': 'bar1', 'environment': 'Production', 'service': ['Web'], 'customer': 'Soylent Corporation' # tier 2 } self.tier2_ocp_alert = { 'event': 'bar1', 'resource': 'bar1', 'environment': 'Production', 'service': ['Web'], 'customer': 'Omni Consumer Products' # tier 2 } self.tier2_dsc_alert = { 'event': 'bar1', 'resource': 'bar1', 'environment': 'Production', 'service': ['Web'], 'customer': 'Dolmansaxlil Shoe Corporation' # tier 2 } self.tier3_it_alert = { 'event': 'bar1', 'resource': 'bar1', 'environment': 'Production', 'service': ['Web'], 'customer': 'Initech' # tier 3 } with self.app.test_request_context('/'): self.app.preprocess_request() self.api_key = ApiKey( user='******', scopes=[Scope.admin, Scope.read, Scope.write], text='admin-key' ) self.api_key.create() self.headers = { 'Authorization': 'Key %s' % self.api_key.key, 'Content-type': 'application/json' } # create dummy plugins plugins.plugins['pagerduty'] = DummyPagerDutyPlugin() plugins.plugins['slack'] = DummySlackPlugin() plugins.plugins['config'] = DummyConfigPlugin() def tearDown(self): self.dist._ep_map.clear() def test_config(self): os.environ['BOOL_ENVVAR'] = 'yes' os.environ['INT_ENVVAR'] = '2020' os.environ['FLOAT_ENVVAR'] = '0.99' os.environ['LIST_ENVVAR'] = 'up,down,left,right' os.environ['STR_ENVVAR'] = 'a string with spaces' os.environ['DICT_ENVVAR'] = '{"key":"value", "key2": "value2" }' self.app.config.update({ 'BOOL_SETTING': True, 'INT_SETTING': 1001, 'FLOAT_SETTING': 7.07, 'LIST_SETTING': ['a', 2, 'z'], 'STR_SETTING': ' long string with spaces', 'DICT_SETTING': {'a': 'dict', 'with': 'three', 'keys': 3}, }) # create alert response = self.client.post('/alert', data=json.dumps(self.tier1_tc_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['attributes']['env']['bool'], True) self.assertEqual(data['alert']['attributes']['env']['int'], 2020) self.assertEqual(data['alert']['attributes']['env']['float'], 0.99) self.assertEqual(data['alert']['attributes']['env']['list'], ['up', 'down', 'left', 'right']) self.assertEqual(data['alert']['attributes']['env']['str'], 'a string with spaces') self.assertEqual(data['alert']['attributes']['env']['dict'], dict(key='value', key2='value2')) self.assertEqual(data['alert']['attributes']['setting']['bool'], True) self.assertEqual(data['alert']['attributes']['setting']['int'], 1001) self.assertEqual(data['alert']['attributes']['setting']['float'], 7.07) self.assertEqual(data['alert']['attributes']['setting']['list'], ['a', 2, 'z']) self.assertEqual(data['alert']['attributes']['setting']['str'], ' long string with spaces') self.assertEqual(data['alert']['attributes']['setting']['dict'], {'a': 'dict', 'with': 'three', 'keys': 3}) self.assertEqual(data['alert']['attributes']['default']['bool'], False) self.assertEqual(data['alert']['attributes']['default']['int'], 999) self.assertEqual(data['alert']['attributes']['default']['float'], 5.55) self.assertEqual(data['alert']['attributes']['default']['list'], ['j', 'k']) self.assertEqual(data['alert']['attributes']['default']['str'], 'setting') self.assertEqual(data['alert']['attributes']['default']['dict'], dict(baz='quux')) def test_config_precedence(self): os.environ['var1'] = 'env1' self.app.config.update({ 'var1': 'setting1', 'var2': 'setting2' }) # create alert response = self.client.post('/alert', data=json.dumps(self.tier1_tc_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['attributes']['precedence']['var1'], 'env1') self.assertEqual(data['alert']['attributes']['precedence']['var2'], 'setting2') self.assertEqual(data['alert']['attributes']['precedence']['var3'], 'default3') def test_routing(self): # create alert (pagerduty key for Tyrell Corporation) response = self.client.post('/alert', data=json.dumps(self.tier1_tc_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['attributes']['NOTIFY'], 'pagerduty') self.assertEqual(data['alert']['attributes']['API_KEY'], 'tc-key') # create alert (pagerduty key for Weyland-Yutani) response = self.client.post('/alert', data=json.dumps(self.tier1_wy_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['attributes']['NOTIFY'], 'pagerduty') self.assertEqual(data['alert']['attributes']['API_KEY'], 'wy-key') # create alert (slack key for customer Soylent Corporation) response = self.client.post('/alert', data=json.dumps(self.tier2_sc_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['attributes']['NOTIFY'], 'slack') self.assertEqual(data['alert']['attributes']['API_KEY'], 'sc-key') # create alert (slack key for customer Omni Consumer Products) response = self.client.post('/alert', data=json.dumps(self.tier2_ocp_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['attributes']['NOTIFY'], 'slack') self.assertEqual(data['alert']['attributes']['API_KEY'], 'ocp-key') # create alert (use default slack key for Dolmansaxlil Shoe Corporation) response = self.client.post('/alert', data=json.dumps(self.tier2_dsc_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['attributes']['NOTIFY'], 'slack') self.assertEqual(data['alert']['attributes']['API_KEY'], 'default-key') # create alert (no key) response = self.client.post('/alert', data=json.dumps(self.tier3_it_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertNotIn('NOTIFY', data['alert']['attributes']) self.assertNotIn('API_KEY', data['alert']['attributes'])
class AuthTestCase(unittest.TestCase): def setUp(self): self.access_key = 'cc3b7f30-360e-47bc-8abb-c0a27625e134' self.secret_key = 'MjM0ODU4NGI1YWQxZWMyYzcxNjAxZDA4MzczNGQ1M2IK' test_config = { 'DEBUG': True, 'TESTING': True, 'AUTH_REQUIRED': True, 'CUSTOMER_VIEWS': True, 'ADMIN_USERS': ['*****@*****.**'], 'DELETE_SCOPES': ['delete:alerts'], 'ALLOWED_EMAIL_DOMAINS': ['bonaparte.fr', 'debeauharnais.fr', 'manorfarm.ru'], 'HMAC_AUTH_CREDENTIALS': [ { 'key': self.access_key, 'secret': self.secret_key, 'algorithm': 'sha256' } ] } self.app = create_app(test_config) self.client = self.app.test_client() self.alert = { 'event': 'Foo', 'resource': 'Bar', 'environment': 'Production', 'service': ['Quux'] } with self.app.test_request_context('/'): self.app.preprocess_request() self.api_key = ApiKey( user='******', scopes=[Scope.admin, Scope.read, Scope.write], text='Demo API key - not for production use', key='demo-key' ) self.api_key.create() self.headers = { 'Authorization': f'Key {self.api_key.key}', 'Content-type': 'application/json' } def tearDown(self): plugins.plugins.clear() db.destroy() def test_401_error(self): response = self.client.get('/alerts') self.assertEqual(response.status_code, 401) def test_user_defined_key(self): self.assertEqual(self.api_key.key, 'demo-key') def test_admin_key(self): payload = { 'user': '******', 'scopes': ['admin'] } response = self.client.post('/key', data=json.dumps(payload), content_type='application/json', headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertIsNotNone(data['key'], 'Failed to create read-write key') admin_api_key = data['key'] response = self.client.post('/alert', data=json.dumps(self.alert), content_type='application/json', headers={'Authorization': 'Key ' + admin_api_key}) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['history'][0]['user'], 'rw-demo-key-user') alert_id = data['id'] response = self.client.get('/alerts', headers={'Authorization': 'Key ' + admin_api_key}) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertIn('total', data) response = self.client.get('/key/' + admin_api_key, headers={'Authorization': 'Key ' + admin_api_key}) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['key']['scopes'], ['admin']) # delete alert response = self.client.delete('/alert/' + alert_id, headers={'Authorization': 'Key ' + admin_api_key}) self.assertEqual(response.status_code, 200) response = self.client.delete('/key/' + admin_api_key, headers=self.headers) self.assertEqual(response.status_code, 200) def test_readwrite_key(self): payload = { 'user': '******', 'type': 'read-write' } response = self.client.post('/key', data=json.dumps(payload), content_type='application/json', headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertIsNotNone(data['key'], 'Failed to create read-write key') rw_api_key = data['key'] response = self.client.post('/alert', data=json.dumps(self.alert), content_type='application/json', headers={'Authorization': 'Key ' + rw_api_key}) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['history'][0]['user'], 'rw-demo-key-user') alert_id = data['id'] response = self.client.get('/alerts', headers={'Authorization': 'Key ' + rw_api_key}) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertIn('total', data) response = self.client.get('/key/' + rw_api_key, headers={'Authorization': 'Key ' + rw_api_key}) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['key']['scopes'], ['read', 'write']) # delete alert response = self.client.delete('/alert/' + alert_id, headers={'Authorization': 'Key ' + rw_api_key}) self.assertEqual(response.status_code, 403) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['message'], 'Missing required scope: delete:alerts') response = self.client.delete('/key/' + rw_api_key, headers=self.headers) self.assertEqual(response.status_code, 200) def test_rw_delete_key(self): payload = { 'user': '******', 'scopes': ['read', 'write', 'delete:alerts'] } response = self.client.post('/key', data=json.dumps(payload), content_type='application/json', headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertIsNotNone(data['key'], 'Failed to create read-write-delete key') self.assertEqual(data['data']['scopes'], ['read', 'write', 'delete:alerts']) rwd_api_key = data['key'] response = self.client.post('/alert', data=json.dumps(self.alert), content_type='application/json', headers={'Authorization': 'Key ' + rwd_api_key}) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['history'][0]['user'], 'rw-delete-demo-key-user') alert_id = data['id'] response = self.client.get('/alerts', headers={'Authorization': 'Key ' + rwd_api_key}) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertIn('total', data) response = self.client.get('/key/' + rwd_api_key, headers={'Authorization': 'Key ' + rwd_api_key}) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['key']['scopes'], ['read', 'write', 'delete:alerts']) # delete alert response = self.client.delete('/alert/' + alert_id, headers={'Authorization': 'Key ' + rwd_api_key}) self.assertEqual(response.status_code, 200) response = self.client.delete('/key/' + rwd_api_key, headers=self.headers) self.assertEqual(response.status_code, 200) def test_readonly_key(self): payload = { 'user': '******', 'type': 'read-only' } response = self.client.post('/key', data=json.dumps(payload), content_type='application/json', headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertIsNotNone(data['key'], 'Failed to create read-only key') ro_api_key = data['key'] response = self.client.post('/alert', data=json.dumps(self.alert), content_type='application/json', headers={'Authorization': 'Key ' + ro_api_key}) self.assertEqual(response.status_code, 403) response = self.client.get('/alerts', headers={'Authorization': 'Key ' + ro_api_key}) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertIn('total', data) response = self.client.delete('/key/' + ro_api_key, headers=self.headers) self.assertEqual(response.status_code, 200) def test_users(self): # add customer mapping payload = { 'customer': 'Bonaparte Industries', 'match': 'bonaparte.fr' } response = self.client.post('/customer', data=json.dumps(payload), content_type='application/json', headers=self.headers) self.assertEqual(response.status_code, 201) payload = { 'name': 'Napoleon Bonaparte', 'email': '*****@*****.**', 'password': '******', 'text': 'added to circle of trust' } # create user response = self.client.post('/auth/signup', data=json.dumps(payload), content_type='application/json', headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertIsNotNone(data, 'Failed to create user') with self.app.test_request_context(): jwt = Jwt.parse(data['token']) user_id = jwt.subject # get user response = self.client.get('/users', headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertIn(user_id, [u['id'] for u in data['users']]) # create duplicate user response = self.client.post('/auth/signup', data=json.dumps(payload), content_type='application/json', headers=self.headers) self.assertEqual(response.status_code, 409) # delete user response = self.client.delete('/user/' + user_id, headers=self.headers) self.assertEqual(response.status_code, 200) def test_login(self): name = 'Josephine de Beauharnais' payload = { 'name': name, 'email': '*****@*****.**', 'password': '******', 'text': 'Test login' } # sign-up user with no customer mapping response = self.client.post('/auth/signup', data=json.dumps(payload), content_type='application/json') self.assertEqual(response.status_code, 403) # add customer mapping payload = { 'customer': 'Bonaparte Industries', 'match': 'debeauharnais.fr' } response = self.client.post('/customer', data=json.dumps(payload), content_type='application/json', headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) customer_id = data['id'] payload = { 'email': '*****@*****.**', 'password': '******' } # login now that customer mapping exists response = self.client.post('/auth/login', data=json.dumps(payload), content_type='application/json') # self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertIn('token', data) token = data['token'] headers = { 'Authorization': 'Bearer ' + token, 'Content-type': 'application/json' } # create a customer demo key payload = { 'user': '******', 'type': 'read-only' } response = self.client.post('/key', data=json.dumps(payload), content_type='application/json', headers=headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertIsNotNone(data['key'], 'Failed to create read-only key') customer_api_key = data['key'] response = self.client.get('/alerts', headers={'Authorization': 'Key ' + customer_api_key}) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertIn('total', data) response = self.client.get('/key/' + customer_api_key, headers=headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['key']['scopes'], ['read']) response = self.client.delete('/key/' + customer_api_key, headers={'Authorization': 'Key ' + customer_api_key}) self.assertEqual(response.status_code, 403) response = self.client.delete('/key/' + customer_api_key, headers=self.headers) self.assertEqual(response.status_code, 200) # get user response = self.client.get('/users', headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertIn(name, [u['name'] for u in data['users']]) user_id = [u['id'] for u in data['users'] if u['name'] == name][0] # delete user response = self.client.delete('/user/' + user_id, headers=self.headers) self.assertEqual(response.status_code, 200) # delete customer mapping response = self.client.delete('/customer/' + customer_id, headers=self.headers) self.assertEqual(response.status_code, 200) def test_x_api_key(self): self.headers = { 'X-API-Key': self.api_key.key, 'Content-type': 'application/json' } payload = { 'user': '******', 'type': 'read-write' } response = self.client.post('/key', data=json.dumps(payload), content_type='application/json', headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertIsNotNone(data['key'], 'Failed to create read-write key') rw_api_key = data['key'] response = self.client.post('/alert', data=json.dumps(self.alert), content_type='application/json', headers={'X-API-Key': rw_api_key}) self.assertEqual(response.status_code, 201) response = self.client.get('/alerts', headers={'X-API-Key': rw_api_key}) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertIn('total', data) response = self.client.delete('/key/' + rw_api_key, headers=self.headers) self.assertEqual(response.status_code, 200) def test_edit_api_keys(self): self.headers = { 'Authorization': f'Key {self.api_key.key}', 'Content-type': 'application/json' } # create api key payload = { 'scopes': [Scope.read, Scope.write_alerts, Scope.write_blackouts], 'text': 'devops automation key', 'expireTime': '2099-12-31T23:59:59.999Z' } response = self.client.post('/key', data=json.dumps(payload), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) api_key_id = data['key'] # extend blackout period & change environment update = { 'scopes': [Scope.read, Scope.write_blackouts, Scope.write_webhooks], 'expireTime': '2022-12-31T23:59:59.999Z' } response = self.client.put('/key/' + api_key_id, data=json.dumps(update), headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['status'], 'ok') # check updates worked and didn't change anything else response = self.client.get('/key/' + api_key_id, headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['key']['scopes'], [Scope.read, Scope.write_blackouts, Scope.write_webhooks]) self.assertEqual(data['key']['user'], '*****@*****.**') self.assertEqual(data['key']['text'], 'devops automation key') self.assertEqual(data['key']['expireTime'], '2022-12-31T23:59:59.999Z') def test_basic_auth(self): # add customer mapping payload = { 'customer': 'Bonaparte Industries', 'match': 'bonaparte.fr' } response = self.client.post('/customer', data=json.dumps(payload), content_type='application/json', headers=self.headers) self.assertEqual(response.status_code, 201) payload = { 'name': 'Napoleon Bonaparte', 'email': '*****@*****.**', 'password': '******', 'text': 'added to circle of trust' } # create user response = self.client.post('/auth/signup', data=json.dumps(payload), content_type='application/json', headers=self.headers) self.assertEqual(response.status_code, 200) # authenticate using basic auth headers = { 'Authorization': 'Basic ' + base64.b64encode(b'[email protected]:blackforest').decode(), 'Content-type': 'application/json' } response = self.client.get('/users', headers=headers) self.assertEqual(response.status_code, 403) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['message'], 'Missing required scope: admin:users') response = self.client.get('/alerts', headers=headers) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['status'], 'ok', response.data) def test_edit_user(self): # add customer mapping payload = { 'customer': 'Manor Farm', 'match': 'manorfarm.ru' } response = self.client.post('/customer', data=json.dumps(payload), content_type='application/json', headers=self.headers) self.assertEqual(response.status_code, 201) payload = { 'name': 'Snowball', 'email': '*****@*****.**', 'password': '******', 'text': 'Can you not understand that liberty is worth more than ribbons?', 'attributes': {'two-legs': 'bad', 'hasFourLegs': True, 'isEvil': False} } # create user response = self.client.post('/auth/signup', data=json.dumps(payload), content_type='application/json') self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) with self.app.test_request_context(): jwt = Jwt.parse(data['token']) user_id = jwt.subject # get user response = self.client.get('/user/' + user_id, headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['status'], 'ok') self.assertEqual(data['user']['name'], 'Snowball') self.assertEqual(data['user']['email'], '*****@*****.**') self.assertEqual(data['user']['text'], 'Can you not understand that liberty is worth more than ribbons?') # FIXME: attribute keys with None (null) values aren't deleted in postgres # change user details update = { 'name': 'Squealer', 'text': 'Four legs good, two legs bad.', 'attributes': {'four-legs': 'good', 'isEvil': True} } response = self.client.put('/user/' + user_id, data=json.dumps(update), headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['status'], 'ok') # check updates worked and didn't change anything else response = self.client.get('/user/' + user_id, headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['user']['name'], 'Squealer') self.assertEqual(data['user']['email'], '*****@*****.**') self.assertEqual(data['user']['text'], 'Four legs good, two legs bad.') self.assertEqual(data['user']['attributes'], { 'four-legs': 'good', 'two-legs': 'bad', 'hasFourLegs': True, 'isEvil': True }) # just update attributes update = { 'attributes': {'four-legs': 'double good', 'isEvil': False, 'hasFourLegs': None} } response = self.client.put('/user/' + user_id + '/attributes', data=json.dumps(update), headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['status'], 'ok') # check updates worked and didn't change anything else response = self.client.get('/user/' + user_id, headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['user']['name'], 'Squealer') self.assertEqual(data['user']['email'], '*****@*****.**') self.assertEqual(data['user']['text'], 'Four legs good, two legs bad.') self.assertEqual(data['user']['attributes'], { 'four-legs': 'double good', 'two-legs': 'bad', 'isEvil': False }) def test_hmac_auth(self): credentials = { 'id': self.access_key, 'key': self.secret_key, 'algorithm': 'sha256' } sender = Sender( url='http://localhost/alerts', method='GET', content='', content_type='application/json', credentials=credentials ) headers = { 'Authorization': sender.request_header, 'Content-Type': 'application/json' } response = self.client.get('/alerts', headers=headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) sender = Sender( url='http://localhost/alert', method='POST', content=json.dumps(self.alert), content_type='application/json', credentials=credentials ) headers = { 'Authorization': sender.request_header, 'Content-Type': 'application/json' } response = self.client.post('/alert', data=json.dumps(self.alert), content_type='application/json', headers=headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['event'], 'Foo')
class AuthTestCase(unittest.TestCase): def setUp(self): test_config = { 'TESTING': True, 'AUTH_REQUIRED': True, 'CUSTOMER_VIEWS': True, 'ADMIN_USERS': ['*****@*****.**'], 'ALLOWED_EMAIL_DOMAINS': ['bonaparte.fr', 'debeauharnais.fr', 'manorfarm.ru'] } self.app = create_app(test_config) self.client = self.app.test_client() self.alert = { 'event': 'Foo', 'resource': 'Bar', 'environment': 'Production', 'service': ['Quux'] } with self.app.test_request_context('/'): self.app.preprocess_request() self.api_key = ApiKey( user='******', scopes=[Scope.admin, Scope.read, Scope.write], text='demo-key' ) self.api_key.create() self.headers = { 'Authorization': 'Key %s' % self.api_key.key, 'Content-type': 'application/json' } def tearDown(self): db.destroy() def test_401_error(self): response = self.client.get('/alerts') self.assertEqual(response.status_code, 401) def test_readwrite_key(self): payload = { 'user': '******', 'type': 'read-write' } response = self.client.post('/key', data=json.dumps(payload), content_type='application/json', headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertIsNotNone(data['key'], 'Failed to create read-write key') rw_api_key = data['key'] response = self.client.post('/alert', data=json.dumps(self.alert), content_type='application/json', headers={'Authorization': 'Key ' + rw_api_key}) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['history'][0]['user'], 'rw-demo-key-user') response = self.client.get('/alerts', headers={'Authorization': 'Key ' + rw_api_key}) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertIn('total', data) response = self.client.get('/key/' + rw_api_key, headers={'Authorization': 'Key ' + rw_api_key}) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['key']['scopes'], ['read', 'write']) response = self.client.delete('/key/' + rw_api_key, headers=self.headers) self.assertEqual(response.status_code, 200) def test_readonly_key(self): payload = { 'user': '******', 'type': 'read-only' } response = self.client.post('/key', data=json.dumps(payload), content_type='application/json', headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertIsNotNone(data['key'], 'Failed to create read-only key') ro_api_key = data['key'] response = self.client.post('/alert', data=json.dumps(self.alert), content_type='application/json', headers={'Authorization': 'Key ' + ro_api_key}) self.assertEqual(response.status_code, 403) response = self.client.get('/alerts', headers={'Authorization': 'Key ' + ro_api_key}) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertIn('total', data) response = self.client.delete('/key/' + ro_api_key, headers=self.headers) self.assertEqual(response.status_code, 200) def test_users(self): # add customer mapping payload = { 'customer': 'Bonaparte Industries', 'match': 'bonaparte.fr' } response = self.client.post('/customer', data=json.dumps(payload), content_type='application/json', headers=self.headers) self.assertEqual(response.status_code, 201) payload = { 'name': 'Napoleon Bonaparte', 'email': '*****@*****.**', 'password': '******', 'text': 'added to circle of trust' } # create user response = self.client.post('/auth/signup', data=json.dumps(payload), content_type='application/json', headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertIsNotNone(data, 'Failed to create user') with self.app.test_request_context(): jwt = Jwt.parse(data['token']) user_id = jwt.subject # get user response = self.client.get('/users', headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertIn(user_id, [u['id'] for u in data['users']]) # create duplicate user response = self.client.post('/auth/signup', data=json.dumps(payload), content_type='application/json', headers=self.headers) self.assertEqual(response.status_code, 409) # delete user response = self.client.delete('/user/' + user_id, headers=self.headers) self.assertEqual(response.status_code, 200) def test_login(self): name = 'Josephine de Beauharnais' payload = { 'name': name, 'email': '*****@*****.**', 'password': '******', 'text': 'Test login' } # sign-up user with no customer mapping response = self.client.post('/auth/signup', data=json.dumps(payload), content_type='application/json') self.assertEqual(response.status_code, 403) # add customer mapping payload = { 'customer': 'Bonaparte Industries', 'match': 'debeauharnais.fr' } response = self.client.post('/customer', data=json.dumps(payload), content_type='application/json', headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) customer_id = data['id'] payload = { 'email': '*****@*****.**', 'password': '******' } # login now that customer mapping exists response = self.client.post('/auth/login', data=json.dumps(payload), content_type='application/json') # self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertIn('token', data) token = data['token'] headers = { 'Authorization': 'Bearer ' + token, 'Content-type': 'application/json' } # create a customer demo key payload = { 'user': '******', 'type': 'read-only' } response = self.client.post('/key', data=json.dumps(payload), content_type='application/json', headers=headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertIsNotNone(data['key'], 'Failed to create read-only key') customer_api_key = data['key'] response = self.client.get('/alerts', headers={'Authorization': 'Key ' + customer_api_key}) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertIn('total', data) response = self.client.get('/key/' + customer_api_key, headers=headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['key']['scopes'], ['read']) response = self.client.delete('/key/' + customer_api_key, headers={'Authorization': 'Key ' + customer_api_key}) self.assertEqual(response.status_code, 403) response = self.client.delete('/key/' + customer_api_key, headers=self.headers) self.assertEqual(response.status_code, 200) # get user response = self.client.get('/users', headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertIn(name, [u['name'] for u in data['users']]) user_id = [u['id'] for u in data['users'] if u['name'] == name][0] # delete user response = self.client.delete('/user/' + user_id, headers=self.headers) self.assertEqual(response.status_code, 200) # delete customer mapping response = self.client.delete('/customer/' + customer_id, headers=self.headers) self.assertEqual(response.status_code, 200) def test_x_api_key(self): self.headers = { 'X-API-Key': self.api_key.key, 'Content-type': 'application/json' } payload = { 'user': '******', 'type': 'read-write' } response = self.client.post('/key', data=json.dumps(payload), content_type='application/json', headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertIsNotNone(data['key'], 'Failed to create read-write key') rw_api_key = data['key'] response = self.client.post('/alert', data=json.dumps(self.alert), content_type='application/json', headers={'X-API-Key': rw_api_key}) self.assertEqual(response.status_code, 201) response = self.client.get('/alerts', headers={'X-API-Key': rw_api_key}) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertIn('total', data) response = self.client.delete('/key/' + rw_api_key, headers=self.headers) self.assertEqual(response.status_code, 200) def test_edit_api_keys(self): self.headers = { 'Authorization': 'Key %s' % self.api_key.key, 'Content-type': 'application/json' } # create api key payload = { 'scopes': [Scope.read, Scope.write_alerts, Scope.write_blackouts], 'text': 'devops automation key', 'expireTime': '2099-12-31T23:59:59.999Z' } response = self.client.post('/key', data=json.dumps(payload), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) api_key_id = data['key'] # extend blackout period & change environment update = { 'scopes': [Scope.read, Scope.write_blackouts, Scope.write_webhooks], 'expireTime': '2022-12-31T23:59:59.999Z' } response = self.client.put('/key/' + api_key_id, data=json.dumps(update), headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['status'], 'ok') # check updates worked and didn't change anything else response = self.client.get('/key/' + api_key_id, headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['key']['scopes'], [Scope.read, Scope.write_blackouts, Scope.write_webhooks]) self.assertEqual(data['key']['user'], '*****@*****.**') self.assertEqual(data['key']['text'], 'devops automation key') self.assertEqual(data['key']['expireTime'], '2022-12-31T23:59:59.999Z') def test_basic_auth(self): # add customer mapping payload = { 'customer': 'Bonaparte Industries', 'match': 'bonaparte.fr' } response = self.client.post('/customer', data=json.dumps(payload), content_type='application/json', headers=self.headers) self.assertEqual(response.status_code, 201) payload = { 'name': 'Napoleon Bonaparte', 'email': '*****@*****.**', 'password': '******', 'text': 'added to circle of trust' } # create user response = self.client.post('/auth/signup', data=json.dumps(payload), content_type='application/json', headers=self.headers) self.assertEqual(response.status_code, 200) # authenticate using basic auth headers = { 'Authorization': 'Basic ' + base64.b64encode('[email protected]:blackforest'.encode('utf-8')).decode(), 'Content-type': 'application/json' } response = self.client.get('/users', headers=headers) self.assertEqual(response.status_code, 403) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['message'], 'Missing required scope: admin:users') response = self.client.get('/alerts', headers=headers) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['status'], 'ok', response.data) def test_edit_user(self): # add customer mapping payload = { 'customer': 'Manor Farm', 'match': 'manorfarm.ru' } response = self.client.post('/customer', data=json.dumps(payload), content_type='application/json', headers=self.headers) self.assertEqual(response.status_code, 201) payload = { 'name': 'Snowball', 'email': '*****@*****.**', 'password': '******', 'text': 'Can you not understand that liberty is worth more than ribbons?', 'attributes': {'two-legs': 'bad', 'hasFourLegs': True, 'isEvil': False} } # create user response = self.client.post('/auth/signup', data=json.dumps(payload), content_type='application/json') self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) with self.app.test_request_context(): jwt = Jwt.parse(data['token']) user_id = jwt.subject # get user response = self.client.get('/user/' + user_id, headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['status'], 'ok') self.assertEqual(data['user']['name'], 'Snowball') self.assertEqual(data['user']['email'], '*****@*****.**') self.assertEqual(data['user']['text'], 'Can you not understand that liberty is worth more than ribbons?') # FIXME: attribute keys with None (null) values aren't deleted in postgres # change user details update = { 'name': 'Squealer', 'text': 'Four legs good, two legs bad.', 'attributes': {'four-legs': 'good', 'isEvil': True} } response = self.client.put('/user/' + user_id, data=json.dumps(update), headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['status'], 'ok') # check updates worked and didn't change anything else response = self.client.get('/user/' + user_id, headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['user']['name'], 'Squealer') self.assertEqual(data['user']['email'], '*****@*****.**') self.assertEqual(data['user']['text'], 'Four legs good, two legs bad.') self.assertEqual(data['user']['attributes'], { 'four-legs': 'good', 'two-legs': 'bad', 'hasFourLegs': True, 'isEvil': True }) # just update attributes update = { 'attributes': {'four-legs': 'double good', 'isEvil': False, 'hasFourLegs': None} } response = self.client.put('/user/' + user_id + '/attributes', data=json.dumps(update), headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['status'], 'ok') # check updates worked and didn't change anything else response = self.client.get('/user/' + user_id, headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['user']['name'], 'Squealer') self.assertEqual(data['user']['email'], '*****@*****.**') self.assertEqual(data['user']['text'], 'Four legs good, two legs bad.') self.assertEqual(data['user']['attributes'], { 'four-legs': 'double good', 'two-legs': 'bad', 'isEvil': False })
class AlertNotesTestCase(unittest.TestCase): def setUp(self): test_config = { 'TESTING': True, 'AUTH_REQUIRED': True, 'CUSTOMER_VIEWS': True, 'PLUGINS': [] } self.app = create_app(test_config) self.client = self.app.test_client() self.prod_alert = { 'resource': 'node404', 'event': 'node_down', 'environment': 'Production', 'severity': 'major', 'correlate': ['node_down', 'node_marginal', 'node_up'], 'service': ['Core', 'Web', 'Network'], 'group': 'Network', 'tags': ['level=20', 'switch:off'] } self.dev_alert = { 'resource': 'node404', 'event': 'node_marginal', 'environment': 'Development', 'severity': 'warning', 'correlate': ['node_down', 'node_marginal', 'node_up'], 'service': ['Core', 'Web', 'Network'], 'group': 'Network', 'tags': ['level=20', 'switch:off'] } self.fatal_alert = { 'event': 'node_down', 'resource': 'net01', 'environment': 'Production', 'service': ['Network'], 'severity': 'critical', 'correlate': ['node_down', 'node_marginal', 'node_up'], 'tags': ['foo'], 'attributes': { 'foo': 'abc def', 'bar': 1234, 'baz': False }, } self.critical_alert = { 'event': 'node_marginal', 'resource': 'net02', 'environment': 'Production', 'service': ['Network'], 'severity': 'critical', 'correlate': ['node_down', 'node_marginal', 'node_up'], 'timeout': 30 } self.major_alert = { 'event': 'node_marginal', 'resource': 'net03', 'environment': 'Production', 'service': ['Network'], 'severity': 'major', 'correlate': ['node_down', 'node_marginal', 'node_up'], 'timeout': 40 } self.normal_alert = { 'event': 'node_up', 'resource': 'net03', 'environment': 'Production', 'service': ['Network'], 'severity': 'normal', 'correlate': ['node_down', 'node_marginal', 'node_up'], 'timeout': 100 } with self.app.test_request_context('/'): self.app.preprocess_request() self.admin_api_key = ApiKey(user='******', scopes=ADMIN_SCOPES, text='demo-key') self.customer_api_key = ApiKey(user='******', scopes=ADMIN_SCOPES, text='demo-key', customer='Foo') self.admin_api_key.create() self.customer_api_key.create() def tearDown(self): db.destroy() def test_alert_notes(self): self.headers = { 'Authorization': f'Key {self.admin_api_key.key}', 'Content-type': 'application/json' } # create alert response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) alert_id = data['id'] # get alert response = self.client.get(f'/alert/{alert_id}', headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'open') # add note to alert note = {'text': 'this is a note'} response = self.client.put(f'/alert/{alert_id}/note', data=json.dumps(note), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) note_id = data['id'] self.assertEqual(data['note']['text'], 'this is a note') self.assertEqual(data['note']['user'], '*****@*****.**') self.assertEqual( sorted(data['note']['attributes']), sorted({ 'resource': 'node404', 'event': 'node_down', 'environment': 'Production', 'severity': 'major', 'status': 'open' })) self.assertEqual(data['note']['type'], 'alert') self.assertIsNotNone(data['note']['createTime']) self.assertIsNone(data['note']['updateTime']) self.assertIn(alert_id, data['note']['_links']['alert']) self.assertEqual(data['note']['customer'], None) # list notes for alert response = self.client.get(f'/alert/{alert_id}/notes', headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['status'], 'ok') self.assertEqual(data['notes'][0]['id'], note_id) self.assertEqual(data['notes'][0]['text'], 'this is a note') # update note text note = {'text': 'this note has changed'} response = self.client.put(f'/alert/{alert_id}/note/{note_id}', data=json.dumps(note), headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['status'], 'ok') self.assertEqual(data['note']['text'], 'this note has changed') self.assertEqual(data['note']['user'], '*****@*****.**') self.assertEqual( sorted(data['note']['attributes']), sorted({ 'resource': 'node404', 'event': 'node_down', 'environment': 'Production', 'severity': 'major', 'status': 'open' })) self.assertEqual(data['note']['type'], 'alert') self.assertIsNotNone(data['note']['createTime']) self.assertIsNotNone(data['note']['updateTime']) self.assertIn(alert_id, data['note']['_links']['alert']) self.assertEqual(data['note']['customer'], None) # list notes for alert (again) response = self.client.get(f'/alert/{alert_id}/notes', headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['status'], 'ok') self.assertEqual(data['notes'][0]['id'], note_id) self.assertEqual(data['notes'][0]['text'], 'this note has changed') # delete note response = self.client.delete(f'/alert/{alert_id}/note/{note_id}', headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['status'], 'ok')
class BlackoutsTestCase(unittest.TestCase): def setUp(self): test_config = { 'TESTING': True, 'AUTH_REQUIRED': True, 'CUSTOMER_VIEWS': True, 'PLUGINS': ['reject'] } self.app = create_app(test_config) self.client = self.app.test_client() self.alert = { 'event': 'node_marginal', 'resource': 'node404', 'environment': 'Production', 'service': ['Network'], 'severity': 'warning', 'correlate': ['node_down', 'node_marginal', 'node_up'] } with self.app.test_request_context('/'): self.app.preprocess_request() self.admin_api_key = ApiKey(user='******', scopes=['admin', 'read', 'write'], text='demo-key') self.customer_api_key = ApiKey(user='******', scopes=['admin', 'read', 'write'], text='demo-key', customer='Foo') self.admin_api_key.create() self.customer_api_key.create() def tearDown(self): db.destroy() def test_suppress_blackout(self): plugins.plugins['blackout'] = SuppressionBlackout() self.headers = { 'Authorization': 'Key %s' % self.admin_api_key.key, 'Content-type': 'application/json' } # create alert response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) # create blackout response = self.client.post('/blackout', data=json.dumps( {"environment": "Production"}), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) blackout_id = data['id'] # suppress alert response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 202) self.headers = { 'Authorization': 'Key %s' % self.customer_api_key.key, 'Content-type': 'application/json' } # create alert response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 202) self.headers = { 'Authorization': 'Key %s' % self.admin_api_key.key, 'Content-type': 'application/json' } response = self.client.delete('/blackout/' + blackout_id, headers=self.headers) self.assertEqual(response.status_code, 200) def test_notification_blackout(self): plugins.plugins['blackout'] = NotificationBlackout() self.headers = { 'Authorization': 'Key %s' % self.admin_api_key.key, 'Content-type': 'application/json' } # create new blackout response = self.client.post('/blackout', data=json.dumps({ "environment": "Production", "service": ["Network"] }), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) blackout_id = data['id'] # new alert should be status=blackout response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'blackout') # duplicate alert should be status=blackout response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'blackout') # duplicate alert should be status=blackout (again) response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'blackout') # increase severity alert should be status=blackout self.alert['severity'] = 'major' response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'blackout') # increase severity alert should be status=blackout (again) self.alert['severity'] = 'critical' response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'blackout') # decrease severity alert should be status=blackout self.alert['severity'] = 'minor' response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'blackout') # decrease severity alert should be status=blackout (again) self.alert['severity'] = 'warning' response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'blackout') # normal severity alert should be status=closed self.alert['severity'] = 'ok' response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'closed') # normal severity alert should be status=closed (again) response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'closed') # non-normal severity alert should be status=blackout (again) self.alert['severity'] = 'major' response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'blackout') # decrease severity alert should be status=blackout self.alert['severity'] = 'minor' response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'blackout') # remove blackout response = self.client.delete('/blackout/' + blackout_id, headers=self.headers) self.assertEqual(response.status_code, 200) # normal severity alert should be status=closed self.alert['severity'] = 'ok' response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'closed')
class UsersTestCase(unittest.TestCase): def setUp(self): test_config = { 'TESTING': True, 'AUTH_REQUIRED': True, 'ADMIN_USERS': ['*****@*****.**'], 'ALLOWED_EMAIL_DOMAINS': ['alerta.io', 'doe.com'] } self.app = create_app(test_config) self.client = self.app.test_client() self.alert = { 'event': 'Foo', 'resource': 'Bar', 'environment': 'Production', 'service': ['Quux'] } with self.app.test_request_context('/'): self.app.preprocess_request() self.api_key = ApiKey( user='******', scopes=[Scope.admin, Scope.read, Scope.write], text='demo-key' ) self.api_key.create() self.headers = { 'Authorization': 'Key %s' % self.api_key.key, 'Content-type': 'application/json' } def tearDown(self): db.destroy() def test_user(self): payload = { 'name': 'John Doe', 'email': '*****@*****.**', 'password': '******', 'roles': ['operator'], 'text': 'devops user' } # create user response = self.client.post('/user', data=json.dumps(payload), headers=self.headers) self.assertEqual(response.status_code, 201, response.data) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['user']['name'], 'John Doe') self.assertEqual(data['user']['email'], '*****@*****.**') self.assertEqual(data['user']['roles'], ['operator']) self.assertEqual(data['user']['email_verified'], False) user_id = data['id'] payload = { 'role': 'devops' } # modify user (assign different role) response = self.client.put('/user/' + user_id, data=json.dumps(payload), headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) # get user response = self.client.get('/user/' + user_id, headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['user']['name'], 'John Doe') self.assertEqual(data['user']['email'], '*****@*****.**') self.assertEqual(data['user']['roles'], ['devops']) self.assertEqual(data['user']['email_verified'], False) payload = { 'roles': ['devops', 'operator', 'user'] } # modify user (assign multiple roles) response = self.client.put('/user/' + user_id, data=json.dumps(payload), headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) # get user response = self.client.get('/user/' + user_id, headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['user']['name'], 'John Doe') self.assertEqual(data['user']['email'], '*****@*****.**') self.assertEqual(data['user']['roles'], ['devops', 'operator', 'user']) self.assertEqual(data['user']['email_verified'], False) def test_user_attributes(self): payload = { 'name': 'John Doe', 'email': '*****@*****.**', 'password': '******', 'roles': ['operator'], 'text': 'devops user' } # create user response = self.client.post('/user', data=json.dumps(payload), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['user']['name'], 'John Doe') self.assertEqual(data['user']['login'], '*****@*****.**') self.assertEqual(data['user']['roles'], ['operator']) self.assertEqual(data['user']['email'], '*****@*****.**') self.assertEqual(data['user']['email_verified'], False) payload = { 'email': '*****@*****.**', 'password': '******' } # login using new user response = self.client.post('/auth/login', data=json.dumps(payload), content_type='application/json') self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertIn('token', data) token = data['token'] headers = { 'Authorization': 'Bearer ' + token, 'Content-type': 'application/json' } payload = { 'attributes': { 'prefs': { 'isDark': True } } } # set user attribute response = self.client.put('/user/me/attributes', data=json.dumps(payload), headers=headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) # get user attribute response = self.client.get('/user/me/attributes', data=json.dumps(payload), headers=headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['attributes']['prefs'], {'isDark': True}) payload = { 'attributes': { 'prefs': { 'isMute': False, 'refreshInterval': 5000 } } } # set user attribute response = self.client.put('/user/me/attributes', data=json.dumps(payload), headers=headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) # get user attribute response = self.client.get('/user/me/attributes', data=json.dumps(payload), headers=headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['attributes']['prefs'], {'isDark': True, 'isMute': False, 'refreshInterval': 5000}) payload = { 'attributes': { 'prefs': { 'isMute': None } } } # unset user attribute response = self.client.put('/user/me/attributes', data=json.dumps(payload), headers=headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) # get user attribute response = self.client.get('/user/me/attributes', data=json.dumps(payload), headers=headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['attributes']['prefs'], {'isDark': True, 'isMute': None, 'refreshInterval': 5000})
class BlackoutsTestCase(unittest.TestCase): def setUp(self): test_config = { 'TESTING': True, 'AUTH_REQUIRED': True, 'CUSTOMER_VIEWS': True } self.app = create_app(test_config) self.client = self.app.test_client() self.alert = { 'event': 'node_marginal', 'resource': 'node404', 'environment': 'Production', 'service': ['Network'], 'severity': 'warning', 'correlate': ['node_down', 'node_marginal', 'node_up'] } with self.app.test_request_context('/'): self.app.preprocess_request() self.admin_api_key = ApiKey(user='******', scopes=['admin', 'read', 'write'], text='demo-key') self.customer_api_key = ApiKey(user='******', scopes=['admin', 'read', 'write'], text='demo-key', customer='Foo') self.admin_api_key.create() self.customer_api_key.create() def tearDown(self): db.destroy() def test_suppress_alerts(self): self.headers = { 'Authorization': 'Key %s' % self.admin_api_key.key, 'Content-type': 'application/json' } # create alert response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 201) # create blackout response = self.client.post('/blackout', data=json.dumps( {"environment": "Production"}), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) blackout_id = data['id'] # suppress alert response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 202) self.headers = { 'Authorization': 'Key %s' % self.customer_api_key.key, 'Content-type': 'application/json' } # create alert response = self.client.post('/alert', data=json.dumps(self.alert), headers=self.headers) self.assertEqual(response.status_code, 202) self.headers = { 'Authorization': 'Key %s' % self.admin_api_key.key, 'Content-type': 'application/json' } response = self.client.delete('/blackout/' + blackout_id, headers=self.headers) self.assertEqual(response.status_code, 200)
class AuthTestCase(unittest.TestCase): def setUp(self): test_config = { 'TESTING': True, 'AUTH_REQUIRED': True, 'CUSTOMER_VIEWS': True, 'ADMIN_USERS': ['*****@*****.**'], 'ALLOWED_EMAIL_DOMAINS': ['bonaparte.fr', 'debeauharnais.fr'] } self.app = create_app(test_config) self.client = self.app.test_client() self.alert = { 'event': 'Foo', 'resource': 'Bar', 'environment': 'Production', 'service': ['Quux'] } with self.app.test_request_context('/'): self.app.preprocess_request() self.api_key = ApiKey(user='******', scopes=['admin', 'read', 'write'], text='demo-key') self.api_key.create() self.headers = { 'Authorization': 'Key %s' % self.api_key.key, 'Content-type': 'application/json' } def tearDown(self): db.destroy() def test_401_error(self): response = self.client.get('/alerts') self.assertEqual(response.status_code, 401) def test_readwrite_key(self): payload = {'user': '******', 'type': 'read-write'} response = self.client.post('/key', data=json.dumps(payload), content_type='application/json', headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertIsNotNone(data['key'], 'Failed to create read-write key') rw_api_key = data['key'] response = self.client.post( '/alert', data=json.dumps(self.alert), content_type='application/json', headers={'Authorization': 'Key ' + rw_api_key}) self.assertEqual(response.status_code, 201) response = self.client.get( '/alerts', headers={'Authorization': 'Key ' + rw_api_key}) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertIn('total', data) response = self.client.delete('/key/' + rw_api_key, headers=self.headers) self.assertEqual(response.status_code, 200) def test_readonly_key(self): payload = {'user': '******', 'type': 'read-only'} response = self.client.post('/key', data=json.dumps(payload), content_type='application/json', headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertIsNotNone(data['key'], 'Failed to create read-only key') ro_api_key = data['key'] response = self.client.post( '/alert', data=json.dumps(self.alert), content_type='application/json', headers={'Authorization': 'Key ' + ro_api_key}) self.assertEqual(response.status_code, 403) response = self.client.get( '/alerts', headers={'Authorization': 'Key ' + ro_api_key}) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertIn('total', data) response = self.client.delete('/key/' + ro_api_key, headers=self.headers) self.assertEqual(response.status_code, 200) def test_users(self): # add customer mapping payload = {'customer': 'Bonaparte Industries', 'match': 'bonaparte.fr'} response = self.client.post('/customer', data=json.dumps(payload), content_type='application/json', headers=self.headers) self.assertEqual(response.status_code, 201) payload = { 'name': 'Napoleon Bonaparte', 'email': '*****@*****.**', 'password': '******', 'text': 'added to circle of trust' } # create user response = self.client.post('/auth/signup', data=json.dumps(payload), content_type='application/json', headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertIsNotNone(data, 'Failed to create user') with self.app.test_request_context(): jwt = Jwt.parse(data['token']) user_id = jwt.subject # get user response = self.client.get('/users', headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertIn(user_id, [u['id'] for u in data['users']]) # create duplicate user response = self.client.post('/auth/signup', data=json.dumps(payload), content_type='application/json', headers=self.headers) self.assertEqual(response.status_code, 409) # delete user response = self.client.delete('/user/' + user_id, headers=self.headers) self.assertEqual(response.status_code, 200) def test_login(self): name = 'Josephine de Beauharnais' payload = { 'name': name, 'email': '*****@*****.**', 'password': '******', 'text': 'Test login' } # sign-up user with no customer mapping response = self.client.post('/auth/signup', data=json.dumps(payload), content_type='application/json') self.assertEqual(response.status_code, 403) # add customer mapping payload = { 'customer': 'Bonaparte Industries', 'match': 'debeauharnais.fr' } response = self.client.post('/customer', data=json.dumps(payload), content_type='application/json', headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) customer_id = data['id'] payload = {'email': '*****@*****.**', 'password': '******'} # login now that customer mapping exists response = self.client.post('/auth/login', data=json.dumps(payload), content_type='application/json') # self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertIn('token', data) token = data['token'] headers = { 'Authorization': 'Bearer ' + token, 'Content-type': 'application/json' } # create a customer demo key payload = {'user': '******', 'type': 'read-only'} response = self.client.post('/key', data=json.dumps(payload), content_type='application/json', headers=headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertIsNotNone(data['key'], 'Failed to create read-only key') customer_api_key = data['key'] response = self.client.get( '/alerts', headers={'Authorization': 'Key ' + customer_api_key}) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertIn('total', data) response = self.client.delete( '/key/' + customer_api_key, headers={'Authorization': 'Key ' + customer_api_key}) self.assertEqual(response.status_code, 403) response = self.client.delete('/key/' + customer_api_key, headers=self.headers) self.assertEqual(response.status_code, 200) # get user response = self.client.get('/users', headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertIn(name, [u['name'] for u in data['users']]) user_id = [u['id'] for u in data['users'] if u['name'] == name][0] # delete user response = self.client.delete('/user/' + user_id, headers=self.headers) self.assertEqual(response.status_code, 200) # delete customer mapping response = self.client.delete('/customer/' + customer_id, headers=self.headers) self.assertEqual(response.status_code, 200) def test_x_api_key(self): self.headers = { 'X-API-Key': self.api_key.key, 'Content-type': 'application/json' } payload = {'user': '******', 'type': 'read-write'} response = self.client.post('/key', data=json.dumps(payload), content_type='application/json', headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertIsNotNone(data['key'], 'Failed to create read-write key') rw_api_key = data['key'] response = self.client.post('/alert', data=json.dumps(self.alert), content_type='application/json', headers={'X-API-Key': rw_api_key}) self.assertEqual(response.status_code, 201) response = self.client.get('/alerts', headers={'X-API-Key': rw_api_key}) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertIn('total', data) response = self.client.delete('/key/' + rw_api_key, headers=self.headers) self.assertEqual(response.status_code, 200) def test_basic_auth(self): # add customer mapping payload = {'customer': 'Bonaparte Industries', 'match': 'bonaparte.fr'} response = self.client.post('/customer', data=json.dumps(payload), content_type='application/json', headers=self.headers) self.assertEqual(response.status_code, 201) payload = { 'name': 'Napoleon Bonaparte', 'email': '*****@*****.**', 'password': '******', 'text': 'added to circle of trust' } # create user response = self.client.post('/auth/signup', data=json.dumps(payload), content_type='application/json', headers=self.headers) self.assertEqual(response.status_code, 200) # authenticate using basic auth headers = { 'Authorization': 'Basic ' + base64.b64encode( '[email protected]:blackforest'.encode('utf-8')).decode(), 'Content-type': 'application/json' } response = self.client.get('/users', headers=headers) self.assertEqual(response.status_code, 403) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['message'], 'Missing required scope: admin:users') response = self.client.get('/alerts', headers=headers) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['status'], 'ok', response.data)
class GroupsTestCase(unittest.TestCase): def setUp(self): test_config = { 'TESTING': True, 'AUTH_REQUIRED': True, 'ADMIN_USERS': ['*****@*****.**'], 'ALLOWED_EMAIL_DOMAINS': ['alerta.io', 'doe.com'] } self.app = create_app(test_config) self.client = self.app.test_client() self.alert = { 'event': 'Foo', 'resource': 'Bar', 'environment': 'Production', 'service': ['Quux'] } with self.app.test_request_context('/'): self.app.preprocess_request() self.api_key = ApiKey( user='******', scopes=[Scope.admin, Scope.read, Scope.write], text='demo-key') self.api_key.create() self.headers = { 'Authorization': 'Key %s' % self.api_key.key, 'Content-type': 'application/json' } def tearDown(self): plugins.plugins.clear() db.destroy() def test_groups(self): # create a group payload = {'name': 'Group 1', 'text': 'Test group #1'} response = self.client.post('/group', data=json.dumps(payload), headers=self.headers) self.assertEqual(response.status_code, 201, response.data) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['group']['name'], 'Group 1') self.assertEqual(data['group']['text'], 'Test group #1') group_id = data['group']['id'] # get group response = self.client.get('/group/' + group_id, headers=self.headers) self.assertEqual(response.status_code, 200, response.data) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['group']['name'], 'Group 1') self.assertEqual(data['group']['text'], 'Test group #1') # create a duplicate group name # payload = { # 'name': 'Group 1', # 'text': 'Test group #1 duplicate' # } # response = self.client.post('/group', data=json.dumps(payload), headers=self.headers) # self.assertEqual(response.status_code, 500, response.data) # update a group name, text payload = { 'name': 'Group 1 changed', 'text': 'Test group #1 changed too' } response = self.client.put('/group/' + group_id, data=json.dumps(payload), headers=self.headers) self.assertEqual(response.status_code, 200, response.data) response = self.client.get('/group/' + group_id, headers=self.headers) self.assertEqual(response.status_code, 200, response.data) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['group']['name'], 'Group 1 changed') self.assertEqual(data['group']['text'], 'Test group #1 changed too') # create a different group payload = {'name': 'Group 2', 'text': 'Test group #2'} response = self.client.post('/group', data=json.dumps(payload), headers=self.headers) self.assertEqual(response.status_code, 201, response.data) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['group']['name'], 'Group 2') self.assertEqual(data['group']['text'], 'Test group #2') group2_id = data['group']['id'] # list groups response = self.client.get('/groups', headers=self.headers) self.assertEqual(response.status_code, 200, response.data) data = json.loads(response.data.decode('utf-8')) self.assertCountEqual([g['name'] for g in data['groups']], ['Group 1 changed', 'Group 2']) # create a user payload = { 'name': 'John Doe', 'email': '*****@*****.**', 'password': '******', 'roles': ['operator'], 'text': 'devops user' } response = self.client.post('/user', data=json.dumps(payload), headers=self.headers) self.assertEqual(response.status_code, 201, response.data) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['user']['name'], 'John Doe') user_id = data['user']['id'] # add a user to first group response = self.client.put('/group/' + group_id + '/user/' + user_id, headers=self.headers) self.assertEqual(response.status_code, 200, response.data) data = json.loads(response.data.decode('utf-8')) # get users for first group response = self.client.get('/group/' + group_id + '/users', headers=self.headers) self.assertEqual(response.status_code, 200, response.data) data = json.loads(response.data.decode('utf-8')) self.assertCountEqual([u['name'] for u in data['users']], ['John Doe']) # create another user payload = { 'name': 'Jane Doe', 'email': '*****@*****.**', 'password': '******', 'roles': ['manager'], 'text': 'manager' } response = self.client.post('/user', data=json.dumps(payload), headers=self.headers) self.assertEqual(response.status_code, 201, response.data) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['user']['name'], 'Jane Doe') user2_id = data['user']['id'] # add another user to first group response = self.client.put('/group/' + group_id + '/user/' + user2_id, headers=self.headers) self.assertEqual(response.status_code, 200, response.data) data = json.loads(response.data.decode('utf-8')) # get users for first group again response = self.client.get('/group/' + group_id + '/users', headers=self.headers) self.assertEqual(response.status_code, 200, response.data) data = json.loads(response.data.decode('utf-8')) self.assertCountEqual([u['name'] for u in data['users']], ['John Doe', 'Jane Doe']) # add second user to second group response = self.client.put('/group/' + group2_id + '/user/' + user2_id, headers=self.headers) self.assertEqual(response.status_code, 200, response.data) data = json.loads(response.data.decode('utf-8')) # get users for second group response = self.client.get('/group/' + group2_id + '/users', headers=self.headers) self.assertEqual(response.status_code, 200, response.data) data = json.loads(response.data.decode('utf-8')) self.assertCountEqual([u['name'] for u in data['users']], ['Jane Doe']) # get groups for first user response = self.client.get('/user/' + user_id + '/groups', headers=self.headers) self.assertEqual(response.status_code, 200, response.data) data = json.loads(response.data.decode('utf-8')) self.assertCountEqual([g['name'] for g in data['groups']], ['Group 1 changed']) # get groups for second user response = self.client.get('/user/' + user2_id + '/groups', headers=self.headers) self.assertEqual(response.status_code, 200, response.data) data = json.loads(response.data.decode('utf-8')) self.assertCountEqual([g['name'] for g in data['groups']], ['Group 1 changed', 'Group 2']) # delete groups response = self.client.delete('/group/' + group_id, headers=self.headers) self.assertEqual(response.status_code, 200, response.data) response = self.client.delete('/group/' + group2_id, headers=self.headers) self.assertEqual(response.status_code, 200, response.data)
class AuthTestCase(unittest.TestCase): def setUp(self): test_config = { 'TESTING': True, 'AUTH_REQUIRED': True, 'CUSTOMER_VIEWS': True, 'ADMIN_USERS': ['*****@*****.**'], 'ALLOWED_EMAIL_DOMAINS': ['alerta.io', 'example.com'] } self.app = create_app(test_config) self.client = self.app.test_client() self.alert = { 'event': 'Foo', 'resource': 'Bar', 'environment': 'Production', 'service': ['Quux'] } with self.app.test_request_context('/'): self.app.preprocess_request() self.api_key = ApiKey( user='******', scopes=['admin', 'read', 'write'], text='admin-key' ) self.api_key.create() self.headers = { 'Authorization': 'Key %s' % self.api_key.key, 'Content-type': 'application/json' } def tearDown(self): db.destroy() def test_blackouts(self): # add customer mapping payload = { 'customer': 'Example Corp', 'match': 'example.com' } response = self.client.post('/customer', data=json.dumps(payload), content_type='application/json', headers=self.headers) self.assertEqual(response.status_code, 201) # create user payload = { 'name': 'Example User', 'email': '*****@*****.**', 'password': '******', 'text': '' } response = self.client.post('/auth/signup', data=json.dumps(payload), content_type='application/json', headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertIsNotNone(data, 'Failed to create user') # use JWT token for user auth token = data['token'] user_headers = { 'Authorization': 'Bearer %s' % token, 'Content-type': 'application/json' } # create user blackout response = self.client.post('/blackout', data=json.dumps({"environment": "Production"}), headers=user_headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) blackout_id = data['id'] # delete user blackout by admin response = self.client.delete('/blackout/' + blackout_id, headers=self.headers) self.assertEqual(response.status_code, 200)
class GroupsTestCase(unittest.TestCase): def setUp(self): test_config = { 'TESTING': True, 'AUTH_REQUIRED': True, 'ADMIN_USERS': ['*****@*****.**'], 'ALLOWED_EMAIL_DOMAINS': ['alerta.io', 'doe.com'] } self.app = create_app(test_config) self.client = self.app.test_client() self.alert = { 'event': 'Foo', 'resource': 'Bar', 'environment': 'Production', 'service': ['Quux'] } with self.app.test_request_context('/'): self.app.preprocess_request() self.api_key = ApiKey( user='******', scopes=[Scope.admin, Scope.read, Scope.write], text='demo-key' ) self.api_key.create() self.headers = { 'Authorization': 'Key %s' % self.api_key.key, 'Content-type': 'application/json' } def tearDown(self): db.destroy() def test_groups(self): # create a group payload = { 'name': 'Group 1', 'text': 'Test group #1' } response = self.client.post('/group', data=json.dumps(payload), headers=self.headers) self.assertEqual(response.status_code, 201, response.data) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['group']['name'], 'Group 1') self.assertEqual(data['group']['text'], 'Test group #1') group_id = data['group']['id'] # get group response = self.client.get('/group/' + group_id, headers=self.headers) self.assertEqual(response.status_code, 200, response.data) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['group']['name'], 'Group 1') self.assertEqual(data['group']['text'], 'Test group #1') # create a duplicate group name # payload = { # 'name': 'Group 1', # 'text': 'Test group #1 duplicate' # } # response = self.client.post('/group', data=json.dumps(payload), headers=self.headers) # self.assertEqual(response.status_code, 500, response.data) # update a group name, text payload = { 'name': 'Group 1 changed', 'text': 'Test group #1 changed too' } response = self.client.put('/group/' + group_id, data=json.dumps(payload), headers=self.headers) self.assertEqual(response.status_code, 200, response.data) response = self.client.get('/group/' + group_id, headers=self.headers) self.assertEqual(response.status_code, 200, response.data) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['group']['name'], 'Group 1 changed') self.assertEqual(data['group']['text'], 'Test group #1 changed too') # create a different group payload = { 'name': 'Group 2', 'text': 'Test group #2' } response = self.client.post('/group', data=json.dumps(payload), headers=self.headers) self.assertEqual(response.status_code, 201, response.data) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['group']['name'], 'Group 2') self.assertEqual(data['group']['text'], 'Test group #2') group2_id = data['group']['id'] # list groups response = self.client.get('/groups', headers=self.headers) self.assertEqual(response.status_code, 200, response.data) data = json.loads(response.data.decode('utf-8')) self.assertListEqual([g['name'] for g in data['groups']], ['Group 1 changed', 'Group 2']) # create a user payload = { 'name': 'John Doe', 'email': '*****@*****.**', 'password': '******', 'roles': ['operator'], 'text': 'devops user' } response = self.client.post('/user', data=json.dumps(payload), headers=self.headers) self.assertEqual(response.status_code, 201, response.data) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['user']['name'], 'John Doe') user_id = data['user']['id'] # add a user to first group response = self.client.put('/group/' + group_id + '/user/' + user_id, headers=self.headers) self.assertEqual(response.status_code, 200, response.data) data = json.loads(response.data.decode('utf-8')) # get users for first group response = self.client.get('/group/' + group_id + '/users', headers=self.headers) self.assertEqual(response.status_code, 200, response.data) data = json.loads(response.data.decode('utf-8')) self.assertListEqual([u['name'] for u in data['users']], ['John Doe']) # create another user payload = { 'name': 'Jane Doe', 'email': '*****@*****.**', 'password': '******', 'roles': ['manager'], 'text': 'manager' } response = self.client.post('/user', data=json.dumps(payload), headers=self.headers) self.assertEqual(response.status_code, 201, response.data) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['user']['name'], 'Jane Doe') user2_id = data['user']['id'] # add another user to first group response = self.client.put('/group/' + group_id + '/user/' + user2_id, headers=self.headers) self.assertEqual(response.status_code, 200, response.data) data = json.loads(response.data.decode('utf-8')) # get users for first group again response = self.client.get('/group/' + group_id + '/users', headers=self.headers) self.assertEqual(response.status_code, 200, response.data) data = json.loads(response.data.decode('utf-8')) self.assertListEqual([u['name'] for u in data['users']], ['John Doe', 'Jane Doe']) # add second user to second group response = self.client.put('/group/' + group2_id + '/user/' + user2_id, headers=self.headers) self.assertEqual(response.status_code, 200, response.data) data = json.loads(response.data.decode('utf-8')) # get users for second group response = self.client.get('/group/' + group2_id + '/users', headers=self.headers) self.assertEqual(response.status_code, 200, response.data) data = json.loads(response.data.decode('utf-8')) self.assertListEqual([u['name'] for u in data['users']], ['Jane Doe']) # get groups for first user response = self.client.get('/user/' + user_id + '/groups', headers=self.headers) self.assertEqual(response.status_code, 200, response.data) data = json.loads(response.data.decode('utf-8')) self.assertListEqual([g['name'] for g in data['groups']], ['Group 1 changed']) # get groups for second user response = self.client.get('/user/' + user2_id + '/groups', headers=self.headers) self.assertEqual(response.status_code, 200, response.data) data = json.loads(response.data.decode('utf-8')) self.assertListEqual([g['name'] for g in data['groups']], ['Group 1 changed', 'Group 2']) # delete groups response = self.client.delete('/group/' + group_id, headers=self.headers) self.assertEqual(response.status_code, 200, response.data) response = self.client.delete('/group/' + group2_id, headers=self.headers) self.assertEqual(response.status_code, 200, response.data)
class CustomersTestCase(unittest.TestCase): def setUp(self): test_config = { 'TESTING': True, 'AUTH_REQUIRED': True, 'CUSTOMER_VIEWS': True, 'ADMIN_USERS': ['*****@*****.**'], 'ALLOWED_EMAIL_DOMAINS': ['alerta.io', 'foo.com', 'bar.com'] } self.app = create_app(test_config) self.client = self.app.test_client() self.foo_alert = { 'event': 'foo1', 'resource': 'foo1', 'environment': 'Production', 'service': ['Web'] } self.bar_alert = { 'event': 'bar1', 'resource': 'bar1', 'environment': 'Production', 'service': ['Web'] } with self.app.test_request_context('/'): self.app.preprocess_request() self.api_key = ApiKey( user='******', scopes=[Scope.admin, Scope.read, Scope.write], text='admin-key' ) self.api_key.create() self.admin_headers = { 'Authorization': 'Key %s' % self.api_key.key, 'Content-type': 'application/json' } def tearDown(self): db.destroy() def test_customers(self): # add customer mappings payload = { 'customer': 'Bar Corp', 'match': 'bar.com' } response = self.client.post('/customer', data=json.dumps(payload), content_type='application/json', headers=self.admin_headers) self.assertEqual(response.status_code, 201) payload = { 'customer': 'Foo Bar Corp', 'match': '*****@*****.**' } response = self.client.post('/customer', data=json.dumps(payload), content_type='application/json', headers=self.admin_headers) self.assertEqual(response.status_code, 201) response = self.client.get('/customers', headers=self.admin_headers) self.assertEqual(response.status_code, 200) # create users payload = { 'name': 'Bar User', 'email': '*****@*****.**', 'password': '******', 'text': '' } response = self.client.post('/auth/signup', data=json.dumps(payload), content_type='application/json', headers=self.admin_headers) self.assertEqual(response.status_code, 200, response.data) data = json.loads(response.data.decode('utf-8')) self.assertIsNotNone(data, 'Failed to create user') self.bar_bearer_headers = { 'Authorization': 'Bearer %s' % data['token'], 'Content-type': 'application/json' } payload = { 'name': 'Foo Bar User', 'email': '*****@*****.**', 'password': '******', 'text': '' } response = self.client.post('/auth/signup', data=json.dumps(payload), content_type='application/json', headers=self.admin_headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertIsNotNone(data, 'Failed to create user') self.foobar_bearer_headers = { 'Authorization': 'Bearer %s' % data['token'], 'Content-type': 'application/json' } # create API key for [email protected] payload = { 'user': '******', 'scopes': ['read', 'write'], 'text': '' } response = self.client.post('/key', data=json.dumps(payload), content_type='application/json', headers=self.bar_bearer_headers) self.assertEqual(response.status_code, 201, response.data) data = json.loads(response.data.decode('utf-8')) self.assertIsNotNone(data['key'], 'Failed to create read-write key') self.bar_api_key_headers = { 'Authorization': 'Key %s' % data['key'], 'Content-type': 'application/json' } # create API keys for [email protected] payload = { 'user': '******', 'scopes': ['read', 'write'], 'text': '', 'customer': 'Foo Bar Corp' } response = self.client.post('/key', data=json.dumps(payload), content_type='application/json', headers=self.foobar_bearer_headers) self.assertEqual(response.status_code, 201, response.data) data = json.loads(response.data.decode('utf-8')) self.assertIsNotNone(data['key'], 'Failed to create read-write key') self.foobar_api_key_headers = { 'Authorization': 'Key %s' % data['key'], 'Content-type': 'application/json' } payload = { 'user': '******', 'scopes': ['read', 'write'], 'text': '', 'customer': 'Bar Corp' } response = self.client.post('/key', data=json.dumps(payload), content_type='application/json', headers=self.foobar_bearer_headers) self.assertEqual(response.status_code, 201, response.data) data = json.loads(response.data.decode('utf-8')) self.assertIsNotNone(data['key'], 'Failed to create read-write key') self.foobar_bar_only_api_key_headers = { 'Authorization': 'Key %s' % data['key'], 'Content-type': 'application/json' } # get list of customers for users response = self.client.get('/customers', headers=self.bar_api_key_headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual([c['customer'] for c in data['customers']], ['Bar Corp']) response = self.client.get('/customers', headers=self.foobar_api_key_headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual([c['customer'] for c in data['customers']], ['Foo Bar Corp']) # create alerts using API keys response = self.client.post('/alert', data=json.dumps(self.foo_alert), headers=self.bar_api_key_headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['customer'], 'Bar Corp') response = self.client.post('/alert', data=json.dumps(self.foo_alert), headers=self.foobar_api_key_headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['customer'], 'Foo Bar Corp') response = self.client.post('/alert', data=json.dumps(self.foo_alert), headers=self.foobar_bar_only_api_key_headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['customer'], 'Bar Corp') response = self.client.post('/alert', data=json.dumps(self.foo_alert), headers=self.foobar_bar_only_api_key_headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['customer'], 'Bar Corp') # create alerts using Bearer tokens response = self.client.post('/alert', data=json.dumps(self.foo_alert), headers=self.bar_bearer_headers) self.assertEqual(response.status_code, 201, response.data) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['customer'], 'Bar Corp') self.foo_alert['customer'] = 'Foo Bar Corp' response = self.client.post('/alert', data=json.dumps(self.foo_alert), headers=self.foobar_bearer_headers) self.assertEqual(response.status_code, 201, response.data) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['customer'], 'Foo Bar Corp') def test_blackouts(self): # add customer mappings payload = { 'customer': 'Foo Corp', 'match': 'foo.com' } response = self.client.post('/customer', data=json.dumps(payload), content_type='application/json', headers=self.admin_headers) self.assertEqual(response.status_code, 201) payload = { 'customer': 'Bar Corp', 'match': 'bar.com' } response = self.client.post('/customer', data=json.dumps(payload), content_type='application/json', headers=self.admin_headers) self.assertEqual(response.status_code, 201) # create users payload = { 'name': 'Foo User', 'email': '*****@*****.**', 'password': '******', 'text': '' } response = self.client.post('/auth/signup', data=json.dumps(payload), content_type='application/json', headers=self.admin_headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertIsNotNone(data, 'Failed to create user') foo_user_headers = { 'Authorization': 'Bearer %s' % data['token'], 'Content-type': 'application/json' } payload = { 'name': 'Bar User', 'email': '*****@*****.**', 'password': '******', 'text': '' } response = self.client.post('/auth/signup', data=json.dumps(payload), content_type='application/json', headers=self.admin_headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertIsNotNone(data, 'Failed to create user') bar_user_headers = { 'Authorization': 'Bearer %s' % data['token'], 'Content-type': 'application/json' } # create customer blackout by foo user response = self.client.post( '/blackout', data=json.dumps({'environment': 'Production'}), headers=foo_user_headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) blackout_id = data['id'] # new alert by foo user should be suppressed response = self.client.post('/alert', data=json.dumps(self.foo_alert), headers=foo_user_headers) self.assertEqual(response.status_code, 202) # new alert by bar user should not be suppressed response = self.client.post('/alert', data=json.dumps(self.bar_alert), headers=bar_user_headers) self.assertEqual(response.status_code, 201) # delete blackout by id response = self.client.delete('/blackout/' + blackout_id, headers=self.admin_headers) self.assertEqual(response.status_code, 200) # create global blackout by admin user response = self.client.post( '/blackout', data=json.dumps({'environment': 'Production'}), headers=self.admin_headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) blackout_id = data['id'] # new alert by foo user should be suppressed response = self.client.post('/alert', data=json.dumps(self.foo_alert), headers=foo_user_headers) self.assertEqual(response.status_code, 202) # new alert by bar user should be suppressed response = self.client.post('/alert', data=json.dumps(self.bar_alert), headers=bar_user_headers) self.assertEqual(response.status_code, 202) # delete blackout by id response = self.client.delete('/blackout/' + blackout_id, headers=self.admin_headers) self.assertEqual(response.status_code, 200) def test_assign_customer(self): with self.app.test_request_context('/'): self.app.preprocess_request() # nothing wanted, assign one g.customers = ['Customer1'] g.scopes = [] self.assertEqual(assign_customer(wanted=None), 'Customer1') # nothing wanted, but too many, throw error g.customers = ['Customer1', 'Customer2'] g.scopes = [] with self.assertRaises(ApiError) as e: assign_customer(wanted=None) exc = e.exception self.assertEqual(str(exc), 'must define customer as more than one possibility') # customer wanted, matches so allow g.customers = ['Customer1'] g.scopes = [] self.assertEqual(assign_customer(wanted='Customer1'), 'Customer1') # customer wanted, in list so allow g.customers = ['Customer1', 'Customer2'] g.scopes = [] self.assertEqual(assign_customer(wanted='Customer2'), 'Customer2') # customer wanted not in list, throw exception g.customers = ['Customer1', 'Customer2'] g.scopes = [] with self.assertRaises(ApiError) as e: assign_customer(wanted='Customer3') exc = e.exception self.assertEqual(str(exc), "not allowed to set customer to 'Customer3'") # no customers, admin scope so allow g.customers = [] g.scopes = ['admin'] self.assertEqual(assign_customer(wanted=None), None) self.assertEqual(assign_customer(wanted='Customer1'), 'Customer1') g.customers = ['Customer1', 'Customer2'] g.scopes = ['admin'] with self.assertRaises(ApiError) as e: assign_customer(wanted=None) exc = e.exception self.assertEqual(str(exc), 'must define customer as more than one possibility') self.assertEqual(assign_customer(wanted='Customer3'), 'Customer3') # wrong scope g.customers = ['Customer1'] g.scopes = ['read:keys', 'write:keys'] with self.assertRaises(ApiError) as e: assign_customer(wanted='Customer2', permission=Scope.admin_keys) exc = e.exception self.assertEqual(str(exc), "not allowed to set customer to 'Customer2'") # right scope g.customers = ['Customer1'] g.scopes = ['admin:keys', 'read:keys', 'write:keys'] self.assertEqual(assign_customer(wanted='Customer2', permission=Scope.admin_keys), 'Customer2') def test_invalid_customer(self): self.foo_alert['customer'] = '' response = self.client.post('/alert', data=json.dumps(self.foo_alert), headers=self.admin_headers) self.assertEqual(response.status_code, 400) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['message'], 'customer must not be an empty string') def test_edit_customer(self): # add customer mappings payload = { 'customer': 'Foo Corp', 'match': 'foo.com' } response = self.client.post('/customer', data=json.dumps(payload), content_type='application/json', headers=self.admin_headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) customer_id = data['id'] # change customer name update = { 'customer': 'Bar Corp' } response = self.client.put('/customer/' + customer_id, data=json.dumps(update), headers=self.admin_headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['status'], 'ok') # check updates worked and didn't change anything else response = self.client.get('/customer/' + customer_id, headers=self.admin_headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['customer']['customer'], 'Bar Corp') self.assertEqual(data['customer']['match'], 'foo.com') # change customer lookup update = { 'match': 'bar.com' } response = self.client.put('/customer/' + customer_id, data=json.dumps(update), headers=self.admin_headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['status'], 'ok') # check updates worked and didn't change anything else response = self.client.get('/customer/' + customer_id, headers=self.admin_headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['customer']['customer'], 'Bar Corp') self.assertEqual(data['customer']['match'], 'bar.com')
class BlackoutsTestCase(unittest.TestCase): def setUp(self): test_config = { 'TESTING': True, 'AUTH_REQUIRED': True, 'CUSTOMER_VIEWS': True, 'PLUGINS': [] } self.app = create_app(test_config) self.client = self.app.test_client() self.prod_alert = { 'resource': 'node404', 'event': 'node_down', 'environment': 'Production', 'severity': 'major', 'correlate': ['node_down', 'node_marginal', 'node_up'], 'service': ['Core', 'Web', 'Network'], 'group': 'Network', 'tags': ['level=20', 'switch:off'], 'origin': 'foo/bar' } self.dev_alert = { 'resource': 'node404', 'event': 'node_marginal', 'environment': 'Development', 'severity': 'warning', 'correlate': ['node_down', 'node_marginal', 'node_up'], 'service': ['Core', 'Web', 'Network'], 'group': 'Network', 'tags': ['level=20', 'switch:off'], 'origin': 'foo/bar' } self.fatal_alert = { 'event': 'node_down', 'resource': 'net01', 'environment': 'Production', 'service': ['Network'], 'severity': 'critical', 'correlate': ['node_down', 'node_marginal', 'node_up'], 'tags': ['foo'], 'attributes': {'foo': 'abc def', 'bar': 1234, 'baz': False}, 'origin': 'foo/bar' } self.critical_alert = { 'event': 'node_marginal', 'resource': 'net02', 'environment': 'Production', 'service': ['Network'], 'severity': 'critical', 'correlate': ['node_down', 'node_marginal', 'node_up'], 'origin': 'foo/bar', 'timeout': 30 } self.major_alert = { 'event': 'node_marginal', 'resource': 'net03', 'environment': 'Production', 'service': ['Network'], 'severity': 'major', 'correlate': ['node_down', 'node_marginal', 'node_up'], 'origin': 'foo/bar', 'timeout': 40 } self.normal_alert = { 'event': 'node_up', 'resource': 'net03', 'environment': 'Production', 'service': ['Network'], 'severity': 'normal', 'correlate': ['node_down', 'node_marginal', 'node_up'], 'origin': 'foo/quux', 'timeout': 100 } self.minor_alert = { 'event': 'node_marginal', 'resource': 'net04', 'environment': 'Production', 'service': ['Network'], 'severity': 'minor', 'correlate': ['node_down', 'node_marginal', 'node_up'], 'origin': 'foo/quux', 'timeout': 40 } self.ok_alert = { 'event': 'node_up', 'resource': 'net04', 'environment': 'Production', 'service': ['Network'], 'severity': 'ok', 'correlate': ['node_down', 'node_marginal', 'node_up'], 'origin': 'foo/quux', 'timeout': 100 } self.warn_alert = { 'event': 'node_marginal', 'resource': 'net05', 'environment': 'Production', 'service': ['Network'], 'severity': 'warning', 'correlate': ['node_down', 'node_marginal', 'node_up'], 'origin': 'foo/quux', 'timeout': 50 } with self.app.test_request_context('/'): self.app.preprocess_request() self.admin_api_key = ApiKey( user='******', scopes=['admin', 'read', 'write'], text='demo-key' ) self.customer_api_key = ApiKey( user='******', scopes=['admin', 'read', 'write'], text='demo-key', customer='Foo' ) self.admin_api_key.create() self.customer_api_key.create() def tearDown(self): plugins.plugins.clear() db.destroy() def test_suppress_blackout(self): os.environ['NOTIFICATION_BLACKOUT'] = 'False' plugins.plugins['blackout'] = Blackout() self.headers = { 'Authorization': 'Key %s' % self.admin_api_key.key, 'Content-type': 'application/json' } # create alert response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 201) # create blackout response = self.client.post('/blackout', data=json.dumps({'environment': 'Production'}), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) blackout_id = data['id'] # suppress alert response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 202) self.headers = { 'Authorization': 'Key %s' % self.customer_api_key.key, 'Content-type': 'application/json' } # create alert response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 202) self.headers = { 'Authorization': 'Key %s' % self.admin_api_key.key, 'Content-type': 'application/json' } response = self.client.delete('/blackout/' + blackout_id, headers=self.headers) self.assertEqual(response.status_code, 200) def test_notification_blackout(self): os.environ['NOTIFICATION_BLACKOUT'] = 'True' plugins.plugins['blackout'] = Blackout() self.headers = { 'Authorization': 'Key %s' % self.admin_api_key.key, 'Content-type': 'application/json' } # create new blackout blackout = { 'environment': 'Production', 'service': ['Core'] } response = self.client.post('/blackout', data=json.dumps(blackout), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) blackout_id = data['id'] # new alert should be status=blackout response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'blackout') # duplicate alert should be status=blackout response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'blackout') # duplicate alert should be status=blackout (again) response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'blackout') # increase severity alert should be status=blackout self.prod_alert['severity'] = 'major' response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'blackout') # increase severity alert should be status=blackout (again) self.prod_alert['severity'] = 'critical' response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'blackout') # decrease severity alert should be status=blackout self.prod_alert['severity'] = 'minor' response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'blackout') # decrease severity alert should be status=blackout (again) self.prod_alert['severity'] = 'warning' response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'blackout') # normal severity alert should be status=closed self.prod_alert['severity'] = 'ok' response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'closed') # normal severity alert should be status=closed (again) response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'closed') # non-normal severity alert should be status=blackout (again) self.prod_alert['severity'] = 'major' response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'blackout') # decrease severity alert should be status=blackout self.prod_alert['severity'] = 'minor' response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'blackout') # remove blackout response = self.client.delete('/blackout/' + blackout_id, headers=self.headers) self.assertEqual(response.status_code, 200) # non-normal severity alert should be status=open self.prod_alert['severity'] = 'minor' response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'open') # normal severity alert should be status=closed self.prod_alert['severity'] = 'ok' response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['status'], 'closed') def test_previous_status(self): self.headers = { 'Authorization': 'Key %s' % self.admin_api_key.key, 'Content-type': 'application/json' } # create an alert => critical, open response = self.client.post('/alert', data=json.dumps(self.fatal_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['severity'], 'critical') self.assertEqual(data['alert']['status'], 'open') alert_id_1 = data['id'] # ack the alert => critical, ack response = self.client.put('/alert/' + alert_id_1 + '/action', data=json.dumps({'action': 'ack'}), headers=self.headers) self.assertEqual(response.status_code, 200) response = self.client.get('/alert/' + alert_id_1, headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['severity'], 'critical') self.assertEqual(data['alert']['status'], 'ack') # create 2nd alert => critical, open response = self.client.post('/alert', data=json.dumps(self.critical_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['severity'], 'critical') self.assertEqual(data['alert']['status'], 'open') alert_id_2 = data['id'] # shelve 2nd alert => critical, shelved response = self.client.put('/alert/' + alert_id_2 + '/action', data=json.dumps({'action': 'shelve'}), headers=self.headers) self.assertEqual(response.status_code, 200) response = self.client.get('/alert/' + alert_id_2, headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['severity'], 'critical') self.assertEqual(data['alert']['status'], 'shelved') # create a blackout os.environ['NOTIFICATION_BLACKOUT'] = 'yes' plugins.plugins['blackout'] = Blackout() blackout = { 'environment': 'Production', 'service': ['Network'] } response = self.client.post('/blackout', data=json.dumps(blackout), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) blackout_id = data['id'] # update 1st alert => critical, blackout response = self.client.post('/alert', data=json.dumps(self.fatal_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['severity'], 'critical') self.assertEqual(data['alert']['status'], 'blackout') # create 3rd alert => major, blackout response = self.client.post('/alert', data=json.dumps(self.major_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['severity'], 'major') self.assertEqual(data['alert']['status'], 'blackout') # clear 3rd alert => normal, closed response = self.client.post('/alert', data=json.dumps(self.normal_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['severity'], 'normal') self.assertEqual(data['alert']['status'], 'closed') # create 4th alert => minor, blackout response = self.client.post('/alert', data=json.dumps(self.minor_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['severity'], 'minor') self.assertEqual(data['alert']['status'], 'blackout') # clear 4th alert => ok, closed response = self.client.post('/alert', data=json.dumps(self.ok_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['severity'], 'ok') self.assertEqual(data['alert']['status'], 'closed') # create 5th alert => warning, blackout response = self.client.post('/alert', data=json.dumps(self.warn_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['severity'], 'warning') self.assertEqual(data['alert']['status'], 'blackout') # remove blackout response = self.client.delete('/blackout/' + blackout_id, headers=self.headers) self.assertEqual(response.status_code, 200) # update 1st alert => critical, ack response = self.client.post('/alert', data=json.dumps(self.fatal_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['severity'], 'critical') self.assertEqual(data['alert']['status'], 'ack') # update 2nd alert => critical, shelved response = self.client.post('/alert', data=json.dumps(self.critical_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['severity'], 'critical') self.assertEqual(data['alert']['status'], 'shelved') # update 3rd alert => normal, closed response = self.client.post('/alert', data=json.dumps(self.normal_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['severity'], 'normal') self.assertEqual(data['alert']['status'], 'closed') # update 4th alert => minor, open response = self.client.post('/alert', data=json.dumps(self.minor_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['severity'], 'minor') self.assertEqual(data['alert']['status'], 'open') # update 5th alert => warning, open response = self.client.post('/alert', data=json.dumps(self.warn_alert), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['alert']['severity'], 'warning') self.assertEqual(data['alert']['status'], 'open') def test_whole_environment_blackout(self): os.environ['NOTIFICATION_BLACKOUT'] = 'False' plugins.plugins['blackout'] = Blackout() self.headers = { 'Authorization': 'Key %s' % self.admin_api_key.key, 'Content-type': 'application/json' } # create alert response = self.client.post('/alert', data=json.dumps(self.dev_alert), headers=self.headers) self.assertEqual(response.status_code, 201) # create blackout (for whole development environment) blackout = { 'environment': 'Development' } response = self.client.post('/blackout', data=json.dumps(blackout), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) blackout_id = data['id'] # do not suppress production alert response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 201) # suppress development alert response = self.client.post('/alert', data=json.dumps(self.dev_alert), headers=self.headers) self.assertEqual(response.status_code, 202) # remove blackout response = self.client.delete('/blackout/' + blackout_id, headers=self.headers) self.assertEqual(response.status_code, 200) # do not suppress any alerts response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 201) response = self.client.post('/alert', data=json.dumps(self.dev_alert), headers=self.headers) self.assertEqual(response.status_code, 201) def test_combination_blackout(self): os.environ['NOTIFICATION_BLACKOUT'] = 'False' plugins.plugins['blackout'] = Blackout() self.headers = { 'Authorization': 'Key %s' % self.admin_api_key.key, 'Content-type': 'application/json' } # create alert response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 201) # create blackout (only for services on a particular host) blackout = { 'environment': 'Production', 'resource': 'node404', 'service': ['Network', 'Web'] } response = self.client.post('/blackout', data=json.dumps(blackout), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) blackout_id = data['id'] # suppress alert response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 202) # remove blackout response = self.client.delete('/blackout/' + blackout_id, headers=self.headers) self.assertEqual(response.status_code, 200) # create alert response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 201) # create blackout (only for groups of alerts with particular tags) blackout = { 'environment': 'Production', 'group': 'Network', 'tags': ['system:web01', 'switch:off'] } response = self.client.post('/blackout', data=json.dumps(blackout), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) blackout_id = data['id'] # do not suppress alert response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 201) self.prod_alert['tags'].append('system:web01') # suppress alert response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 202) # remove blackout response = self.client.delete('/blackout/' + blackout_id, headers=self.headers) self.assertEqual(response.status_code, 200) # create alert response = self.client.post('/alert', data=json.dumps(self.dev_alert), headers=self.headers) self.assertEqual(response.status_code, 201) # create blackout (only for resources with a particular tag) blackout = { 'environment': 'Development', 'resource': 'node404', 'tags': ['level=40'] } response = self.client.post('/blackout', data=json.dumps(blackout), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) blackout_id = data['id'] # do not suppress alert response = self.client.post('/alert', data=json.dumps(self.dev_alert), headers=self.headers) self.assertEqual(response.status_code, 201) self.dev_alert['tags'].append('level=40') # suppress alert response = self.client.post('/alert', data=json.dumps(self.dev_alert), headers=self.headers) self.assertEqual(response.status_code, 202) # remove blackout response = self.client.delete('/blackout/' + blackout_id, headers=self.headers) self.assertEqual(response.status_code, 200) def test_origin_blackout(self): os.environ['NOTIFICATION_BLACKOUT'] = 'False' plugins.plugins['blackout'] = Blackout() self.headers = { 'Authorization': 'Key %s' % self.admin_api_key.key, 'Content-type': 'application/json' } # create alert response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 201) # create blackout (only for an origin) blackout = { 'environment': 'Production', 'origin': 'foo/bar', } response = self.client.post('/blackout', data=json.dumps(blackout), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) blackout_id = data['id'] # suppress alert response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 202) # do not suppress alert response = self.client.post('/alert', data=json.dumps(self.minor_alert), headers=self.headers) self.assertEqual(response.status_code, 201) # remove blackout response = self.client.delete('/blackout/' + blackout_id, headers=self.headers) self.assertEqual(response.status_code, 200) # create alert response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 201) # create blackout (only for origin with particular tags) blackout = { 'environment': 'Production', 'tags': ['system:web01', 'switch:off'], 'origin': 'foo/bar' } response = self.client.post('/blackout', data=json.dumps(blackout), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) blackout_id = data['id'] # do not suppress alert response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 201) self.prod_alert['tags'].append('system:web01') # suppress alert response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 202) # remove blackout response = self.client.delete('/blackout/' + blackout_id, headers=self.headers) self.assertEqual(response.status_code, 200) # create alert response = self.client.post('/alert', data=json.dumps(self.dev_alert), headers=self.headers) self.assertEqual(response.status_code, 201) # create blackout (only for origin with certain event) blackout = { 'environment': 'Development', 'event': 'node_marginal', 'origin': 'foo/quux' } response = self.client.post('/blackout', data=json.dumps(blackout), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) blackout_id = data['id'] # do not suppress alert response = self.client.post('/alert', data=json.dumps(self.dev_alert), headers=self.headers) self.assertEqual(response.status_code, 201) self.dev_alert['origin'] = 'foo/quux' # suppress alert response = self.client.post('/alert', data=json.dumps(self.dev_alert), headers=self.headers) self.assertEqual(response.status_code, 202) # list blackouts response = self.client.get('/blackouts', headers=self.headers) self.assertEqual(response.status_code, 200) # remove blackout response = self.client.delete('/blackout/' + blackout_id, headers=self.headers) self.assertEqual(response.status_code, 200) def test_edit_blackout(self): # create new blackout os.environ['NOTIFICATION_BLACKOUT'] = 'False' plugins.plugins['blackout'] = Blackout() self.headers = { 'Authorization': 'Key %s' % self.admin_api_key.key, 'Content-type': 'application/json' } # create alert response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 201) # create blackout (only for services on a particular host) blackout = { 'environment': 'Production', 'resource': 'node404', 'service': ['Network', 'Web'], 'startTime': '2019-01-01T00:00:00.000Z', 'endTime': '2049-12-31T23:59:59.999Z' } response = self.client.post('/blackout', data=json.dumps(blackout), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) blackout_id = data['id'] # suppress alert response = self.client.post('/alert', data=json.dumps(self.prod_alert), headers=self.headers) self.assertEqual(response.status_code, 202) # extend blackout period & change environment update = { 'environment': 'Development', 'event': None, 'tags': [], 'endTime': '2099-12-31T23:59:59.999Z' } response = self.client.put('/blackout/' + blackout_id, data=json.dumps(update), headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['status'], 'ok') # check updates worked and didn't change anything else response = self.client.get('/blackout/' + blackout_id, headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['blackout']['environment'], 'Development') self.assertEqual(data['blackout']['resource'], 'node404') self.assertEqual(data['blackout']['service'], ['Network', 'Web']) self.assertEqual(data['blackout']['group'], None) self.assertEqual(data['blackout']['startTime'], '2019-01-01T00:00:00.000Z') self.assertEqual(data['blackout']['endTime'], '2099-12-31T23:59:59.999Z') # suppress alert response = self.client.post('/alert', data=json.dumps(self.dev_alert), headers=self.headers) self.assertEqual(response.status_code, 202) def test_user_info(self): self.headers = { 'Authorization': 'Key %s' % self.admin_api_key.key, 'Content-type': 'application/json' } # create new blackout response = self.client.post('/blackout', data=json.dumps({'environment': 'Production', 'service': [ 'Network'], 'text': 'administratively down'}), headers=self.headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) self.assertEqual(data['blackout']['user'], '*****@*****.**') self.assertIsInstance(DateTime.parse(data['blackout']['createTime']), datetime) self.assertEqual(data['blackout']['text'], 'administratively down')
class AuthTestCase(unittest.TestCase): def setUp(self): test_config = { 'TESTING': True, 'AUTH_REQUIRED': True, 'CUSTOMER_VIEWS': True, 'ADMIN_USERS': ['*****@*****.**'], 'ALLOWED_EMAIL_DOMAINS': ['alerta.io', 'example.com'] } self.app = create_app(test_config) self.client = self.app.test_client() self.alert = { 'event': 'Foo', 'resource': 'Bar', 'environment': 'Production', 'service': ['Quux'] } with self.app.test_request_context('/'): self.app.preprocess_request() self.api_key = ApiKey(user='******', scopes=['admin', 'read', 'write'], text='admin-key') self.api_key.create() self.headers = { 'Authorization': 'Key %s' % self.api_key.key, 'Content-type': 'application/json' } def tearDown(self): db.destroy() def test_blackouts(self): # add customer mapping payload = {'customer': 'Example Corp', 'match': 'example.com'} response = self.client.post('/customer', data=json.dumps(payload), content_type='application/json', headers=self.headers) self.assertEqual(response.status_code, 201) # create user payload = { 'name': 'Example User', 'email': '*****@*****.**', 'password': '******', 'text': '' } response = self.client.post('/auth/signup', data=json.dumps(payload), content_type='application/json', headers=self.headers) self.assertEqual(response.status_code, 200) data = json.loads(response.data.decode('utf-8')) self.assertIsNotNone(data, 'Failed to create user') # use JWT token for user auth token = data['token'] user_headers = { 'Authorization': 'Bearer %s' % token, 'Content-type': 'application/json' } # create user blackout response = self.client.post('/blackout', data=json.dumps( {"environment": "Production"}), headers=user_headers) self.assertEqual(response.status_code, 201) data = json.loads(response.data.decode('utf-8')) blackout_id = data['id'] # delete user blackout by admin response = self.client.delete('/blackout/' + blackout_id, headers=self.headers) self.assertEqual(response.status_code, 200)