mirror of
https://github.com/status-im/cabot.git
synced 2025-02-24 18:38:07 +00:00
Merge branch 'instances' of github.com:jmontineri/cabot into jmontineri-instances
Conflicts: app/cabotapp/views.py
This commit is contained in:
commit
45c2e13653
@ -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)
|
||||
|
@ -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']
|
@ -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):
|
||||
|
@ -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
|
||||
|
@ -41,6 +41,9 @@
|
||||
</div>
|
||||
<div class="navbar-collapse collapse" id="navbar-main">
|
||||
<ul class="nav navbar-nav">
|
||||
<li>
|
||||
<a href="{% url instances %}"><i class="fa fa-desktop"></i> Instances</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url services %}"><i class="fa fa-gears"></i> Services</a>
|
||||
</li>
|
||||
@ -54,15 +57,21 @@
|
||||
<li>
|
||||
<a href="{% url create-service %}"><i class="fa fa-gears"></i> Service</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url create-instance %}"><i class="fa fa-desktop"></i> Instance</a>
|
||||
</li>
|
||||
<li class="divider"></li>
|
||||
<li>
|
||||
<a href="{% url create-check %}?service={{ service.id }}" class=""><i class="glyphicon glyphicon-signal" title="Add new metric check"></i> Graphite check</a>
|
||||
<a href="{% url create-check %}?service={{ service.id }}&instance={{ instance.id }}" class=""><i class="glyphicon glyphicon-signal" title="Add new metric check"></i> Graphite check</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url create-http-check %}?service={{ service.id }}" class="" title="Add new Http check"><i class="glyphicon glyphicon-arrow-up"></i> Http check</a>
|
||||
<a href="{% url create-http-check %}?service={{ service.id }}&instance={{ instance.id }}" class="" title="Add new Http check"><i class="glyphicon glyphicon-arrow-up"></i> Http check</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url create-jenkins-check %}?service={{ service.id }}" class="" title="Add new Jenkins check"><i class="glyphicon glyphicon-ok"></i> Jenkins check</a>
|
||||
<a href="{% url create-jenkins-check %}?service={{ service.id }}&instance={{ instance.id }}" class="" title="Add new Jenkins check"><i class="glyphicon glyphicon-ok"></i> Jenkins check</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url create-icmp-check %}?service={{ service.id }}&instance={{ instance.id }}" class="" title="Add new ICMP check"><i class="glyphicon glyphicon-transfer"></i> ICMP check</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
43
app/templates/cabotapp/_instance_list.html
Normal file
43
app/templates/cabotapp/_instance_list.html
Normal file
@ -0,0 +1,43 @@
|
||||
|
||||
<table class="table bootstrap-datatable datatable">
|
||||
<thead>
|
||||
<tr>
|
||||
{% if not instances %}
|
||||
<div class="col-xs-11 col-xs-offset-1">
|
||||
<hr></hr>
|
||||
No instances configured
|
||||
</div>
|
||||
</tr>
|
||||
{% else %}
|
||||
<th>Name</th>
|
||||
<th>Overall</th>
|
||||
<th>Active checks</th>
|
||||
<th>Disabled checks</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for instance in instances %}
|
||||
<tr class="{% if instance.alerts_enabled %}enabled{% else %}warning{% endif %}">
|
||||
<td>
|
||||
<a href="{% url instance pk=instance.id %}" title="Alerts {% if instance.alerts_enabled %}enabled{% else %}disabled{% endif %}">{{instance.name}} </a>
|
||||
</td>
|
||||
<td>
|
||||
<span class="label label-{% if not instance.alerts_enabled %}warning{% else %}{% if instance.overall_status == instance.PASSING_STATUS %}success{% else %}danger{% endif %}{% endif %}">{% if instance.alerts_enabled %}{{ instance.overall_status|lower|capfirst }}{% else %}Disabled{% endif %}</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="label label-{% if instance.active_status_checks.all.count > 0 %}{% if instance.overall_status != instance.PASSING_STATUS %}danger{% else %}success{% endif %}{% else %}default{% endif %}">{{ instance.active_status_checks.all.count }}</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="label label-{% if instance.inactive_status_checks.all.count > 0 %}warning{% else %}default{% endif %}">{{ instance.inactive_status_checks.all.count }}</span>
|
||||
</td>
|
||||
<td class="text-right">
|
||||
<a class="btn btn-xs" href="{% url update-instance pk=instance.id %}" role="button">
|
||||
<i class="glyphicon glyphicon-edit"></i>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
{% endif %}
|
||||
</table>
|
43
app/templates/cabotapp/_service_list.html
Normal file
43
app/templates/cabotapp/_service_list.html
Normal file
@ -0,0 +1,43 @@
|
||||
|
||||
<table class="table bootstrap-datatable datatable">
|
||||
<thead>
|
||||
<tr>
|
||||
{% if not services %}
|
||||
<div class="col-xs-11 col-xs-offset-1">
|
||||
<hr></hr>
|
||||
No services configured
|
||||
</div>
|
||||
</tr>
|
||||
{% else %}
|
||||
<th>Name</th>
|
||||
<th>Overall</th>
|
||||
<th>Active checks</th>
|
||||
<th>Disabled checks</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for service in services %}
|
||||
<tr class="{% if service.alerts_enabled %}enabled{% else %}warning{% endif %}">
|
||||
<td>
|
||||
<a href="{% url service pk=service.id %}" title="Alerts {% if service.alerts_enabled %}enabled{% else %}disabled{% endif %}">{{service.name}} </a>
|
||||
</td>
|
||||
<td>
|
||||
<span class="label label-{% if not service.alerts_enabled %}warning{% else %}{% if service.overall_status == service.PASSING_STATUS %}success{% else %}danger{% endif %}{% endif %}">{% if service.alerts_enabled %}{{ service.overall_status|lower|capfirst }}{% else %}Disabled{% endif %}</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="label label-{% if service.active_status_checks.all.count > 0 %}{% if service.overall_status != service.PASSING_STATUS %}danger{% else %}success{% endif %}{% else %}default{% endif %}">{{ service.active_status_checks.all.count }}</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="label label-{% if service.inactive_status_checks.all.count > 0 %}warning{% else %}default{% endif %}">{{ service.inactive_status_checks.all.count }}</span>
|
||||
</td>
|
||||
<td class="text-right">
|
||||
<a class="btn btn-xs" href="{% url update-service pk=service.id %}" role="button">
|
||||
<i class="glyphicon glyphicon-edit"></i>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
{% endif %}
|
||||
</table>
|
@ -15,6 +15,9 @@
|
||||
{% if checks_type == "All" or checks_type == "Jenkins" %}
|
||||
<a href="{% url create-jenkins-check %}?service={{ service.id }}" class="" title="Add new Jenkins check"><i class="glyphicon glyphicon-plus"></i><i class="glyphicon glyphicon-ok"></i></a>
|
||||
{% endif %}
|
||||
{% if checks_type == "All" or checks_type == "ICMP" %}
|
||||
<a href="{% url create-icmp-check %}?service={{ service.id }}" class="" title="Add new ICMP check"><i class="glyphicon glyphicon-plus"></i><i class="glyphicon glyphicon-transfer"></i></a>
|
||||
{% endif %}
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
@ -37,6 +40,7 @@
|
||||
<th>Test description</th>
|
||||
<th>Importance</th>
|
||||
<th>Service(s)</th>
|
||||
<th>Instance(s)</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
@ -81,6 +85,18 @@
|
||||
<span class="label label-warning">No service</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% for instance in check.instance_set.all %}
|
||||
<a href="{% url instance pk=instance.id %}">{{ instance.name }}</a>
|
||||
{% if forloop.last %}
|
||||
{% else %}
|
||||
/
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% if not check.instance_set.all %}
|
||||
<span class="label label-warning">No instance</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="text-right">
|
||||
<a class="btn btn-xs" href="{% if check.polymorphic_ctype.model == 'graphitestatuscheck' %}{% url update-check pk=check.id %}{% elif check.polymorphic_ctype.model == 'httpstatuscheck' %}{% url update-http-check pk=check.id %}{% elif check.polymorphic_ctype.model == 'jenkinsstatuscheck' %}{% url update-jenkins-check pk=check.id %}{% endif %}">
|
||||
<i class="glyphicon glyphicon-edit"></i><span class="break"></span>
|
||||
@ -100,4 +116,4 @@
|
||||
</table>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
119
app/templates/cabotapp/_statuscheck_list_instance.html
Normal file
119
app/templates/cabotapp/_statuscheck_list_instance.html
Normal file
@ -0,0 +1,119 @@
|
||||
{% load extra %}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="col-xs-1"><h3><i class="{% if checks_type == "All" %}fa fa-cog{% else %}glyphicon glyphicon-{% if checks_type == "Http" %}arrow-up{% elif checks_type == "Jenkins" %}ok{% elif checks_type == "ICMP" %}transfer{% else %}signal{% endif %}{% endif %}"></i></h3></div>
|
||||
<div class="col-xs-8"><h3>{{ checks_type }} checks</h3></div>
|
||||
<div class="col-xs-3 text-right">
|
||||
<h3>
|
||||
{% if checks_type == "All" or checks_type == "Graphite" %}
|
||||
<a href="{% url create-check %}?instance={{ instance.id }}" class=""><i class="glyphicon glyphicon-plus" title="Add new metric check"></i><i class="glyphicon glyphicon-signal" title="Add new metric check"></i></a>
|
||||
{% endif %}
|
||||
{% if checks_type == "All" or checks_type == "Http" %}
|
||||
<a href="{% url create-http-check %}?instance={{ instance.id }}" class="" title="Add new Http check"><i class="glyphicon glyphicon-plus"></i><i class="glyphicon glyphicon-arrow-up"></i></a>
|
||||
{% endif %}
|
||||
{% if checks_type == "All" or checks_type == "Jenkins" %}
|
||||
<a href="{% url create-jenkins-check %}?instance={{ instance.id }}" class="" title="Add new Jenkins check"><i class="glyphicon glyphicon-plus"></i><i class="glyphicon glyphicon-ok"></i></a>
|
||||
{% endif %}
|
||||
{% if checks_type == "All" or checks_type == "ICMP" %}
|
||||
<a href="{% url create-icmp-check %}?instance={{ instance.id }}" class="" title="Add new ICMP check"><i class="glyphicon glyphicon-plus"></i><i class="glyphicon glyphicon-transfer"></i></a>
|
||||
{% endif %}
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
{% if not checks %}
|
||||
<div class="col-xs-11 col-xs-offset-1">No checks configured</div>
|
||||
{% else %}
|
||||
<table class="table bootstrap-datatable datatable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Status</th>
|
||||
<th></th>
|
||||
{% if checks_type == "All" %}
|
||||
<th class="text-center">Type</th>
|
||||
{% endif %}
|
||||
<th>Test description</th>
|
||||
<th>Importance</th>
|
||||
<th>Service(s)</th>
|
||||
<th>Instance(s)</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for check in checks %}
|
||||
<tr class="{% if check.active %}enabled{% else %}warning{% endif %}">
|
||||
<td title="{{ check.name }} - alerts {% if check.active %}enabled{% else %}disabled{% endif %}">
|
||||
<a href="{% url check pk=check.id %}">{{check.name}}</a>
|
||||
</td>
|
||||
<td title="{{ check.calculated_status }}">
|
||||
{% if check.active %}
|
||||
<span class="label label-{% if check.calculated_status == 'passing' %}success{% else %}danger{% endif %}">
|
||||
{{ check.calculated_status|capfirst }}
|
||||
</span>
|
||||
{% else %}
|
||||
<span class="label label-warning">Disabled</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td title="Last result from {{ check.last_run|timesince }} ago (rightmost is newest)" class="sparktristate" values="{{ check.cached_health }}">
|
||||
{% if not check.recent_results %}
|
||||
No results available
|
||||
{% endif %}
|
||||
</td>
|
||||
{% if checks_type == "All" %}
|
||||
<td class="text-center">
|
||||
<i class="glyphicon glyphicon-{% if check.polymorphic_ctype.model == 'graphitestatuscheck' %}signal{% elif check.polymorphic_ctype.model == 'httpstatuscheck' %}arrow-up{% elif check.polymorphic_ctype.model == 'jenkinsstatuscheck' %}ok{% endif %}"></i>
|
||||
</td>
|
||||
{% endif %}
|
||||
<td title="">
|
||||
{% 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 %}
|
||||
</td>
|
||||
<td>{{ check.get_importance_display }}</td>
|
||||
<td>
|
||||
{% for service in check.service_set.all %}
|
||||
<a href="{% url service pk=service.id %}">{{ service.name }}</a>
|
||||
{% if forloop.last %}
|
||||
{% else %}
|
||||
/
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% if not check.service_set.all %}
|
||||
<span class="label label-warning">No service</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% for instance in check.instance_set.all %}
|
||||
<a href="{% url instance pk=instance.id %}">{{ instance.name }}</a>
|
||||
{% if forloop.last %}
|
||||
{% else %}
|
||||
/
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% if not check.instance_set.all %}
|
||||
<span class="label label-warning">No instance</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="text-right">
|
||||
<a class="btn btn-xs" href="{% if check.polymorphic_ctype.model == 'graphitestatuscheck' %}{% url update-check pk=check.id %}{% elif check.polymorphic_ctype.model == 'httpstatuscheck' %}{% url update-http-check pk=check.id %}{% elif check.polymorphic_ctype.model == 'jenkinsstatuscheck' %}{% url update-jenkins-check pk=check.id %}{% endif %}">
|
||||
<i class="glyphicon glyphicon-edit"></i><span class="break"></span>
|
||||
</a>
|
||||
<a class="btn btn-xs" href="{% url run-check pk=check.id %}">
|
||||
<i class="glyphicon glyphicon-refresh"></i><span class="break"></span>
|
||||
</a>
|
||||
{% if checks_type == "Jenkins" %}
|
||||
<a class="btn btn-xs" href="{% jenkins_human_url check.name %}">
|
||||
<i class="glyphicon glyphicon-link"></i><span class="break"></span>
|
||||
</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
103
app/templates/cabotapp/_statuscheck_list_service.html
Normal file
103
app/templates/cabotapp/_statuscheck_list_service.html
Normal file
@ -0,0 +1,103 @@
|
||||
{% load extra %}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="col-xs-1"><h3><i class="{% if checks_type == "All" %}fa fa-cog{% else %}glyphicon glyphicon-{% if checks_type == "Http" %}arrow-up{% elif checks_type == "Jenkins" %}ok{% else %}signal{% endif %}{% endif %}"></i></h3></div>
|
||||
<div class="col-xs-8"><h3>{{ checks_type }} checks</h3></div>
|
||||
<div class="col-xs-3 text-right">
|
||||
<h3>
|
||||
{% if checks_type == "All" or checks_type == "Graphite" %}
|
||||
<a href="{% url create-check %}?service={{ service.id }}" class=""><i class="glyphicon glyphicon-plus" title="Add new metric check"></i><i class="glyphicon glyphicon-signal" title="Add new metric check"></i></a>
|
||||
{% endif %}
|
||||
{% if checks_type == "All" or checks_type == "Http" %}
|
||||
<a href="{% url create-http-check %}?service={{ service.id }}" class="" title="Add new Http check"><i class="glyphicon glyphicon-plus"></i><i class="glyphicon glyphicon-arrow-up"></i></a>
|
||||
{% endif %}
|
||||
{% if checks_type == "All" or checks_type == "Jenkins" %}
|
||||
<a href="{% url create-jenkins-check %}?service={{ service.id }}" class="" title="Add new Jenkins check"><i class="glyphicon glyphicon-plus"></i><i class="glyphicon glyphicon-ok"></i></a>
|
||||
{% endif %}
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
{% if not checks %}
|
||||
<div class="col-xs-11 col-xs-offset-1">No checks configured</div>
|
||||
{% else %}
|
||||
<table class="table bootstrap-datatable datatable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Status</th>
|
||||
<th></th>
|
||||
{% if checks_type == "All" %}
|
||||
<th class="text-center">Type</th>
|
||||
{% endif %}
|
||||
<th>Test description</th>
|
||||
<th>Importance</th>
|
||||
<th>Service(s)</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for check in checks %}
|
||||
<tr class="{% if check.active %}enabled{% else %}warning{% endif %}">
|
||||
<td title="{{ check.name }} - alerts {% if check.active %}enabled{% else %}disabled{% endif %}">
|
||||
<a href="{% url check pk=check.id %}">{{check.name}}</a>
|
||||
</td>
|
||||
<td title="{{ check.calculated_status }}">
|
||||
{% if check.active %}
|
||||
<span class="label label-{% if check.calculated_status == 'passing' %}success{% else %}danger{% endif %}">
|
||||
{{ check.calculated_status|capfirst }}
|
||||
</span>
|
||||
{% else %}
|
||||
<span class="label label-warning">Disabled</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td title="Last result from {{ check.last_run|timesince }} ago (rightmost is newest)" class="sparktristate" values="{{ check.cached_health }}">
|
||||
{% if not check.recent_results %}
|
||||
No results available
|
||||
{% endif %}
|
||||
</td>
|
||||
{% if checks_type == "All" %}
|
||||
<td class="text-center">
|
||||
<i class="glyphicon glyphicon-{% if check.polymorphic_ctype.model == 'graphitestatuscheck' %}signal{% elif check.polymorphic_ctype.model == 'httpstatuscheck' %}arrow-up{% elif check.polymorphic_ctype.model == 'jenkinsstatuscheck' %}ok{% endif %}"></i>
|
||||
</td>
|
||||
{% endif %}
|
||||
<td title="">
|
||||
{% 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 %}
|
||||
</td>
|
||||
<td>{{ check.get_importance_display }}</td>
|
||||
<td>
|
||||
{% for service in check.service_set.all %}
|
||||
<a href="{% url service pk=service.id %}">{{ service.name }}</a>
|
||||
{% if forloop.last %}
|
||||
{% else %}
|
||||
/
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% if not check.service_set.all %}
|
||||
<span class="label label-warning">No service</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="text-right">
|
||||
<a class="btn btn-xs" href="{% if check.polymorphic_ctype.model == 'graphitestatuscheck' %}{% url update-check pk=check.id %}{% elif check.polymorphic_ctype.model == 'httpstatuscheck' %}{% url update-http-check pk=check.id %}{% elif check.polymorphic_ctype.model == 'jenkinsstatuscheck' %}{% url update-jenkins-check pk=check.id %}{% endif %}">
|
||||
<i class="glyphicon glyphicon-edit"></i><span class="break"></span>
|
||||
</a>
|
||||
<a class="btn btn-xs" href="{% url run-check pk=check.id %}">
|
||||
<i class="glyphicon glyphicon-refresh"></i><span class="break"></span>
|
||||
</a>
|
||||
{% if checks_type == "Jenkins" %}
|
||||
<a class="btn btn-xs" href="{% jenkins_human_url check.name %}">
|
||||
<i class="glyphicon glyphicon-link"></i><span class="break"></span>
|
||||
</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
18
app/templates/cabotapp/instance_confirm_delete.html
Normal file
18
app/templates/cabotapp/instance_confirm_delete.html
Normal file
@ -0,0 +1,18 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Delete service</h1>
|
||||
<form action="." method="post">{% csrf_token %}
|
||||
<button type="submit" class="btn btn-danger">Delete {{ object }}</button>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
{% load compress %}
|
||||
{% block js %}
|
||||
{{ block.super }}
|
||||
{% compress js %}
|
||||
<script type="text/coffeescript">
|
||||
|
||||
</script>
|
||||
{% endcompress %}
|
||||
{% endblock %}
|
225
app/templates/cabotapp/instance_detail.html
Normal file
225
app/templates/cabotapp/instance_detail.html
Normal file
@ -0,0 +1,225 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block title %}{{ block.super }} - {{ instance.name }}{% endblock title %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="col-xs-1"><h2><i class="fa fa-desktop"></i></h2></div>
|
||||
<div class="col-xs-5"><h2><span class="break"></span>{{ instance.name }}</h2></div>
|
||||
<div class="col-xs-4 text-right"><h2><span class="label label-{% if instance.overall_status == instance.PASSING_STATUS %}success{% else %}danger{% endif %}">{{ instance.overall_status|lower|capfirst }}</span> <span class="label label-{% if instance.alerts_enabled %}success{% else %}warning{% endif %}">{% if instance.alerts_enabled %}Alerts enabled{%else %}Alerts disabled{% endif %}</span></h2></div>
|
||||
<div class="col-xs-2 text-right"><h2><a href="{% url update-instance instance.id %}"><i class="glyphicon glyphicon-edit"></i></a></h2></div>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="row">
|
||||
<div class="col-md-6 col-xs-12">
|
||||
<div class="col-xs-1"><h3><i class="fa fa-cog"></i></h3></div>
|
||||
<div class="col-xs-11"><h3>Configuration</h3></div>
|
||||
<div class="col-xs-12">
|
||||
<div class="col-xs-1"><h5><i class="glyphicon glyphicon-home"></i></h5></div>
|
||||
<div class="col-xs-3"><h5><span class="break"></span>Address</h5></div>
|
||||
<div class="col-xs-8"><h5>{{ instance.address|urlize|default:"None configured" }}</h5></div>
|
||||
</div>
|
||||
<div class="col-xs-12">
|
||||
<div class="col-xs-1"><h5><i class="glyphicon glyphicon-user"></i></h5></div>
|
||||
<div class="col-xs-3"><h5><span class="break"></span>Users watching</h5></div>
|
||||
<div class="col-xs-8"><h5>
|
||||
{% if not instance.users_to_notify.all %}
|
||||
No users subscribed
|
||||
{% else %}
|
||||
{{ instance.users_to_notify.all|join:", " }}
|
||||
{% endif %}
|
||||
</h5></div>
|
||||
</div>
|
||||
<div class="col-xs-12">
|
||||
<div class="col-xs-1"><h5><i class="fa fa-exclamation-triangle"></i></h5></div>
|
||||
<div class="col-xs-3"><h5><span class="break"></span>Alert types</h5></div>
|
||||
<div class="col-xs-8">
|
||||
<h5>
|
||||
{% if instance.email_alert %}<i class="fa fa-envelope"></i> Email{% endif %}
|
||||
{% if instance.hipchat_alert %}<i class="fa fa-comment"></i> Hipchat{% endif %}
|
||||
{% if instance.sms_alert %}<i class="fa fa-mobile"></i> SMS{% endif %}
|
||||
{% if instance.telephone_alert %}<i class="fa fa-phone"></i> Telephone{% endif %}
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-12 col-md-6">
|
||||
<div class="col-xs-1"><h3><i class="fa fa-bar-chart-o"></i></h3></div>
|
||||
<div class="col-xs-11"><h3>Status (24 hours)</h3></div>
|
||||
<div class="col-xs-12">
|
||||
<div id="graph" style="height: 150px; margin: 1 0px;"></div>
|
||||
<div id="timeline"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="col-xs-1"><h3><i class="fa fa-gears"></i></h3></div>
|
||||
<div class="col-xs-8"><h3>Services</h3></div>
|
||||
</div>
|
||||
{% include 'cabotapp/_service_list.html' with services=instance.service_set.all %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
{% include 'cabotapp/_statuscheck_list_instance.html' with checks=instance.graphite_status_checks.all instance=instance checks_type="Graphite" %}
|
||||
|
||||
<hr>
|
||||
|
||||
{% include 'cabotapp/_statuscheck_list_instance.html' with checks=instance.http_status_checks.all instance=instance checks_type="Http" %}
|
||||
|
||||
<hr>
|
||||
|
||||
{% include 'cabotapp/_statuscheck_list_instance.html' with checks=instance.jenkins_status_checks.all instance=instance checks_type="Jenkins" %}
|
||||
|
||||
<hr>
|
||||
|
||||
{% include 'cabotapp/_statuscheck_list_instance.html' with checks=instance.icmp_status_checks.all instance=instance checks_type="ICMP" %}
|
||||
|
||||
<hr>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="col-xs-1"><h3><i class="fa fa-table"></i></h3></div>
|
||||
<div class="col-xs-11">
|
||||
<h3>Status check report</h3>
|
||||
</div>
|
||||
<div class="col-xs-12">
|
||||
<form action="{% url checks-report %}" method="get">
|
||||
<div class="form-group">
|
||||
<div class="col-xs-12">
|
||||
{{ report_form.instance }}
|
||||
<label class="col-xs-2 control-label">{{ report_form.checks.label_tag }}</label>
|
||||
<div class="col-xs-10">{{ report_form.checks }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-xs-12">
|
||||
<label class="col-xs-2 control-label">{{ report_form.date_from.label_tag }}</label>
|
||||
<div class="col-xs-10">{{ report_form.date_from }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-xs-12">
|
||||
<label class="col-xs-2 control-label">{{ report_form.date_to.label_tag }}</label>
|
||||
<div class="col-xs-10">{{ report_form.date_to }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-12">
|
||||
<div class="form-group">
|
||||
<div class="col-xs-6 col-xs-offset-2">
|
||||
<button type="submit" class="btn btn-primary">Get report</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="col-xs-1"><h3><i class="fa fa-exclamation-triangle"></i></h3></div>
|
||||
<div class="col-xs-11">
|
||||
<h3>Recovery instructions</h3>
|
||||
</div>
|
||||
{% if instance.hackpad_id %}
|
||||
<div class="col-xs-12">
|
||||
<script src="{{ instance.hackpad_id }}"></script>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="col-xs-11 col-xs-offset-1">No hackpad configured</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock content %}
|
||||
|
||||
{% block js %}
|
||||
{% load compress %}
|
||||
{% load jsonify %}
|
||||
{{ block.super }}
|
||||
<script type="text/javascript">
|
||||
window.INSTANCE_HISTORY = {{ instance.recent_snapshots|jsonify }}
|
||||
</script>
|
||||
<script type="text/javascript" src="{{ STATIC_URL }}arachnys/js/d3.js"></script>
|
||||
{% compress js %}
|
||||
<script type="text/javascript" src="{{ STATIC_URL }}arachnys/js/rickshaw.js"></script>
|
||||
<script type="text/coffeescript">
|
||||
|
||||
$(document).ready ->
|
||||
data = window.INSTANCE_HISTORY
|
||||
labels = {
|
||||
num_checks_active: 'blue'
|
||||
num_checks_failing: '#f00'
|
||||
}
|
||||
processedData = formatDataForRickshaw data, labels
|
||||
drawRickshaw processedData.series, labels, processedData.events
|
||||
|
||||
formatDataForRickshaw = (data, labels) ->
|
||||
series = {}
|
||||
events = []
|
||||
for label, color of labels
|
||||
series[label] = {
|
||||
color: color
|
||||
name: label
|
||||
data: []
|
||||
}
|
||||
for slice in data
|
||||
if slice.did_send_alert
|
||||
events.push {time: slice.time, message: 'Sent alert'}
|
||||
for label, color of labels
|
||||
series[label].data.push
|
||||
x: slice.time
|
||||
y: slice[label]
|
||||
ret = []
|
||||
for line, val of series
|
||||
ret.push val
|
||||
return {
|
||||
series: ret
|
||||
events: events
|
||||
}
|
||||
|
||||
drawRickshaw = (data, labels, events = []) ->
|
||||
rickshawLine = new Rickshaw.Graph
|
||||
renderer: 'line'
|
||||
element: document.querySelector('#graph')
|
||||
series: data
|
||||
height: 140
|
||||
rickshawLine.render()
|
||||
|
||||
hoverDetail = new Rickshaw.Graph.HoverDetail({graph: rickshawLine})
|
||||
xAxis = new Rickshaw.Graph.Axis.Time({graph: rickshawLine})
|
||||
xAxis.render()
|
||||
yAxis = new Rickshaw.Graph.Axis.Y({graph: rickshawLine})
|
||||
yAxis.render()
|
||||
|
||||
window.annotator = annotator = new Rickshaw.Graph.Annotate({
|
||||
graph: rickshawLine
|
||||
element: document.getElementById('timeline')
|
||||
})
|
||||
for evt in events
|
||||
annotator.add evt.time, evt.message
|
||||
annotator.update()
|
||||
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
$(function(){
|
||||
$(':input.datepicker').datepicker({
|
||||
dateFormat: 'yy-mm-dd',
|
||||
buttonImage: '{{ STATIC_URL }}theme/img/calendar.gif',
|
||||
buttonImageOnly: true,
|
||||
showOn: 'button'
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endcompress %}
|
||||
{% endblock js %}
|
36
app/templates/cabotapp/instance_form.html
Normal file
36
app/templates/cabotapp/instance_form.html
Normal file
@ -0,0 +1,36 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="col-xs-10 col-xs-offset-2">
|
||||
<h2>{% if form.instance.id %}Edit instance{% else %}New instance{% endif %}</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<form class="form-horizontal" action="" method="post" role="form">
|
||||
{% include "cabotapp/_base_form.html" %}
|
||||
<div class="col-xs-12">
|
||||
<div class="form-group">
|
||||
<div class="col-xs-6 col-xs-offset-2">
|
||||
<button type="submit" class="btn btn-primary">Submit</button>
|
||||
<a href="{% url dashboard %}" class="btn">Back to dashboard</a>
|
||||
</div>
|
||||
{% if form.instance.id %}
|
||||
<div class="col-xs-4">
|
||||
<a class="btn btn-danger" href="{% url delete-service form.instance.id %}">Delete instance</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
{% load compress %}
|
||||
{% block js %}
|
||||
{{ block.super }}
|
||||
{% compress js %}
|
||||
<script type="text/coffeescript">
|
||||
</script>
|
||||
{% endcompress %}
|
||||
{% endblock %}
|
63
app/templates/cabotapp/instance_list.html
Normal file
63
app/templates/cabotapp/instance_list.html
Normal file
@ -0,0 +1,63 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row sortable ui-sortable">
|
||||
<div class="col-xs-12" data-original-title="">
|
||||
<div class="col-xs-1"><h2><i class="fa fa-desktop"></i></h2></div>
|
||||
<div class="col-xs-10"><h2><span class="break"></span>Instances</h2></div>
|
||||
<div class="col-xs-1 text-right">
|
||||
<h2><a href="{% url create-instance %}" title="New instance"><i class="glyphicon glyphicon-plus"></i></a></h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-12">
|
||||
{% if not instances %}
|
||||
No instances
|
||||
{% else %}
|
||||
<table class="table bootstrap-datatable datatable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Overall</th>
|
||||
<th>Active checks</th>
|
||||
<th>Disabled checks</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for instance in instances %}
|
||||
<tr class="{% if instance.alerts_enabled %}enabled{% else %}warning{% endif %}">
|
||||
<td>
|
||||
<a href="{% url instance pk=instance.id %}" title="Alerts {% if instance.alerts_enabled %}enabled{% else %}disabled{% endif %}">{{instance.name}} </a>
|
||||
</td>
|
||||
<td>
|
||||
<span class="label label-{% if not instance.alerts_enabled %}warning{% else %}{% if instance.overall_status == instance.PASSING_STATUS %}success{% else %}danger{% endif %}{% endif %}">{% if instance.alerts_enabled %}{{ instance.overall_status|lower|capfirst }}{% else %}Disabled{% endif %}</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="label label-{% if instance.active_status_checks.all.count > 0 %}{% if instance.overall_status != instance.PASSING_STATUS %}danger{% else %}success{% endif %}{% else %}default{% endif %}">{{ instance.active_status_checks.all.count }}</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="label label-{% if instance.inactive_status_checks.all.count > 0 %}warning{% else %}default{% endif %}">{{ instance.inactive_status_checks.all.count }}</span>
|
||||
</td>
|
||||
<td class="text-right">
|
||||
<a class="btn btn-xs" href="{% url update-instance pk=instance.id %}" role="button">
|
||||
<i class="glyphicon glyphicon-edit"></i>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock content %}
|
||||
|
||||
{% block js %}
|
||||
{% load compress %}
|
||||
{{ block.super }}
|
||||
{% compress js %}
|
||||
<script type="text/coffeescript">
|
||||
|
||||
</script>
|
||||
{% endcompress %}
|
||||
{% endblock js %}
|
@ -55,18 +55,29 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="col-xs-1"><h3><i class="fa fa-desktop"></i></h3></div>
|
||||
<div class="col-xs-8"><h3>Instances</h3></div>
|
||||
<div class="col-xs-3 text-right">
|
||||
<h3>
|
||||
<a href="{% url create-instance %}?service={{ service.id }}" class=""><i class="glyphicon glyphicon-plus" title="Add new instance for this service"></i><i class="fa fa-desktop" title=""></i></a>
|
||||
</h3>
|
||||
</div>
|
||||
{% include 'cabotapp/_instance_list.html' with instances=service.instances.all %}
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
|
||||
{% include 'cabotapp/_statuscheck_list_service.html' with checks=service.graphite_status_checks.all service=service checks_type="Graphite" %}
|
||||
|
||||
<hr>
|
||||
|
||||
{% 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" %}
|
||||
|
||||
<hr>
|
||||
|
||||
{% include 'cabotapp/_statuscheck_list.html' with checks=service.http_status_checks.all service=service checks_type="Http" %}
|
||||
|
||||
<hr>
|
||||
|
||||
{% 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" %}
|
||||
|
||||
<hr>
|
||||
|
||||
|
@ -6,14 +6,14 @@
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="col-xs-1"><h2><i class="glyphicon glyphicon-{% if check.polymorphic_ctype.model == 'graphitestatuscheck' %}signal{% elif check.polymorphic_ctype.model == 'httpstatuscheck' %}arrow-up{% elif check.polymorphic_ctype.model == 'jenkinsstatuscheck' %}ok{% endif %}"></i></h2></div>
|
||||
<div class="col-xs-1"><h2><i class="glyphicon glyphicon-{% if check.polymorphic_ctype.model == 'graphitestatuscheck' %}signal{% elif check.polymorphic_ctype.model == 'httpstatuscheck' %}arrow-up{% elif check.polymorphic_ctype.model == 'jenkinsstatuscheck' %}ok{% elif check.polymorphic_ctype.model == 'icmpstatuscheck' %}transfer{% endif %}"></i></h2></div>
|
||||
<div class="col-xs-5"><h2>{{ check.name }}</h2></div>
|
||||
<div class="col-xs-4 text-right"><h2><span class="label label-{% if check.calculated_status == 'passing' %}success{% else %}danger{% endif %}">{{ check.calculated_status|capfirst }}</span></h2></div>
|
||||
<div class="col-xs-2 text-right"><h2>
|
||||
{% if check.polymorphic_ctype.model == 'jenkinsstatuscheck' %}
|
||||
<a href="{% jenkins_human_url check.name %}" class=""><i class="glyphicon glyphicon-link"></i></a>
|
||||
{% endif %}
|
||||
<a href="{% if check.polymorphic_ctype.model == 'graphitestatuscheck' %}{% url update-check pk=check.id %}{% elif check.polymorphic_ctype.model == 'httpstatuscheck' %}{% url update-http-check pk=check.id %}{% elif check.polymorphic_ctype.model == 'jenkinsstatuscheck' %}{% url update-jenkins-check pk=check.id %}{% endif %}" class=""><i class="glyphicon glyphicon-edit"></i></a> <a href="{% url run-check pk=check.id %}"><i class="glyphicon glyphicon-refresh"></i></a>
|
||||
<a href="{% if check.polymorphic_ctype.model == 'graphitestatuscheck' %}{% url update-check pk=check.id %}{% elif check.polymorphic_ctype.model == 'httpstatuscheck' %}{% url update-http-check pk=check.id %}{% elif check.polymorphic_ctype.model == 'jenkinsstatuscheck' %}{% url update-jenkins-check pk=check.id %}{% elif check.polymorphic_ctype.model == 'icmpstatuscheck' %}{% url update-icmp-check pk=check.id %}{% endif %}" class=""><i class="glyphicon glyphicon-edit"></i></a> <a href="{% url run-check pk=check.id %}"><i class="glyphicon glyphicon-refresh"></i></a>
|
||||
</h2></div>
|
||||
</div>
|
||||
</div>
|
||||
@ -81,4 +81,4 @@
|
||||
|
||||
</script>
|
||||
{% endcompress %}
|
||||
{% endblock js %}
|
||||
{% endblock js %}
|
||||
|
@ -21,4 +21,4 @@
|
||||
$('.sparktristate').sparkline('html', {type: 'tristate'})
|
||||
</script>
|
||||
{% endcompress %}
|
||||
{% endblock js %}
|
||||
{% endblock js %}
|
||||
|
22
app/urls.py
22
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<pk>\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<pk>\d+)/',
|
||||
view=InstanceUpdateView.as_view(
|
||||
), name='update-instance'),
|
||||
url(r'^instance/delete/(?P<pk>\d+)/',
|
||||
view=InstanceDeleteView.as_view(
|
||||
), name='delete-instance'),
|
||||
url(r'^instance/(?P<pk>\d+)/',
|
||||
view=InstanceDetailView.as_view(), name='instance'),
|
||||
|
||||
url(r'^checks/$', view=StatusCheckListView.as_view(),
|
||||
name='checks'),
|
||||
url(r'^check/run/(?P<pk>\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<pk>\d+)/',
|
||||
view=ICMPCheckUpdateView.as_view(
|
||||
), name='update-icmp-check'),
|
||||
url(r'^graphitecheck/create/',
|
||||
view=GraphiteCheckCreateView.as_view(
|
||||
), name='create-check'),
|
||||
|
Loading…
x
Reference in New Issue
Block a user