cabot/app/cabotapp/views.py

421 lines
12 KiB
Python
Raw Normal View History

2014-01-05 17:24:04 +00:00
from django.template import RequestContext, loader
from datetime import datetime, timedelta
from django.http import HttpResponse, HttpResponseRedirect
from django.core.urlresolvers import reverse_lazy
2014-01-28 00:53:34 +00:00
from models import (
StatusCheck, GraphiteStatusCheck, JenkinsStatusCheck, HttpStatusCheck,
StatusCheckResult, UserProfile, Service, Shift, get_duty_officers)
2014-01-05 17:24:04 +00:00
from tasks import run_status_check as _run_status_check
from tasks import update_service as _update_service
from tasks import run_all_checks as _run_all_checks
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.views.generic import DetailView, CreateView, UpdateView, ListView, DeleteView
from django import forms
from .graphite import get_data, get_matching_metrics
from .alert import telephone_alert_twiml_callback
from django.contrib.auth.models import User
from django.utils.timezone import utc
2014-01-05 20:57:07 +00:00
from django.core.urlresolvers import reverse
2014-01-05 17:24:04 +00:00
import requests
import json
2014-01-28 00:53:34 +00:00
2014-01-05 17:24:04 +00:00
class LoginRequiredMixin(object):
2014-01-28 00:53:34 +00:00
@method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super(LoginRequiredMixin, self).dispatch(*args, **kwargs)
2014-01-05 17:24:04 +00:00
@login_required
def subscriptions(request):
2014-01-28 00:53:34 +00:00
""" Simple list of all checks """
t = loader.get_template('cabotapp/subscriptions.html')
services = Service.objects.all().order_by('alerts_enabled')
users = User.objects.filter(is_active=True)
c = RequestContext(request, {
'services': services,
'users': users,
'duty_officers': get_duty_officers(),
})
return HttpResponse(t.render(c))
2014-01-05 17:24:04 +00:00
@login_required
def run_status_check(request, pk):
2014-01-28 00:53:34 +00:00
"""Runs a specific check"""
_run_status_check(check_or_id=pk)
return HttpResponseRedirect(reverse('check', kwargs={'pk': pk}))
2014-01-05 17:24:04 +00:00
class StatusCheckResultDetailView(LoginRequiredMixin, DetailView):
2014-01-28 00:53:34 +00:00
model = StatusCheckResult
context_object_name = 'result'
2014-01-05 17:24:04 +00:00
class SymmetricalForm(forms.ModelForm):
2014-01-28 00:53:34 +00:00
symmetrical_fields = () # Iterable of 2-tuples (field, model)
def __init__(self, *args, **kwargs):
super(SymmetricalForm, self).__init__(*args, **kwargs)
if self.instance and self.instance.pk:
for field in self.symmetrical_fields:
self.fields[field].initial = getattr(
self.instance, field).all()
def save(self, commit=True):
instance = super(SymmetricalForm, self).save(commit=False)
if commit:
instance.save()
if instance.pk:
for field in self.symmetrical_fields:
setattr(instance, field, self.cleaned_data[field])
self.save_m2m()
return instance
2014-01-05 17:24:04 +00:00
base_widgets = {
2014-01-28 00:53:34 +00:00
'name': forms.TextInput(attrs={
'style': 'width:30%',
}),
'importance': forms.RadioSelect(),
2014-01-05 17:24:04 +00:00
}
2014-01-28 00:53:34 +00:00
2014-01-05 17:24:04 +00:00
class StatusCheckForm(SymmetricalForm):
2014-01-28 00:53:34 +00:00
symmetrical_fields = ('service_set',)
service_set = forms.ModelMultipleChoiceField(
queryset=Service.objects.all(),
required=False,
help_text='Link to service(s).',
widget=forms.SelectMultiple(
attrs={
'data-rel': 'chosen',
'style': 'width: 70%',
},
)
2014-01-05 17:24:04 +00:00
)
class GraphiteStatusCheckForm(StatusCheckForm):
2014-01-28 00:53:34 +00:00
class Meta:
model = GraphiteStatusCheck
fields = (
'name',
'metric',
'check_type',
'value',
'frequency',
'active',
'importance',
'expected_num_hosts',
'debounce',
)
widgets = dict(**base_widgets)
widgets.update({
'value': forms.TextInput(attrs={
'style': 'width: 100px',
'placeholder': 'threshold value',
}),
'metric': forms.TextInput(attrs={
'style': 'width: 100%',
'placeholder': 'graphite metric key'
}),
'check_type': forms.Select(attrs={
'data-rel': 'chosen',
})
})
2014-01-05 17:24:04 +00:00
class HttpStatusCheckForm(StatusCheckForm):
2014-01-28 00:53:34 +00:00
class Meta:
model = HttpStatusCheck
fields = (
'name',
'endpoint',
'username',
'password',
'text_match',
'status_code',
'timeout',
'frequency',
'importance',
'active',
'debounce',
)
widgets = dict(**base_widgets)
widgets.update({
'endpoint': forms.TextInput(attrs={
'style': 'width: 100%',
'placeholder': 'https://www.arachnys.com',
}),
'username': forms.TextInput(attrs={
'style': 'width: 30%',
}),
'password': forms.TextInput(attrs={
'style': 'width: 30%',
}),
'text_match': forms.TextInput(attrs={
'style': 'width: 100%',
'placeholder': '[Aa]rachnys\s+[Rr]ules',
}),
'status_code': forms.TextInput(attrs={
'style': 'width: 20%',
'placeholder': '200',
}),
})
2014-01-05 17:24:04 +00:00
class JenkinsStatusCheckForm(StatusCheckForm):
2014-01-28 00:53:34 +00:00
class Meta:
model = JenkinsStatusCheck
fields = (
'name',
'importance',
'debounce',
'max_queued_build_time',
)
widgets = dict(**base_widgets)
2014-01-05 17:24:04 +00:00
class UserProfileForm(forms.ModelForm):
2014-01-28 00:53:34 +00:00
class Meta:
model = UserProfile
exclude = ('user',)
2014-01-05 17:24:04 +00:00
class ServiceForm(forms.ModelForm):
2014-01-28 00:53:34 +00:00
class Meta:
model = Service
template_name = 'service_form.html'
fields = (
'name',
'url',
'users_to_notify',
'status_checks',
'email_alert',
'hipchat_alert',
'sms_alert',
'telephone_alert',
'alerts_enabled',
'hackpad_id',
)
widgets = {
'name': forms.TextInput(attrs={'style': 'width: 30%;'}),
'url': forms.TextInput(attrs={'style': 'width: 70%;'}),
'status_checks': forms.SelectMultiple(attrs={
'data-rel': 'chosen',
'style': 'width: 70%',
}),
'users_to_notify': forms.CheckboxSelectMultiple(),
'hackpad_id': forms.TextInput(attrs={'style': 'width:30%;'}),
}
def __init__(self, *args, **kwargs):
ret = super(ServiceForm, self).__init__(*args, **kwargs)
self.fields['users_to_notify'].queryset = User.objects.filter(
is_active=True)
return ret
2014-01-05 17:24:04 +00:00
2014-01-28 00:53:34 +00:00
class CheckCreateView(LoginRequiredMixin, CreateView):
template_name = 'cabotapp/statuscheck_form.html'
def form_valid(self, form):
form.instance.created_by = self.request.user
return super(CheckCreateView, self).form_valid(form)
def get_initial(self):
if self.initial:
initial = self.initial
else:
initial = {}
metric = self.request.GET.get('metric')
if metric:
initial['metric'] = metric
service_id = self.request.GET.get('service')
if service_id:
try:
service = Service.objects.get(id=service_id)
initial['service_set'] = [service]
except Service.DoesNotExist:
pass
return initial
def get_success_url(self):
return reverse('check', kwargs={'pk': self.object.id})
2014-01-05 20:57:07 +00:00
2014-01-05 17:24:04 +00:00
class CheckUpdateView(LoginRequiredMixin, UpdateView):
2014-01-28 00:53:34 +00:00
template_name = 'cabotapp/statuscheck_form.html'
2014-01-05 17:24:04 +00:00
2014-01-28 00:53:34 +00:00
def get_success_url(self):
return reverse('check', kwargs={'pk': self.object.id})
2014-01-05 20:57:07 +00:00
2014-01-05 17:24:04 +00:00
class GraphiteCheckCreateView(CheckCreateView):
2014-01-28 00:53:34 +00:00
model = GraphiteStatusCheck
form_class = GraphiteStatusCheckForm
2014-01-05 17:24:04 +00:00
class GraphiteCheckUpdateView(CheckUpdateView):
2014-01-28 00:53:34 +00:00
model = GraphiteStatusCheck
form_class = GraphiteStatusCheckForm
2014-01-05 17:24:04 +00:00
class HttpCheckCreateView(CheckCreateView):
2014-01-28 00:53:34 +00:00
model = HttpStatusCheck
form_class = HttpStatusCheckForm
2014-01-05 17:24:04 +00:00
class HttpCheckUpdateView(CheckUpdateView):
2014-01-28 00:53:34 +00:00
model = HttpStatusCheck
form_class = HttpStatusCheckForm
2014-01-05 17:24:04 +00:00
class JenkinsCheckCreateView(CheckCreateView):
2014-01-28 00:53:34 +00:00
model = JenkinsStatusCheck
form_class = JenkinsStatusCheckForm
2014-01-05 17:24:04 +00:00
class JenkinsCheckUpdateView(CheckUpdateView):
2014-01-28 00:53:34 +00:00
model = JenkinsStatusCheck
form_class = JenkinsStatusCheckForm
2014-01-05 17:24:04 +00:00
class StatusCheckListView(LoginRequiredMixin, ListView):
2014-01-28 00:53:34 +00:00
model = StatusCheck
context_object_name = 'checks'
2014-01-05 17:24:04 +00:00
2014-01-28 00:53:34 +00:00
def get_queryset(self):
return StatusCheck.objects.all().order_by('name').prefetch_related('service_set')
2014-01-05 17:24:04 +00:00
class StatusCheckDeleteView(LoginRequiredMixin, DeleteView):
2014-01-28 00:53:34 +00:00
model = StatusCheck
success_url = reverse_lazy('checks')
context_object_name = 'check'
template_name = 'cabotapp/statuscheck_confirm_delete.html'
2014-01-05 17:24:04 +00:00
class StatusCheckDetailView(LoginRequiredMixin, DetailView):
2014-01-28 00:53:34 +00:00
model = StatusCheck
context_object_name = 'check'
template_name = 'cabotapp/statuscheck_detail.html'
2014-01-05 17:24:04 +00:00
2014-01-28 00:53:34 +00:00
def render_to_response(self, context, *args, **kwargs):
if context == None:
context = {}
context['checkresults'] = self.object.statuscheckresult_set.order_by(
'-time_complete')[:100]
return super(StatusCheckDetailView, self).render_to_response(context, *args, **kwargs)
2014-01-05 17:24:04 +00:00
class UserProfileUpdateView(LoginRequiredMixin, UpdateView):
2014-01-28 00:53:34 +00:00
model = UserProfile
success_url = reverse_lazy('subscriptions')
form_class = UserProfileForm
2014-01-05 17:24:04 +00:00
2014-01-28 00:53:34 +00:00
def get_object(self, *args, **kwargs):
try:
return self.model.objects.get(user=self.kwargs['pk'])
except self.model.DoesNotExist:
user = User.objects.get(id=self.kwargs['pk'])
profile = UserProfile(user=user)
profile.save()
return profile
2014-01-05 17:24:04 +00:00
class ServiceListView(LoginRequiredMixin, ListView):
2014-01-28 00:53:34 +00:00
model = Service
context_object_name = 'services'
2014-01-05 17:24:04 +00:00
2014-01-28 00:53:34 +00:00
def get_queryset(self):
return Service.objects.all().order_by('name').prefetch_related('status_checks')
2014-01-05 17:24:04 +00:00
class ServiceDetailView(LoginRequiredMixin, DetailView):
2014-01-28 00:53:34 +00:00
model = Service
context_object_name = 'service'
2014-01-05 17:24:04 +00:00
class ServiceCreateView(LoginRequiredMixin, CreateView):
2014-01-28 00:53:34 +00:00
model = Service
form_class = ServiceForm
2014-01-05 20:57:07 +00:00
2014-01-28 00:53:34 +00:00
def get_success_url(self):
return reverse('service', kwargs={'pk': self.object.id})
2014-01-05 17:24:04 +00:00
class ServiceUpdateView(LoginRequiredMixin, UpdateView):
2014-01-28 00:53:34 +00:00
model = Service
form_class = ServiceForm
2014-01-05 20:57:07 +00:00
2014-01-28 00:53:34 +00:00
def get_success_url(self):
return reverse('service', kwargs={'pk': self.object.id})
2014-01-05 17:24:04 +00:00
class ServiceDeleteView(LoginRequiredMixin, DeleteView):
2014-01-28 00:53:34 +00:00
model = Service
success_url = reverse_lazy('services')
context_object_name = 'service'
template_name = 'cabotapp/service_confirm_delete.html'
2014-01-05 17:24:04 +00:00
class ShiftListView(LoginRequiredMixin, ListView):
2014-01-28 00:53:34 +00:00
model = Shift
context_object_name = 'shifts'
2014-01-05 17:24:04 +00:00
2014-01-28 00:53:34 +00:00
def get_queryset(self):
return Shift.objects.filter(
end__gt=datetime.utcnow().replace(tzinfo=utc),
deleted=False).order_by('start')
2014-01-05 17:24:04 +00:00
2014-01-28 00:53:34 +00:00
# Misc JSON api and other stuff
2014-01-05 17:24:04 +00:00
def twiml_callback(request, service_id):
2014-01-28 00:53:34 +00:00
service = Service.objects.get(id=service_id)
twiml = telephone_alert_twiml_callback(service)
return HttpResponse(twiml, content_type='application/xml')
2014-01-05 17:24:04 +00:00
def checks_run_recently(request):
2014-01-28 00:53:34 +00:00
"""
Checks whether or not stuff is running by looking to see if checks have run in last 10 mins
"""
ten_mins = datetime.utcnow().replace(tzinfo=utc) - timedelta(minutes=10)
most_recent = StatusCheckResult.objects.filter(time_complete__gte=ten_mins)
if most_recent.exists():
return HttpResponse('Checks running')
return HttpResponse('Checks not running')
2014-01-05 17:24:04 +00:00
def jsonify(d):
2014-01-28 00:53:34 +00:00
return HttpResponse(json.dumps(d), content_type='application/json')
2014-01-05 17:24:04 +00:00
@login_required
def graphite_api_data(request):
2014-01-28 00:53:34 +00:00
metric = request.GET.get('metric')
data = None
matching_metrics = None
2014-01-05 17:24:04 +00:00
try:
2014-01-28 00:53:34 +00:00
data = get_data(metric)
2014-01-05 17:24:04 +00:00
except requests.exceptions.RequestException, e:
2014-01-28 00:53:34 +00:00
pass
if not data:
try:
matching_metrics = get_matching_metrics(metric)
except requests.exceptions.RequestException, e:
return jsonify({'status': 'error', 'message': str(e)})
matching_metrics = {'metrics': matching_metrics}
return jsonify({'status': 'ok', 'data': data, 'matchingMetrics': matching_metrics})