You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

95 lines
2.8 KiB

  1. import time
  2. from threading import Thread
  3. from django.core.management.base import BaseCommand
  4. from django.db import connection
  5. from django.utils import timezone
  6. from hc.api.models import Check
  7. def notify(check_id, stdout):
  8. check = Check.objects.get(id=check_id)
  9. tmpl = "\nSending alert, status=%s, code=%s\n"
  10. stdout.write(tmpl % (check.status, check.code))
  11. errors = check.send_alert()
  12. for ch, error in errors:
  13. stdout.write("ERROR: %s %s %s\n" % (ch.kind, ch.value, error))
  14. def notify_on_thread(check_id, stdout):
  15. t = Thread(target=notify, args=(check_id, stdout))
  16. t.start()
  17. class Command(BaseCommand):
  18. help = 'Sends UP/DOWN email alerts'
  19. owned = Check.objects.filter(user__isnull=False)
  20. def add_arguments(self, parser):
  21. parser.add_argument(
  22. '--no-loop',
  23. action='store_false',
  24. dest='loop',
  25. default=True,
  26. help='Do not keep running indefinitely in a 2 second wait loop',
  27. )
  28. def handle_one(self):
  29. """ Process a single check. """
  30. now = timezone.now()
  31. # Look for checks that are going down
  32. q = self.owned.filter(alert_after__lt=now, status="up")
  33. check = q.first()
  34. # If none found, look for checks that are going up
  35. if not check:
  36. q = self.owned.filter(alert_after__gt=now, status="down")
  37. check = q.first()
  38. if check is None:
  39. return False
  40. q = Check.objects.filter(id=check.id, status=check.status)
  41. current_status = check.get_status()
  42. if check.status == current_status:
  43. # Stored status is already up-to-date. Update alert_after
  44. # as needed but don't send notifications
  45. q.update(alert_after=check.get_alert_after())
  46. return True
  47. else:
  48. # Atomically update status to the opposite
  49. num_updated = q.update(status=current_status)
  50. if num_updated == 1:
  51. # Send notifications only if status update succeeded
  52. # (no other sendalerts process got there first)
  53. notify_on_thread(check.id, self.stdout)
  54. return True
  55. return False
  56. def handle(self, *args, **options):
  57. if not options["loop"]:
  58. x = 0
  59. while self.handle_one():
  60. # returns True when there are more alerts to send.
  61. x += 1
  62. return "Sent %d alert(s)" % x
  63. self.stdout.write("sendalerts is now running")
  64. ticks = 0
  65. while True:
  66. while self.handle_one():
  67. ticks = 0
  68. ticks += 1
  69. time.sleep(2)
  70. if ticks % 60 == 0:
  71. formatted = timezone.now().isoformat()
  72. self.stdout.write("-- MARK %s --" % formatted)
  73. connection.close()