manage availability check through the UI (#29965)
This commit is contained in:
parent
d501c6055b
commit
fa76fbc8d7
|
@ -0,0 +1,30 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.17 on 2019-02-05 10:26
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('contenttypes', '0002_remove_content_type_name'),
|
||||
('base', '0010_loggingparameters_trace_emails'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='AvailabilityParameters',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('resource_pk', models.PositiveIntegerField()),
|
||||
('run_check', models.BooleanField(default=True, verbose_name='Run regular availability checks')),
|
||||
('resource_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.ContentType')),
|
||||
],
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='availabilityparameters',
|
||||
unique_together=set([('resource_type', 'resource_pk')]),
|
||||
),
|
||||
]
|
|
@ -176,6 +176,18 @@ class BaseResource(models.Model):
|
|||
parameters.log_level = value
|
||||
parameters.save()
|
||||
|
||||
@property
|
||||
def availability_parameters(self):
|
||||
resource_type = ContentType.objects.get_for_model(self)
|
||||
try:
|
||||
return AvailabilityParameters.objects.get(
|
||||
resource_type=resource_type,
|
||||
resource_pk=self.id)
|
||||
except AvailabilityParameters.DoesNotExist:
|
||||
return AvailabilityParameters(
|
||||
resource_type=resource_type,
|
||||
resource_pk=self.id)
|
||||
|
||||
def soap_client(self, **kwargs):
|
||||
return passerelle.utils.SOAPClient(resource=self, **kwargs)
|
||||
|
||||
|
@ -387,9 +399,15 @@ class BaseResource(models.Model):
|
|||
def check_status(self):
|
||||
# should raise an exception if status is not ok
|
||||
raise NotImplementedError
|
||||
check_status.not_implemented = True
|
||||
|
||||
def availability(self):
|
||||
# "availability" cron job to update service statuses
|
||||
|
||||
# eventually skip it
|
||||
if not self.availability_parameters.run_check:
|
||||
return
|
||||
|
||||
currently_down = self.down()
|
||||
try:
|
||||
self.check_status()
|
||||
|
@ -477,6 +495,18 @@ class LoggingParameters(models.Model):
|
|||
unique_together = (('resource_type', 'resource_pk'))
|
||||
|
||||
|
||||
class AvailabilityParameters(models.Model):
|
||||
resource_type = models.ForeignKey(ContentType)
|
||||
resource_pk = models.PositiveIntegerField()
|
||||
resource = fields.GenericForeignKey('resource_type', 'resource_pk')
|
||||
run_check = models.BooleanField(
|
||||
default=True, verbose_name=_('Run regular availability checks'),
|
||||
help_text=_('Run an availability check every 5 minutes'))
|
||||
|
||||
class Meta:
|
||||
unique_together = (('resource_type', 'resource_pk'))
|
||||
|
||||
|
||||
|
||||
class ResourceLog(models.Model):
|
||||
timestamp = models.DateTimeField(auto_now_add=True)
|
||||
|
|
|
@ -2,7 +2,7 @@ from django.conf.urls import url
|
|||
|
||||
from .views import ApiUserCreateView, ApiUserUpdateView, ApiUserDeleteView, \
|
||||
ApiUserListView, AccessRightDeleteView, AccessRightCreateView, \
|
||||
LoggingParametersUpdateView
|
||||
LoggingParametersUpdateView, ManageAvailabilityView
|
||||
|
||||
access_urlpatterns = [
|
||||
url(r'^$', ApiUserListView.as_view(), name='apiuser-list'),
|
||||
|
@ -15,5 +15,8 @@ access_urlpatterns = [
|
|||
url(r'^accessright/add/(?P<resource_type>[\w,-]+)/(?P<resource_pk>[\w,-]+)/(?P<codename>[\w,-]+)/',
|
||||
AccessRightCreateView.as_view(), name='access-right-add'),
|
||||
url(r'logging/parameters/(?P<resource_type>[\w,-]+)/(?P<resource_pk>[\w,-]+)/$',
|
||||
LoggingParametersUpdateView.as_view(), name='logging-parameters')
|
||||
LoggingParametersUpdateView.as_view(), name='logging-parameters'),
|
||||
url(r'manage/availability/(?P<resource_type>[\w,-]+)/(?P<resource_pk>[\w,-]+)/$',
|
||||
ManageAvailabilityView.as_view(), name='manage-availability')
|
||||
|
||||
]
|
||||
|
|
|
@ -5,7 +5,7 @@ from django.forms import models as model_forms
|
|||
from django.views.generic import *
|
||||
from django.http import Http404
|
||||
|
||||
from .models import ApiUser, AccessRight, LoggingParameters
|
||||
from .models import ApiUser, AccessRight, LoggingParameters, AvailabilityParameters, ResourceStatus
|
||||
from .forms import ApiUserForm, AccessRightForm
|
||||
from ..utils import get_trusted_services
|
||||
|
||||
|
@ -30,6 +30,7 @@ class ResourceView(DetailView):
|
|||
context['absolute_uri'] = '%s%s' % (
|
||||
context['site_base_uri'],
|
||||
self.request.path)
|
||||
|
||||
return context
|
||||
|
||||
|
||||
|
@ -136,3 +137,54 @@ class LoggingParametersUpdateView(FormView):
|
|||
parameters.trace_emails = form.cleaned_data['trace_emails']
|
||||
parameters.save()
|
||||
return super(LoggingParametersUpdateView, self).form_valid(form)
|
||||
|
||||
|
||||
class ManageAvailabilityView(FormView):
|
||||
template_name = 'passerelle/manage/manage_availability_form.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(ManageAvailabilityView, self).get_context_data(**kwargs)
|
||||
connector = self.get_resource()
|
||||
context['connector'] = connector
|
||||
context['availability_status'] = connector.get_availability_status()
|
||||
return context
|
||||
|
||||
def get_form_class(self):
|
||||
form_class = model_forms.modelform_factory(
|
||||
AvailabilityParameters,
|
||||
fields=['run_check'])
|
||||
return form_class
|
||||
|
||||
def get_initial(self):
|
||||
d = self.initial.copy()
|
||||
d['resource_type'] = self.kwargs['resource_type']
|
||||
d['resource_pk'] = self.kwargs['resource_pk']
|
||||
d['run_check'] = self.get_resource().availability_parameters.run_check
|
||||
return d
|
||||
|
||||
def get_resource(self):
|
||||
content_type = ContentType.objects.get_for_id(self.kwargs['resource_type'])
|
||||
return content_type.model_class().objects.get(pk=self.kwargs['resource_pk'])
|
||||
|
||||
def get_success_url(self):
|
||||
return self.get_resource().get_absolute_url()
|
||||
|
||||
def form_valid(self, form):
|
||||
resource = self.get_resource()
|
||||
parameters = resource.availability_parameters
|
||||
run_check = form.cleaned_data['run_check']
|
||||
|
||||
if not run_check and resource.down():
|
||||
resource_type = ContentType.objects.get_for_model(resource)
|
||||
ResourceStatus(
|
||||
resource_type=resource_type,
|
||||
resource_pk=self.kwargs['resource_pk'],
|
||||
status='up',
|
||||
message='').save()
|
||||
|
||||
if parameters.run_check != run_check:
|
||||
parameters.run_check = run_check
|
||||
parameters.save()
|
||||
resource.logger.info(u'availability checks %s', 'enabled' if run_check else 'disabled')
|
||||
|
||||
return super(ManageAvailabilityView, self).form_valid(form)
|
||||
|
|
|
@ -602,6 +602,11 @@ class PlanitechConnector(BaseResource):
|
|||
}
|
||||
}
|
||||
|
||||
def check_status(self):
|
||||
auth_url = urlparse.urljoin(self.url, 'auth')
|
||||
response = self.requests.get(auth_url, headers={'MH-LOGIN': self.username})
|
||||
response.raise_for_status()
|
||||
|
||||
|
||||
class Pairing(models.Model):
|
||||
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
{% extends "passerelle/manage.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block appbar %}
|
||||
<h2>{% trans 'Connector Status' %} : {{availability_status.status}}</h2>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
<div class="buttons">
|
||||
<button class="submit-button">{% trans 'Save' %}</button>
|
||||
<a href="{{ connector.get_absolute_url }}" class="cancel">{% trans 'Cancel' %}</a>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
|
@ -15,6 +15,9 @@
|
|||
{% endwith %}
|
||||
</h2>
|
||||
<span class="actions">
|
||||
{% if object|can_edit:request.user and has_check_status %}
|
||||
<a rel="popup" href="{% url 'manage-availability' resource_type=object|resource_type resource_pk=object.id %}">{% trans 'availability check' %}</a>
|
||||
{% endif %}
|
||||
{% if object|can_edit:request.user %}
|
||||
<a rel="popup" href="{% url 'logging-parameters' resource_type=object|resource_type resource_pk=object.id %}">{% trans 'logging parameters' %}</a>
|
||||
{% endif %}
|
||||
|
|
|
@ -138,6 +138,13 @@ class GenericConnectorMixin(object):
|
|||
|
||||
|
||||
class GenericConnectorView(GenericConnectorMixin, DetailView):
|
||||
|
||||
def get_context_data(self, slug=None, **kwargs):
|
||||
context = super(GenericConnectorView, self).get_context_data(**kwargs)
|
||||
context['has_check_status'] = not hasattr(
|
||||
context['object'].check_status, 'not_implemented')
|
||||
return context
|
||||
|
||||
def get_template_names(self):
|
||||
template_names = super(DetailView, self).get_template_names()[:]
|
||||
if self.model.manager_view_template_name:
|
||||
|
|
|
@ -73,3 +73,23 @@ def test_feed_availability(app, connector):
|
|||
connector.availability()
|
||||
assert connector.get_availability_status().down()
|
||||
assert '500' in connector.get_availability_status().message
|
||||
|
||||
|
||||
def test_availability_checks_disabled(app, connector):
|
||||
with HTTMock(up_mock):
|
||||
connector.availability()
|
||||
assert connector.get_availability_status().up()
|
||||
|
||||
av = connector.availability_parameters
|
||||
av.run_check = False
|
||||
av.save()
|
||||
|
||||
with HTTMock(down_mock):
|
||||
connector.availability()
|
||||
assert connector.get_availability_status().up()
|
||||
|
||||
av.run_check = True
|
||||
av.save()
|
||||
with HTTMock(down_mock):
|
||||
connector.availability()
|
||||
assert connector.get_availability_status().down()
|
||||
|
|
|
@ -7,7 +7,7 @@ from django.contrib.contenttypes.models import ContentType
|
|||
from django.core.files import File
|
||||
import pytest
|
||||
|
||||
from passerelle.base.models import ApiUser, AccessRight, ResourceLog
|
||||
from passerelle.base.models import ApiUser, AccessRight, ResourceLog, ResourceStatus
|
||||
from passerelle.apps.csvdatasource.models import CsvDataSource, Query
|
||||
|
||||
pytestmark = pytest.mark.django_db
|
||||
|
@ -197,3 +197,54 @@ def test_logging_parameters(app, admin_user):
|
|||
resp = app.get(csv.get_absolute_url())
|
||||
resp = resp.click('logging parameters')
|
||||
assert resp.form['trace_emails'].value == 'fred@localhost'
|
||||
|
||||
|
||||
def test_availability_parameters(app, admin_user, monkeypatch):
|
||||
data = StringIO('1;Foo\n2;Bar\n3;Baz')
|
||||
csv = CsvDataSource.objects.create(
|
||||
csv_file=File(data, 't.csv'),
|
||||
columns_keynames='id, text', slug='test', title='a title', description='a description')
|
||||
app = login(app)
|
||||
resp = app.get(csv.get_absolute_url())
|
||||
|
||||
assert csv.availability_parameters.run_check
|
||||
# csv connector has the default check_status which does nothing
|
||||
# so availability check is hidden
|
||||
assert 'availability check' not in resp.text
|
||||
|
||||
def check_status(*args, **kwargs):
|
||||
return True
|
||||
|
||||
monkeypatch.setattr(CsvDataSource, 'check_status', check_status)
|
||||
|
||||
resp = app.get(csv.get_absolute_url())
|
||||
assert 'availability check' in resp.text
|
||||
|
||||
resp = resp.click('availability check')
|
||||
assert 'up' in resp.text
|
||||
resp.form['run_check'] = False
|
||||
resp = resp.form.submit()
|
||||
# Connector status not changed, availability parameters changed
|
||||
assert not csv.availability_parameters.run_check
|
||||
|
||||
resp = app.get(csv.get_absolute_url())
|
||||
resp = resp.click('availability check')
|
||||
resp.form['run_check'] = True
|
||||
resp = resp.form.submit()
|
||||
|
||||
# Connector down
|
||||
resource_type = ContentType.objects.get_for_model(csv)
|
||||
status = ResourceStatus(
|
||||
resource_type=resource_type, resource_pk=csv.pk,
|
||||
status='down', message='')
|
||||
status.save()
|
||||
assert csv.down()
|
||||
resp = app.get(csv.get_absolute_url())
|
||||
resp = resp.click('availability check')
|
||||
resp.form['run_check'] = False
|
||||
resp = resp.form.submit()
|
||||
# Connector is put back up
|
||||
assert not csv.availability_parameters.run_check
|
||||
assert not csv.down()
|
||||
status = csv.get_availability_status()
|
||||
assert status.status == 'up'
|
||||
|
|
Loading…
Reference in New Issue