diff options
-rw-r--r-- | mirrors/templatetags/__init__.py | 0 | ||||
-rw-r--r-- | mirrors/templatetags/mirror_status.py | 15 | ||||
-rw-r--r-- | mirrors/views.py | 50 | ||||
-rw-r--r-- | templates/mirrors/status.html | 53 | ||||
-rw-r--r-- | templates/mirrors/status_table.html | 29 | ||||
-rw-r--r-- | urls.py | 1 |
6 files changed, 148 insertions, 0 deletions
diff --git a/mirrors/templatetags/__init__.py b/mirrors/templatetags/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/mirrors/templatetags/__init__.py diff --git a/mirrors/templatetags/mirror_status.py b/mirrors/templatetags/mirror_status.py new file mode 100644 index 00000000..09c5b331 --- /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 b4c2c2c7..a31c1371 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 00000000..8dd6fa11 --- /dev/null +++ b/templates/mirrors/status.html @@ -0,0 +1,53 @@ +{% extends "base.html" %} + +{% block title %}Arch Linux - Mirror Status{% endblock %} + +{% block content %} +<div id="mirrorstatus" class="box"> + <h2>Mirror Status</h2> + + <h3>Out of Sync Mirrors</h3> + {% with bad_urls as urls %} + {% include "mirrors/status_table.html" %} + {% endwith %} + + <h3>Successfully Syncing Mirrors</h3> + {% with good_urls as urls %} + {% include "mirrors/status_table.html" %} + {% endwith %} + + <h3>Mirror Syncing Error Log</h3> + <table class="results"> + <thead> + <tr> + <th>Mirror URL</th> + <th>Protocol</th> + <th>Country</th> + <th>Error Message</th> + <th>Last Occurred</th> + <th>Occurrences (last 24 hours)</th> + </tr> + </thead> + <tbody> + {% for log in error_logs %} + <tr class="{% cycle 'odd' 'even' %}"> + <td>{{ log.url__url }}</td> + <td>{{ log.url__protocol__protocol }}</td> + <td>{{ log.url__mirror__country }}</td> + <td>{{ log.error }}</td> + <td>{{ log.check_time__max|date:'Y-m-d H:i' }}</td> + <td>{{ log.error__count }}</td> + </tr> + {% endfor %} + </tbody> + </table> + +</div> +{% load cdn %}{% jquery %} +<script type="text/javascript" src="/media/jquery.tablesorter.min.js"></script> +<script type="text/javascript"> +$(document).ready(function() { + $(".results").tablesorter({widgets: ['zebra']}); +}); +</script> +{% endblock %} diff --git a/templates/mirrors/status_table.html b/templates/mirrors/status_table.html new file mode 100644 index 00000000..d7f5b0ec --- /dev/null +++ b/templates/mirrors/status_table.html @@ -0,0 +1,29 @@ +{% load mirror_status %} +<table class="results"> + <thead> + <tr> + <th>Mirror URL</th> + <th>Protocol</th> + <th>Country</th> + <th>Last Sync</th> + <th>Delay (hh:mm)</th> + <th>μ Duration (secs)</th> + <th>σ Duration (secs)</th> + <th>Mirror Score</th> + </tr> + </thead> + <tbody> + {% for m_url in urls %} + <tr class="{% cycle 'odd' 'even' %}"> + <td>{{ m_url.url }}</td> + <td>{{ m_url.protocol }}</td> + <td>{{ m_url.mirror.country }}</td> + <td>{{ m_url.last_sync|date:'Y-m-d H:i'|default:'unknown' }}</td> + <td>{{ m_url.delay|duration|default:'unknown' }}</td> + <td>{{ m_url.duration_avg|floatformat:2|default:'unknown' }}</td> + <td>{{ m_url.duration_stddev|floatformat:2|default:'unknown' }}</td> + <td>{{ m_url.score|floatformat:1|default:'unknown' }}</td> + </tr> + {% endfor %} + </tbody> +</table> @@ -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']}), |