Skip to content
This repository was archived by the owner on Aug 26, 2019. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@

# Ignore development environment variables.
.env
*.swp
1 change: 1 addition & 0 deletions app/assets/javascripts/incident.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ commentsList = null
$(document).on("page:change", ->
commentsList.leave() if commentsList
commentsEl = $("#comments-container")[0]

if commentsEl
commentsList = new CommentsList(commentsEl)
else
Expand Down
7 changes: 6 additions & 1 deletion app/controllers/comments_controller.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
class CommentsController < ApplicationController
before_action :set_incident

after_action :post_to_pagerduty, only: :create

def index
@comments = @incident.comments.since(params[:after_id]).order(:id)
end
Expand Down Expand Up @@ -43,4 +44,8 @@ def set_incident
def comment_params
params.require(:comment).permit(:content)
end

def post_to_pagerduty
Pagerduty.new().post_note(@comment['incident_id'], @comment['content'])
end
end
2 changes: 1 addition & 1 deletion app/controllers/incidents_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -74,4 +74,4 @@ def last_updated(incidents)
end
updated_at
end
end
end
35 changes: 35 additions & 0 deletions app/controllers/pagerduty_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
class PagerdutyController < ApplicationController
skip_before_action :verify_authenticity_token

def callback
pg = Pagerduty.new

result = pg.get_pagerduty_user
if result.has_key?(:error)
head :unprocessable_entity
return
end

messages = params['messages']
unless messages.kind_of?(Array)
messages = [messages]
end

messages.each do |message|
incident = message['data']['incident']
data = {
title: incident['trigger_summary_data']['subject'],
description: incident['trigger_summary_data']['description'] || incident['trigger_summary_data']['subject'],
severity: 'critical',
status: incident['status'] == 'triggered' ? 'open': incident['status'],
started_at: incident['created_on'],
detected_at: incident['created_on'],
user_id: result[:user][:id],
id: incident['id']
}
pg.create_or_update_incident(data)
end

head :ok
end
end
1 change: 1 addition & 0 deletions app/models/incident.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ class Incident < ActiveRecord::Base
validates :user, presence: true

has_many :comments
has_one :pagerduty_incident
belongs_to :user
end
4 changes: 4 additions & 0 deletions app/models/pagerduty_incident.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
class PagerdutyIncident < ActiveRecord::Base
validates :incident, presence: true
belongs_to :incident
end
66 changes: 66 additions & 0 deletions app/services/pagerduty.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
require('net/http')

class Pagerduty
def get_pagerduty_user
puser = User.find_by(github_id: 766800)
puser ? {user: puser} : { error: 'Pagerduty user does not exist. Run pagerduty:create_user task.' }
end

def create_or_update_incident(params)
pincident = PagerdutyIncident.find_by(pagerduty_id: params[:id])
begin
if not pincident # creates a new incident
incident = Incident.new params.to_hash
if incident.save!
pincident = PagerdutyIncident.new(
pagerduty_id: params[:id],
incident_id: incident[:id]
)
pincident.save!
end

elsif params[:status] == 'resolved' # resolve an existing incident
incident = Incident.find_by(id: pincident[:incident_id])

if incident and incident[:status] != 'resolved'
incident.status = 'resolved'
incident.save!
end

end
rescue Exception => e
{ error: e.message }
end
end

def post_note(incident_id, note_content)
pg_sub_domain = ENV['PAGERDUTY_SUBDOMAIN']
pg_api_key = ENV['PAGERDUTY_API_KEY']
pg_requester_id = ENV['PAGERDUTY_REQUESTER_ID']

if not pg_api_key or not pg_sub_domain or not pg_requester_id
return
end

pg_incident = PagerdutyIncident.find_by(incident_id: incident_id)
data = {
requester_id: pg_requester_id,
note: { content: note_content }
}

if pg_incident
uri = URI.parse("https://#{pg_sub_domain}.pagerduty.com/api/v1/incidents/#{pg_incident.pagerduty_id}/notes")
headers = { 'Content-Type'=>'application/json', 'Authorization'=> "Token token=#{pg_api_key}"}
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
post = Net::HTTP::Post.new(uri.path, headers)
response = http.request post, data.to_json
case response
when Net::HTTPSuccess; response.body
else response.error!
end
else
{ error: 'No pagerduty details found for the incident' }
end
end
end
8 changes: 8 additions & 0 deletions app/views/incidents/_incident.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<tr>
<td><%= link_to incident.title, incident %></td>
<td><%= incident_severity_label(incident) %></td>
<td><%= incident.status %></td>
<td><%= incident_user_name(incident) %></td>
<td><%= incident.started_at %></td>
<td><%= incident.detected_at %></td>
</tr>
9 changes: 1 addition & 8 deletions app/views/incidents/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,7 @@

<tbody>
<% @incidents.each do |incident| %>
<tr>
<td><%= link_to incident.title, incident %></td>
<td><%= incident_severity_label(incident) %></td>
<td><%= incident.status %></td>
<td><%= incident_user_name(incident) %></td>
<td><%= incident.started_at %></td>
<td><%= incident.detected_at %></td>
</tr>
<%= render partial: "incident" , object: incident %>
<% end %>
</tbody>
</table>
Expand Down
3 changes: 2 additions & 1 deletion config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@

resources :incidents, except: :destroy do
resources :comments, only: [:new, :create, :index, :show, :update, :edit]

patch :status, on: :member
end
end

post 'pagerduty/callback' => 'pagerduty#callback'
end
6 changes: 6 additions & 0 deletions db/migrate/20141211111121_create_pagerduty_incidents.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
class CreatePagerdutyIncidents < ActiveRecord::Migration
def change
create_table :pagerduty_incidents do |t|
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddIncidentIdToPagerdutyIncidents < ActiveRecord::Migration
def change
add_reference :pagerduty_incidents, :incident, index: true
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class ChangePagerdutyIdIntegerToString < ActiveRecord::Migration
def change
change_column :pagerduty_incidents, :id, :string
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddPagerdutyIdToPagerdutyIncidents < ActiveRecord::Migration
def change
add_column :pagerduty_incidents, :pagerduty_id, :string
end
end
9 changes: 8 additions & 1 deletion db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema.define(version: 20140907001718) do
ActiveRecord::Schema.define(version: 20150105122354) do

# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
Expand Down Expand Up @@ -40,6 +40,13 @@

add_index "incidents", ["user_id"], name: "index_incidents_on_user_id", using: :btree

create_table "pagerduty_incidents", force: true do |t|
t.integer "incident_id"
t.string "pagerduty_id"
end

add_index "pagerduty_incidents", ["incident_id"], name: "index_pagerduty_incidents_on_incident_id", using: :btree

create_table "users", force: true do |t|
t.integer "github_id"
t.string "github_username"
Expand Down
15 changes: 15 additions & 0 deletions lib/tasks/pagerduty.rake
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace :pagerduty do
desc 'Create a PagerDuty user in the database'
task create_user: :environment do
PagerDutyGithubUser = Struct.new(:id, :login, :name, :avatar_url)

pagerduty_github_user = PagerDutyGithubUser.new(
766800,
'PagerDuty',
'',
'https://avatars.githubusercontent.com/u/766800?v=3'
)

User.create_or_update_from_github_user(pagerduty_github_user)
end
end
45 changes: 45 additions & 0 deletions spec/controllers/pagerduty_controller_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
require 'rake'
require 'rails_helper'
require 'json'

RSpec.describe PagerdutyController, type: :controller do

before(:all) {
unless User.find_by(github_id: 766800)
load File.expand_path("../../../lib/tasks/pagerduty.rake", __FILE__)
Rake::Task.define_task(:environment)
Rake::Task['pagerduty:create_user'].invoke
end
}

describe "on pagerduty event" do
before do
fixture = File.read(File.expand_path(File.join(File.dirname(__FILE__), "../fixtures/pagerduty_payload.json")))
post "callback", JSON.parse(fixture)
end

it "respond with success" do
expect(response).to be_success
expect(Incident.all.length).to eq(1)
expect(Incident.find_by(title: "45645").status).to eq('resolved')
expect(PagerdutyIncident.all.length).to eq(1)
expect(PagerdutyIncident.find_by(pagerduty_id: "PIJ90N7").incident_id).to eq(Incident.find_by(title: "45645").id)
end

end

describe "on pagerduty event but no pagerduty user exists" do
before do
User.find_by(github_id: 766800).delete
fixture = File.read(File.expand_path(File.join(File.dirname(__FILE__), "../fixtures/pagerduty_payload.json")))
post "callback", JSON.parse(fixture)
end

it "respond with 422" do
expect(response.code).to eq("422")
expect(Incident.all.length).to eq(0)
expect(PagerdutyIncident.all.length).to eq(0)
end
end

end
74 changes: 74 additions & 0 deletions spec/fixtures/pagerduty_payload.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
{
"messages": [
{
"id": "bb8b8fe0-e8d5-11e2-9c1e-22000afd16cf",
"created_on": "2013-07-09T20:25:44Z",
"type": "incident.trigger",
"data": {
"incident": {
"id": "PIJ90N7",
"incident_number": 1,
"created_on": "2013-07-09T20:25:44Z",
"status": "triggered",
"html_url": "https://acme.pagerduty.com/incidents/PIJ90N7",
"incident_key": "null",
"service": {
"id": "PBAZLIU",
"name": "service",
"html_url": "https://acme.pagerduty.com/services/PBAZLIU"
},
"assigned_to_user": {
"id": "PPI9KUT",
"name": "Alan Kay",
"email": "alan@pagerduty.com",
"html_url": "https://acme.pagerduty.com/users/PPI9KUT"
},
"trigger_summary_data": {
"subject": "45645"
},
"trigger_details_html_url": "https://acme.pagerduty.com/incidents/PIJ90N7/log_entries/PIJ90N7",
"last_status_change_on": "2013-07-09T20:25:44Z",
"last_status_change_by": "null"
}
}
},
{
"id": "8a1d6420-e9c4-11e2-b33e-f23c91699516",
"created_on": "2013-07-09T20:25:45Z",
"type": "incident.resolve",
"data": {
"incident": {
"id": "PIJ90N7",
"incident_number": 1,
"created_on": "2013-07-09T20:25:44Z",
"status": "resolved",
"html_url": "https://acme.pagerduty.com/incidents/PIJ90N7",
"incident_key": "null",
"service": {
"id": "PBAZLIU",
"name": "service",
"html_url": "https://acme.pagerduty.com/services/PBAZLIU"
},
"assigned_to_user": "null",
"resolved_by_user": {
"id": "PPI9KUT",
"name": "Alan Kay",
"email": "alan@pagerduty.com",
"html_url": "https://acme.pagerduty.com/users/PPI9KUT"
},
"trigger_summary_data": {
"subject": "45645"
},
"trigger_details_html_url": "https://acme.pagerduty.com/incidents/PIJ90N7/log_entries/PIJ90N7",
"last_status_change_on": "2013-07-09T20:25:45Z",
"last_status_change_by": {
"id": "PPI9KUT",
"name": "Alan Kay",
"email": "alan@pagerduty.com",
"html_url": "https://acme.pagerduty.com/users/PPI9KUT"
}
}
}
}
]
}
6 changes: 6 additions & 0 deletions spec/models/pagerduty_incident_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
require 'rails_helper'

RSpec.describe PagerdutyIncident, type: :model do
it { should validate_presence_of(:incident) }
it { should belong_to(:incident) }
end