Alerts

Now that we have a basic status page up and running, let's talk about allowing the user to configure some alert conditions. For now, we will inform the user of any alert condition by showing that node's information in red color on the status page.

First, we need to figure out what kind of alerts we want our users to set. From there, we can figure out the technical details. So, let's think about it. Given that the data types we are recording all have numeric values, it makes sense that the user should be able to set thresholds. They can, for instance, set an alert if the system load of any node goes above 1.0 or if the disk usage of a node goes above 80%.

Furthermore, maybe our users don't want to have the same alert conditions for each node. A database node is expected to handle a lot of system load, so maybe our users want to have a separate alert condition for the database node. Finally, if they are doing maintenance on some of the nodes, they may want to stop some alerts from triggering.

From all this, it seems that our alerts need to have fields to hold the following:

  • Data type on which to trigger
  • Maximum value to trigger on
  • Minimum value to trigger on
  • Node name to trigger on
  • If the alert is currently active

Of these, the data type and active status are required fields that should never be null. The node name can be an empty string in which the alert conditions will be checked for each node. If the node name is not an empty string, it will be checked for nodes whose names match the provided string exactly.

As for the maximum and minimum values, one of those is required. This is so that the user may set alerts for just the maximum value without having to care about the minimum value for the data points. This will require manual validation in the model.

The model

Let's look at the model. To keep things simple, we'll use the data_collector app instead of creating a new one for alerts. Here is the code for our Alert model. Put this in data_collector/models.py after the DataPoint model code:

class Alert(models.Model):
    data_type = models.CharField(max_length=100)
    min_value = models.FloatField(null=True, blank=True)
    max_value = models.FloatField(null=True, blank=True)
    node_name = models.CharField(max_length=250, blank=True)

    is_active = models.BooleanField(default=True)

    def save(self, *args, **kwargs):
        if self.min_value is None and self.max_value is None:
            raise models.exceptions.ValidationError('Both min and max value can not be empty for an alert')

        super(Alert, self).save(*args, **kwargs)

Due to our special requirements for the min and max fields, we had to override the save method. As you can probably tell, our custom save method raises an error if both the min and max values are not set. As there is no way to express this condition with normal Django field configuration, we have to override the save method and add our custom logic here. This is a pretty common thing to do in Django if you have some custom validation requirements that depend on more than one field.

One more thing to note is the blank=True parameter to the min and max FloatField. This is required so that any model forms constructed from this model, which we will use for the create and update views later, allow blank values for these fields.

Make and run migrations to add this to your database.

> python manage.py makemigrations data_collector
> python manage.py migrate data_collector

Management views

The users will need some views that they can use to manage alerts. They will need pages to view all the alerts defined in the system, a page to create new alerts and edit existing ones, and some way to delete alerts they no longer require. All of these are achievable using the generic view provided by Django and some templates. Let's get to it!

First, let's look at the list view first. Add this to data_collector/views.py:

class AlertListView(ListView):
    template_name = 'alerts_list.html'
    model = Alert

Remember to import ListView from django.views.generic and Alert from data_collector.models. Next, create the alerts_list.html template file in data_collector/templates and give it the following content:

{% extends "base.html" %}

{% block content %}
<h1>Defined Alerts</h1>

{% if object_list %}
<table>
    <tr>
        <th>Data Type</th>
        <th>Min Value</th>
        <th>Max Value</th>
        <th>Node Name</th>
        <th>Is Active</th>
    </tr>

    {% for alert in object_list %}
    <tr>
        <td>{{ alert.data_type }}</td>
        <td>{{ alert.min_value }}</td>
        <td>{{ alert.max_value }}</td>
        <td>{{ alert.node_name }}</td>
        <td>{{ alert.is_active }}</td>
    </tr>
    {% endfor %}
</table>
{% else %}
<i>No alerts defined</i>
{% endif %}
{% endblock %}

Finally, edit djagios/urls.py. Import the new view, and then add this to the URL patterns:

url(r'^alerts/$', AlertListView.as_view(), name='alerts-list'),

To test it out, open http://127.0.0.1:8000/alerts/. You should see the No Alerts Defined message. The list view is pretty basic. The ListVew generic view renders a template with all the objects for the specified model, providing the list of objects in the object_list template context variable. Next, let's look at the view to create new alerts.

In the data_collector/view.py file, first import the following:

from django.core.urlresolvers import reverse
from django.views.generic import CreateView

Then add this view class:

class NewAlertView(CreateView):
    template_name = 'create_or_update_alert.html'
    model = Alert
    fields = [
        'data_type', 'min_value', 'max_value', 'node_name', 'is_active'
    ]

    def get_success_url(self):
        return reverse('alerts-list')

Nothing new in the view code. The template code is quite simple as well. Put this code in data_collector/templates/create_or_update_alert.html:

{% extends "base.html" %}

{% block content %}
{% if object %}
<h1>Update Alert</h1>
{% else %}
<h1>New Alert</h1>
{% endif %}

<form action="" method="post">{% csrf_token %}
    {{ form.as_p }}
    <input type="submit" value="{% if object %}Update{% else %}Create{% endif %}" />
    <a href="{% url 'alerts-list' %}">Cancel</a>
</form>
{% endblock %}

As in previous chapters, we use the object context variable to decide if this template was used from CreateView or UpdateView and change some elements based on this. Otherwise, it's pretty straightforward. Let's see the code for UpdateView as well:

class EditAlertView(UpdateView):
    template_name = 'create_or_update_alert.html'
    model = Alert
    fields = [
        'data_type', 'min_value', 'max_value', 'node_name', 'is_active'
    ]

    def get_success_url(self):
        return reverse('alerts-list')

It's an almost identical copy of the previous create view. Make sure that you have imported the UpdateView generic view. We still need to add both of these views to our URL configuration. In the djagios/urls.py file, import both NewAlertView and EditAlertView and add these patterns:

url(r'^alerts/new/$', NewAlertView.as_view(), name='alerts-new'),
url(r'^alerts/(?P<pk>d+)/edit/$', EditAlertView.as_view(), name='alerts-edit'),

Before we can test these views, we should add links to allow users to get to these views. Modify the alerts_list.html template to match this code:

{% extends "base.html" %}

{% block content %}
<h1>Defined Alerts</h1>

{% if object_list %}
<table>
    <tr>
        <th>Data Type</th>
        <th>Min Value</th>
        <th>Max Value</th>
        <th>Node Name</th>
        <th>Is Active</th>
    </tr>

    {% for alert in object_list %}
    <tr>
        <td>{{ alert.data_type }}</td>
        <td>{{ alert.min_value }}</td>
        <td>{{ alert.max_value }}</td>
        <td>{{ alert.node_name }}</td>
        <td>{{ alert.is_active }}</td>
        <td><a href="{% url 'alerts-edit' pk=alert.pk %}">Edit</a></td>
    </tr>
    {% endfor %}
</table>
{% else %}
<i>No alerts defined</i>
{% endif %}
<p><a href="{% url 'alerts-new' %}">Add New Alert</a></p>
{% endblock %}

Two new lines, which are highlighted, have been added. Now, let's see what our alerts list page looks like. As before, open http://127.0.0.1:8000/alerts/ in your browser. You should see a page as follows:

Management views

Click on the Add New Alert link and you should see the form to create an alert. Fill it in with some sample data and click on the Create button. If your form didn't have any errors, you should be back to the alerts list view and your screen should now list the new alert, as shown in the following screenshot:

Management views

All that's left now is to allow users the option to delete their alerts. For this, create a view that subclasses from the generic DeleteView, remembering to import DeleteView from django.views.generic first. Here's the code you should put in data_collector/view.py:

class DeleteAlertView(DeleteView):
    template_name = 'delete_alert.html'
    model = Alert

    def get_success_url(self):
        return reverse('alerts-list')

Create a new data_collector/templates/delete_alert.html template:

{% extends "base.html" %}

{% block content %}
<h1>Delete alert?</h1>
<p>Are you sure you want to delete this alert?</p>
<form action="" method="post">{% csrf_token %}
    {{ form.as_p }}
    <input type="submit" value="Delete" />
    <a href="{% url 'alerts-list' %}">Cancel</a>
</form>
{% endblock %}

Next, import DeleteAlertView in djagios/urls.py and add this new pattern:

url(r'^alerts/(?P<pk>d+)/delete/$', DeleteAlertView.as_view(), name='alerts-delete'),

Finally, let's add a link to the delete view from the alerts list page. Edit the alerts_list.html template and add this line right after the Edit link:

<td><a href="{% url 'alerts-delete' pk=alert.pk %}">Delete</a></td>

Now when you open the alerts list view, you should see a Delete link. Your screen should look similar to the following screenshot:

Management views

If you click on the Delete link, you should see a confirmation page. If you confirm the deletion, you will see that your alert will be gone from the list page. These are all the views that we will need to manage alerts. Let's move on to detecting alert conditions and showing them in the status page.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.47.218