From 40ac4818aa7812a5399a0d4c176137984d5cfd30 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sun, 12 Sep 2010 10:14:34 -0500 Subject: Add mirror status view Signed-off-by: Dan McGee --- mirrors/templatetags/__init__.py | 0 mirrors/templatetags/mirror_status.py | 15 ++++++++++ mirrors/views.py | 50 +++++++++++++++++++++++++++++++++ templates/mirrors/status.html | 53 +++++++++++++++++++++++++++++++++++ templates/mirrors/status_table.html | 29 +++++++++++++++++++ urls.py | 1 + 6 files changed, 148 insertions(+) create mode 100644 mirrors/templatetags/__init__.py create mode 100644 mirrors/templatetags/mirror_status.py create mode 100644 templates/mirrors/status.html create mode 100644 templates/mirrors/status_table.html diff --git a/mirrors/templatetags/__init__.py b/mirrors/templatetags/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mirrors/templatetags/mirror_status.py b/mirrors/templatetags/mirror_status.py new file mode 100644 index 0000000..09c5b33 --- /dev/null +++ b/mirrors/templatetags/mirror_status.py @@ -0,0 +1,15 @@ +from django import template + +register = template.Library() + +@register.filter +def duration(value): + if not value: + return u'\u221e' + # does not take microseconds into account + total_secs = value.seconds + value.days * 24 * 3600 + mins, secs = divmod(total_secs, 60) + hrs, mins = divmod(mins, 60) + return '%d:%02d' % (hrs, mins) + +# vim: set ts=4 sw=4 et: diff --git a/mirrors/views.py b/mirrors/views.py index b4c2c2c..a31c137 100644 --- a/mirrors/views.py +++ b/mirrors/views.py @@ -1,9 +1,14 @@ from django import forms +from django.db.models import Avg, Count, Max, Min, StdDev +from django.db.models import Q from django.views.decorators.csrf import csrf_exempt from django.views.generic.simple import direct_to_template from main.utils import make_choice from .models import Mirror, MirrorUrl, MirrorProtocol +from .models import MirrorLog + +import datetime class MirrorlistForm(forms.Form): country = forms.MultipleChoiceField(required=False) @@ -49,4 +54,49 @@ def find_mirrors(request, countries=None, protocols=None): }, mimetype='text/plain') +def status(request): + cutoff_time = datetime.datetime.utcnow() - datetime.timedelta(hours=24) + bad_timedelta = datetime.timedelta(days=3) + + protocols = MirrorProtocol.objects.exclude(protocol__iexact='rsync') + # I swear, this actually has decent performance... + urls = MirrorUrl.objects.select_related( + 'mirror', 'protocol').filter( + mirror__active=True, mirror__public=True, + protocol__in=protocols).filter( + logs__check_time__gte=cutoff_time).annotate( + check_count=Count('logs'), last_sync=Max('logs__last_sync'), + last_check=Max('logs__check_time'), + duration_avg=Avg('logs__duration'), duration_min=Min('logs__duration'), + duration_max=Max('logs__duration'), duration_stddev=StdDev('logs__duration') + ).order_by('mirror__country', 'url') + # errors during check process go in another table + error_logs = MirrorLog.objects.filter( + is_success=False, check_time__gte=cutoff_time).values( + 'url__url', 'url__protocol__protocol', 'url__mirror__country', + 'error').annotate(Count('error'), Max('check_time')) + + good_urls = [] + bad_urls = [] + for url in urls: + if url.last_check and url.last_sync: + d = url.last_check - url.last_sync + url.delay = d + url.score = d.days * 24 + d.seconds / 3600 + url.duration_avg + url.duration_stddev + else: + url.delay = None + url.score = None + # split them into good and bad lists based on delay + if not url.delay or url.delay > bad_timedelta: + bad_urls.append(url) + else: + good_urls.append(url) + + context = { + 'good_urls': good_urls, + 'bad_urls': bad_urls, + 'error_logs': error_logs, + } + return direct_to_template(request, 'mirrors/status.html', context) + # vim: set ts=4 sw=4 et: diff --git a/templates/mirrors/status.html b/templates/mirrors/status.html new file mode 100644 index 0000000..8dd6fa1 --- /dev/null +++ b/templates/mirrors/status.html @@ -0,0 +1,53 @@ +{% extends "base.html" %} + +{% block title %}Arch Linux - Mirror Status{% endblock %} + +{% block content %} +
+

Mirror Status

+ +

Out of Sync Mirrors

+ {% with bad_urls as urls %} + {% include "mirrors/status_table.html" %} + {% endwith %} + +

Successfully Syncing Mirrors

+ {% with good_urls as urls %} + {% include "mirrors/status_table.html" %} + {% endwith %} + +

Mirror Syncing Error Log

+ + + + + + + + + + + + + {% for log in error_logs %} + + + + + + + + + {% endfor %} + +
Mirror URLProtocolCountryError MessageLast OccurredOccurrences (last 24 hours)
{{ log.url__url }}{{ log.url__protocol__protocol }}{{ log.url__mirror__country }}{{ log.error }}{{ log.check_time__max|date:'Y-m-d H:i' }}{{ log.error__count }}
+ +
+{% load cdn %}{% jquery %} + + +{% endblock %} diff --git a/templates/mirrors/status_table.html b/templates/mirrors/status_table.html new file mode 100644 index 0000000..d7f5b0e --- /dev/null +++ b/templates/mirrors/status_table.html @@ -0,0 +1,29 @@ +{% load mirror_status %} + + + + + + + + + + + + + + + {% for m_url in urls %} + + + + + + + + + + + {% endfor %} + +
Mirror URLProtocolCountryLast SyncDelay (hh:mm)μ Duration (secs)σ Duration (secs)Mirror Score
{{ m_url.url }}{{ m_url.protocol }}{{ m_url.mirror.country }}{{ m_url.last_sync|date:'Y-m-d H:i'|default:'unknown' }}{{ m_url.delay|duration|default:'unknown' }}{{ m_url.duration_avg|floatformat:2|default:'unknown' }}{{ m_url.duration_stddev|floatformat:2|default:'unknown' }}{{ m_url.score|floatformat:1|default:'unknown' }}
diff --git a/urls.py b/urls.py index f2ef341..7cc60cf 100644 --- a/urls.py +++ b/urls.py @@ -72,6 +72,7 @@ urlpatterns = patterns('', (r'^news/$', 'news.views.news_list', {}, 'news-list'), (r'^mirrors/$', 'devel.views.mirrorlist', {}, 'mirrors-list'), + (r'^mirrors/status/$', 'mirrors.views.status', {}, 'mirrors-status'), (r'^mirrorlist/$', 'mirrors.views.generate_mirrorlist', {}, 'mirrorlist'), (r'^mirrorlist/all/$', 'mirrors.views.find_mirrors', {'countries': ['all']}), -- cgit v1.2.3-24-g4f1b