General cleanup (#346)

* updated to latest distribute
* removed django-mptt dependency as it's not used anywhere
* PEP8 cleanup. Removed unused imports, reformatted files
This commit is contained in:
Mark Unsworth 2016-05-14 00:06:40 +01:00 committed by Jean-Frédéric
parent 1d29d7134f
commit 3270540427
11 changed files with 136 additions and 151 deletions

2
.gitignore vendored
View File

@ -18,3 +18,5 @@ conf/*.env
dist/
local_config.yml
build/
.idea

View File

@ -1,8 +1,8 @@
from django.contrib import admin
from .models import (UserProfile, Service, Shift,
ServiceStatusSnapshot, StatusCheck, StatusCheckResult,
Instance, AlertAcknowledgement)
from .alert import AlertPluginUserData, AlertPlugin
ServiceStatusSnapshot, StatusCheck, StatusCheckResult,
Instance, AlertAcknowledgement)
from .alert import AlertPluginUserData, AlertPlugin
admin.site.register(UserProfile)
admin.site.register(Shift)
@ -13,4 +13,4 @@ admin.site.register(StatusCheckResult)
admin.site.register(Instance)
admin.site.register(AlertPlugin)
admin.site.register(AlertPluginUserData)
admin.site.register(AlertAcknowledgement)
admin.site.register(AlertAcknowledgement)

View File

@ -1,23 +1,11 @@
from os import environ as env
from django.conf import settings
from django.core.mail import send_mail
from django.core.urlresolvers import reverse
from django.template import Context, Template
from django.db import models
from django.db.models import get_models
from twilio.rest import TwilioRestClient
from twilio import twiml
import requests
import logging
import re
from django.db import models
from polymorphic import PolymorphicModel
logger = logging.getLogger(__name__)
class AlertPlugin(PolymorphicModel):
title = models.CharField(max_length=30, unique=True, editable=False)
enabled = models.BooleanField(default=True)
@ -33,6 +21,7 @@ class AlertPlugin(PolymorphicModel):
"""
return True
class AlertPluginUserData(PolymorphicModel):
title = models.CharField(max_length=30, editable=False)
user = models.ForeignKey('UserProfile', editable=False)
@ -43,6 +32,7 @@ class AlertPluginUserData(PolymorphicModel):
def __unicode__(self):
return u'%s' % (self.title)
def send_alert(service, duty_officers=None):
users = service.users_to_notify.filter(is_active=True)
for alert in service.alerts.all():
@ -51,6 +41,7 @@ def send_alert(service, duty_officers=None):
except Exception as e:
logging.exception('Could not send %s alert: %s' % (alert.name, e))
def send_alert_update(service, duty_officers=None):
users = service.users_to_notify.filter(is_active=True)
for alert in service.alerts.all():

View File

@ -1,7 +1,6 @@
from django.conf import settings
from icalendar import Calendar, Event
import requests
from django.conf import settings
from icalendar import Calendar
def get_calendar_data():

View File

@ -1,10 +1,9 @@
from os import environ as env
from django.conf import settings
import requests
from datetime import datetime
from django.utils import timezone
import requests
from celery.utils.log import get_task_logger
from django.conf import settings
from django.utils import timezone
logger = get_task_logger(__name__)

View File

@ -1,36 +1,28 @@
from django.db import models
from django.conf import settings
from django.core.exceptions import ValidationError
from polymorphic import PolymorphicModel
from django.db.models import F
from django.core.urlresolvers import reverse
from django.contrib.auth.models import User
from celery.exceptions import SoftTimeLimitExceeded
import itertools
import json
import re
import subprocess
import time
from datetime import timedelta
import requests
from celery.exceptions import SoftTimeLimitExceeded
from celery.utils.log import get_task_logger
from django.conf import settings
from django.contrib.auth.models import User
from django.db import models
from django.utils import timezone
from polymorphic import PolymorphicModel
from .jenkins import get_job_status
from .alert import (
send_alert,
send_alert_update,
AlertPlugin,
AlertPluginUserData,
update_alert_plugins
AlertPluginUserData
)
from .calendar import get_events
from .graphite import parse_metric
from .graphite import get_data
from .jenkins import get_job_status
from .tasks import update_service, update_instance
from datetime import datetime, timedelta
from django.utils import timezone
import json
import re
import time
import os
import subprocess
import itertools
import requests
from celery.utils.log import get_task_logger
RAW_DATA_LIMIT = 5000
@ -44,6 +36,7 @@ CHECK_TYPES = (
('==', 'Equal to'),
)
def serialize_recent_results(recent_results):
if not recent_results:
return ''
@ -53,6 +46,7 @@ def serialize_recent_results(recent_results):
return '1'
else:
return '-1'
vals = [result_to_value(r) for r in recent_results]
vals.reverse()
return ','.join(vals)
@ -76,7 +70,6 @@ def calculate_debounced_passing(recent_results, debounce=0):
class CheckGroupMixin(models.Model):
class Meta:
abstract = True
@ -141,14 +134,13 @@ class CheckGroupMixin(models.Model):
null=True,
blank=True,
verbose_name='Recovery instructions',
help_text='Gist, Hackpad or Refheap js embed with recovery instructions e.g. https://you.hackpad.com/some_document.js'
help_text='Gist, Hackpad or Refheap js embed with recovery instructions e.g. '
'https://you.hackpad.com/some_document.js'
)
def __unicode__(self):
return self.name
def most_severe(self, check_list):
failures = [c.importance for c in check_list]
if self.CRITICAL_STATUS in failures:
@ -175,10 +167,12 @@ class CheckGroupMixin(models.Model):
if self.overall_status != self.PASSING_STATUS:
# Don't alert every time
if self.overall_status == self.WARNING_STATUS:
if self.last_alert_sent and (timezone.now() - timedelta(minutes=settings.NOTIFICATION_INTERVAL)) < self.last_alert_sent:
if self.last_alert_sent and (
timezone.now() - timedelta(minutes=settings.NOTIFICATION_INTERVAL)) < self.last_alert_sent:
return
elif self.overall_status in (self.CRITICAL_STATUS, self.ERROR_STATUS):
if self.last_alert_sent and (timezone.now() - timedelta(minutes=settings.ALERT_INTERVAL)) < self.last_alert_sent:
if self.last_alert_sent and (
timezone.now() - timedelta(minutes=settings.ALERT_INTERVAL)) < self.last_alert_sent:
return
self.last_alert_sent = timezone.now()
else:
@ -194,13 +188,13 @@ class CheckGroupMixin(models.Model):
def unexpired_acknowledgements(self):
acknowledgements = self.alertacknowledgement_set.all().filter(
time__gte=timezone.now()-timedelta(minutes=settings.ACKNOWLEDGEMENT_EXPIRY),
time__gte=timezone.now() - timedelta(minutes=settings.ACKNOWLEDGEMENT_EXPIRY),
cancelled_time__isnull=True,
).order_by('-time')
return acknowledgements
def acknowledge_alert(self, user):
if self.unexpired_acknowledgements(): # Don't allow users to jump on each other
if self.unexpired_acknowledgements(): # Don't allow users to jump on each other
return None
acknowledgement = AlertAcknowledgement.objects.create(
user=user,
@ -261,7 +255,6 @@ class CheckGroupMixin(models.Model):
class Service(CheckGroupMixin):
def update_status(self):
self.old_overall_status = self.overall_status
# Only active checks feed into our calculation
@ -280,6 +273,7 @@ class Service(CheckGroupMixin):
self.save()
if not (self.overall_status == Service.PASSING_STATUS and self.old_overall_status == Service.PASSING_STATUS):
self.alert()
instances = models.ManyToManyField(
'Instance',
blank=True,
@ -296,8 +290,6 @@ class Service(CheckGroupMixin):
class Instance(CheckGroupMixin):
def duplicate(self):
checks = self.status_checks.all()
new_instance = self
@ -349,7 +341,6 @@ class Instance(CheckGroupMixin):
class Snapshot(models.Model):
class Meta:
abstract = True
@ -376,7 +367,6 @@ class InstanceStatusSnapshot(Snapshot):
class StatusCheck(PolymorphicModel):
"""
Base class for polymorphic models. We're going to use
proxy models for inheriting because it makes life much simpler,
@ -397,7 +387,9 @@ class StatusCheck(PolymorphicModel):
max_length=30,
choices=Service.IMPORTANCES,
default=Service.ERROR_STATUS,
help_text='Severity level of a failure. Critical alerts are for failures you want to wake you up at 2am, Errors are things you can sleep through but need to fix in the morning, and warnings for less important things.'
help_text='Severity level of a failure. Critical alerts are for failures you want to wake you up at 2am, '
'Errors are things you can sleep through but need to fix in the morning, and warnings for less '
'important things.'
)
frequency = models.IntegerField(
default=5,
@ -406,7 +398,8 @@ class StatusCheck(PolymorphicModel):
debounce = models.IntegerField(
default=0,
null=True,
help_text='Number of successive failures permitted before check will be marked as failed. Default is 0, i.e. fail on first failure.'
help_text='Number of successive failures permitted before check will be marked as failed. Default is 0, '
'i.e. fail on first failure.'
)
created_by = models.ForeignKey(User, null=True)
calculated_status = models.CharField(
@ -417,7 +410,8 @@ class StatusCheck(PolymorphicModel):
# Graphite checks
metric = models.TextField(
null=True,
help_text='fully.qualified.name of the Graphite metric you want to watch. This can be any valid Graphite expression, including wildcards, multiple hosts, etc.',
help_text='fully.qualified.name of the Graphite metric you want to watch. This can be any valid Graphite '
'expression, including wildcards, multiple hosts, etc.',
)
check_type = models.CharField(
choices=CHECK_TYPES,
@ -436,7 +430,8 @@ class StatusCheck(PolymorphicModel):
allowed_num_failures = models.IntegerField(
default=0,
null=True,
help_text='The maximum number of data series (metrics) you expect to fail. For example, you might be OK with 2 out of 3 webservers having OK load (1 failing), but not 1 out of 3 (2 failing).',
help_text='The maximum number of data series (metrics) you expect to fail. For example, you might be OK with '
'2 out of 3 webservers having OK load (1 failing), but not 1 out of 3 (2 failing).',
)
# HTTP checks
@ -567,7 +562,6 @@ class StatusCheck(PolymorphicModel):
class ICMPStatusCheck(StatusCheck):
class Meta(StatusCheck.Meta):
proxy = True
@ -580,8 +574,10 @@ class ICMPStatusCheck(StatusCheck):
instances = self.instance_set.all()
target = self.instance_set.get().address
# We need to read both STDOUT and STDERR because ping can write to both, depending on the kind of error. Thanks a lot, ping.
ping_process = subprocess.Popen("ping -c 1 " + target, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True)
# We need to read both STDOUT and STDERR because ping can write to both, depending on the kind of error.
# Thanks a lot, ping.
ping_process = subprocess.Popen("ping -c 1 " + target, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
shell=True)
response = ping_process.wait()
if response == 0:
@ -616,7 +612,6 @@ def minimize_targets(targets):
class GraphiteStatusCheck(StatusCheck):
class Meta(StatusCheck.Meta):
proxy = True
@ -632,7 +627,7 @@ class GraphiteStatusCheck(StatusCheck):
threshold = float(self.value)
failures_by_host = ["%s: %s %s %0.1f" % (
hosts_by_target[target], value, self.check_type, threshold)
for target, value in failures]
for target, value in failures]
return ", ".join(failures_by_host)
else:
target, value = failures[0]
@ -704,7 +699,6 @@ class GraphiteStatusCheck(StatusCheck):
class HttpStatusCheck(StatusCheck):
class Meta(StatusCheck.Meta):
proxy = True
@ -751,7 +745,6 @@ class HttpStatusCheck(StatusCheck):
class JenkinsStatusCheck(StatusCheck):
class Meta(StatusCheck.Meta):
proxy = True
@ -811,7 +804,6 @@ class JenkinsStatusCheck(StatusCheck):
class StatusCheckResult(models.Model):
"""
We use the same StatusCheckResult model for all check types,
because really they are not so very different.
@ -850,7 +842,7 @@ class StatusCheckResult(models.Model):
"""
try:
diff = self.time_complete - self.time
return (diff.microseconds + (diff.seconds + diff.days * 24 * 3600) * 10**6) / 1000
return (diff.microseconds + (diff.seconds + diff.days * 24 * 3600) * 10 ** 6) / 1000
except:
return None
@ -869,7 +861,6 @@ class StatusCheckResult(models.Model):
class AlertAcknowledgement(models.Model):
time = models.DateTimeField()
user = models.ForeignKey(User)
service = models.ForeignKey(Service)
@ -887,6 +878,7 @@ class AlertAcknowledgement(models.Model):
def expires(self):
return self.time + timedelta(minutes=settings.ACKNOWLEDGEMENT_EXPIRY)
class UserProfile(models.Model):
user = models.OneToOneField(User, related_name='profile')

View File

@ -1,13 +1,9 @@
import os
import os.path
import sys
import random
import logging
import random
from celery import Celery
from celery._state import set_default_app
from celery.task import task
from django.conf import settings
from django.utils import timezone
@ -39,7 +35,7 @@ def run_status_check(check_or_id):
@task(ignore_result=True)
def run_all_checks():
from .models import StatusCheck
from datetime import timedelta, datetime
from datetime import timedelta
checks = StatusCheck.objects.all()
seconds = range(60)
for check in checks:

View File

@ -1,32 +1,29 @@
# -*- coding: utf-8 -*-
import requests
from django.conf import settings
from django.utils import timezone
from django.core.urlresolvers import reverse
from django.test import TestCase
from django.contrib.auth.models import User
from django.test.client import Client
from django.contrib.auth.models import Permission
from rest_framework import status, HTTP_HEADER_ENCODING
from rest_framework.test import APITestCase
from rest_framework.reverse import reverse as api_reverse
from twilio import rest
from django.core import mail
from datetime import timedelta, date, datetime
import json
import os
import base64
import json
import time
from mock import Mock, patch
from datetime import timedelta, date
import os
import requests
from cabot.cabotapp.graphite import parse_metric
from cabot.cabotapp.models import (
GraphiteStatusCheck, JenkinsStatusCheck,
HttpStatusCheck, ICMPStatusCheck, Service, Instance,
StatusCheckResult, UserProfile, minimize_targets)
from cabot.cabotapp.views import StatusCheckReportForm
from cabot.cabotapp.alert import send_alert
from cabot.cabotapp.graphite import parse_metric
from django.contrib.auth.models import Permission
from django.contrib.auth.models import User
from django.core import mail
from django.core.urlresolvers import reverse
from django.test.client import Client
from django.utils import timezone
from mock import Mock, patch
from rest_framework import status, HTTP_HEADER_ENCODING
from rest_framework.reverse import reverse as api_reverse
from rest_framework.test import APITestCase
from twilio import rest
def get_content(fname):

View File

@ -1,38 +1,34 @@
from django.template import RequestContext, loader
import json
import re
from datetime import datetime, timedelta, date
from itertools import groupby, dropwhile, izip_longest
import requests
from cabot.cabotapp import alert
from dateutil.relativedelta import relativedelta
from django.http import HttpResponse, HttpResponseRedirect
from django.core.urlresolvers import reverse_lazy
from django import forms
from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
from django.core.exceptions import ValidationError
from django.core.urlresolvers import reverse
from django.core.urlresolvers import reverse_lazy
from django.http import HttpResponse, HttpResponseRedirect
from django.template import RequestContext, loader
from django.utils import timezone
from django.utils.decorators import method_decorator
from django.utils.timezone import utc
from django.views.generic import (
DetailView, CreateView, UpdateView, ListView, DeleteView, TemplateView, View)
from models import AlertPluginUserData
from models import (
StatusCheck, GraphiteStatusCheck, JenkinsStatusCheck, HttpStatusCheck, ICMPStatusCheck,
StatusCheckResult, UserProfile, Service, Instance, Shift, get_duty_officers)
from tasks import run_status_check as _run_status_check
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, TemplateView, FormView, View)
from django import forms
from .graphite import get_data, get_matching_metrics
from django.contrib.auth.models import User
from django.utils import timezone
from django.utils.timezone import utc
from django.core.urlresolvers import reverse
from django.core.exceptions import ValidationError
from cabot.cabotapp import alert
from models import AlertPluginUserData
from django.forms.models import (inlineformset_factory, modelformset_factory)
from django import shortcuts
from itertools import groupby, dropwhile, izip_longest
import requests
import json
import re
class LoginRequiredMixin(object):
@method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super(LoginRequiredMixin, self).dispatch(*args, **kwargs)
@ -51,32 +47,38 @@ def subscriptions(request):
})
return HttpResponse(t.render(c))
@login_required
def run_status_check(request, pk):
"""Runs a specific check"""
_run_status_check(check_or_id=pk)
return HttpResponseRedirect(reverse('check', kwargs={'pk': pk}))
def duplicate_icmp_check(request, pk):
pc = StatusCheck.objects.get(pk=pk)
npk = pc.duplicate()
return HttpResponseRedirect(reverse('update-icmp-check', kwargs={'pk': npk}))
def duplicate_instance(request, pk):
instance = Instance.objects.get(pk=pk)
new_instance = instance.duplicate()
return HttpResponseRedirect(reverse('update-instance', kwargs={'pk': new_instance}))
def duplicate_http_check(request, pk):
pc = StatusCheck.objects.get(pk=pk)
npk = pc.duplicate()
return HttpResponseRedirect(reverse('update-http-check', kwargs={'pk': npk}))
def duplicate_graphite_check(request, pk):
pc = StatusCheck.objects.get(pk=pk)
npk = pc.duplicate()
return HttpResponseRedirect(reverse('update-graphite-check', kwargs={'pk': npk}))
def duplicate_jenkins_check(request, pk):
pc = StatusCheck.objects.get(pk=pk)
npk = pc.duplicate()
@ -109,6 +111,7 @@ class SymmetricalForm(forms.ModelForm):
self.save_m2m()
return instance
base_widgets = {
'name': forms.TextInput(attrs={
'style': 'width:30%',
@ -118,7 +121,6 @@ base_widgets = {
class StatusCheckForm(SymmetricalForm):
symmetrical_fields = ('service_set', 'instance_set')
service_set = forms.ModelMultipleChoiceField(
@ -147,7 +149,6 @@ class StatusCheckForm(SymmetricalForm):
class GraphiteStatusCheckForm(StatusCheckForm):
class Meta:
model = GraphiteStatusCheck
fields = (
@ -179,7 +180,6 @@ class GraphiteStatusCheckForm(StatusCheckForm):
class ICMPStatusCheckForm(StatusCheckForm):
class Meta:
model = ICMPStatusCheck
fields = (
@ -193,7 +193,6 @@ class ICMPStatusCheckForm(StatusCheckForm):
class HttpStatusCheckForm(StatusCheckForm):
class Meta:
model = HttpStatusCheck
fields = (
@ -234,7 +233,6 @@ class HttpStatusCheckForm(StatusCheckForm):
class JenkinsStatusCheckForm(StatusCheckForm):
class Meta:
model = JenkinsStatusCheck
fields = (
@ -245,8 +243,8 @@ class JenkinsStatusCheckForm(StatusCheckForm):
)
widgets = dict(**base_widgets)
class InstanceForm(SymmetricalForm):
class InstanceForm(SymmetricalForm):
symmetrical_fields = ('service_set',)
service_set = forms.ModelMultipleChoiceField(
queryset=Service.objects.all(),
@ -260,7 +258,6 @@ class InstanceForm(SymmetricalForm):
)
)
class Meta:
model = Instance
template_name = 'instance_form.html'
@ -298,7 +295,6 @@ class InstanceForm(SymmetricalForm):
class ServiceForm(forms.ModelForm):
class Meta:
model = Service
template_name = 'service_form.html'
@ -400,7 +396,7 @@ class CheckCreateView(LoginRequiredMixin, CreateView):
if metric:
initial['metric'] = metric
service_id = self.request.GET.get('service')
instance_id = self.request.GET.get('instance')
instance_id = self.request.GET.get('instance')
if service_id:
try:
@ -423,7 +419,7 @@ class CheckCreateView(LoginRequiredMixin, CreateView):
return reverse('service', kwargs={'pk': self.request.GET.get('service')})
if self.request.GET.get('instance'):
return reverse('instance', kwargs={'pk': self.request.GET.get('instance')})
return reverse('checks')
return reverse('checks')
class CheckUpdateView(LoginRequiredMixin, UpdateView):
@ -432,6 +428,7 @@ class CheckUpdateView(LoginRequiredMixin, UpdateView):
def get_success_url(self):
return reverse('check', kwargs={'pk': self.object.id})
class ICMPCheckCreateView(CheckCreateView):
model = ICMPStatusCheck
form_class = ICMPStatusCheckForm
@ -441,14 +438,17 @@ class ICMPCheckUpdateView(CheckUpdateView):
model = ICMPStatusCheck
form_class = ICMPStatusCheckForm
class GraphiteCheckUpdateView(CheckUpdateView):
model = GraphiteStatusCheck
form_class = GraphiteStatusCheckForm
class GraphiteCheckCreateView(CheckCreateView):
model = GraphiteStatusCheck
form_class = GraphiteStatusCheckForm
class HttpCheckCreateView(CheckCreateView):
model = HttpStatusCheck
form_class = HttpStatusCheckForm
@ -498,7 +498,7 @@ class StatusCheckDetailView(LoginRequiredMixin, DetailView):
template_name = 'cabotapp/statuscheck_detail.html'
def render_to_response(self, context, *args, **kwargs):
if context == None:
if context is None:
context = {}
context['checkresults'] = self.object.statuscheckresult_set.order_by(
'-time_complete')[:100]
@ -507,9 +507,11 @@ class StatusCheckDetailView(LoginRequiredMixin, DetailView):
class UserProfileUpdateView(LoginRequiredMixin, View):
model = AlertPluginUserData
def get(self, *args, **kwargs):
return HttpResponseRedirect(reverse('update-alert-user-data', args=(self.kwargs['pk'], u'General')))
class UserProfileUpdateAlert(LoginRequiredMixin, View):
template = loader.get_template('cabotapp/alertpluginuserdata_form.html')
model = AlertPluginUserData
@ -524,13 +526,13 @@ class UserProfileUpdateAlert(LoginRequiredMixin, View):
profile.user_data()
if (alerttype == u'General'):
if alerttype == u'General':
form = GeneralSettingsForm(initial={
'first_name': profile.user.first_name,
'last_name' : profile.user.last_name,
'email_address' : profile.user.email,
'enabled' : profile.user.is_active,
})
'last_name': profile.user.last_name,
'email_address': profile.user.email,
'enabled': profile.user.is_active,
})
else:
plugin_userdata = self.model.objects.get(title=alerttype, user=profile)
form_model = get_object_form(type(plugin_userdata))
@ -539,12 +541,12 @@ class UserProfileUpdateAlert(LoginRequiredMixin, View):
c = RequestContext(request, {
'form': form,
'alert_preferences': profile.user_data(),
})
})
return HttpResponse(self.template.render(c))
def post(self, request, pk, alerttype):
profile = UserProfile.objects.get(user=pk)
if (alerttype == u'General'):
if alerttype == u'General':
form = GeneralSettingsForm(request.POST)
if form.is_valid():
profile.user.first_name = form.cleaned_data['first_name']
@ -562,22 +564,28 @@ class UserProfileUpdateAlert(LoginRequiredMixin, View):
if form.is_valid():
return HttpResponseRedirect(reverse('update-alert-user-data', args=(self.kwargs['pk'], alerttype)))
def get_object_form(model_type):
class AlertPreferencesForm(forms.ModelForm):
class Meta:
model = model_type
def is_valid(self):
return True
return AlertPreferencesForm
class GeneralSettingsForm(forms.Form):
first_name = forms.CharField(label='First name', max_length=30, required=False)
last_name = forms.CharField(label='Last name', max_length=30, required=False)
email_address = forms.CharField(label='Email Address', max_length=75, required=False) #We use 75 and not the 254 because Django 1.6.8 only supports 75. See commit message for details.
last_name = forms.CharField(label='Last name', max_length=30, required=False)
email_address = forms.CharField(label='Email Address', max_length=75,
required=False) # We use 75 and not the 254 because Django 1.6.8 only supports
# 75. See commit message for details.
enabled = forms.BooleanField(label='Enabled', required=False)
class InstanceListView(LoginRequiredMixin, ListView):
class InstanceListView(LoginRequiredMixin, ListView):
model = Instance
context_object_name = 'instances'
@ -592,6 +600,7 @@ class ServiceListView(LoginRequiredMixin, ListView):
def get_queryset(self):
return Service.objects.all().order_by('name').prefetch_related('status_checks')
class InstanceDetailView(LoginRequiredMixin, DetailView):
model = Instance
context_object_name = 'instance'
@ -607,6 +616,7 @@ class InstanceDetailView(LoginRequiredMixin, DetailView):
})
return context
class ServiceDetailView(LoginRequiredMixin, DetailView):
model = Service
context_object_name = 'service'
@ -684,6 +694,7 @@ class ServiceCreateView(LoginRequiredMixin, CreateView):
form_class = ServiceForm
alert.update_alert_plugins()
def get_success_url(self):
return reverse('service', kwargs={'pk': self.object.id})

View File

@ -119,7 +119,6 @@ INSTALLED_APPS = (
'compressor',
'polymorphic',
'djcelery',
'mptt',
'jsonify',
'cabot.cabotapp',
'rest_framework',

View File

@ -25,7 +25,7 @@ setup(
'argparse==1.2.1',
'billiard==3.3.0.23',
'celery==3.1.23',
'distribute==0.6.24',
'distribute==0.7.3',
'dj-database-url==0.2.2',
'django-appconf==0.6',
'django-celery==3.1.1',
@ -33,7 +33,6 @@ setup(
'django-compressor==1.4',
'django-filter==0.7',
'django-jsonify==0.2.1',
'django-mptt==0.6.0',
'django-polymorphic==0.5.6',
'django-redis==1.4.5',
'django-smtp-ssl==1.0',