diff --git a/app/cabotapp/admin.py b/app/cabotapp/admin.py
index 8ab4972..2da3a86 100644
--- a/app/cabotapp/admin.py
+++ b/app/cabotapp/admin.py
@@ -1,5 +1,5 @@
from django.contrib import admin
-from .models import UserProfile, Service, Shift, ServiceStatusSnapshot, StatusCheck, StatusCheckResult
+from .models import UserProfile, Service, Shift, ServiceStatusSnapshot, StatusCheck, StatusCheckResult, Instance
admin.site.register(UserProfile)
admin.site.register(Shift)
@@ -7,3 +7,4 @@ admin.site.register(Service)
admin.site.register(ServiceStatusSnapshot)
admin.site.register(StatusCheck)
admin.site.register(StatusCheckResult)
+admin.site.register(Instance)
diff --git a/app/cabotapp/migrations/0004_auto__add_instance__del_field_service_telephone_alert__del_field_servi.py b/app/cabotapp/migrations/0004_auto__add_instance__del_field_service_telephone_alert__del_field_servi.py
new file mode 100644
index 0000000..d5183bb
--- /dev/null
+++ b/app/cabotapp/migrations/0004_auto__add_instance__del_field_service_telephone_alert__del_field_servi.py
@@ -0,0 +1,217 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Adding model 'Instance'
+ db.create_table('cabotapp_instance', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('last_alert_sent', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)),
+ ('email_alert', self.gf('django.db.models.fields.BooleanField')(default=False)),
+ ('hipchat_alert', self.gf('django.db.models.fields.BooleanField')(default=True)),
+ ('sms_alert', self.gf('django.db.models.fields.BooleanField')(default=False)),
+ ('telephone_alert', self.gf('django.db.models.fields.BooleanField')(default=False)),
+ ('alerts_enabled', self.gf('django.db.models.fields.BooleanField')(default=True)),
+ ('overall_status', self.gf('django.db.models.fields.TextField')(default='PASSING')),
+ ('old_overall_status', self.gf('django.db.models.fields.TextField')(default='PASSING')),
+ ('hackpad_id', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
+ ('name', self.gf('django.db.models.fields.TextField')()),
+ ('address', self.gf('django.db.models.fields.TextField')(blank=True)),
+ ))
+ db.send_create_signal('cabotapp', ['Instance'])
+
+ # Adding M2M table for field users_to_notify on 'Instance'
+ db.create_table('cabotapp_instance_users_to_notify', (
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+ ('instance', models.ForeignKey(orm['cabotapp.instance'], null=False)),
+ ('user', models.ForeignKey(orm['auth.user'], null=False))
+ ))
+ db.create_unique('cabotapp_instance_users_to_notify', ['instance_id', 'user_id'])
+
+ # Adding M2M table for field status_checks on 'Instance'
+ db.create_table('cabotapp_instance_status_checks', (
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+ ('instance', models.ForeignKey(orm['cabotapp.instance'], null=False)),
+ ('statuscheck', models.ForeignKey(orm['cabotapp.statuscheck'], null=False))
+ ))
+ db.create_unique('cabotapp_instance_status_checks', ['instance_id', 'statuscheck_id'])
+
+ # Adding M2M table for field services on 'Instance'
+ db.create_table('cabotapp_instance_services', (
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+ ('instance', models.ForeignKey(orm['cabotapp.instance'], null=False)),
+ ('service', models.ForeignKey(orm['cabotapp.service'], null=False))
+ ))
+ db.create_unique('cabotapp_instance_services', ['instance_id', 'service_id'])
+
+ # Adding M2M table for field instances on 'Service'
+ db.create_table('cabotapp_service_instances', (
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+ ('service', models.ForeignKey(orm['cabotapp.service'], null=False)),
+ ('instance', models.ForeignKey(orm['cabotapp.instance'], null=False))
+ ))
+ db.create_unique('cabotapp_service_instances', ['service_id', 'instance_id'])
+
+
+ def backwards(self, orm):
+ # Deleting model 'Instance'
+ db.delete_table('cabotapp_instance')
+
+ # Removing M2M table for field users_to_notify on 'Instance'
+ db.delete_table('cabotapp_instance_users_to_notify')
+
+ # Removing M2M table for field status_checks on 'Instance'
+ db.delete_table('cabotapp_instance_status_checks')
+
+ # Removing M2M table for field services on 'Instance'
+ db.delete_table('cabotapp_instance_services')
+
+ # Removing M2M table for field instances on 'Service'
+ db.delete_table('cabotapp_service_instances')
+
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'cabotapp.instance': {
+ 'Meta': {'ordering': "['name']", 'object_name': 'Instance'},
+ 'address': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'alerts_enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'email_alert': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'hackpad_id': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'hipchat_alert': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_alert_sent': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.TextField', [], {}),
+ 'old_overall_status': ('django.db.models.fields.TextField', [], {'default': "'PASSING'"}),
+ 'overall_status': ('django.db.models.fields.TextField', [], {'default': "'PASSING'"}),
+ 'services': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['cabotapp.Service']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'sms_alert': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'status_checks': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['cabotapp.StatusCheck']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'telephone_alert': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'users_to_notify': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.User']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'cabotapp.service': {
+ 'Meta': {'ordering': "['name']", 'object_name': 'Service'},
+ 'alerts_enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'email_alert': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'hackpad_id': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'hipchat_alert': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'instances': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['cabotapp.Instance']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'last_alert_sent': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.TextField', [], {}),
+ 'old_overall_status': ('django.db.models.fields.TextField', [], {'default': "'PASSING'"}),
+ 'overall_status': ('django.db.models.fields.TextField', [], {'default': "'PASSING'"}),
+ 'sms_alert': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'status_checks': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['cabotapp.StatusCheck']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'telephone_alert': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'url': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'users_to_notify': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.User']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'cabotapp.servicestatussnapshot': {
+ 'Meta': {'object_name': 'ServiceStatusSnapshot'},
+ 'did_send_alert': ('django.db.models.fields.IntegerField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'num_checks_active': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'num_checks_failing': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'num_checks_passing': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'overall_status': ('django.db.models.fields.TextField', [], {'default': "'PASSING'"}),
+ 'service': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'snapshots'", 'to': "orm['cabotapp.Service']"}),
+ 'time': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'})
+ },
+ 'cabotapp.shift': {
+ 'Meta': {'object_name': 'Shift'},
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'end': ('django.db.models.fields.DateTimeField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'start': ('django.db.models.fields.DateTimeField', [], {}),
+ 'uid': ('django.db.models.fields.TextField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'cabotapp.statuscheck': {
+ 'Meta': {'ordering': "['name']", 'object_name': 'StatusCheck'},
+ 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'cached_health': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'calculated_status': ('django.db.models.fields.CharField', [], {'default': "'passing'", 'max_length': '50', 'blank': 'True'}),
+ 'check_type': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+ 'debounce': ('django.db.models.fields.IntegerField', [], {'default': '0', 'null': 'True'}),
+ 'endpoint': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'expected_num_hosts': ('django.db.models.fields.IntegerField', [], {'default': '0', 'null': 'True'}),
+ 'frequency': ('django.db.models.fields.IntegerField', [], {'default': '5'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'importance': ('django.db.models.fields.CharField', [], {'default': "'ERROR'", 'max_length': '30'}),
+ 'last_run': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'max_queued_build_time': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'metric': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'name': ('django.db.models.fields.TextField', [], {}),
+ 'password': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'polymorphic_ctype': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'polymorphic_cabotapp.statuscheck_set'", 'null': 'True', 'to': "orm['contenttypes.ContentType']"}),
+ 'status_code': ('django.db.models.fields.TextField', [], {'default': '200', 'null': 'True'}),
+ 'text_match': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'timeout': ('django.db.models.fields.IntegerField', [], {'default': '30', 'null': 'True'}),
+ 'username': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'value': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'verify_ssl_certificate': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
+ },
+ 'cabotapp.statuscheckresult': {
+ 'Meta': {'object_name': 'StatusCheckResult'},
+ 'check': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['cabotapp.StatusCheck']"}),
+ 'error': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'raw_data': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'succeeded': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'time': ('django.db.models.fields.DateTimeField', [], {}),
+ 'time_complete': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'db_index': 'True'})
+ },
+ 'cabotapp.userprofile': {
+ 'Meta': {'object_name': 'UserProfile'},
+ 'fallback_alert_user': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'hipchat_alias': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mobile_number': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '20', 'blank': 'True'}),
+ 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'profile'", 'unique': 'True', 'to': "orm['auth.User']"})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['cabotapp']
\ No newline at end of file
diff --git a/app/cabotapp/models.py b/app/cabotapp/models.py
index e21198b..c245896 100644
--- a/app/cabotapp/models.py
+++ b/app/cabotapp/models.py
@@ -17,6 +17,7 @@ from django.utils import timezone
import json
import re
import time
+import os
import requests
from celery.utils.log import get_task_logger
@@ -65,7 +66,11 @@ def calculate_debounced_passing(recent_results, debounce=0):
return False
-class Service(models.Model):
+class CheckGroupMixin(models.Model):
+
+ class Meta:
+ abstract = True
+
PASSING_STATUS = 'PASSING'
WARNING_STATUS = 'WARNING'
ERROR_STATUS = 'ERROR'
@@ -88,10 +93,7 @@ class Service(models.Model):
)
name = models.TextField()
- url = models.TextField(
- blank=True,
- help_text="URL of service."
- )
+
users_to_notify = models.ManyToManyField(
User,
blank=True,
@@ -126,8 +128,6 @@ class Service(models.Model):
help_text='Gist, Hackpad or Refheap js embed with recovery instructions e.g. https://you.hackpad.com/some_document.js'
)
- class Meta:
- ordering = ['name']
def __unicode__(self):
return self.name
@@ -201,18 +201,6 @@ class Service(models.Model):
s['time'] = time.mktime(s['time'].timetuple())
return snapshots
- def active_status_checks(self):
- return self.status_checks.filter(active=True)
-
- def inactive_status_checks(self):
- return self.status_checks.filter(active=False)
-
- def all_passing_checks(self):
- return self.active_status_checks().filter(calculated_status=self.CALCULATED_PASSING_STATUS)
-
- def all_failing_checks(self):
- return self.active_status_checks().exclude(calculated_status=self.CALCULATED_PASSING_STATUS)
-
def graphite_status_checks(self):
return self.status_checks.filter(polymorphic_ctype__model='graphitestatuscheck')
@@ -231,6 +219,53 @@ class Service(models.Model):
def active_jenkins_status_checks(self):
return self.jenkins_status_checks().filter(active=True)
+ def active_status_checks(self):
+ return self.status_checks.filter(active=True)
+
+ def inactive_status_checks(self):
+ return self.status_checks.filter(active=False)
+
+ def all_passing_checks(self):
+ return self.active_status_checks().filter(calculated_status=self.CALCULATED_PASSING_STATUS)
+
+ def all_failing_checks(self):
+ return self.active_status_checks().exclude(calculated_status=self.CALCULATED_PASSING_STATUS)
+
+class Service(CheckGroupMixin):
+
+ instances = models.ManyToManyField(
+ 'Instance',
+ blank=True,
+ help_text='Instances this service is running on.',
+ )
+
+
+ url = models.TextField(
+ blank=True,
+ help_text="URL of service."
+ )
+
+ class Meta:
+ ordering = ['name']
+
+
+class Instance(CheckGroupMixin):
+
+
+ class Meta:
+ ordering = ['name']
+
+ address = models.TextField(
+ blank=True,
+ help_text="Address (IP/Hostname) of service."
+ )
+
+ def icmp_status_checks(self):
+ return self.status_checks.filter(polymorphic_ctype__model='icmpstatuscheck')
+
+ def active_icmp_status_checks(self):
+ return self.icmp_status_checks().filter(active=True)
+
class ServiceStatusSnapshot(models.Model):
service = models.ForeignKey(Service, related_name='snapshots')
@@ -399,6 +434,28 @@ class StatusCheck(PolymorphicModel):
for service in services:
update_service.delay(service.id)
+class ICMPStatusCheck(StatusCheck):
+
+
+ class Meta(StatusCheck.Meta):
+ proxy = True
+
+ @property
+ def check_category(self):
+ return "ICMP/Ping Check"
+
+ def _run(self):
+ result = StatusCheckResult(check=self)
+ instances = self.instance_set.all()
+ target = self.instance_set.get().address
+ response = os.system("ping -c 1 " + target)
+ if response == 0:
+ result.succeeded = True
+ else:
+ result.succeeded = False
+ result.error = "Could not connect, host is most likely down"
+ return result
+
class GraphiteStatusCheck(StatusCheck):
@@ -532,7 +589,6 @@ class HttpStatusCheck(StatusCheck):
result.succeeded = True
return result
-
class JenkinsStatusCheck(StatusCheck):
class Meta(StatusCheck.Meta):
diff --git a/app/cabotapp/views.py b/app/cabotapp/views.py
index 4067245..e002233 100644
--- a/app/cabotapp/views.py
+++ b/app/cabotapp/views.py
@@ -5,8 +5,8 @@ from django.http import HttpResponse, HttpResponseRedirect
from django.core.urlresolvers import reverse_lazy
from django.conf import settings
from models import (
- StatusCheck, GraphiteStatusCheck, JenkinsStatusCheck, HttpStatusCheck,
- StatusCheckResult, UserProfile, Service, Shift, get_duty_officers)
+ 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
@@ -59,7 +59,6 @@ class StatusCheckResultDetailView(LoginRequiredMixin, DetailView):
model = StatusCheckResult
context_object_name = 'result'
-
class SymmetricalForm(forms.ModelForm):
symmetrical_fields = () # Iterable of 2-tuples (field, model)
@@ -90,7 +89,7 @@ base_widgets = {
class StatusCheckForm(SymmetricalForm):
- symmetrical_fields = ('service_set',)
+ symmetrical_fields = ('service_set', 'instance_set')
service_set = forms.ModelMultipleChoiceField(
queryset=Service.objects.all(),
required=False,
@@ -103,6 +102,17 @@ class StatusCheckForm(SymmetricalForm):
)
)
+ instance_set = forms.ModelMultipleChoiceField(
+ queryset=Instance.objects.all(),
+ required=False,
+ help_text='Link to instance(s).',
+ widget=forms.SelectMultiple(
+ attrs={
+ 'data-rel': 'chosen',
+ 'style': 'width: 70%',
+ },
+ )
+ )
class GraphiteStatusCheckForm(StatusCheckForm):
@@ -135,6 +145,19 @@ class GraphiteStatusCheckForm(StatusCheckForm):
})
+class ICMPStatusCheckForm(StatusCheckForm):
+
+ class Meta:
+ model = ICMPStatusCheck
+ fields = (
+ 'name',
+ 'frequency',
+ 'importance',
+ 'active',
+ 'debounce',
+ )
+ widgets = dict(**base_widgets)
+
class HttpStatusCheckForm(StatusCheckForm):
class Meta:
@@ -195,6 +218,57 @@ class UserProfileForm(forms.ModelForm):
model = UserProfile
exclude = ('user',)
+class InstanceForm(SymmetricalForm):
+
+ 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%',
+ },
+ )
+ )
+
+
+ class Meta:
+ model = Instance
+ template_name = 'instance_form.html'
+ fields = (
+ 'name',
+ 'address',
+ 'users_to_notify',
+ 'status_checks',
+ 'service_set',
+ 'email_alert',
+ 'hipchat_alert',
+ 'sms_alert',
+ 'telephone_alert',
+ 'alerts_enabled',
+ )
+ widgets = {
+ 'name': forms.TextInput(attrs={'style': 'width: 30%;'}),
+ 'address': forms.TextInput(attrs={'style': 'width: 70%;'}),
+ 'status_checks': forms.SelectMultiple(attrs={
+ 'data-rel': 'chosen',
+ 'style': 'width: 70%',
+ }),
+ 'service_set': forms.SelectMultiple(attrs={
+ 'data-rel': 'chosen',
+ 'style': 'width: 70%',
+ }),
+ 'users_to_notify': forms.CheckboxSelectMultiple(),
+ }
+
+ def __init__(self, *args, **kwargs):
+ ret = super(InstanceForm, self).__init__(*args, **kwargs)
+ self.fields['users_to_notify'].queryset = User.objects.filter(
+ is_active=True)
+ return ret
+
class ServiceForm(forms.ModelForm):
@@ -206,6 +280,7 @@ class ServiceForm(forms.ModelForm):
'url',
'users_to_notify',
'status_checks',
+ 'instances',
'email_alert',
'hipchat_alert',
'sms_alert',
@@ -220,6 +295,10 @@ class ServiceForm(forms.ModelForm):
'data-rel': 'chosen',
'style': 'width: 70%',
}),
+ 'instances': forms.SelectMultiple(attrs={
+ 'data-rel': 'chosen',
+ 'style': 'width: 70%',
+ }),
'users_to_notify': forms.CheckboxSelectMultiple(),
'hackpad_id': forms.TextInput(attrs={'style': 'width:30%;'}),
}
@@ -293,20 +372,30 @@ class CheckCreateView(LoginRequiredMixin, CreateView):
if metric:
initial['metric'] = metric
service_id = self.request.GET.get('service')
+ instance_id = self.request.GET.get('instance')
+
if service_id:
try:
service = Service.objects.get(id=service_id)
initial['service_set'] = [service]
except Service.DoesNotExist:
pass
+
+ if instance_id:
+ try:
+ instance = Instance.objects.get(id=instance_id)
+ initial['instance_set'] = [instance]
+ except Instance.DoesNotExist:
+ pass
+
return initial
def get_success_url(self):
- if self.request.GET.get('service') != '':
+ if self.request.GET.get('service'):
return reverse('service', kwargs={'pk': self.request.GET.get('service')})
- else:
- return reverse('checks')
-
+ if self.request.GET.get('instance'):
+ return reverse('instance', kwargs={'pk': self.request.GET.get('instance')})
+ return reverse('checks')
class CheckUpdateView(LoginRequiredMixin, UpdateView):
@@ -315,8 +404,16 @@ 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
-class GraphiteCheckCreateView(CheckCreateView):
+
+class ICMPCheckUpdateView(CheckUpdateView):
+ model = ICMPStatusCheck
+ form_class = ICMPStatusCheckForm
+
+class ICMPhiteCheckCreateView(CheckCreateView):
model = GraphiteStatusCheck
form_class = GraphiteStatusCheckForm
@@ -325,6 +422,9 @@ class GraphiteCheckUpdateView(CheckUpdateView):
model = GraphiteStatusCheck
form_class = GraphiteStatusCheckForm
+class GraphiteCheckCreateView(CheckCreateView):
+ model = GraphiteStatusCheck
+ form_class = GraphiteStatusCheckForm
class HttpCheckCreateView(CheckCreateView):
model = HttpStatusCheck
@@ -397,6 +497,14 @@ class UserProfileUpdateView(LoginRequiredMixin, UpdateView):
return profile
+class InstanceListView(LoginRequiredMixin, ListView):
+
+ model = Instance
+ context_object_name = 'instances'
+
+ def get_queryset(self):
+ return Instance.objects.all().order_by('name').prefetch_related('status_checks')
+
class ServiceListView(LoginRequiredMixin, ListView):
model = Service
context_object_name = 'services'
@@ -404,6 +512,20 @@ 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'
+
+ def get_context_data(self, **kwargs):
+ context = super(InstanceDetailView, self).get_context_data(**kwargs)
+ date_from = date.today() - relativedelta(day=1)
+ context['report_form'] = StatusCheckReportForm(initial={
+ 'checks': self.object.status_checks.all(),
+ 'service': self.object,
+ 'date_from': date_from,
+ 'date_to': date_from + relativedelta(months=1) - relativedelta(days=1)
+ })
+ return context
class ServiceDetailView(LoginRequiredMixin, DetailView):
model = Service
@@ -421,6 +543,43 @@ class ServiceDetailView(LoginRequiredMixin, DetailView):
return context
+class InstanceCreateView(LoginRequiredMixin, CreateView):
+ model = Instance
+ form_class = InstanceForm
+
+ def generateDefaultPingCheck(self):
+ pc = ICMPStatusCheck()
+ pc.created_by = self.request.user
+ pc.name = "Default Ping Check"
+ pc.frequency = 5
+ pc.importance = Service.ERROR_STATUS
+ pc.active = True
+ pc.debounce = 0
+ pc.save()
+ pc.instance_set = [Instance.objects.get(pk=self.object.id)]
+ pc.save()
+
+ def get_success_url(self):
+#Where else can I run things when an instance gets created?
+ self.generateDefaultPingCheck()
+ return reverse('instance', kwargs={'pk': self.object.id})
+
+ def get_initial(self):
+ if self.initial:
+ initial = self.initial
+ else:
+ initial = {}
+ 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
+
class ServiceCreateView(LoginRequiredMixin, CreateView):
model = Service
form_class = ServiceForm
@@ -428,6 +587,12 @@ class ServiceCreateView(LoginRequiredMixin, CreateView):
def get_success_url(self):
return reverse('service', kwargs={'pk': self.object.id})
+class InstanceUpdateView(LoginRequiredMixin, UpdateView):
+ model = Instance
+ form_class = InstanceForm
+
+ def get_success_url(self):
+ return reverse('instance', kwargs={'pk': self.object.id})
class ServiceUpdateView(LoginRequiredMixin, UpdateView):
model = Service
@@ -443,6 +608,11 @@ class ServiceDeleteView(LoginRequiredMixin, DeleteView):
context_object_name = 'service'
template_name = 'cabotapp/service_confirm_delete.html'
+class InstanceDeleteView(LoginRequiredMixin, DeleteView):
+ model = Instance
+ success_url = reverse_lazy('instances')
+ context_object_name = 'instance'
+ template_name = 'cabotapp/instance_confirm_delete.html'
class ShiftListView(LoginRequiredMixin, ListView):
model = Shift
diff --git a/app/templates/base.html b/app/templates/base.html
index 1f1016b..a862060 100644
--- a/app/templates/base.html
+++ b/app/templates/base.html
@@ -41,6 +41,9 @@
diff --git a/app/templates/cabotapp/_instance_list.html b/app/templates/cabotapp/_instance_list.html
new file mode 100644
index 0000000..a29668c
--- /dev/null
+++ b/app/templates/cabotapp/_instance_list.html
@@ -0,0 +1,43 @@
+
+
+
+
+{% if not instances %}
+
+
+ No instances configured
+
+
+{% else %}
+ Name |
+ Overall |
+ Active checks |
+ Disabled checks |
+ |
+
+
+
+ {% for instance in instances %}
+
+
+ {{instance.name}}
+ |
+
+ {% if instance.alerts_enabled %}{{ instance.overall_status|lower|capfirst }}{% else %}Disabled{% endif %}
+ |
+
+ {{ instance.active_status_checks.all.count }}
+ |
+
+ {{ instance.inactive_status_checks.all.count }}
+ |
+
+
+
+
+ |
+
+ {% endfor %}
+
+{% endif %}
+
diff --git a/app/templates/cabotapp/_service_list.html b/app/templates/cabotapp/_service_list.html
new file mode 100644
index 0000000..e5f57e4
--- /dev/null
+++ b/app/templates/cabotapp/_service_list.html
@@ -0,0 +1,43 @@
+
+
+
+
+{% if not services %}
+
+
+ No services configured
+
+
+{% else %}
+ Name |
+ Overall |
+ Active checks |
+ Disabled checks |
+ |
+
+
+
+ {% for service in services %}
+
+
+ {{service.name}}
+ |
+
+ {% if service.alerts_enabled %}{{ service.overall_status|lower|capfirst }}{% else %}Disabled{% endif %}
+ |
+
+ {{ service.active_status_checks.all.count }}
+ |
+
+ {{ service.inactive_status_checks.all.count }}
+ |
+
+
+
+
+ |
+
+ {% endfor %}
+
+{% endif %}
+
diff --git a/app/templates/cabotapp/_statuscheck_list.html b/app/templates/cabotapp/_statuscheck_list.html
index 2fd8097..07dd356 100644
--- a/app/templates/cabotapp/_statuscheck_list.html
+++ b/app/templates/cabotapp/_statuscheck_list.html
@@ -15,6 +15,9 @@
{% if checks_type == "All" or checks_type == "Jenkins" %}
{% endif %}
+ {% if checks_type == "All" or checks_type == "ICMP" %}
+
+ {% endif %}
@@ -37,6 +40,7 @@
Test description |
Importance |
Service(s) |
+ Instance(s) |
|
@@ -81,6 +85,18 @@
No service
{% endif %}
+
+ {% for instance in check.instance_set.all %}
+ {{ instance.name }}
+ {% if forloop.last %}
+ {% else %}
+ /
+ {% endif %}
+ {% endfor %}
+ {% if not check.instance_set.all %}
+ No instance
+ {% endif %}
+ |
@@ -100,4 +116,4 @@
{% endif %}
-
\ No newline at end of file
+
diff --git a/app/templates/cabotapp/_statuscheck_list_instance.html b/app/templates/cabotapp/_statuscheck_list_instance.html
new file mode 100644
index 0000000..d851a70
--- /dev/null
+++ b/app/templates/cabotapp/_statuscheck_list_instance.html
@@ -0,0 +1,119 @@
+{% load extra %}
+
+
+
+
+ {{ checks_type }} checks
+
+
+ {% if checks_type == "All" or checks_type == "Graphite" %}
+
+ {% endif %}
+ {% if checks_type == "All" or checks_type == "Http" %}
+
+ {% endif %}
+ {% if checks_type == "All" or checks_type == "Jenkins" %}
+
+ {% endif %}
+ {% if checks_type == "All" or checks_type == "ICMP" %}
+
+ {% endif %}
+
+
+
+
+
+
+
+ {% if not checks %}
+ No checks configured
+ {% else %}
+
+
+
+ Name |
+ Status |
+ |
+ {% if checks_type == "All" %}
+ Type |
+ {% endif %}
+ Test description |
+ Importance |
+ Service(s) |
+ Instance(s) |
+ |
+
+
+
+ {% for check in checks %}
+
+
+ {{check.name}}
+ |
+
+ {% if check.active %}
+
+ {{ check.calculated_status|capfirst }}
+
+ {% else %}
+ Disabled
+ {% endif %}
+ |
+
+ {% if not check.recent_results %}
+ No results available
+ {% endif %}
+ |
+ {% if checks_type == "All" %}
+
+
+ |
+ {% endif %}
+
+ {% if check.polymorphic_ctype.model == 'graphitestatuscheck' %}{{ check.metric|truncatechars:70 }} {{ check.check_type }} {{ check.value }}{% if check.expected_num_hosts %} (from {{ check.expected_num_hosts }} hosts){% endif %}{% elif check.polymorphic_ctype.model == 'httpstatuscheck' %}Status code {{ check.status_code }} from {{ check.endpoint }}{% if check.text_match %}; match text /{{ check.text_match }}/{% endif %}{% elif check.polymorphic_ctype.model == 'jenkinsstatuscheck' %}Monitor job {{ check.name }}{% if check.max_queued_build_time %}; check no build waiting for >{{ check.max_queued_build_time }} minutes{% endif %}{% endif %}
+ |
+ {{ check.get_importance_display }} |
+
+ {% for service in check.service_set.all %}
+ {{ service.name }}
+ {% if forloop.last %}
+ {% else %}
+ /
+ {% endif %}
+ {% endfor %}
+ {% if not check.service_set.all %}
+ No service
+ {% endif %}
+ |
+
+ {% for instance in check.instance_set.all %}
+ {{ instance.name }}
+ {% if forloop.last %}
+ {% else %}
+ /
+ {% endif %}
+ {% endfor %}
+ {% if not check.instance_set.all %}
+ No instance
+ {% endif %}
+ |
+
+
+
+
+
+
+
+ {% if checks_type == "Jenkins" %}
+
+
+
+ {% endif %}
+ |
+
+ {% endfor %}
+
+
+ {% endif %}
+
+
diff --git a/app/templates/cabotapp/_statuscheck_list_service.html b/app/templates/cabotapp/_statuscheck_list_service.html
new file mode 100644
index 0000000..6f3b759
--- /dev/null
+++ b/app/templates/cabotapp/_statuscheck_list_service.html
@@ -0,0 +1,103 @@
+{% load extra %}
+
+
+
+
+ {{ checks_type }} checks
+
+
+ {% if checks_type == "All" or checks_type == "Graphite" %}
+
+ {% endif %}
+ {% if checks_type == "All" or checks_type == "Http" %}
+
+ {% endif %}
+ {% if checks_type == "All" or checks_type == "Jenkins" %}
+
+ {% endif %}
+
+
+
+
+
+
+
+ {% if not checks %}
+ No checks configured
+ {% else %}
+
+
+
+ Name |
+ Status |
+ |
+ {% if checks_type == "All" %}
+ Type |
+ {% endif %}
+ Test description |
+ Importance |
+ Service(s) |
+ |
+
+
+
+ {% for check in checks %}
+
+
+ {{check.name}}
+ |
+
+ {% if check.active %}
+
+ {{ check.calculated_status|capfirst }}
+
+ {% else %}
+ Disabled
+ {% endif %}
+ |
+
+ {% if not check.recent_results %}
+ No results available
+ {% endif %}
+ |
+ {% if checks_type == "All" %}
+
+
+ |
+ {% endif %}
+
+ {% if check.polymorphic_ctype.model == 'graphitestatuscheck' %}{{ check.metric|truncatechars:70 }} {{ check.check_type }} {{ check.value }}{% if check.expected_num_hosts %} (from {{ check.expected_num_hosts }} hosts){% endif %}{% elif check.polymorphic_ctype.model == 'httpstatuscheck' %}Status code {{ check.status_code }} from {{ check.endpoint }}{% if check.text_match %}; match text /{{ check.text_match }}/{% endif %}{% elif check.polymorphic_ctype.model == 'jenkinsstatuscheck' %}Monitor job {{ check.name }}{% if check.max_queued_build_time %}; check no build waiting for >{{ check.max_queued_build_time }} minutes{% endif %}{% endif %}
+ |
+ {{ check.get_importance_display }} |
+
+ {% for service in check.service_set.all %}
+ {{ service.name }}
+ {% if forloop.last %}
+ {% else %}
+ /
+ {% endif %}
+ {% endfor %}
+ {% if not check.service_set.all %}
+ No service
+ {% endif %}
+ |
+
+
+
+
+
+
+
+ {% if checks_type == "Jenkins" %}
+
+
+
+ {% endif %}
+ |
+
+ {% endfor %}
+
+
+ {% endif %}
+
+
diff --git a/app/templates/cabotapp/instance_confirm_delete.html b/app/templates/cabotapp/instance_confirm_delete.html
new file mode 100644
index 0000000..dd037ed
--- /dev/null
+++ b/app/templates/cabotapp/instance_confirm_delete.html
@@ -0,0 +1,18 @@
+{% extends 'base.html' %}
+
+{% block content %}
+Delete service
+
+{% endblock %}
+
+{% load compress %}
+{% block js %}
+{{ block.super }}
+{% compress js %}
+
+{% endcompress %}
+{% endblock %}
diff --git a/app/templates/cabotapp/instance_detail.html b/app/templates/cabotapp/instance_detail.html
new file mode 100644
index 0000000..d16faa4
--- /dev/null
+++ b/app/templates/cabotapp/instance_detail.html
@@ -0,0 +1,225 @@
+{% extends 'base.html' %}
+
+{% block title %}{{ block.super }} - {{ instance.name }}{% endblock title %}
+
+{% block content %}
+
+
+
+
+ {{ instance.name }}
+ {{ instance.overall_status|lower|capfirst }} {% if instance.alerts_enabled %}Alerts enabled{%else %}Alerts disabled{% endif %}
+
+
+
+
+
+
+
+ Configuration
+
+
+ Address
+ {{ instance.address|urlize|default:"None configured" }}
+
+
+
+ Users watching
+
+ {% if not instance.users_to_notify.all %}
+ No users subscribed
+ {% else %}
+ {{ instance.users_to_notify.all|join:", " }}
+ {% endif %}
+
+
+
+
+ Alert types
+
+
+ {% if instance.email_alert %} Email{% endif %}
+ {% if instance.hipchat_alert %} Hipchat{% endif %}
+ {% if instance.sms_alert %} SMS{% endif %}
+ {% if instance.telephone_alert %} Telephone{% endif %}
+
+
+
+
+
+
+ Status (24 hours)
+
+
+
+
+
+
+{% include 'cabotapp/_service_list.html' with services=instance.service_set.all %}
+
+
+
+
+
+{% include 'cabotapp/_statuscheck_list_instance.html' with checks=instance.graphite_status_checks.all instance=instance checks_type="Graphite" %}
+
+
+
+{% include 'cabotapp/_statuscheck_list_instance.html' with checks=instance.http_status_checks.all instance=instance checks_type="Http" %}
+
+
+
+{% include 'cabotapp/_statuscheck_list_instance.html' with checks=instance.jenkins_status_checks.all instance=instance checks_type="Jenkins" %}
+
+
+
+{% include 'cabotapp/_statuscheck_list_instance.html' with checks=instance.icmp_status_checks.all instance=instance checks_type="ICMP" %}
+
+
+
+
+
+
+
+ Status check report
+
+
+
+
+
+
+
+
+
+
+
+ Recovery instructions
+
+ {% if instance.hackpad_id %}
+
+
+
+ {% else %}
+ No hackpad configured
+ {% endif %}
+
+
+
+
+{% endblock content %}
+
+{% block js %}
+{% load compress %}
+{% load jsonify %}
+{{ block.super }}
+
+
+{% compress js %}
+
+
+
+{% endcompress %}
+{% endblock js %}
diff --git a/app/templates/cabotapp/instance_form.html b/app/templates/cabotapp/instance_form.html
new file mode 100644
index 0000000..5da7d3c
--- /dev/null
+++ b/app/templates/cabotapp/instance_form.html
@@ -0,0 +1,36 @@
+{% extends 'base.html' %}
+
+{% block content %}
+
+
+
+ {% if form.instance.id %}Edit instance{% else %}New instance{% endif %}
+
+
+
+
+{% endblock %}
+
+{% load compress %}
+{% block js %}
+{{ block.super }}
+{% compress js %}
+
+{% endcompress %}
+{% endblock %}
diff --git a/app/templates/cabotapp/instance_list.html b/app/templates/cabotapp/instance_list.html
new file mode 100644
index 0000000..6d4f850
--- /dev/null
+++ b/app/templates/cabotapp/instance_list.html
@@ -0,0 +1,63 @@
+{% extends 'base.html' %}
+
+{% block content %}
+
+
+
+ {% if not instances %}
+ No instances
+ {% else %}
+
+
+
+ Name |
+ Overall |
+ Active checks |
+ Disabled checks |
+ |
+
+
+
+ {% for instance in instances %}
+
+
+ {{instance.name}}
+ |
+
+ {% if instance.alerts_enabled %}{{ instance.overall_status|lower|capfirst }}{% else %}Disabled{% endif %}
+ |
+
+ {{ instance.active_status_checks.all.count }}
+ |
+
+ {{ instance.inactive_status_checks.all.count }}
+ |
+
+
+
+
+ |
+
+ {% endfor %}
+
+
+ {% endif %}
+
+
+{% endblock content %}
+
+{% block js %}
+{% load compress %}
+{{ block.super }}
+{% compress js %}
+
+{% endcompress %}
+{% endblock js %}
diff --git a/app/templates/cabotapp/service_detail.html b/app/templates/cabotapp/service_detail.html
index 9e6781b..fed5863 100644
--- a/app/templates/cabotapp/service_detail.html
+++ b/app/templates/cabotapp/service_detail.html
@@ -55,18 +55,29 @@
+
+
+
+ Instances
+
+{% include 'cabotapp/_instance_list.html' with instances=service.instances.all %}
+
+
+
+
+{% include 'cabotapp/_statuscheck_list_service.html' with checks=service.graphite_status_checks.all service=service checks_type="Graphite" %}
-{% include 'cabotapp/_statuscheck_list.html' with checks=service.graphite_status_checks.all service=service checks_type="Graphite" %}
+{% include 'cabotapp/_statuscheck_list_service.html' with checks=service.http_status_checks.all service=service checks_type="Http" %}
-{% include 'cabotapp/_statuscheck_list.html' with checks=service.http_status_checks.all service=service checks_type="Http" %}
-
-
-
-{% include 'cabotapp/_statuscheck_list.html' with checks=service.jenkins_status_checks.all service=service checks_type="Jenkins" %}
+{% include 'cabotapp/_statuscheck_list_service.html' with checks=service.jenkins_status_checks.all service=service checks_type="Jenkins" %}
diff --git a/app/templates/cabotapp/statuscheck_detail.html b/app/templates/cabotapp/statuscheck_detail.html
index 17114a5..84d4218 100644
--- a/app/templates/cabotapp/statuscheck_detail.html
+++ b/app/templates/cabotapp/statuscheck_detail.html
@@ -6,14 +6,14 @@
-
+
{{ check.name }}
{{ check.calculated_status|capfirst }}
{% if check.polymorphic_ctype.model == 'jenkinsstatuscheck' %}
{% endif %}
-
+
@@ -81,4 +81,4 @@
{% endcompress %}
-{% endblock js %}
\ No newline at end of file
+{% endblock js %}
diff --git a/app/templates/cabotapp/statuscheck_list.html b/app/templates/cabotapp/statuscheck_list.html
index 2f50b60..101821b 100644
--- a/app/templates/cabotapp/statuscheck_list.html
+++ b/app/templates/cabotapp/statuscheck_list.html
@@ -21,4 +21,4 @@
$('.sparktristate').sparkline('html', {type: 'tristate'})
{% endcompress %}
-{% endblock js %}
\ No newline at end of file
+{% endblock js %}
diff --git a/app/urls.py b/app/urls.py
index c263b6e..70a25ae 100644
--- a/app/urls.py
+++ b/app/urls.py
@@ -3,10 +3,12 @@ from cabotapp.views import (
run_status_check, graphite_api_data, twiml_callback, checks_run_recently,
GraphiteCheckCreateView, GraphiteCheckUpdateView,
HttpCheckCreateView, HttpCheckUpdateView,
+ ICMPCheckCreateView, ICMPCheckUpdateView,
JenkinsCheckCreateView, JenkinsCheckUpdateView,
StatusCheckDeleteView, StatusCheckListView, StatusCheckDetailView,
StatusCheckResultDetailView, StatusCheckReportView)
-from cabotapp.views import (ServiceListView, ServiceDetailView,
+from cabotapp.views import (InstanceListView, InstanceDetailView,
+ InstanceUpdateView, InstanceCreateView, InstanceDeleteView, ServiceListView, ServiceDetailView,
ServiceUpdateView, ServiceCreateView, ServiceDeleteView,
UserProfileUpdateView, ShiftListView, subscriptions)
from django.contrib import admin
@@ -43,6 +45,19 @@ urlpatterns = patterns('',
url(r'^service/(?P\d+)/',
view=ServiceDetailView.as_view(), name='service'),
+ url(r'^instances/', view=InstanceListView.as_view(),
+ name='instances'),
+ url(r'^instance/create/', view=InstanceCreateView.as_view(),
+ name='create-instance'),
+ url(r'^instance/update/(?P\d+)/',
+ view=InstanceUpdateView.as_view(
+ ), name='update-instance'),
+ url(r'^instance/delete/(?P\d+)/',
+ view=InstanceDeleteView.as_view(
+ ), name='delete-instance'),
+ url(r'^instance/(?P\d+)/',
+ view=InstanceDetailView.as_view(), name='instance'),
+
url(r'^checks/$', view=StatusCheckListView.as_view(),
name='checks'),
url(r'^check/run/(?P\d+)/',
@@ -55,6 +70,11 @@ urlpatterns = patterns('',
url(r'^checks/report/$',
view=StatusCheckReportView.as_view(), name='checks-report'),
+ url(r'^icmpcheck/create/', view=ICMPCheckCreateView.as_view(),
+ name='create-icmp-check'),
+ url(r'^icmpcheck/update/(?P\d+)/',
+ view=ICMPCheckUpdateView.as_view(
+ ), name='update-icmp-check'),
url(r'^graphitecheck/create/',
view=GraphiteCheckCreateView.as_view(
), name='create-check'),
|