Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor pagerduty #52

Merged
merged 31 commits into from
Oct 1, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
078286a
Start a pagerduty lib, move get to there
technicalpickles Sep 30, 2015
eb1a227
Move pagerDutyPut to the lib
technicalpickles Sep 30, 2015
0599309
move pagerDutyPost to the lib
technicalpickles Sep 30, 2015
d7ff892
Move pagerDutyDelete to the lib
technicalpickles Sep 30, 2015
a65b29b
Rename pagerDutyGet to pagerduty.get
technicalpickles Sep 30, 2015
26199b5
Rename pagerduty.put to pagerDutyPut
technicalpickles Sep 30, 2015
378f1ce
Rename pagerDutyPost to pagerduty.post
technicalpickles Sep 30, 2015
04141d4
Rename pagerDutyDelete to pagerduty.delete
technicalpickles Sep 30, 2015
1a0b4ff
Use scoped-http-client directly, and re-use logic
technicalpickles Sep 30, 2015
bd553ce
move pagerDutyIncident(s) to lib, and rename to getIncident(s)
technicalpickles Sep 30, 2015
4fe388c
remove old method names
technicalpickles Sep 30, 2015
82737dc
integration, not intergration
technicalpickles Sep 30, 2015
9d6d55e
Scripts should check for missing environment, rather than the client …
technicalpickles Sep 30, 2015
145befe
log noop, instead of sending it
technicalpickles Sep 30, 2015
7b60f0c
Fix missingEnvironmentForApi
technicalpickles Sep 30, 2015
e0f1544
Start using callbacks with errors
technicalpickles Sep 30, 2015
eee9812
Make getIncidents use 2 param callback, with error for first
technicalpickles Sep 30, 2015
4d682c1
Update getIncident to use error param in callback
technicalpickles Sep 30, 2015
17a68aa
update put callback to use an err
technicalpickles Sep 30, 2015
8719a16
Update delete to use error callback
technicalpickles Sep 30, 2015
5d97dbd
Update post to use error callback. Add HTTP errors the other methods
technicalpickles Sep 30, 2015
441d91b
Remove support for single-arg callbacks.
technicalpickles Sep 30, 2015
af456a5
Add getSchedules
technicalpickles Sep 30, 2015
ea2a084
Only keep env variables used in the specific files. Make subdomain ac…
technicalpickles Sep 30, 2015
4a7ce35
Remove msg parameter everywhere
technicalpickles Oct 1, 2015
1211963
remove last reference to robot
technicalpickles Oct 1, 2015
77c0045
Remove last references to robot. become a class
technicalpickles Oct 1, 2015
772201f
Make query to get and getSchedules optional
technicalpickles Oct 1, 2015
d739069
Add webhook to its own thing
technicalpickles Oct 1, 2015
762267a
remove backward compatible missingEnvironmentForApi
technicalpickles Oct 1, 2015
a635714
reorganize
technicalpickles Oct 1, 2015
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
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
},
"dependencies": {
"coffee-script": "~1.6",
"moment-timezone": "~0.4.0"
"moment-timezone": "~0.4.0",
"scoped-http-client": "^0.11.0"
},
"devDependencies": {
"chai": "^2.1.1",
Expand Down
138 changes: 138 additions & 0 deletions src/pagerduty.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
HttpClient = require 'scoped-http-client'

pagerDutyApiKey = process.env.HUBOT_PAGERDUTY_API_KEY
pagerDutySubdomain = process.env.HUBOT_PAGERDUTY_SUBDOMAIN
pagerDutyBaseUrl = "https://#{pagerDutySubdomain}.pagerduty.com/api/v1"
pagerDutyServices = process.env.HUBOT_PAGERDUTY_SERVICES
pagerNoop = process.env.HUBOT_PAGERDUTY_NOOP
pagerNoop = false if pagerNoop is "false" or pagerNoop is "off"

class PagerDutyError extends Error
module.exports =
http: (path) ->
HttpClient.create("#{pagerDutyBaseUrl}#{path}")
.headers(Authorization: "Token token=#{pagerDutyApiKey}", Accept: 'application/json')

missingEnvironmentForApi: (msg) ->
missingAnything = false
unless pagerDutySubdomain?
msg.send "PagerDuty Subdomain is missing: Ensure that HUBOT_PAGERDUTY_SUBDOMAIN is set."
missingAnything |= true
unless pagerDutyApiKey?
msg.send "PagerDuty API Key is missing: Ensure that HUBOT_PAGERDUTY_API_KEY is set."
missingAnything |= true
missingAnything

get: (url, query, cb) ->
if typeof(query) is 'function'
cb = query
query = {}

if pagerDutyServices? && url.match /\/incidents/
query['service'] = pagerDutyServices

@http(url)
.query(query)
.get() (err, res, body) ->
if err?
cb(err)
return
json_body = null
switch res.statusCode
when 200 then json_body = JSON.parse(body)
else
cb(new PagerDutyError("#{res.statusCode} back from #{url}"))

cb null, json_body

put: (url, data, cb) ->
if pagerNoop
console.log "Would have PUT #{url}: #{inspect data}"
return

json = JSON.stringify(data)
@http(url)
.header("content-type","application/json")
.header("content-length",json.length)
.put(json) (err, res, body) ->
if err?
callback(err)
return

json_body = null
switch res.statusCode
when 200 then json_body = JSON.parse(body)
else
return cb(new PagerDutyError("#{res.statusCode} back from #{url}"))
cb null, json_body

post: (url, data, cb) ->
if pagerNoop
console.log "Would have POST #{url}: #{inspect data}"
return

json = JSON.stringify(data)
@http(url)
.header("content-type","application/json")
.header("content-length",json.length)
.post(json) (err, res, body) ->
if err?
return cb(err)

json_body = null
switch res.statusCode
when 201 then json_body = JSON.parse(body)
else
return cb(new PagerDutyError("#{res.statusCode} back from #{url}"))
cb null, json_body

delete: (url, cb) ->
if pagerNoop
console.log "Would have DELETE #{url}"
return

auth = "Token token=#{pagerDutyApiKey}"
http(url)
.header("content-length",0)
.delete() (err, res, body) ->
if err?
return cb(err)
json_body = null
switch res.statusCode
when 204, 200
value = true
else
console.log res.statusCode
console.log body
value = false
cb null, value

getIncident: (incident, cb) ->
@get "/incidents/#{encodeURIComponent incident}", {}, (err, json) ->
if err?
cb(err)
return

cb(null, json)

getIncidents: (status, cb) ->
query =
status: status
sort_by: "incident_number:asc"
@get "/incidents", query, (err, json) ->
if err?
cb(err)
return
cb(null, json.incidents)

getSchedules: (query, cb) ->
if typeof(query) is 'function'
cb = query
query = {}

@get "/schedules", query, (err, json) ->
if err?
cb(err)
return

cb(null, json.schedules)
92 changes: 92 additions & 0 deletions src/scripts/pagerduty-webhook.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# Description:
# Receive webhooks from PagerDuty and post them to chat
#

pagerRoom = process.env.HUBOT_PAGERDUTY_ROOM
# Webhook listener endpoint. Set it to whatever URL you want, and make sure it matches your pagerduty service settings
pagerEndpoint = process.env.HUBOT_PAGERDUTY_ENDPOINT || "/hook"

module.exports = (robot) ->
# Webhook listener
if pagerEndpoint && pagerRoom
robot.router.post pagerEndpoint, (req, res) ->
robot.messageRoom(pagerRoom, parseWebhook(req,res))
res.end()

# Pagerduty Webhook Integration (For a payload example, see http://developer.pagerduty.com/documentation/rest/webhooks)
parseWebhook = (req, res) ->
hook = req.body

messages = hook.messages

if /^incident.*$/.test(messages[0].type)
parseIncidents(messages)
else
"No incidents in webhook"

parseIncidents = (messages) ->
returnMessage = []
count = 0
for message in messages
incident = message.data.incident
hookType = message.type
returnMessage.push(generateIncidentString(incident, hookType))
count = count+1
returnMessage.unshift("You have " + count + " PagerDuty update(s): \n")
returnMessage.join("\n")

getUserForIncident = (incident) ->
if incident.assigned_to_user
incident.assigned_to_user.email
else if incident.resolved_by_user
incident.resolved_by_user.email
else
'(???)'

generateIncidentString = (incident, hookType) ->
console.log "hookType is " + hookType
assigned_user = getUserForIncident(incident)
incident_number = incident.incident_number

if hookType == "incident.trigger"
"""
Incident # #{incident_number} :
#{incident.status} and assigned to #{assigned_user}
#{incident.html_url}
To acknowledge: @#{robot.name} pager me ack #{incident_number}
To resolve: @#{robot.name} pager me resolve #{}
"""
else if hookType == "incident.acknowledge"
"""
Incident # #{incident_number} :
#{incident.status} and assigned to #{assigned_user}
#{incident.html_url}
To resolve: @#{robot.name} pager me resolve #{incident_number}
"""
else if hookType == "incident.resolve"
"""
Incident # #{incident_number} has been resolved by #{assigned_user}
#{incident.html_url}
"""
else if hookType == "incident.unacknowledge"
"""
#{incident.status} , unacknowledged and assigned to #{assigned_user}
#{incident.html_url}
To acknowledge: @#{robot.name} pager me ack #{incident_number}
To resolve: @#{robot.name} pager me resolve #{incident_number}
"""
else if hookType == "incident.assign"
"""
Incident # #{incident_number} :
#{incident.status} , reassigned to #{assigned_user}
#{incident.html_url}
To resolve: @#{robot.name} pager me resolve #{incident_number}
"""
else if hookType == "incident.escalate"
"""
Incident # #{incident_number} :
#{incident.status} , was escalated and assigned to #{assigned_user}
#{incident.html_url}
To acknowledge: @#{robot.name} pager me ack #{incident_number}
To resolve: @#{robot.name} pager me resolve #{incident_number}
"""
Loading