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

Support for multiple notifications #4

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

amckenna-sfdc
Copy link

@amckenna-sfdc amckenna-sfdc commented Jan 24, 2017

The current code silently discards notifications when adding more than one using syntax like so:

        alertobj = Alert(
            alert_name,
            alert_expr,
            alert['alert']['cron_entry'],
            trigger=trigger,
            enabled=True,
            notifications=notifications,
            missingDataNotificationEnabled=True,
        )

@hdara-sfdc
Copy link
Contributor

Apologies for not paying attention, I wasn't apparently watching this project and so haven't received notifications of the PR. I will get back to you soon.

@hdara-sfdc
Copy link
Contributor

Thanks for highlighting the fact that multiple notifications are not being handled correctly. There is actually a bigger problem here with the overall design and interface, as I don't think loading an alert even works as expected when there are multiple notifications. The same should be applicable for triggers too. We need to think through the interface a bit and redesign it and fix the missing functionality. I have some ideas and will try it out. I will create an issue to track this.

Copy link
Contributor

@hdara-sfdc hdara-sfdc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just submitted a fix for issue #1, which so please rebase against this latest change.

Please add unit tests. I have added a couple of new tests in test_service.py which can serve as basis for you.

@@ -391,7 +391,18 @@ def add(self, alert):
alertobj.trigger = alertobj.triggers.add(alert.trigger)
if alert.notification:
alertobj.notification = alertobj.notifications.add(alert.notification)
if alert.trigger and alert.notification:
elif alert.notifications and isinstance(alert.notifications, list):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you make the same change for alert.triggers also?

@@ -324,7 +324,8 @@ def notifications(self):
@notifications.setter
def notifications(self, value):
if not isinstance(value, list): raise ValueError("value should be of list type, but is: %s" % type(value))
# TODO Check for item type also
for item in value:
if not isinstance(item, Notification): raise ValueError("array member should be of Notification type, but is: %s" % type(item))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need the same change for triggers too.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The notifications and triggers properties would be a list only for new Alert object, as otherwise these would be set to a service instance. Additional validations are required to ensure that argus_id of these objects is None. Also ensure that self.argus_id itself is None.

notifications = []
for notification in alert.notifications:
notifications.append(alertobj.notifications.add(notification))
alertobj.notifications = notifications
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By this time, alertobj.notifications is already set by the prior call to _fill() as a service object, so we need to call alertobj.notifications._init_all(notifications) on it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I think this is not required now, since alertobj.notifications.add() is already taking care of populating the service cache, so you may just drop the local notifications list.

alertobj.notifications = notifications
if alert.trigger and alert.notifications:
alertobj.trigger.notificationsIds = []
for notification in alertobj.notifications:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would change to alertobj.notifications.items(), as this would remain a service object at this point. I guess the difference in the type of this object for new vs. existing alert is going to make it confusing, but since the iteration is only useful on an existing alert, it may not be all that bad.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I mentioned earlier, alertobj.notifications should remain a service object, so this iteration will change.

if alert.trigger and alert.notifications:
alertobj.trigger.notificationsIds = []
for notification in alertobj.notifications:
self.argus.alerts.add_notification_trigger(alertobj.id, notification.id, alertobj.trigger.id)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this automatically connects notifications, but only when there is a single trigger. Could you add some additional documentation to this method on this behavior?

@amckenna-sfdc
Copy link
Author

Thanks for reviewing this. I have some Python work slated for next sprint so hopefully i'll have time to work on this then.

@hdara-sfdc
Copy link
Contributor

@amckenna-sfdc Any chance you can work on this PR again?

@amckenna-sfdc
Copy link
Author

amckenna-sfdc commented Oct 25, 2017 via email

@amckenna-sfdc
Copy link
Author

amckenna-sfdc commented Oct 25, 2017 via email

@hdara-sfdc
Copy link
Contributor

Sounds good!

@salesforce-cla
Copy link

Thanks for the contribution! Before we can merge this, we need @amckenna-sfdc to sign the Salesforce Contributor License Agreement.

Copy link
Contributor

@hdara-sfdc hdara-sfdc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@amckenna-sfdc Thanks for fixing the conflicts! I am not sure if I should have waited for another change, but I took a quick look anyway and here is my overall feedback:

  • Your Salesforce CLA is still pending
  • At least some of the previous review comments are still valid
  • I added a few new comments, as I got some additional clarity on the service objects
  • We need new unit tests to cover these new scenarios
  • Some documentation updates are needed

notifications = []
for notification in alert.notifications:
notifications.append(alertobj.notifications.add(notification))
alertobj.notifications = notifications
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

alertobj.notifications is expected to be a service object of type AlertNotificationsServiceClient, so this will break the contract. You can however use the notifications list to initialize the collection that is behind the service object so that it will avoid one API call.

@@ -416,7 +416,18 @@ def add(self, alert):
alertobj.trigger = alertobj.triggers.add(alert.trigger)
if alert.notification:
alertobj.notification = alertobj.notifications.add(alert.notification)
if alert.trigger and alert.notification:
elif alert.notifications and isinstance(alert.notifications, list):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The notifications member of a new alert should never be anything other than a list type. It is worth establishing this at the beginning of the method and drop the check here. Also, what if both notification and notifications members exist?

alertobj.notifications = notifications
if alert.trigger and alert.notifications:
alertobj.trigger.notificationsIds = []
for notification in alertobj.notifications:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I mentioned earlier, alertobj.notifications should remain a service object, so this iteration will change.

for notification in alert.notifications:
notifications.append(alertobj.notifications.add(notification))
alertobj.notifications = notifications
if alert.trigger and alert.notifications:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't the logic here same as the existing logic for a single notification? You should be able to condense both into one loop (i.e., if you initialize a list with a single notification).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants