Skip to content

Commit b0056c6

Browse files
committed
Merge pull request arachnys#152 from bonniejools/jenkins_job_number
Updated models to show jenkins job number in StatusCheckResult
2 parents d33c57a + 3040cff commit b0056c6

File tree

5 files changed

+183
-5
lines changed

5 files changed

+183
-5
lines changed

cabot/cabotapp/alert.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
{% endif %}
2424
"""
2525

26-
hipchat_template = "Service {{ service.name }} {% if service.overall_status == service.PASSING_STATUS %}is back to normal{% else %}reporting {{ service.overall_status }} status{% endif %}: {{ scheme }}://{{ host }}{% url 'service' pk=service.id %}. {% if service.overall_status != service.PASSING_STATUS %}Checks failing:{% for check in service.all_failing_checks %} {{ check.name }}{% if check.last_result.error %} ({{ check.last_result.error|safe }}){% endif %}{% endfor %}{% endif %}{% if alert %}{% for alias in users %} @{{ alias }}{% endfor %}{% endif %}"
26+
hipchat_template = "Service {{ service.name }} {% if service.overall_status == service.PASSING_STATUS %}is back to normal{% else %}reporting {{ service.overall_status }} status{% endif %}: {{ scheme }}://{{ host }}{% url 'service' pk=service.id %}. {% if service.overall_status != service.PASSING_STATUS %}Checks failing:{% for check in service.all_failing_checks %}{% if check.check_category == 'Jenkins check' %}{% if check.last_result.error %} {{ check.name }} ({{ check.last_result.error|safe }}) {{jenkins_api}}job/{{ check.name }}/{{ check.last_result.job_number }}/console{% else %} {{ check.name }} {{jenkins_api}}/job/{{ check.name }}/{{check.last_result.job_number}}/console {% endif %}{% else %} {{ check.name }} {% if check.last_result.error %} ({{ check.last_result.error|safe }}){% endif %}{% endif %}{% endfor %}{% endif %}{% if alert %}{% for alias in users %} @{{ alias }}{% endfor %}{% endif %}"
2727

2828
sms_template = "Service {{ service.name }} {% if service.overall_status == service.PASSING_STATUS %}is back to normal{% else %}reporting {{ service.overall_status }} status{% endif %}: {{ scheme }}://{{ host }}{% url 'service' pk=service.id %}"
2929

@@ -91,6 +91,7 @@ def send_hipchat_alert(service, users, duty_officers):
9191
'host': settings.WWW_HTTP_HOST,
9292
'scheme': settings.WWW_SCHEME,
9393
'alert': alert,
94+
'jenkins_api': settings.JENKINS_API,
9495
})
9596
message = Template(hipchat_template).render(c)
9697
_send_hipchat_alert(message, color=color, sender='Cabot/%s' % service.name)

cabot/cabotapp/jenkins.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ def get_job_status(jobname):
2222
resp = requests.get(endpoint, auth=auth, verify=True)
2323
status = resp.json
2424
ret['status_code'] = resp.status_code
25+
ret['job_number'] = status['lastBuild'].get('number', None)
2526
if status['color'].startswith('blue'):
2627
ret['active'] = True
2728
ret['succeeded'] = True
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
# -*- coding: utf-8 -*-
2+
import datetime
3+
from south.db import db
4+
from south.v2 import SchemaMigration
5+
from django.db import models
6+
7+
8+
class Migration(SchemaMigration):
9+
10+
def forwards(self, orm):
11+
# Adding field 'StatusCheckResult.job_number'
12+
db.add_column('cabotapp_statuscheckresult', 'job_number',
13+
self.gf('django.db.models.fields.PositiveIntegerField')(null=True),
14+
keep_default=False)
15+
16+
17+
def backwards(self, orm):
18+
# Deleting field 'StatusCheckResult.job_number'
19+
db.delete_column('cabotapp_statuscheckresult', 'job_number')
20+
21+
22+
models = {
23+
'auth.group': {
24+
'Meta': {'object_name': 'Group'},
25+
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
26+
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
27+
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
28+
},
29+
'auth.permission': {
30+
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
31+
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
32+
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
33+
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
34+
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
35+
},
36+
'auth.user': {
37+
'Meta': {'object_name': 'User'},
38+
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
39+
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
40+
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
41+
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
42+
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
43+
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
44+
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
45+
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
46+
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
47+
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
48+
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
49+
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
50+
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
51+
},
52+
'cabotapp.instance': {
53+
'Meta': {'ordering': "['name']", 'object_name': 'Instance'},
54+
'address': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
55+
'alerts_enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
56+
'email_alert': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
57+
'hackpad_id': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
58+
'hipchat_alert': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
59+
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
60+
'last_alert_sent': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
61+
'name': ('django.db.models.fields.TextField', [], {}),
62+
'old_overall_status': ('django.db.models.fields.TextField', [], {'default': "'PASSING'"}),
63+
'overall_status': ('django.db.models.fields.TextField', [], {'default': "'PASSING'"}),
64+
'sms_alert': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
65+
'status_checks': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['cabotapp.StatusCheck']", 'symmetrical': 'False', 'blank': 'True'}),
66+
'telephone_alert': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
67+
'users_to_notify': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.User']", 'symmetrical': 'False', 'blank': 'True'})
68+
},
69+
'cabotapp.instancestatussnapshot': {
70+
'Meta': {'object_name': 'InstanceStatusSnapshot'},
71+
'did_send_alert': ('django.db.models.fields.IntegerField', [], {'default': 'False'}),
72+
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
73+
'instance': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'snapshots'", 'to': "orm['cabotapp.Instance']"}),
74+
'num_checks_active': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
75+
'num_checks_failing': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
76+
'num_checks_passing': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
77+
'overall_status': ('django.db.models.fields.TextField', [], {'default': "'PASSING'"}),
78+
'time': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'})
79+
},
80+
'cabotapp.service': {
81+
'Meta': {'ordering': "['name']", 'object_name': 'Service'},
82+
'alerts_enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
83+
'email_alert': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
84+
'hackpad_id': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
85+
'hipchat_alert': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
86+
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
87+
'instances': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['cabotapp.Instance']", 'symmetrical': 'False', 'blank': 'True'}),
88+
'last_alert_sent': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
89+
'name': ('django.db.models.fields.TextField', [], {}),
90+
'old_overall_status': ('django.db.models.fields.TextField', [], {'default': "'PASSING'"}),
91+
'overall_status': ('django.db.models.fields.TextField', [], {'default': "'PASSING'"}),
92+
'sms_alert': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
93+
'status_checks': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['cabotapp.StatusCheck']", 'symmetrical': 'False', 'blank': 'True'}),
94+
'telephone_alert': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
95+
'url': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
96+
'users_to_notify': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.User']", 'symmetrical': 'False', 'blank': 'True'})
97+
},
98+
'cabotapp.servicestatussnapshot': {
99+
'Meta': {'object_name': 'ServiceStatusSnapshot'},
100+
'did_send_alert': ('django.db.models.fields.IntegerField', [], {'default': 'False'}),
101+
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
102+
'num_checks_active': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
103+
'num_checks_failing': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
104+
'num_checks_passing': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
105+
'overall_status': ('django.db.models.fields.TextField', [], {'default': "'PASSING'"}),
106+
'service': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'snapshots'", 'to': "orm['cabotapp.Service']"}),
107+
'time': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'})
108+
},
109+
'cabotapp.shift': {
110+
'Meta': {'object_name': 'Shift'},
111+
'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
112+
'end': ('django.db.models.fields.DateTimeField', [], {}),
113+
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
114+
'start': ('django.db.models.fields.DateTimeField', [], {}),
115+
'uid': ('django.db.models.fields.TextField', [], {}),
116+
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
117+
},
118+
'cabotapp.statuscheck': {
119+
'Meta': {'ordering': "['name']", 'object_name': 'StatusCheck'},
120+
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
121+
'cached_health': ('django.db.models.fields.TextField', [], {'null': 'True'}),
122+
'calculated_status': ('django.db.models.fields.CharField', [], {'default': "'passing'", 'max_length': '50', 'blank': 'True'}),
123+
'check_type': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
124+
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
125+
'debounce': ('django.db.models.fields.IntegerField', [], {'default': '0', 'null': 'True'}),
126+
'endpoint': ('django.db.models.fields.TextField', [], {'null': 'True'}),
127+
'expected_num_hosts': ('django.db.models.fields.IntegerField', [], {'default': '0', 'null': 'True'}),
128+
'frequency': ('django.db.models.fields.IntegerField', [], {'default': '5'}),
129+
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
130+
'importance': ('django.db.models.fields.CharField', [], {'default': "'ERROR'", 'max_length': '30'}),
131+
'last_run': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
132+
'max_queued_build_time': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
133+
'metric': ('django.db.models.fields.TextField', [], {'null': 'True'}),
134+
'name': ('django.db.models.fields.TextField', [], {}),
135+
'password': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
136+
'polymorphic_ctype': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'polymorphic_cabotapp.statuscheck_set'", 'null': 'True', 'to': "orm['contenttypes.ContentType']"}),
137+
'status_code': ('django.db.models.fields.TextField', [], {'default': '200', 'null': 'True'}),
138+
'text_match': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
139+
'timeout': ('django.db.models.fields.IntegerField', [], {'default': '30', 'null': 'True'}),
140+
'username': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
141+
'value': ('django.db.models.fields.TextField', [], {'null': 'True'}),
142+
'verify_ssl_certificate': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
143+
},
144+
'cabotapp.statuscheckresult': {
145+
'Meta': {'object_name': 'StatusCheckResult'},
146+
'check': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['cabotapp.StatusCheck']"}),
147+
'error': ('django.db.models.fields.TextField', [], {'null': 'True'}),
148+
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
149+
'job_number': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}),
150+
'raw_data': ('django.db.models.fields.TextField', [], {'null': 'True'}),
151+
'succeeded': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
152+
'time': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}),
153+
'time_complete': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'db_index': 'True'})
154+
},
155+
'cabotapp.userprofile': {
156+
'Meta': {'object_name': 'UserProfile'},
157+
'fallback_alert_user': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
158+
'hipchat_alias': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'blank': 'True'}),
159+
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
160+
'mobile_number': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '20', 'blank': 'True'}),
161+
'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'profile'", 'unique': 'True', 'to': "orm['auth.User']"})
162+
},
163+
'contenttypes.contenttype': {
164+
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
165+
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
166+
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
167+
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
168+
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
169+
}
170+
}
171+
172+
complete_apps = ['cabotapp']

cabot/cabotapp/models.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -687,6 +687,7 @@ def _run(self):
687687
try:
688688
status = get_job_status(self.name)
689689
active = status['active']
690+
result.job_number = status['job_number']
690691
if status['status_code'] == 404:
691692
result.error = u'Job %s not found on Jenkins' % self.name
692693
result.succeeded = False
@@ -744,6 +745,9 @@ class StatusCheckResult(models.Model):
744745
succeeded = models.BooleanField(default=False)
745746
error = models.TextField(null=True)
746747

748+
# Jenkins specific
749+
job_number = models.PositiveIntegerField(null=True)
750+
747751
def __unicode__(self):
748752
return '%s: %s @%s' % (self.status, self.check.name, self.time)
749753

cabot/cabotapp/tests/tests_basic.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# -*- coding: utf-8 -*-
22

33
import requests
4+
from django.conf import settings
45
from django.utils import timezone
56
from django.core.urlresolvers import reverse
67
from django.test import TestCase
@@ -12,15 +13,14 @@
1213
from rest_framework.reverse import reverse as api_reverse
1314
from cabot.cabotapp.models import (
1415
GraphiteStatusCheck, JenkinsStatusCheck,
15-
HttpStatusCheck, ICMPStatusCheck, Service, Instance, StatusCheckResult,
16-
UserProfile)
16+
HttpStatusCheck, ICMPStatusCheck, Service, Instance,
17+
StatusCheckResult, UserProfile)
1718
from cabot.cabotapp.views import StatusCheckReportForm
1819
from cabot.cabotapp.alert import (send_hipchat_alert, send_alert)
1920
from mock import Mock, patch
2021
from twilio import rest
21-
from django.utils import timezone
2222
from django.core import mail
23-
from datetime import timedelta, date
23+
from datetime import timedelta, date, datetime
2424
import json
2525
import os
2626
import base64

0 commit comments

Comments
 (0)