From fae0cfdc4a1ce56edf91a1992dcbe9750f892867 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= Date: Wed, 27 Dec 2017 11:17:20 +0100 Subject: [PATCH] general: add service availability basics (#9416) --- debian/passerelle.cron.d | 9 ++-- passerelle/apps/base_adresse/models.py | 5 ++ passerelle/apps/feeds/models.py | 7 +++ passerelle/apps/opengis/models.py | 9 ++++ passerelle/base/management/commands/cron.py | 2 +- passerelle/base/migrations/0006_resourcestatus.py | 29 +++++++++++ passerelle/base/models.py | 60 ++++++++++++++++++++++ passerelle/static/css/style.css | 9 ++++ .../templates/passerelle/manage/service_view.html | 6 ++- 9 files changed, 130 insertions(+), 6 deletions(-) create mode 100644 passerelle/base/migrations/0006_resourcestatus.py diff --git a/debian/passerelle.cron.d b/debian/passerelle.cron.d index 14e1930..d72cd8c 100644 --- a/debian/passerelle.cron.d +++ b/debian/passerelle.cron.d @@ -1,6 +1,7 @@ MAILTO=root -17 * * * * passerelle /usr/bin/passerelle-manage tenant_command cron --all-tenants hourly -25 1 * * * passerelle /usr/bin/passerelle-manage tenant_command cron --all-tenants daily -47 2 * * 7 passerelle /usr/bin/passerelle-manage tenant_command cron --all-tenants weekly -52 3 1 * * passerelle /usr/bin/passerelle-manage tenant_command cron --all-tenants monthly +*/5 * * * * passerelle /usr/bin/passerelle-manage tenant_command cron --all-tenants availability +17 * * * * passerelle /usr/bin/passerelle-manage tenant_command cron --all-tenants hourly +25 1 * * * passerelle /usr/bin/passerelle-manage tenant_command cron --all-tenants daily +47 2 * * 7 passerelle /usr/bin/passerelle-manage tenant_command cron --all-tenants weekly +52 3 1 * * passerelle /usr/bin/passerelle-manage tenant_command cron --all-tenants monthly diff --git a/passerelle/apps/base_adresse/models.py b/passerelle/apps/base_adresse/models.py index 9b2d6ae..44c6187 100644 --- a/passerelle/apps/base_adresse/models.py +++ b/passerelle/apps/base_adresse/models.py @@ -121,6 +121,11 @@ class BaseAdresse(BaseResource): return {'data': result} + def check_status(self): + result = self.search(None, '169 rue du chateau, paris') + if len(result) == 0: + raise Exception('no results') + def daily(self): super(BaseAdresse, self).daily() if not self.zipcode: diff --git a/passerelle/apps/feeds/models.py b/passerelle/apps/feeds/models.py index 62de62e..08ef452 100644 --- a/passerelle/apps/feeds/models.py +++ b/passerelle/apps/feeds/models.py @@ -37,3 +37,10 @@ class Feed(BaseResource): response.raise_for_status() feed = feedparser.parse(response.content) return {'data': feed} + + def check_status(self): + if not self.url: + return + feed = self.json(None) + if not feed['data'].get('feed'): + raise Exception('empty feed') diff --git a/passerelle/apps/opengis/models.py b/passerelle/apps/opengis/models.py index 9725b3e..16314bb 100644 --- a/passerelle/apps/opengis/models.py +++ b/passerelle/apps/opengis/models.py @@ -73,6 +73,15 @@ class OpenGIS(BaseResource): def get_wfs_service_version(self, renew=False): return self.get_service_version('wfs', self.wfs_service_url, renew=renew) + def check_status(self): + if self.wms_service_url: + response = self.requests.get(self.wms_service_url, + params={'service': 'WMS', 'request': 'GetCapabilities'}) + response.raise_for_status() + if self.wfs_service_url: + response = self.requests.get(self.wfs_service_url, + params={'service': 'WFS', 'request': 'GetCapabilities'}) + response.raise_for_status() @endpoint(perm='can_access', description='Get features', parameters={'type_names': {'description': _('Type of feature to query'), 'example_value':'feature'}, diff --git a/passerelle/base/management/commands/cron.py b/passerelle/base/management/commands/cron.py index 64e3450..7745cd1 100644 --- a/passerelle/base/management/commands/cron.py +++ b/passerelle/base/management/commands/cron.py @@ -34,7 +34,7 @@ class Command(BaseCommand): def handle(self, frequency, **options): - if frequency not in ('hourly', 'daily', 'weekly', 'monthly'): + if frequency not in ('hourly', 'daily', 'weekly', 'monthly', 'availability'): raise CommandError('unknown frequency') errors = [] for app in get_all_apps(): diff --git a/passerelle/base/migrations/0006_resourcestatus.py b/passerelle/base/migrations/0006_resourcestatus.py new file mode 100644 index 0000000..7c89c61 --- /dev/null +++ b/passerelle/base/migrations/0006_resourcestatus.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('contenttypes', '0002_remove_content_type_name'), + ('base', '0005_resourcelog'), + ] + + operations = [ + migrations.CreateModel( + name='ResourceStatus', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('resource_pk', models.PositiveIntegerField()), + ('start_timestamp', models.DateTimeField(auto_now_add=True)), + ('status', models.CharField(default=b'unknown', max_length=20, choices=[(b'unknown', 'Unknown'), (b'up', 'Up'), (b'down', 'Down')])), + ('message', models.CharField(max_length=500, blank=True)), + ('resource_type', models.ForeignKey(to='contenttypes.ContentType')), + ], + options={ + 'ordering': ['-start_timestamp'], + }, + ), + ] diff --git a/passerelle/base/models.py b/passerelle/base/models.py index f12884f..568e593 100644 --- a/passerelle/base/models.py +++ b/passerelle/base/models.py @@ -225,6 +225,13 @@ class BaseResource(models.Model): _('Access (%s) is limited to the following API users:') % permission) return [{'key': x[0], 'label': x[1]} for x in perms.items()] + def get_availabity_status(self): + resource_type = ContentType.objects.get_for_model(self) + current_status = ResourceStatus.objects.filter( + resource_type=resource_type, + resource_pk=self.pk).first() + return current_status + def export_json(self): d = { '@type': 'passerelle-resource', @@ -355,6 +362,36 @@ class BaseResource(models.Model): slug=self.slug, timestamp__lt=timestamp).delete() + def check_status(self): + # should raise an exception if status is not ok + raise NotImplementedError + + def availability(self): + # "availability" cron job to update service statuses + try: + self.check_status() + status = 'up' + message = '' + except NotImplementedError: + return + except Exception as e: + status = 'down' + message = unicode(e) + + resource_type = ContentType.objects.get_for_model(self) + current_status = ResourceStatus.objects.filter( + resource_type=resource_type, + resource_pk=self.pk).first() + if not current_status or status != current_status.status: + ResourceStatus( + resource_type=resource_type, + resource_pk=self.pk, + status=status, + message=message).save() + elif status == 'down': + current_status.message = message + current_status.save() + def hourly(self): pass @@ -409,6 +446,29 @@ class ResourceLog(models.Model): return '%s %s %s %s' % (self.timestamp, self.levelno, self.appname, self.slug) +STATUS_CHOICES = ( + ('unknown', _('Unknown')), + ('up', _('Up')), + ('down', _('Down')), +) + +class ResourceStatus(models.Model): + resource_type = models.ForeignKey(ContentType) + resource_pk = models.PositiveIntegerField() + start_timestamp = models.DateTimeField(auto_now_add=True) + status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='unknown') + message = models.CharField(max_length=500, blank=True) + + class Meta: + ordering = ['-start_timestamp'] + + def up(self): + return self.status == 'up' + + def down(self): + return self.status == 'down' + + class ProxyLogger(object): def __init__(self, level, appname=None, slug=None): diff --git a/passerelle/static/css/style.css b/passerelle/static/css/style.css index 3026a49..cb82736 100644 --- a/passerelle/static/css/style.css +++ b/passerelle/static/css/style.css @@ -4,6 +4,15 @@ i.varname { font-style: normal; } +span.down { + background: #CD2026; + color: white; + padding: 0 0.5ex; + font-size: 70%; + border-radius: 5px; + cursor: help; +} + div#queries, div#security, div#logs, diff --git a/passerelle/templates/passerelle/manage/service_view.html b/passerelle/templates/passerelle/manage/service_view.html index e00b4e4..7538796 100644 --- a/passerelle/templates/passerelle/manage/service_view.html +++ b/passerelle/templates/passerelle/manage/service_view.html @@ -7,7 +7,11 @@ {% endblock %} {% block appbar %} -

{{ view.model.get_verbose_name }} - {{ object.title }}

+

{{ view.model.get_verbose_name }} - {{ object.title }} + {% with status=object.get_availabity_status %} + {% if status.down %}{% trans 'Down' %}{% endif %} + {% endwith %} +

{% if object|can_edit:request.user %} {% trans 'edit' %} {% endif %} -- 2.15.1