Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Group permissions update for argus client #1

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions argusclient/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,85 @@ def get_alerts_allinfo(self, ownerName=None, alertNameContains=None, shared=Fals
"""
return self.argus._request("get", "alerts/allinfo", params=dict(ownername=ownerName, alertNameContains=alertNameContains, shared=shared, limit=limit))

'''
Functions to enable support for composite alerts
'''

def get_composite_alert_children(self, comp_alert_id):
"""
Get list of child alerts for a composite alert
:param comp_alert_id: ID of an argus composite alert
:type comp_alert_id: integer
:return: list of :class:`argusclient.model.Alert` object with all fields populated.
"""

if not comp_alert_id: raise ValueError("Need to specify comp_alert_id")
if not isinstance(comp_alert_id, int): raise TypeError("Need an Alert ID, got: %s" % type(comp_alert_id))

uri_path = "alerts/{}/children".format(comp_alert_id)
child_alerts = self.argus._request("get", uri_path)
child_alerts = [self._fill(child_alert) for child_alert in child_alerts]
return child_alerts

def get_composite_alert_children_info(self, comp_alert_id):
"""
Get information for all children (child alerts + triggers associated with them) of a composite alert

:param comp_alert_id: ID of an argus composite alert
:type comp_alert_id: integer
:return: list of child alerts information (alertid, alertname, triggerids, triggernames etc)
"""

if not comp_alert_id: raise ValueError("Need to specify comp_alert_id")
if not isinstance(comp_alert_id, int): raise TypeError("Need an Alert ID, got: %s" % type(comp_alert_id))

uri_path = "alerts/{}/children/info".format(comp_alert_id)
return self.argus._request("get", uri_path)


def add_child_alert_to_composite_alert(self, comp_alert_id, alert):
"""
Add child alert to a composite alert

:param comp_alert_id: ID of a composite alert
:type comp_alert_id: Integer

:param alert: alert definition
:type alert: class:`argusclient.model.Alert` object

:return: newly created child alert object of type class:`argusclient.model.Alert`
"""
if not comp_alert_id: raise ValueError("Need to specify a composite alert id")
if not alert: raise ValueError("Need to specify an Alert object")
if not isinstance(comp_alert_id, int): raise TypeError("Need an Alert ID, got: %s" % type(comp_alert_id))
if not isinstance(alert, Alert): raise TypeError("Need an Alert object, got: %s" % type(alert))

uri_path = "alerts/{}/children".format(comp_alert_id)
alert_obj = self._fill(self.argus._request("post", uri_path, dataObj=alert))
self._coll[alert_obj.id] = alert_obj
return alert_obj


def delete_child_alert_from_composite_alert(self, comp_alert_id, child_alert_id):
"""
Delete a child alert from a composite alert

:param comp_alert_id: ID of a composite alert
:type comp_alert_id: Integer

:param child_alert_id: ID of a child alert
:type child_alert_id: Integer
"""
if not comp_alert_id: raise ValueError("Need to specify a composite alert id")
if not child_alert_id: raise ValueError("Need to specify a child alert id")
if not isinstance(comp_alert_id, int): raise TypeError("Need a composite Alert ID, got: %s" % type(comp_alert_id))
if not isinstance(child_alert_id, int): raise TypeError("Need an Alert ID, got: %s" % type(child_alert_id))

uri_path = "alerts/{}/children/{}".format(comp_alert_id, child_alert_id)
if child_alert_id in self._coll:
del self._coll[child_alert_id]
return self.argus._request("delete", uri_path)


class AlertTriggersServiceClient(BaseUpdatableModelServiceClient):
"""
Expand Down
8 changes: 5 additions & 3 deletions argusclient/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -429,8 +429,9 @@ class Notification(BaseEncodable):

:param name: The name of the notification
:type name: str
:param notifierName or notifier: The name of the notifier implementation. Must be one of :attr:`EMAIL`, :attr:`AUDIT`, :attr:`GOC`,
:attr:`GUS`, :attr:`CALLBACK`, :attr:`PAGER_DUTY`, :attr:`REFOCUS_BOOLEAN`, :attr:`REFOCUS_VALUE`, :attr:`SLACK`
:param notifierName: The name of the notifier implementation. Must be one of :attr:`EMAIL`, :attr:`AUDIT`,
:attr:`GOC`, :attr:`GUS`, :attr:`CALLBACK`, :attr:`PAGER_DUTY`, :attr:`REFOCUS_BOOLEAN`,
:attr:`REFOCUS_VALUE`, :attr:`SLACK`, :attr:`ALERT_ROUTER`
:type notifierName or notifier: str

**Optional parameters to the constructor:**
Expand Down Expand Up @@ -459,10 +460,11 @@ class Notification(BaseEncodable):
REFOCUS_BOOLEAN = "com.salesforce.dva.argus.service.alert.notifier.RefocusBooleanNotifier"
REFOCUS_VALUE = "com.salesforce.dva.argus.service.alert.notifier.RefocusValueNotifier"
SLACK = "com.salesforce.dva.argus.service.alert.notifier.SlackNotifier"
ALERT_ROUTER = "com.salesforce.dva.argus.service.alert.notifier.AlertRouterNotifier"

#: Set of all valid notifier implementation names.
VALID_NOTIFIERS = frozenset((EMAIL, AUDIT, GOC, GUS, CALLBACK, PAGER_DUTY,
REFOCUS_BOOLEAN, REFOCUS_VALUE, SLACK))
REFOCUS_BOOLEAN, REFOCUS_VALUE, SLACK, ALERT_ROUTER))

def __init__(self, name, notifierName=None, metricsToAnnotate=None, **kwargs):
notifierName = notifierName or kwargs.get('notifier')
Expand Down
4 changes: 2 additions & 2 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@
# built documents.
#
# The short X.Y version.
version = '1.0'
version = '1.2'
# The full version, including alpha/beta/rc tags.
release = '1.0.0'
release = '1.2.0'

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from setuptools import setup, find_packages

version = '1.0'
version = '1.2'

with open("README.rst", 'r') as fin:
README = fin.read()
Expand Down
60 changes: 60 additions & 0 deletions tests/test_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@
permissionNames = ["VIEW", "EDIT", "DELETE"]
permissionGroupId = '24231-52321-43523-64353-23111'

compAlertID = 6000
childAlertID_1 = 6003
childAlertID_2 = 6009
triggerID_1 = 6005
compAlert_notificationID = 6007

metric_D = {
"scope": scope,
"metric": metric,
Expand Down Expand Up @@ -296,4 +302,58 @@
"triggers": [trigger_D, trigger_2_D],
"notifications": [notification_D, notification_2_D, notification_3_D],
"ownerName": userName
}

compalert_D = {
'id': compAlertID,
'alertType': 'COMPOSITE',
'name': 'CompAlertTest',
'triggerIds': [],
'enabled': False,
'cronEntry': '*/2 * * * *',
'notificationsIds': [],
'expression': {'expression': {'operator': 'AND', 'join': [], 'terms': []}, 'termDefinitions': []},
'childAlertsIds': []
}

childAlert_1 = {
'id': childAlertID_1,
'triggersIds': [],
'alertType': 'COMPOSITE_CHILD',
'name': 'CompAlertTest-ChildAlert-1',
'cronEntry': '* * * * *',
'notificationsIds': [],
'enabled': False,
'expression': '-1h:-0m:tracer.api.XRD.NONE.none:requestsReceivedLastMin:avg:1m-avg'
}

childAlert_2 = {
'id': childAlertID_2,
'triggersIds': [],
'alertType': 'COMPOSITE_CHILD',
'name': 'CompAlertTest-ChildAlert-2',
'cronEntry': '* * * * *',
'notificationsIds': [],
'enabled': False,
'expression': '-1h:-0m:tracer.api.XRD.NONE.none:avgQueryTime:avg:1m-avg'
}

childAlert_trigger_1 = {
'id': triggerID_1,
'threshold': 1.0,
'type': 'GREATER_THAN',
'inertia': 0L,
'name': 'CompAlertTest/trigger1'
}

compAlert_notification = {
'id': compAlert_notificationID,
'severityLevel': 5,
'name': 'Email1',
'subscriptions': ['[email protected]'],
'notifierName': 'com.salesforce.dva.argus.service.alert.notifier.EmailNotifier',
'metricsToAnnotate': [],
'cooldownPeriod': 0L,
'sractionable': False,
'customText': 'None'
}
168 changes: 168 additions & 0 deletions tests/test_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -830,3 +830,171 @@ def testGetAlertWithMultipleTriggers(self):
self.assertEquals(len(alert.triggers), 2)
self.assertEquals(alert.triggers[100].argus_id, 100)
self.assertEquals(alert.triggers[101].argus_id, 101)



class TestCompositeAlert(TestServiceBase):

def _createCompAlert(self):
with mock.patch('requests.Session.post', return_value=MockResponse(json.dumps(compalert_D), 200)) as mock_add_comp_alert:
alert = Alert.from_dict(compalert_D)
self.assertTrue(isinstance(alert, Alert))
delattr(alert, "id")
comp_alert = self.argus.alerts.add(alert)
self.assertTrue(isinstance(comp_alert, Alert))
self.assertTrue(hasattr(comp_alert, "id"))
self.assertEqual(comp_alert.expression['expression']['operator'], 'AND')
call_args = mock_add_comp_alert.call_args
uri_path = os.path.join(endpoint, "alerts")
self.assertIn((uri_path,), call_args)
return comp_alert

def testAddCompAlert(self):
self._createCompAlert()


def testAddChildAlert(self):
comp_alert = self._createCompAlert()

with mock.patch('requests.Session.post', return_value=MockResponse(json.dumps(childAlert_1), 200)):
child_alert = self.argus.alerts.add_child_alert_to_composite_alert(comp_alert.id, Alert.from_dict(childAlert_1))
self.assertEqual(child_alert.alertType, 'COMPOSITE_CHILD')
self.assertTrue(isinstance(child_alert, Alert))

def testAddTriggerToChildAlert(self):
comp_alert = self._createCompAlert()

with mock.patch('requests.Session.post', return_value=MockResponse(json.dumps(childAlert_1), 200)) as mock_add_childalert:
child_alert = self.argus.alerts.add_child_alert_to_composite_alert(comp_alert.id,
Alert.from_dict(childAlert_1))
self.assertEqual(child_alert.alertType, 'COMPOSITE_CHILD')
self.assertTrue(isinstance(child_alert, Alert))
call_args = tuple(mock_add_childalert.call_args)
uri_path = os.path.join(endpoint, "alerts/{}/children".format(comp_alert.id))
self.assertIn((uri_path,), call_args)

with mock.patch('requests.Session.post', return_value=MockResponse(json.dumps([childAlert_trigger_1]), 200)) as mock_trigger_post:
trigger_obj = Trigger.from_dict(childAlert_trigger_1)
delattr(trigger_obj, "id")
trigger = child_alert.triggers.add(trigger_obj)
self.assertTrue(isinstance(trigger, Trigger))
call_args = tuple(mock_trigger_post.call_args)
uri_path = os.path.join(endpoint, "alerts/{}/triggers".format(child_alert.id))
self.assertIn((uri_path,), call_args)

def testAddNotification(self):
comp_alert = self._createCompAlert()

with mock.patch('requests.Session.post', return_value=MockResponse(json.dumps([compAlert_notification]), 200)) as mock_notification:
notification_obj = Notification.from_dict(compAlert_notification)
delattr(notification_obj, "id")
notification = comp_alert.notifications.add(notification_obj)
self.assertTrue(isinstance(notification, Notification))
call_args = mock_notification.call_args
uri_path = os.path.join(endpoint, "alerts/{}/notifications".format(comp_alert.id))
self.assertIn((uri_path,), call_args)


def testDeleteChildAlert(self):
comp_alert = self._createCompAlert()
with mock.patch('requests.Session.post', return_value=MockResponse(json.dumps(childAlert_1), 200)):
child_alert = self.argus.alerts.add_child_alert_to_composite_alert(comp_alert.id, Alert.from_dict(childAlert_1))
self.assertEqual(child_alert.alertType, 'COMPOSITE_CHILD')
self.assertTrue(isinstance(child_alert, Alert))

'''
Right after add, we can access the child_alert.id without triggering an API call (i.e., no mocking is required)
as it gets added to the local cache
'''
res = self.argus.alerts.get(child_alert.id)
with mock.patch('requests.Session.delete', return_value=MockResponse("", 200)) as mock_delete:
self.argus.alerts.delete_child_alert_from_composite_alert(comp_alert.id, child_alert.id)
call_args = mock_delete.call_args
uri_path = os.path.join(endpoint, "alerts/{}/children/{}".format(comp_alert.id, child_alert.id))
self.assertIn((uri_path,), call_args)

'''
After delete, the object should be gone from the local cache, so the get should result in an API call which
we are mocking to raise a 404 to mimic the real scenario
'''
with mock.patch('requests.Session.get', return_value=MockResponse("", 404)) as mockGet:
self.failUnlessRaises(ArgusObjectNotFoundException, lambda: self.argus.alerts.get(child_alert.id))

def testDeleteTriggerFromChildAlert(self):
comp_alert = self._createCompAlert()

with mock.patch('requests.Session.post', return_value=MockResponse(json.dumps(childAlert_1), 200)) as mock_add_childalert:
child_alert = self.argus.alerts.add_child_alert_to_composite_alert(comp_alert.id,
Alert.from_dict(childAlert_1))
self.assertEqual(child_alert.alertType, 'COMPOSITE_CHILD')
self.assertTrue(isinstance(child_alert, Alert))
call_args = tuple(mock_add_childalert.call_args)
uri_path = os.path.join(endpoint, "alerts/{}/children".format(comp_alert.id))
self.assertIn((uri_path,), call_args)

with mock.patch('requests.Session.post', return_value=MockResponse(json.dumps([childAlert_trigger_1]), 200)) as mock_trigger_post:
trigger_obj = Trigger.from_dict(childAlert_trigger_1)
delattr(trigger_obj,"id")
trigger = child_alert.triggers.add(trigger_obj)
self.assertTrue(isinstance(trigger, Trigger))
call_args = tuple(mock_trigger_post.call_args)
uri_path = os.path.join(endpoint, "alerts/{}/triggers".format(child_alert.id))
self.assertIn((uri_path,), call_args)

with mock.patch('requests.Session.delete', return_value=MockResponse("", 200)) as mock_delete:
child_alert.triggers.delete(trigger.id)
call_args = tuple(mock_trigger_post.call_args)
uri_path = os.path.join(endpoint, "alerts/{}/triggers".format(child_alert.id))
self.assertIn((uri_path,), call_args)

def testDeleteNotification(self):
comp_alert = self._createCompAlert()

with mock.patch('requests.Session.post', return_value=MockResponse(json.dumps([compAlert_notification]), 200)) as mock_notification:
notification_obj = Notification.from_dict(compAlert_notification)
delattr(notification_obj, "id")
notification = comp_alert.notifications.add(notification_obj)
self.assertTrue(isinstance(notification, Notification))
call_args = mock_notification.call_args
uri_path = os.path.join(endpoint, "alerts/{}/notifications".format(comp_alert.id))
self.assertIn((uri_path,), call_args)

with mock.patch('requests.Session.delete', return_value=MockResponse("", 200)) as mock_delete:
comp_alert.notifications.delete(notification.id)
call_args = tuple(mock_delete.call_args)
uri_path = os.path.join(endpoint, "alerts/{}/notifications/{}".format(comp_alert.id, notification.id))
self.assertIn((uri_path,), call_args)

def testGetCompAlertChildrenInfo(self):
with mock.patch('requests.Session.get', return_value=MockResponse(json.dumps([childAlert_1, childAlert_2]), 200)) as mock_get:
res = self.argus.alerts.get_composite_alert_children_info(compAlertID)
if res:
for obj in res:
self.assertTrue(isinstance(obj, Alert))
call_args = tuple(mock_get.call_args)
uri_path = os.path.join(endpoint, "alerts/{}/children/info".format(compAlertID))
self.assertIn((uri_path,), call_args)

def testGetCompAlertChildren(self):
with mock.patch('requests.Session.get', return_value=MockResponse(json.dumps([childAlert_1, childAlert_2]), 200)) as mock_get:
res = self.argus.alerts.get_composite_alert_children(compAlertID)
if res:
for obj in res:
self.assertTrue(isinstance(obj, Alert))
call_args = tuple(mock_get.call_args)
uri_path = os.path.join(endpoint, "alerts/{}/children".format(compAlertID))
self.assertIn((uri_path,), call_args)

def testUpdateCompAlert(self):
comp_alert = self._createCompAlert()

with mock.patch('requests.Session.put', return_value=MockResponse(json.dumps(compalert_D), 200)) as mock_update:
self.argus.alerts.update(compAlertID, Alert.from_dict(compalert_D))
alert_obj = self.argus.alerts.get(compAlertID)
self.assertTrue(isinstance(alert_obj, Alert))
alert_obj_dict = alert_obj.to_dict()
alert_dict = compalert_D
self.assertEquals(alert_obj_dict, alert_dict)
call_args = mock_update.call_args
uri_path = os.path.join(endpoint, "alerts/{}".format(compAlertID))
self.assertIn((uri_path,), call_args)