Pēteris Caune 5cf6f1b51e
Merge Check.get_status() and Check.in_grace_period() into one.
This avoids duplicate calls to Check.get_grace_start() in several places.
2018-06-11 19:05:18 +03:00

112 lines
3.3 KiB
Python

import time
from threading import Thread
from django.core.management.base import BaseCommand
from django.utils import timezone
from hc.api.models import Check
def notify(check_id, stdout):
check = Check.objects.get(id=check_id)
tmpl = "Sending alert, status=%s, code=%s\n"
stdout.write(tmpl % (check.status, check.code))
# Set dates for followup nags
if check.status == "down" and check.user.profile:
check.user.profile.set_next_nag_date()
# Send notifications
errors = check.send_alert()
for ch, error in errors:
stdout.write("ERROR: %s %s %s\n" % (ch.kind, ch.value, error))
def notify_on_thread(check_id, stdout):
t = Thread(target=notify, args=(check_id, stdout))
t.start()
class Command(BaseCommand):
help = 'Sends UP/DOWN email alerts'
owned = Check.objects.filter(user__isnull=False).order_by("alert_after")
def add_arguments(self, parser):
parser.add_argument(
'--no-loop',
action='store_false',
dest='loop',
default=True,
help='Do not keep running indefinitely in a 2 second wait loop',
)
parser.add_argument(
'--no-threads',
action='store_false',
dest='use_threads',
default=False,
help='Send alerts synchronously, without using threads',
)
def handle_one(self, use_threads=True):
""" Process a single check. """
now = timezone.now()
# Look for checks that are going down
q = self.owned.filter(alert_after__lt=now, status="up")
check = q.first()
# If none found, look for checks that are going up
if not check:
q = self.owned.filter(alert_after__gt=now, status="down")
check = q.first()
if check is None:
return False
q = Check.objects.filter(id=check.id, status=check.status)
current_status = check.get_status()
# During the grace period sendalerts considers the check as "up":
if current_status == "grace":
current_status = "up"
if check.status == current_status:
# Stored status is already up-to-date. Update alert_after
# as needed but don't send notifications
q.update(alert_after=check.get_alert_after())
return True
else:
# Atomically update status to the opposite
num_updated = q.update(status=current_status)
if num_updated == 1:
# Send notifications only if status update succeeded
# (no other sendalerts process got there first)
if use_threads:
notify_on_thread(check.id, self.stdout)
else:
notify(check.id, self.stdout)
return True
return False
def handle(self, use_threads=True, loop=True, *args, **options):
self.stdout.write("sendalerts is now running\n")
i, sent = 0, 0
while True:
while self.handle_one(use_threads):
sent += 1
if not loop:
break
time.sleep(2)
i += 1
if i % 60 == 0:
timestamp = timezone.now().isoformat()
self.stdout.write("-- MARK %s --\n" % timestamp)
return "Sent %d alert(s)" % sent