Projet

Général

Profil

0001-general-add-service-availability-basics-9416.patch

Frédéric Péters, 27 décembre 2017 11:26

Télécharger (9,94 ko)

Voir les différences:

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
debian/passerelle.cron.d
1 1
MAILTO=root
2 2

  
3
17 * * * * passerelle /usr/bin/passerelle-manage tenant_command cron --all-tenants hourly
4
25 1 * * * passerelle /usr/bin/passerelle-manage tenant_command cron --all-tenants daily
5
47 2 * * 7 passerelle /usr/bin/passerelle-manage tenant_command cron --all-tenants weekly
6
52 3 1 * * passerelle /usr/bin/passerelle-manage tenant_command cron --all-tenants monthly
3
*/5 * * * * passerelle /usr/bin/passerelle-manage tenant_command cron --all-tenants availability
4
17  * * * * passerelle /usr/bin/passerelle-manage tenant_command cron --all-tenants hourly
5
25  1 * * * passerelle /usr/bin/passerelle-manage tenant_command cron --all-tenants daily
6
47  2 * * 7 passerelle /usr/bin/passerelle-manage tenant_command cron --all-tenants weekly
7
52  3 1 * * passerelle /usr/bin/passerelle-manage tenant_command cron --all-tenants monthly
passerelle/apps/base_adresse/models.py
121 121

  
122 122
        return {'data': result}
123 123

  
124
    def check_status(self):
125
        result = self.search(None, '169 rue du chateau, paris')
126
        if len(result) == 0:
127
            raise Exception('no results')
128

  
124 129
    def daily(self):
125 130
        super(BaseAdresse, self).daily()
126 131
        if not self.zipcode:
passerelle/apps/feeds/models.py
37 37
        response.raise_for_status()
38 38
        feed = feedparser.parse(response.content)
39 39
        return {'data': feed}
40

  
41
    def check_status(self):
42
        if not self.url:
43
            return
44
        feed = self.json(None)
45
        if not feed['data'].get('feed'):
46
            raise Exception('empty feed')
passerelle/apps/opengis/models.py
73 73
    def get_wfs_service_version(self, renew=False):
74 74
        return self.get_service_version('wfs', self.wfs_service_url, renew=renew)
75 75

  
76
    def check_status(self):
77
        if self.wms_service_url:
78
            response = self.requests.get(self.wms_service_url,
79
                    params={'service': 'WMS', 'request': 'GetCapabilities'})
80
            response.raise_for_status()
81
        if self.wfs_service_url:
82
            response = self.requests.get(self.wfs_service_url,
83
                    params={'service': 'WFS', 'request': 'GetCapabilities'})
84
            response.raise_for_status()
76 85

  
77 86
    @endpoint(perm='can_access', description='Get features',
78 87
              parameters={'type_names': {'description': _('Type of feature to query'), 'example_value':'feature'},
passerelle/base/management/commands/cron.py
34 34

  
35 35

  
36 36
    def handle(self, frequency, **options):
37
        if frequency not in ('hourly', 'daily', 'weekly', 'monthly'):
37
        if frequency not in ('hourly', 'daily', 'weekly', 'monthly', 'availability'):
38 38
            raise CommandError('unknown frequency')
39 39
        errors = []
40 40
        for app in get_all_apps():
passerelle/base/migrations/0006_resourcestatus.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4
from django.db import migrations, models
5

  
6

  
7
class Migration(migrations.Migration):
8

  
9
    dependencies = [
10
        ('contenttypes', '0002_remove_content_type_name'),
11
        ('base', '0005_resourcelog'),
12
    ]
13

  
14
    operations = [
15
        migrations.CreateModel(
16
            name='ResourceStatus',
17
            fields=[
18
                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
19
                ('resource_pk', models.PositiveIntegerField()),
20
                ('start_timestamp', models.DateTimeField(auto_now_add=True)),
21
                ('status', models.CharField(default=b'unknown', max_length=20, choices=[(b'unknown', 'Unknown'), (b'up', 'Up'), (b'down', 'Down')])),
22
                ('message', models.CharField(max_length=500, blank=True)),
23
                ('resource_type', models.ForeignKey(to='contenttypes.ContentType')),
24
            ],
25
            options={
26
                'ordering': ['-start_timestamp'],
27
            },
28
        ),
29
    ]
passerelle/base/models.py
225 225
                    _('Access (%s) is limited to the following API users:') % permission)
226 226
        return [{'key': x[0], 'label': x[1]} for x in perms.items()]
227 227

  
228
    def get_availabity_status(self):
229
        resource_type = ContentType.objects.get_for_model(self)
230
        current_status = ResourceStatus.objects.filter(
231
                resource_type=resource_type,
232
                resource_pk=self.pk).first()
233
        return current_status
234

  
228 235
    def export_json(self):
229 236
        d = {
230 237
            '@type': 'passerelle-resource',
......
355 362
                slug=self.slug,
356 363
                timestamp__lt=timestamp).delete()
357 364

  
365
    def check_status(self):
366
        # should raise an exception if status is not ok
367
        raise NotImplementedError
368

  
369
    def availability(self):
370
        # "availability" cron job to update service statuses
371
        try:
372
            self.check_status()
373
            status = 'up'
374
            message = ''
375
        except NotImplementedError:
376
            return
377
        except Exception as e:
378
            status = 'down'
379
            message = unicode(e)
380

  
381
        resource_type = ContentType.objects.get_for_model(self)
382
        current_status = ResourceStatus.objects.filter(
383
                resource_type=resource_type,
384
                resource_pk=self.pk).first()
385
        if not current_status or status != current_status.status:
386
            ResourceStatus(
387
                resource_type=resource_type,
388
                resource_pk=self.pk,
389
                status=status,
390
                message=message).save()
391
        elif status == 'down':
392
            current_status.message = message
393
            current_status.save()
394

  
358 395
    def hourly(self):
359 396
        pass
360 397

  
......
409 446
        return '%s %s %s %s' % (self.timestamp, self.levelno, self.appname, self.slug)
410 447

  
411 448

  
449
STATUS_CHOICES = (
450
    ('unknown', _('Unknown')),
451
    ('up', _('Up')),
452
    ('down', _('Down')),
453
)
454

  
455
class ResourceStatus(models.Model):
456
    resource_type = models.ForeignKey(ContentType)
457
    resource_pk = models.PositiveIntegerField()
458
    start_timestamp = models.DateTimeField(auto_now_add=True)
459
    status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='unknown')
460
    message = models.CharField(max_length=500, blank=True)
461

  
462
    class Meta:
463
        ordering = ['-start_timestamp']
464

  
465
    def up(self):
466
        return self.status == 'up'
467

  
468
    def down(self):
469
        return self.status == 'down'
470

  
471

  
412 472
class ProxyLogger(object):
413 473

  
414 474
    def __init__(self, level, appname=None, slug=None):
passerelle/static/css/style.css
4 4
	font-style: normal;
5 5
}
6 6

  
7
span.down {
8
	background: #CD2026;
9
	color: white;
10
	padding: 0 0.5ex;
11
	font-size: 70%;
12
	border-radius: 5px;
13
	cursor: help;
14
}
15

  
7 16
div#queries,
8 17
div#security,
9 18
div#logs,
passerelle/templates/passerelle/manage/service_view.html
7 7
{% endblock %}
8 8

  
9 9
{% block appbar %}
10
<h2>{{ view.model.get_verbose_name }} - {{ object.title }}</h2>
10
<h2>{{ view.model.get_verbose_name }} - {{ object.title }}
11
    {% with status=object.get_availabity_status %}
12
    {% if status.down %}<span class="down" title="{{status.message}} {% trans 'since:' %} {{status.start_timestamp|date:"SHORT_DATETIME_FORMAT"}} ">{% trans 'Down' %}</span>{% endif %}
13
    {% endwith %}
14
</h2>
11 15
{% if object|can_edit:request.user %}
12 16
<a rel="popup" href="{{ object.get_edit_url }}">{% trans 'edit' %}</a>
13 17
{% endif %}
14
-