diff --git a/common/static/js/momonitoring.js b/common/static/js/momonitoring.js index 392a387..b5d3547 100644 --- a/common/static/js/momonitoring.js +++ b/common/static/js/momonitoring.js @@ -133,6 +133,66 @@ function deleteResource(urlEndpoint) { }); } +function setSilencedDescriptionFromField() { + if ($("#id_silenced_until").length === 0) { + return; + } + + // Both of these vars are timestamps (seconds since the epoch). + var now = new Date().getTime() / 1000; + var silencedUntil = parseInt($("#id_silenced_until").val()); + + function round(num) { + // Rounds 1.8 to 2, but 1.79 to 1. + return Math.floor(num + 0.2); + } + + var diffSeconds = round(silencedUntil - now); + var diffMinutes = round(diffSeconds / 60); + var diffHours = round(diffMinutes / 60); + var diffDays = round(diffHours / 24); + + var description; + + if (2000000000 <= silencedUntil) { + description = "Silenced forever"; + } else if (silencedUntil < now) { + description = "Not silenced"; + } else if (diffDays >= 2) { + description = "Silenced for ~" + diffDays + " day(s)"; + } else if (diffHours >= 2) { + description = "Silenced for ~" + diffHours + " hour(s)"; + } else if (diffMinutes >= 1) { + description = "Silenced for " + diffMinutes + " minute(s)"; + } else { + description = "Silenced for " + diffSeconds + " second(s)"; + } + + $("#silenced_description").text(description); +} + +function setSilencedFor(secondsFromNow) { + var now = new Date().getTime() / 1000; // Timestamp (seconds since the epoch). + var silencedUntil = Math.floor(now + secondsFromNow); + $("#id_silenced_until").val(silencedUntil); + setSilencedDescriptionFromField(); +} + +function setSilencedForever() { + $("#id_silenced_until").val(2000000000); + setSilencedDescriptionFromField(); +} + +function setUnSilenced() { + $("#id_silenced_until").val(0); + setSilencedDescriptionFromField(); +} + +function setSilencedForXHours() { + var hoursToSilenceFor = parseFloat($("#silence_hours").val()); + setSilencedFor(hoursToSilenceFor * 60 * 60); +} + function init(container$) { if(typeof(container$)==='undefined') container$ = $('body'); @@ -239,6 +299,18 @@ function init(container$) { }); }); + setSilencedDescriptionFromField(); + $('#id_silenced_until',container$).change(setSilencedDescriptionFromField); + $('#id_silenced_until',container$).click(setSilencedDescriptionFromField); + $('#id_silenced_until',container$).focus(setSilencedDescriptionFromField); + $('#id_silenced_until',container$).blur(setSilencedDescriptionFromField); + $('#id_silenced_until',container$).keyup(setSilencedDescriptionFromField); + $('#id_silenced_until',container$).keydown(setSilencedDescriptionFromField); + + $('#unsilence',container$).click(setUnSilenced); + $('#silence_for_x_hours',container$).click(setSilencedForXHours); + $('#silence_forever',container$).click(setSilencedForever); + $('form',container$).each(function() { var form$ = $(this); $('input',form$).keypress(function(event) { diff --git a/main/models/service.py b/main/models/service.py index cfdf26b..205ce14 100644 --- a/main/models/service.py +++ b/main/models/service.py @@ -77,6 +77,7 @@ def _send_alert_email(self,description): if not self.email_contact: logging.warning("No email contact for service %s" % self.name) try: + title = "{} Service Check Failed: {}".format(self.name, description) email_msg = get_template("alert_email.txt").render( Context({"description":description, "service_name":self.name, @@ -87,7 +88,7 @@ def _send_alert_email(self,description): }) ) - send_mail("MOMONITOR EVENT TRIGGERED", + send_mail(title, email_msg, settings.SERVER_EMAIL, [self.email_contact,], diff --git a/main/models/service_check.py b/main/models/service_check.py index 1306766..76d22ed 100644 --- a/main/models/service_check.py +++ b/main/models/service_check.py @@ -19,7 +19,7 @@ class Meta: name = models.CharField(max_length=256) description = models.TextField(null=True,blank=True) service = models.ForeignKey(Service,related_name="%(class)s") - silenced = models.BooleanField(default=False) + silenced_until = models.IntegerField(default=0) # This is a timestamp (seconds since unix epoch). alert_type = models.CharField(max_length=64,choices=ALERT_CHOICES,null=True,blank=True) frequency = models.CharField(max_length=128,null=True,blank=True) failures_before_alert = models.IntegerField(null=True,blank=True) @@ -27,6 +27,10 @@ class Meta: def __unicode__(self): return "%s: %s" % (self.service.name,self.name) + @property + def is_silenced(self): + return time.time() < self.silenced_until + @property def _redis_key(self): return "%s:::%s" % (self.resource_name,self.id) @@ -70,7 +74,7 @@ def num_failures(self): return self._get_state().get("num_failures",0) def send_alert(self,alert_type=None): - if not self.silenced: + if not self.is_silenced: self.service.send_alert(self.description or self.name,alert_type) else: logging.info("Triggered alert on %s, but it is silenced" % self.name) diff --git a/main/templates/main/index.html b/main/templates/main/index.html index 3c5a3a5..4e8acbb 100644 --- a/main/templates/main/index.html +++ b/main/templates/main/index.html @@ -20,7 +20,7 @@

All Services

{% if services %} {% for service in services %} - {{service.name}} {% if check.silenced or service.silenced %}silenced{% endif %} + {{service.name}} {% if check.is_silenced or service.silenced %}silenced{% endif %} diff --git a/main/templates/main/modal_forms/codeservicecheck.html b/main/templates/main/modal_forms/codeservicecheck.html index 589d4e3..4b44014 100644 --- a/main/templates/main/modal_forms/codeservicecheck.html +++ b/main/templates/main/modal_forms/codeservicecheck.html @@ -9,12 +9,17 @@ {{form.name}} {{form.description}} - -
- {{form.code_file}}
+
+ + + {{form.silenced_until}} + + + +

diff --git a/main/templates/main/modal_forms/compareservicecheck.html b/main/templates/main/modal_forms/compareservicecheck.html index f7c2571..37c5f21 100644 --- a/main/templates/main/modal_forms/compareservicecheck.html +++ b/main/templates/main/modal_forms/compareservicecheck.html @@ -9,9 +9,6 @@ {{form.name}} {{form.description}} - -
- {{form.endpoint}} @@ -21,6 +18,14 @@ {{form.comparator}} {{form.compared_value}}
+
+ + + {{form.silenced_until}} + + + +

diff --git a/main/templates/main/modal_forms/sensuservicecheck.html b/main/templates/main/modal_forms/sensuservicecheck.html index fd4949d..2e2e760 100644 --- a/main/templates/main/modal_forms/sensuservicecheck.html +++ b/main/templates/main/modal_forms/sensuservicecheck.html @@ -9,12 +9,17 @@ {{form.name}} {{form.description}} - -
- {{form.sensu_check_name}}
+
+ + + {{form.silenced_until}} + + + +

diff --git a/main/templates/main/modal_forms/simpleservicecheck.html b/main/templates/main/modal_forms/simpleservicecheck.html index 445bd3f..9689f8d 100644 --- a/main/templates/main/modal_forms/simpleservicecheck.html +++ b/main/templates/main/modal_forms/simpleservicecheck.html @@ -9,14 +9,19 @@ {{form.name}} {{form.description}} - -
- {{form.endpoint}} {{form.timeout}}
+
+ + + {{form.silenced_until}} + + + +

diff --git a/main/templates/main/modal_forms/umpireservicecheck.html b/main/templates/main/modal_forms/umpireservicecheck.html index 9ab2967..42eacb2 100644 --- a/main/templates/main/modal_forms/umpireservicecheck.html +++ b/main/templates/main/modal_forms/umpireservicecheck.html @@ -13,31 +13,37 @@ {{form.umpire_check_type}} {{form.umpire_range_type}} - -
- {{form.umpire_metric}} +
+
+ + + {{form.silenced_until}} + + + +
- - {{form.umpire_min}} - - {{form.umpire_max}} + + {{form.umpire_min}} + + {{form.umpire_max}}
- - {{form.umpire_percent_error}} - Error range will be computed over time based on past history + + {{form.umpire_percent_error}} + Error range will be computed over time based on past history
- - {{form.umpire_range}} + + {{form.umpire_range}}
- Range will be computed from the beginning of the day + Range will be computed from the beginning of the day
diff --git a/main/templates/main/tables/codeservicecheck.html b/main/templates/main/tables/codeservicecheck.html index 69d227c..c6ae28e 100644 --- a/main/templates/main/tables/codeservicecheck.html +++ b/main/templates/main/tables/codeservicecheck.html @@ -19,9 +19,9 @@

Code Checks {% if service_checks.count %} {% for check in service_checks|dictsort:"id" %} - + - {{check.name}} {% if check.silenced or service.silenced %}silenced{% endif %} + {{check.name}} {% if check.is_silenced or service.silenced %}silenced{% endif %} diff --git a/main/templates/main/tables/compareservicecheck.html b/main/templates/main/tables/compareservicecheck.html index 437f64b..26029df 100644 --- a/main/templates/main/tables/compareservicecheck.html +++ b/main/templates/main/tables/compareservicecheck.html @@ -22,10 +22,10 @@

Compare Checks {% if service_checks.count %} {% for check in service_checks.all|dictsort:"id" %} - + {{check.name}} - {% if check.silenced or service.silenced %}silenced{% endif %} + {% if check.is_silenced or service.silenced %}silenced{% endif %} diff --git a/main/templates/main/tables/sensuservicecheck.html b/main/templates/main/tables/sensuservicecheck.html index f2e4e3c..cc21b88 100644 --- a/main/templates/main/tables/sensuservicecheck.html +++ b/main/templates/main/tables/sensuservicecheck.html @@ -20,9 +20,9 @@

Sensu Checks {% if service_checks.count %} {% for check in service_checks.all|dictsort:"id" %} - + - {{check.name}} {% if check.silenced or service.silenced %}silenced{% endif %} + {{check.name}} {% if check.is_silenced or service.silenced %}silenced{% endif %} diff --git a/main/templates/main/tables/simpleservicecheck.html b/main/templates/main/tables/simpleservicecheck.html index cf7f818..144725a 100644 --- a/main/templates/main/tables/simpleservicecheck.html +++ b/main/templates/main/tables/simpleservicecheck.html @@ -19,9 +19,9 @@

Simple Checks {% if service_checks.count %} {% for check in service_checks|dictsort:"id" %} - + - {{check.name}} {% if check.silenced or service.silenced %}silenced{% endif %} + {{check.name}} {% if check.is_silenced or service.silenced %}silenced{% endif %} diff --git a/main/templates/main/tables/umpireservicecheck.html b/main/templates/main/tables/umpireservicecheck.html index 69f7dc7..4773bb3 100644 --- a/main/templates/main/tables/umpireservicecheck.html +++ b/main/templates/main/tables/umpireservicecheck.html @@ -19,10 +19,10 @@

Umpire Checks {% if service_checks.count %} {% for check in service_checks|dictsort:"id" %} - + {{check.name}} - {% if check.silenced or service.silenced %}silenced{% endif %} + {% if check.is_silenced or service.silenced %}silenced{% endif %} diff --git a/main/tests.py b/main/tests.py new file mode 100644 index 0000000..dd110d7 --- /dev/null +++ b/main/tests.py @@ -0,0 +1,33 @@ +from django.utils import unittest +import mock + +from momonitor.main.constants import STATUS_BAD +from momonitor.main.models import Service, SimpleServiceCheck + + +class ServiceCheckAlertTest(unittest.TestCase): + def setUp(self): + self.service = Service.objects.create( + name='test service', + alert_type='pagerduty') + self.service_check = SimpleServiceCheck.objects.create( + endpoint="http://twitter.com", + service=self.service) + + self.service._send_alert_pagerduty = mock.Mock() + self.service._send_alert_email = mock.Mock() + + def test_service_check_alert(self): + self.service_check.set_state(STATUS_BAD, None) + + self.service._send_alert_pagerduty.assert_called_with('') + assert not self.service._send_alert_email.called + + def test_service_check_alert_override(self): + self.service_check.alert_type = 'email' + self.service_check.save() + + self.service_check.set_state(STATUS_BAD, None) + + assert not self.service._send_alert_pagerduty.called + self.service._send_alert_email.assert_called_with('') diff --git a/mobile/templates/mobile/checks/base.html b/mobile/templates/mobile/checks/base.html index b61977c..6fe7676 100644 --- a/mobile/templates/mobile/checks/base.html +++ b/mobile/templates/mobile/checks/base.html @@ -3,11 +3,11 @@ {% block body %}
-

Check: {{check.name}} {% if check.silenced or check.service.silenced %}(silenced){% endif %}

+

Check: {{check.name}} {% if check.is_silenced or check.service.silenced %}(silenced){% endif %}

Back {% if not check.service.silenced %} - {% if check.silenced %}Unsilence{% else %}Silence{% endif %} + {% if check.is_silenced %}Unsilence{% else %}Silence{% endif %} {% endif %}
diff --git a/urls.py b/urls.py index 00fb9e4..1147918 100644 --- a/urls.py +++ b/urls.py @@ -1,5 +1,7 @@ from django.conf.urls.defaults import * from django.contrib.staticfiles.urls import staticfiles_urlpatterns +from django.contrib.auth.decorators import login_required +from django.views.static import serve from django.conf import settings urlpatterns = patterns('', @@ -7,7 +9,7 @@ url('^social_auth/', include('social_auth.urls')), url('^mobile/', include('momonitor.mobile.urls',namespace="mobile")), url('^slideshow/', include('momonitor.slideshow.urls',namespace="slideshow")), - url(r'^media/(?P.*)$', 'django.views.static.serve', { + url(r'^media/(?P.*)$', login_required(serve), { 'document_root': settings.MEDIA_ROOT}), )