summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mirrors/templatetags/__init__.py0
-rw-r--r--mirrors/templatetags/mirror_status.py15
-rw-r--r--mirrors/views.py50
-rw-r--r--templates/mirrors/status.html53
-rw-r--r--templates/mirrors/status_table.html29
-rw-r--r--urls.py1
6 files changed, 148 insertions, 0 deletions
diff --git a/mirrors/templatetags/__init__.py b/mirrors/templatetags/__init__.py
new file mode 100644
index 0000000..e69de29
--- /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 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 %}
+<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 0000000..d7f5b0e
--- /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>
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']}),