Skip to content

Commit

Permalink
Implement sender whitelist filters
Browse files Browse the repository at this point in the history
- senders with no filters will allow everything to pass
- senders with filters enabled will check labels for whitelist
  • Loading branch information
kfdm committed Mar 11, 2019
1 parent ba8ba0e commit e14a7a8
Show file tree
Hide file tree
Showing 11 changed files with 205 additions and 50 deletions.
6 changes: 6 additions & 0 deletions promgen/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,5 +160,11 @@ class Meta:
exclude = ['content_type', 'object_id', 'owner']


class NotifierUpdate(forms.ModelForm):
class Meta:
model = models.Sender
exclude = ['value']


class HostForm(forms.Form):
hosts = forms.CharField(widget=forms.Textarea)
22 changes: 18 additions & 4 deletions promgen/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,12 +132,26 @@ def test(self):
tasks.send_alert(self.sender, self.value, data)

def filtered(self, alert):
logger.debug('Checking labels %s', alert['commonLabels'])
"""
Check filters for a specific sender
If no filters are defined, then we let the message through
If filters are defined, then we check to see if at least one filter matches
If no filters match, then we assume it's filtered out
"""
logger.debug("Checking labels %s", alert["commonLabels"])
# If we have no specific whitelist, then we let everything through
if self.filter_set.count() == 0:
return False

# If we have filters defined, then we need to check to see if our
# filters match
for f in self.filter_set.all():
logger.debug("Checking filter %s %s", f.name, f.value)
if alert['commonLabels'].get(f.name) == f.value:
return True
return False
if alert["commonLabels"].get(f.name) == f.value:
return False
# If none of our filters match, then we blacklist this sender
return True


class Filter(models.Model):
Expand Down
9 changes: 9 additions & 0 deletions promgen/static/js/promgen.vue.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,15 @@ var app = new Vue({
this_.globalAlerts = alerts.data;
});

},
setTargetList: function(event, target) {
// get the list name
let dst = event.target.list.id;
// and our selected value
let src = event.target.value;
// and set the target list
let tgt = document.getElementById(target);
tgt.setAttribute('list', dst + '.' + src);
}
},
computed: {
Expand Down
24 changes: 24 additions & 0 deletions promgen/templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,30 @@
<script src="{% static "/js/promgen.js" %}"></script>
<script src="{% static "/js/promgen.vue.js" %}"></script>
{% block javascript %}{% endblock %}


<datalist style="display:none" id="common.labels">
<select>
<option>severity</option>
</select>
</datalist>

<datalist style="display:none" id="common.annotations">
<select>
<option>summary</option>
<option>grafana</option>
<option>runbook</option>
</select>
</datalist>

<datalist style="display:none" id="common.labels.severity">
<select>
<option>critical</option>
<option>major</option>
<option>minor</option>
<option>debug</option>
</select>
</datalist>
</body>

</html>
23 changes: 5 additions & 18 deletions promgen/templates/promgen/notifier_block.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,12 @@
<tr>
<th>Notifier</th>
<th>Value</th>
<th>Filters</th>
{% if show_edit %}
<th>Actions</th>
{% endif %}
</tr>
{% for notifier in object.notifiers.all %}
<tr>
<td title="Added by: {{notifier.owner}}">{{ notifier.sender }}</td>
<td>{{ notifier.show_value }}</td>
{% if show_edit %}
<td>
<form method="post" action="{% url 'notifier-test' notifier.id %}" style="display: inline">
{% csrf_token %}
<button class="btn btn-danger btn-xs">{% trans "Test" %}</button>
</form>
</td>
<td>
<form method="post" action="{% url 'notifier-delete' notifier.id %}" onsubmit="return confirm('{% trans "Delete notificiation?" %}')" style="display: inline">
{% csrf_token %}
<button class="btn btn-danger btn-xs">{% trans "Delete" %}</button>
</form>
</td>
{% endif %}
</tr>
{% include 'promgen/sender_row.html' %}
{% endfor %}
</table>
23 changes: 23 additions & 0 deletions promgen/templates/promgen/sender_form.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{% extends "base.html" %}
{% load i18n %}
{% load promgen %}
{% block content %}


<div class="page-header">
<h1>{{object|klass}}: {{object.name}}</h1>
</div>

{% breadcrumb object 'Update Notifier' %}

<table class="table table-bordered table-condensed{% if collapse %} collapse" id="{{ collapse }}{% endif %}">
<tr>
<th>Notifier</th>
<th>Value</th>
<th>Filters</th>
<th>Actions</th>
</tr>
{% include 'promgen/sender_row.html' with notifier=object show_edit=1 %}
</table>

{% endblock %}
43 changes: 43 additions & 0 deletions promgen/templates/promgen/sender_row.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{% load i18n %}
<tr>
<td title="Added by: {{notifier.owner}}">{{ notifier.sender }}</td>
<td>{{ notifier.show_value }}</td>
<td>
{% for f in notifier.filter_set.all %}
<form method="post" action="{% url 'notifier-edit' notifier.id %}" onsubmit="return confirm('Delete this filter?')" style="display: inline">
{% csrf_token %}
<input name="next" type="hidden" value="{{ request.get_full_path }}" />
<input name="filter.pk" value="{{f.id}}" type="hidden" />
<button class="label label-primary" style="display: inline-block;">
{{f.name}}:{{f.value}}
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span>
</button>
</form>
{% endfor %}

<button class="btn btn-primary btn-xs" data-toggle="collapse" data-target="#notifierLabel{{notifier.id}}">+</button>
<div class="collapse" id="notifierLabel{{notifier.id}}">
<form method="post" action="{% url 'notifier-edit' notifier.id %}" style="display: inline">
{% csrf_token %}
<input name="next" type="hidden" value="{{ request.get_full_path }}" />
<input name="filter.name" placeholder="name" required list="common.labels" @change="setTargetList($event, 'newLabel{{notifier.id}}')">
<input name="filter.value" placeholder="value" required id="newLabel{{notifier.id}}">
<button class="btn btn-primary btn-xs">Submit</button>
</form>
</div>
</td>
{% if show_edit %}
<td>
<a href="{% url 'notifier-edit' notifier.id %}" class="btn btn-warning btn-xs">{% trans "Edit" %}</a>
<form method="post" action="{% url 'notifier-test' notifier.id %}" style="display: inline">
{% csrf_token %}
<input name="next" type="hidden" value="{{ request.get_full_path }}" />
<button class="btn btn-info btn-xs">{% trans "Test" %}</button>
</form>
<form method="post" action="{% url 'notifier-delete' notifier.id %}" onsubmit="return confirm('{% trans "Delete notificiation?" %}')" style="display: inline">
{% csrf_token %}
<button class="btn btn-danger btn-xs">{% trans "Delete" %}</button>
</form>
</td>
{% endif %}
</tr>
66 changes: 42 additions & 24 deletions promgen/templates/promgen/status.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,46 @@ <h1>{{user.username}} ({{user.email}})</h1>
<div class="panel panel-primary">
<div class="panel-heading">Subscriptions</div>
<table class="table">
{% for notifier in subscriptions %}
<tr>
<th>&nbsp;</th>
<th>Filters</th>
<th>Actions</th>
</tr>
{% for notifier in subscriptions %}
<tr>
<td><a href="{{notifier.content_object.get_absolute_url}}">{{notifier.content_object}}</td>
<td>
{% for f in notifier.filter_set.all %}
<span class="label label-primary" style="display: inline-block;">
{{f.name}}:{{f.value}}
</span>
{% endfor %}
</td>
<td>
<a href="{% url 'notifier-edit' notifier.id %}" class="btn btn-warning btn-xs">{% trans "Edit" %}</a>
<form method="post" action="{% url 'notifier-test' notifier.id %}" style="display: inline">
{% csrf_token %}
<input name="next" type="hidden" value="{{ request.get_full_path }}" />
<button class="btn btn-info btn-xs">{% trans "Test" %}</button>
</form>
<form method="post" action="{% url 'notifier-delete' notifier.id %}" onsubmit="return confirm('{% trans "Delete notificiation?" %}')" style="display: inline">
{% csrf_token %}
<input name="next" type="hidden" value="{{ request.get_full_path }}" />
<button class="btn btn-danger btn-xs">{% trans "Delete" %}</button>
</form>
</td>
</tr>
{% empty %}
{% empty %}
<tr>
<td colspan="2">No Subscriptions <a href="{% url 'shard-list' %}" >See Services List</a></td>
<td colspan="3">No Subscriptions <a href="{% url 'shard-list' %}">See Services List</a></td>
</tr>
{% endfor %}
{% endfor %}
</table>
</div>

<div class="panel panel-primary">
<div class="panel-heading">Notifications</div>
{% include "promgen/notifier_block.html" with object=notifiers show_edit=1 %}
{% include "promgen/notifier_block.html" with object=notifiers show_edit=1 %}
<div class="panel-body">
<div class="row">
<div class="col-md-3">
Expand All @@ -50,18 +68,18 @@ <h1>{{user.username}} ({{user.email}})</h1>
{% for k, v in view.model.driver_set|dictsort:0 %}
{% if k != "promgen.notification.user" %}
<div role="tabpanel" class="tab-pane panel panel-default" id="{{ k|slugify }}">
<form action="" method="post">{% csrf_token %}
<input type="hidden" name="sender" value="{{k}}" />
<div class="panel-body">
<pre class="help-block">{{ v.help|urlize }}</pre>
</div>
<table class="table">
{{ v.form.as_table }}
</table>
<div class="panel-footer">
<button class="btn btn-primary">Register Notifier</button>
</div>
</form>
<form action="" method="post">{% csrf_token %}
<input type="hidden" name="sender" value="{{k}}" />
<div class="panel-body">
<pre class="help-block">{{ v.help|urlize }}</pre>
</div>
<table class="table">
{{ v.form.as_table }}
</table>
<div class="panel-footer">
<button class="btn btn-primary">Register Notifier</button>
</div>
</form>
</div>
{% endif %}
{% endfor %}
Expand All @@ -78,23 +96,23 @@ <h1>{{user.username}} ({{user.email}})</h1>
<td>Discovery Plugins</td>
<td>
<ul>
{% for plugin in discovery_plugins|dictsort:"name" %}
<li>{{ plugin.name }} - {{ plugin.module_name }}</li>
{% endfor %}
{% for plugin in discovery_plugins|dictsort:"name" %}
<li>{{ plugin.name }} - {{ plugin.module_name }}</li>
{% endfor %}
</td>
</tr>
<tr>
<td>Notifier Plugins</td>
<td>
<ul>
{% for notifier in notifier_plugins|dictsort:"name" %}
<li>{{ notifier.name }} - {{ notifier.module_name }}</li>
{% endfor %}
{% for notifier in notifier_plugins|dictsort:"name" %}
<li>{{ notifier.name }} - {{ notifier.module_name }}</li>
{% endfor %}
</td>
</tr>
</table>
</div>
{% endif %}
{% endif %}


{% endblock %}
4 changes: 2 additions & 2 deletions promgen/templatetags/promgen.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,9 +151,9 @@ def rule(obj):
yield obj.get_absolute_url(), obj.name

def sender(obj):
if isinstance(obj, models.Service):
if obj.content_type.model == "service":
yield from service(obj.content_object)
if isinstance(obj, models.Project):
if obj.content_type.model == "project":
yield from project(obj.content_object)

def generator():
Expand Down
5 changes: 3 additions & 2 deletions promgen/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,9 @@
url(r'^host/(?P<slug>\S+)/$', views.HostDetail.as_view(), name='host-detail'),
url(r'^host/(?P<pk>[0-9]+)/delete$', views.HostDelete.as_view(), name='host-delete'),

url(r'^notifier/(?P<pk>[0-9]+)/delete$', views.NotifierDelete.as_view(), name='notifier-delete'),
url(r'^notifier/(?P<pk>[0-9]+)/test$', views.NotifierTest.as_view(), name='notifier-test'),
path('notifier/<int:pk>/delete', views.NotifierDelete.as_view(), name='notifier-delete'),
path('notifier/<int:pk>/test', views.NotifierTest.as_view(), name='notifier-test'),
path('notifier/<int:pk>', views.NotifierUpdate.as_view(), name='notifier-edit'),

url(r'^rules/$', views.RulesList.as_view(), name='rules-list'),
url(r'^rule/import$', views.RuleImport.as_view(), name='rule-import'),
Expand Down
30 changes: 30 additions & 0 deletions promgen/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,34 @@ def get_success_url(self):
return reverse('service-detail', args=[self.object.service_id])


class NotifierUpdate(LoginRequiredMixin, UpdateView):
model = models.Sender
form_class = forms.NotifierUpdate

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
obj = self.get_object()
# For populating breadcrumb
context[obj.content_type.model] = obj.content_object
return context

def post(self, request, pk):
if 'filter.pk' in request.POST:
f = models.Filter.objects.get(pk=request.POST['filter.pk'])
f.delete()
messages.success(request, 'Removed filter {f.name} {f.value}'.format(f=f))
if 'filter.name' in request.POST:
obj = self.get_object()
f, created = obj.filter_set.get_or_create(name=request.POST['filter.name'], value=request.POST['filter.value'])
if created:
messages.success(request, 'Created filter {f.name} {f.value}'.format(f=f))
else:
messages.warning(request, 'Updated filter {f.name} {f.value}'.format(f=f))
if 'next' in request.POST:
return redirect(request.POST['next'])
return self.get(self, request, pk)


class NotifierDelete(LoginRequiredMixin, DeleteView):
model = models.Sender

Expand All @@ -319,6 +347,8 @@ def post(self, request, pk):
else:
messages.info(request, 'Sent test message with ' + sender.sender)

if 'next' in request.POST:
return redirect(request.POST['next'])
if hasattr(sender.content_object, 'get_absolute_url'):
return redirect(sender.content_object)
return redirect('status')
Expand Down

0 comments on commit e14a7a8

Please sign in to comment.