From c3256ed961f1b9faf4e2a2d5566dda771970e4a3 Mon Sep 17 00:00:00 2001 From: Jesse Newland Date: Fri, 29 Mar 2013 14:20:29 -0400 Subject: [PATCH 01/17] open source @github's hubot pagerduty script --- src/scripts/pagerduty.coffee | 235 +++++++++++++++++++++++++++++++++++ 1 file changed, 235 insertions(+) create mode 100644 src/scripts/pagerduty.coffee diff --git a/src/scripts/pagerduty.coffee b/src/scripts/pagerduty.coffee new file mode 100644 index 000000000..c6588d177 --- /dev/null +++ b/src/scripts/pagerduty.coffee @@ -0,0 +1,235 @@ +# PagerDuty +# +# Required environment variables: +# +# HUBOT_PAGERDUTY_USERNAME +# HUBOT_PAGERDUTY_PASSWORD +# HUBOT_PAGERDUTY_SUBDOMAIN +# HUBOT_PAGERDUTY_APIKEY Service API Key from a 'General API Service' +# HUBOT_PAGERDUTY_SCHEDULE_ID + + +pagerDutyUsers = {} + +module.exports = (robot) -> + robot.respond /pager( me)?$/i, (msg) -> + buffer = "PagerDuty\n\nUsage:\n" + buffer = buffer + " /who's on call # return the username of who's on call\n\n" + buffer = buffer + " /pager me page # create a new incident\n\n" + buffer = buffer + " /pager me 60 # take the pager for 60 minutes\n\n" + buffer = buffer + " /pager me incidents # return the current incidents\n" + buffer = buffer + " /pager me problems # return all open inicidents\n\n" + buffer = buffer + " /pager me ack 24 # ack incident #24\n" + buffer = buffer + " /pager me resolve 24 # resolve incident #24\n" + msg.send buffer + + # Assumes your Campfire usernames and PagerDuty names are identical + robot.respond /pager( me)? (\d+)/i, (msg) -> + withPagerDutyUsers msg, (users) -> + username = msg.message.user.name + if username == "Shell" + username = process.env.USER + userId = users[username].id + now = new Date() + start = now.toISOString() + minutes = parseInt msg.match[2] + end = now.addMinutes(minutes).toISOString() + override = { + 'start': start, + 'end': end, + 'user_id': userId + } + withCurrentOncall msg, (old_username) -> + data = { 'override': override } + pagerDutyPost msg, "/schedules/#{process.env.HUBOT_PAGERDUTY_SCHEDULE_ID}/overrides", data, (json) -> + if json.override + msg.send "rejoice, #{old_username}! #{json.override.user.name} has the pager from #{json.override.start} until #{json.override.end}" + + robot.respond /(pager|major)( me)? (inc|incidents|sup|problems)$/i, (msg) -> + pagerDutyIncidents msg, (incidents) -> + if incidents.length > 0 + buffer = "Triggered\n\n" + for junk, incident of incidents.reverse() + if incident.status == 'triggered' + buffer = buffer + formatIncident(incident) + buffer = buffer + "\nAcknowledged\n\n" + for junk, incident of incidents.reverse() + if incident.status == 'acknowledged' + buffer = buffer + formatIncident(incident) + msg.send buffer + else + msg.send "Chillin" + + robot.respond /(pager|major)( me)? page (.+)$/i, (msg) -> + pagerDutyIntegrationAPI msg, "trigger", msg.match[3], (json) -> + msg.reply "#{json.status}, key: #{json.incident_key}" + + robot.respond /(pager|major)( me)? ack(nowledge)? (.+)$/i, (msg) -> + updateIncident(msg, msg.match[4], 'acknowledged') + + robot.respond /(pager|major)( me)? res(olve)?(d)? (.+)$/i, (msg) -> + updateIncident(msg, msg.match[5], 'resolved') + + # who is on call? + robot.respond /who('s|s| is)? (on call|oncall)/i, (msg) -> + withCurrentOncall msg, (username) -> + msg.reply "#{username} is on call" + +pagerDutyGet = (msg, url, query, cb) -> + user = process.env.HUBOT_PAGERDUTY_USERNAME + pass = process.env.HUBOT_PAGERDUTY_PASSWORD + baseUrl = "https://#{process.env.HUBOT_PAGERDUTY_SUBDOMAIN}.pagerduty.com/api/v1" + + auth = 'Basic ' + new Buffer(user + ':' + pass).toString('base64'); + msg.http(baseUrl + url) + .query(query) + .headers(Authorization: auth, Accept: 'application/json') + .get() (err, res, body) -> + json_body = null + switch res.statusCode + when 200 then json_body = JSON.parse(body) + else + console.log res.statusCode + console.log body + json_body = null + cb json_body + +pagerDutyPut = (msg, url, data, cb) -> + user = process.env.HUBOT_PAGERDUTY_USERNAME + pass = process.env.HUBOT_PAGERDUTY_PASSWORD + baseUrl = "https://#{process.env.HUBOT_PAGERDUTY_SUBDOMAIN}.pagerduty.com/api/v1" + + json = JSON.stringify(data) + auth = 'Basic ' + new Buffer(user + ':' + pass).toString('base64'); + msg.http(baseUrl + url) + .headers(Authorization: auth, Accept: 'application/json') + .header("content-type","application/json") + .header("content-length",json.length) + .put(json) (err, res, body) -> + json_body = null + switch res.statusCode + when 200 then json_body = JSON.parse(body) + else + console.log res.statusCode + console.log body + json_body = null + cb json_body + +pagerDutyPost = (msg, url, data, cb) -> + user = process.env.HUBOT_PAGERDUTY_USERNAME + pass = process.env.HUBOT_PAGERDUTY_PASSWORD + baseUrl = "https://#{process.env.HUBOT_PAGERDUTY_SUBDOMAIN}.pagerduty.com/api/v1" + + json = JSON.stringify(data) + auth = 'Basic ' + new Buffer(user + ':' + pass).toString('base64'); + msg.http(baseUrl + url) + .headers(Authorization: auth, Accept: 'application/json') + .header("content-type","application/json") + .header("content-length",json.length) + .post(json) (err, res, body) -> + json_body = null + switch res.statusCode + when 201 then json_body = JSON.parse(body) + else + console.log res.statusCode + console.log body + json_body = null + cb json_body + +withCurrentOncall = (msg, cb) -> + now = new Date() + oneHour = now.addHours(1).toISOString() + now = now.toISOString() + query = { + since: now, + until: oneHour, + overflow: 'true' + } + pagerDutyGet msg, "/schedules/#{process.env.HUBOT_PAGERDUTY_SCHEDULE_ID}/entries", query, (json) -> + if json.entries and json.entries.length > 0 + cb(json.entries[0].user.name) + +withPagerDutyUsers = (msg, cb) -> + if pagerDutyUsers['loaded'] != true + pagerDutyGet msg, "/users", {}, (json) -> + pagerDutyUsers['loaded'] = true + for user in json.users + pagerDutyUsers[user.id] = user + pagerDutyUsers[user.name] = user + cb(pagerDutyUsers) + else + cb(pagerDutyUsers) + +pagerDutyIncidents = (msg, cb) -> + query = + status: "triggered,acknowledged" + sort_by: "incident_number:asc" + pagerDutyGet msg, "/incidents", query, (json) -> + cb(json.incidents) + +pagerDutyIntegrationAPI = (msg, cmd, args, cb) -> + apikey = process.env.HUBOT_PAGERDUTY_APIKEY + unless apikey? + msg.send "PagerDuty API service key is missing." + msg.send "Ensure that HUBOT_PAGERDUTY_APIKEY is set." + return + + data = null + switch cmd + when "trigger" + data = JSON.stringify { service_key: "#{apikey}", event_type: "trigger", description: "#{args}"} + pagerDutyIntergrationPost msg, data, (json) -> + cb(json) + +formatIncident = (inc) -> + # { pd_nagios_object: 'service', + # HOSTNAME: 'fs1a', + # SERVICEDESC: 'snapshot_repositories', + # SERVICESTATE: 'CRITICAL', + # HOSTSTATE: 'UP' }, + if inc.incident_number + if inc.trigger_summary_data.description + "#{inc.incident_number}: #{inc.trigger_summary_data.description} - assigned to #{inc.assigned_to_user.name}\n" + else if inc.trigger_summary_data.pd_nagios_object == 'service' + "#{inc.incident_number}: #{inc.trigger_summary_data.HOSTNAME}/#{inc.trigger_summary_data.SERVICEDESC} - assigned to #{inc.assigned_to_user.name}\n" + else if inc.trigger_summary_data.pd_nagios_object == 'host' + "#{inc.incident_number}: #{inc.trigger_summary_data.HOSTNAME}/#{inc.trigger_summary_data.HOSTSTATE} - assigned to #{inc.assigned_to_user.name}\n" + else + "" + +updateIncident = (msg, incident_number, status) -> + pagerDutyIncidents msg, (incidents) -> + foundIncidents = [] + for incident in incidents + if "#{incident.incident_number}" == incident_number + foundIncidents = [ incident ] + # loljson + data = { + incidents: [ + { + 'id': incident.id, + 'status': status + } + ] + } + pagerDutyPut msg, "/incidents", data, (json) -> + if incident = json.incidents[0] + msg.reply "Incident #{incident.incident_number} #{incident.status}." + else + msg.reply "Problem updating incident #{incident_number}" + if foundIncidents.length == 0 + msg.reply "Couldn't find incident #{incident_number}" + + +pagerDutyIntergrationPost = (msg, json, cb) -> + msg.http('https://events.pagerduty.com/generic/2010-04-15/create_event.json') + .header("content-type","application/json") + .header("content-length",json.length) + .post(json) (err, res, body) -> + switch res.statusCode + when 200 + json = JSON.parse(body) + cb(json) + else + console.log res.statusCode + console.log body From a4d41d0b0964836dadea5345f681f6193154f7b3 Mon Sep 17 00:00:00 2001 From: Josh Nichols Date: Fri, 29 Mar 2013 15:57:56 -0400 Subject: [PATCH 02/17] Update with documentation status, and use robot.helpCommands for pager me --- src/scripts/pagerduty.coffee | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/scripts/pagerduty.coffee b/src/scripts/pagerduty.coffee index c6588d177..58c61708d 100644 --- a/src/scripts/pagerduty.coffee +++ b/src/scripts/pagerduty.coffee @@ -1,6 +1,17 @@ -# PagerDuty +# Description: +# PagerDuty Integration for checking who's on call, making exceptions, ack, resolve, etc. # -# Required environment variables: +# Commands: +# +# hubot who's on call - return the username of who's on call +# hubot pager me page - create a new incident +# hubot pager me 60 - take the pager for 60 minutes +# hubot pager me incidents - return the current incidents +# hubot pager me problems - return all open inicidents +# hubot pager me ack 24 - ack incident #24 +# hubot pager me resolve 24 - resolve incident #24 + +# Configuration # # HUBOT_PAGERDUTY_USERNAME # HUBOT_PAGERDUTY_PASSWORD @@ -8,20 +19,14 @@ # HUBOT_PAGERDUTY_APIKEY Service API Key from a 'General API Service' # HUBOT_PAGERDUTY_SCHEDULE_ID - pagerDutyUsers = {} module.exports = (robot) -> robot.respond /pager( me)?$/i, (msg) -> - buffer = "PagerDuty\n\nUsage:\n" - buffer = buffer + " /who's on call # return the username of who's on call\n\n" - buffer = buffer + " /pager me page # create a new incident\n\n" - buffer = buffer + " /pager me 60 # take the pager for 60 minutes\n\n" - buffer = buffer + " /pager me incidents # return the current incidents\n" - buffer = buffer + " /pager me problems # return all open inicidents\n\n" - buffer = buffer + " /pager me ack 24 # ack incident #24\n" - buffer = buffer + " /pager me resolve 24 # resolve incident #24\n" - msg.send buffer + + cmds = robot.helpCommands() + cmds = (cmd for cmd in cmds when cmd.match(/(pager me |who's on call)/)) + msg.send cmds.join("\n") # Assumes your Campfire usernames and PagerDuty names are identical robot.respond /pager( me)? (\d+)/i, (msg) -> From f1613a9a2b02f6ac9e94d043efca8ff3150f291a Mon Sep 17 00:00:00 2001 From: Josh Nichols Date: Fri, 29 Mar 2013 16:44:42 -0400 Subject: [PATCH 03/17] Adjust format of incidents --- src/scripts/pagerduty.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scripts/pagerduty.coffee b/src/scripts/pagerduty.coffee index 58c61708d..e009932e7 100644 --- a/src/scripts/pagerduty.coffee +++ b/src/scripts/pagerduty.coffee @@ -53,11 +53,11 @@ module.exports = (robot) -> robot.respond /(pager|major)( me)? (inc|incidents|sup|problems)$/i, (msg) -> pagerDutyIncidents msg, (incidents) -> if incidents.length > 0 - buffer = "Triggered\n\n" + buffer = "Triggered:\n----------\n" for junk, incident of incidents.reverse() if incident.status == 'triggered' buffer = buffer + formatIncident(incident) - buffer = buffer + "\nAcknowledged\n\n" + buffer = buffer + "\nAcknowledged:\n-------------\n" for junk, incident of incidents.reverse() if incident.status == 'acknowledged' buffer = buffer + formatIncident(incident) From 257c8fa982770a5555bee13d18b0f3de4e8b7799 Mon Sep 17 00:00:00 2001 From: Josh Nichols Date: Fri, 29 Mar 2013 17:03:01 -0400 Subject: [PATCH 04/17] Sanity check environment variables --- src/scripts/pagerduty.coffee | 51 +++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/src/scripts/pagerduty.coffee b/src/scripts/pagerduty.coffee index e009932e7..6916c62ab 100644 --- a/src/scripts/pagerduty.coffee +++ b/src/scripts/pagerduty.coffee @@ -20,6 +20,11 @@ # HUBOT_PAGERDUTY_SCHEDULE_ID pagerDutyUsers = {} +pagerDutyUsername = process.env.HUBOT_PAGERDUTY_USERNAME +pagerDutyPassword = process.env.HUBOT_PAGERDUTY_PASSWORD +pagerDutySubdomain = process.env.HUBOT_PAGERDUTY_SUBDOMAIN +pagerDutyBaseUrl = "https://#{pagerDutySubdomain}.pagerduty.com/api/v1" +pagerDutyApiKey = process.env.HUBOT_PAGERDUTY_APIKEY module.exports = (robot) -> robot.respond /pager( me)?$/i, (msg) -> @@ -80,13 +85,26 @@ module.exports = (robot) -> withCurrentOncall msg, (username) -> msg.reply "#{username} is on call" +missingEnvironmentForApi = (msg) -> + missingAnything = false + unless pagerDutySubdomain? + msg.send "PagerDuty Subdomain is missing: Ensure that HUBOT_PAGERDUTY_SUBDOMAIN is set." + missingAnything |= true + unless pagerDutyUsername? + msg.send "PagerDuty username is missing: Ensure that HUBOT_PAGERDUTY_USERNAME is set." + missingAnything |= true + unless pagerDutyPassword? + msg.send "PagerDuty password is missing: Ensure that HUBOT_PAGERDUTY_PASSWORD is set." + missingAnything |= true + missingAnything + + pagerDutyGet = (msg, url, query, cb) -> - user = process.env.HUBOT_PAGERDUTY_USERNAME - pass = process.env.HUBOT_PAGERDUTY_PASSWORD - baseUrl = "https://#{process.env.HUBOT_PAGERDUTY_SUBDOMAIN}.pagerduty.com/api/v1" + if missingEnvironmentForApi(msg) + return - auth = 'Basic ' + new Buffer(user + ':' + pass).toString('base64'); - msg.http(baseUrl + url) + auth = 'Basic ' + new Buffer(pagerDutyUsername + ':' + pagerDutyPassword).toString('base64') + msg.http(pagerDutyBaseUrl + url) .query(query) .headers(Authorization: auth, Accept: 'application/json') .get() (err, res, body) -> @@ -100,13 +118,12 @@ pagerDutyGet = (msg, url, query, cb) -> cb json_body pagerDutyPut = (msg, url, data, cb) -> - user = process.env.HUBOT_PAGERDUTY_USERNAME - pass = process.env.HUBOT_PAGERDUTY_PASSWORD - baseUrl = "https://#{process.env.HUBOT_PAGERDUTY_SUBDOMAIN}.pagerduty.com/api/v1" + if missingEnvironmentForApi(msg) + return json = JSON.stringify(data) - auth = 'Basic ' + new Buffer(user + ':' + pass).toString('base64'); - msg.http(baseUrl + url) + auth = 'Basic ' + new Buffer(pagerDutyUsername + ':' + pagerDutyPassword).toString('base64') + msg.http(pagerDutyBaseUrl + url) .headers(Authorization: auth, Accept: 'application/json') .header("content-type","application/json") .header("content-length",json.length) @@ -121,13 +138,12 @@ pagerDutyPut = (msg, url, data, cb) -> cb json_body pagerDutyPost = (msg, url, data, cb) -> - user = process.env.HUBOT_PAGERDUTY_USERNAME - pass = process.env.HUBOT_PAGERDUTY_PASSWORD - baseUrl = "https://#{process.env.HUBOT_PAGERDUTY_SUBDOMAIN}.pagerduty.com/api/v1" + if missingEnvironmentForApi(msg) + return json = JSON.stringify(data) - auth = 'Basic ' + new Buffer(user + ':' + pass).toString('base64'); - msg.http(baseUrl + url) + auth = 'Basic ' + new Buffer(pagerDutyUsername + ':' + pagerDutyPassword).toString('base64') + msg.http(pagerDutyBaseUrl + url) .headers(Authorization: auth, Accept: 'application/json') .header("content-type","application/json") .header("content-length",json.length) @@ -173,8 +189,7 @@ pagerDutyIncidents = (msg, cb) -> cb(json.incidents) pagerDutyIntegrationAPI = (msg, cmd, args, cb) -> - apikey = process.env.HUBOT_PAGERDUTY_APIKEY - unless apikey? + unless pagerDutyApiKey? msg.send "PagerDuty API service key is missing." msg.send "Ensure that HUBOT_PAGERDUTY_APIKEY is set." return @@ -182,7 +197,7 @@ pagerDutyIntegrationAPI = (msg, cmd, args, cb) -> data = null switch cmd when "trigger" - data = JSON.stringify { service_key: "#{apikey}", event_type: "trigger", description: "#{args}"} + data = JSON.stringify { service_key: pagerDutyApiKey, event_type: "trigger", description: "#{args}"} pagerDutyIntergrationPost msg, data, (json) -> cb(json) From 5f228ce8d73136ee30a4fe6cbcd84bed12a07360 Mon Sep 17 00:00:00 2001 From: Josh Nichols Date: Wed, 10 Apr 2013 20:45:57 -0400 Subject: [PATCH 05/17] Epic pagerduty improvements. * use moment instead of datejs for time manipulation (ie adding hours/minutes) * for `pager me N`, try to use the person who's said it email, instead of their name to find a PagerDuty user * add command to remember your PagerDuty email address * use moment's .calendar() to display nicer time when coverage is * `pager me` will also say what it thinks your PagerDuty email address is --- src/scripts/pagerduty.coffee | 57 +++++++++++++++++++++++++++--------- 1 file changed, 43 insertions(+), 14 deletions(-) diff --git a/src/scripts/pagerduty.coffee b/src/scripts/pagerduty.coffee index 6916c62ab..71a96a109 100644 --- a/src/scripts/pagerduty.coffee +++ b/src/scripts/pagerduty.coffee @@ -10,8 +10,11 @@ # hubot pager me problems - return all open inicidents # hubot pager me ack 24 - ack incident #24 # hubot pager me resolve 24 - resolve incident #24 - -# Configuration +# +# Dependencies: +# "moment": "1.6.2" +# +# Configuration: # # HUBOT_PAGERDUTY_USERNAME # HUBOT_PAGERDUTY_PASSWORD @@ -19,6 +22,10 @@ # HUBOT_PAGERDUTY_APIKEY Service API Key from a 'General API Service' # HUBOT_PAGERDUTY_SCHEDULE_ID +inspect = require('util').inspect + +moment = require('moment') + pagerDutyUsers = {} pagerDutyUsername = process.env.HUBOT_PAGERDUTY_USERNAME pagerDutyPassword = process.env.HUBOT_PAGERDUTY_PASSWORD @@ -29,21 +36,40 @@ pagerDutyApiKey = process.env.HUBOT_PAGERDUTY_APIKEY module.exports = (robot) -> robot.respond /pager( me)?$/i, (msg) -> + emailNote = if msg.message.user.pagerdutyEmail + "You've told me your PagerDuty email is #{msg.message.user.pagerdutyEmail}" + else if msg.message.user.email_address + "I'm assuming your PagerDuty email is #{msg.message.user.email_address}. Change it with `hubot pager me as you@yourdomain.com`" + else + "I don't know your PagerDuty email. Change it with `hubot pager me as you@yourdomain.com`" + cmds = robot.helpCommands() cmds = (cmd for cmd in cmds when cmd.match(/(pager me |who's on call)/)) - msg.send cmds.join("\n") + msg.send emailNote, cmds.join("\n") + + robot.respond /pager(?: me)? as (.*)$/i, (msg) -> + email = msg.match[1] + msg.message.user.pagerdutyEmail = email + msg.send "Okay, I'll remember your PagerDuty email is #{email}" # Assumes your Campfire usernames and PagerDuty names are identical robot.respond /pager( me)? (\d+)/i, (msg) -> withPagerDutyUsers msg, (users) -> - username = msg.message.user.name - if username == "Shell" - username = process.env.USER - userId = users[username].id + email = msg.message.user.pagerdutyEmail || msg.message.user.email_address + unless email + msg.send "Sorry, I can't figure out your email address :( Can you tell me with `hubot pager me as you@yourdomain.com`?" + return + + userId = users[email].id + + unless userId + msg.send "Sorry, I couldn't find a PagerDuty user for #{email}. Double check you have a user, and that I know your PagerDuty email with `hubot pager me as you@yourdomain.com`" + return + now = new Date() - start = now.toISOString() + start = moment().format() minutes = parseInt msg.match[2] - end = now.addMinutes(minutes).toISOString() + end = moment().add('minutes', minutes).format() override = { 'start': start, 'end': end, @@ -53,7 +79,9 @@ module.exports = (robot) -> data = { 'override': override } pagerDutyPost msg, "/schedules/#{process.env.HUBOT_PAGERDUTY_SCHEDULE_ID}/overrides", data, (json) -> if json.override - msg.send "rejoice, #{old_username}! #{json.override.user.name} has the pager from #{json.override.start} until #{json.override.end}" + start = moment(json.override.start) + end = moment(json.override.end) + msg.send "Rejoice, #{old_username}! #{json.override.user.name} has the pager from #{start.calendar()} until #{end.calendar()}" robot.respond /(pager|major)( me)? (inc|incidents|sup|problems)$/i, (msg) -> pagerDutyIncidents msg, (incidents) -> @@ -158,9 +186,9 @@ pagerDutyPost = (msg, url, data, cb) -> cb json_body withCurrentOncall = (msg, cb) -> - now = new Date() - oneHour = now.addHours(1).toISOString() - now = now.toISOString() + oneHour = moment().add('hours', 1).format() + now = moment().format() + query = { since: now, until: oneHour, @@ -175,7 +203,8 @@ withPagerDutyUsers = (msg, cb) -> pagerDutyGet msg, "/users", {}, (json) -> pagerDutyUsers['loaded'] = true for user in json.users - pagerDutyUsers[user.id] = user + pagerDutyUsers[user.id] = user + pagerDutyUsers[user.email] = user pagerDutyUsers[user.name] = user cb(pagerDutyUsers) else From a810a3165e9879359e71421c7c190548a962e168 Mon Sep 17 00:00:00 2001 From: Josh Nichols Date: Wed, 10 Apr 2013 20:50:12 -0400 Subject: [PATCH 06/17] Move process.env.HUBOT_PAGERDUTY_SCHEDULE_ID to a variable --- src/scripts/pagerduty.coffee | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/scripts/pagerduty.coffee b/src/scripts/pagerduty.coffee index 71a96a109..039997968 100644 --- a/src/scripts/pagerduty.coffee +++ b/src/scripts/pagerduty.coffee @@ -6,6 +6,7 @@ # hubot who's on call - return the username of who's on call # hubot pager me page - create a new incident # hubot pager me 60 - take the pager for 60 minutes +# hubot pager me as you@yourdomain.com - remember your pager email is you@yourdomain.com # hubot pager me incidents - return the current incidents # hubot pager me problems - return all open inicidents # hubot pager me ack 24 - ack incident #24 @@ -32,6 +33,7 @@ pagerDutyPassword = process.env.HUBOT_PAGERDUTY_PASSWORD pagerDutySubdomain = process.env.HUBOT_PAGERDUTY_SUBDOMAIN pagerDutyBaseUrl = "https://#{pagerDutySubdomain}.pagerduty.com/api/v1" pagerDutyApiKey = process.env.HUBOT_PAGERDUTY_APIKEY +pagerDutyScheduleId = process.env.HUBOT_PAGERDUTY_SCHEDULE_ID module.exports = (robot) -> robot.respond /pager( me)?$/i, (msg) -> @@ -77,7 +79,7 @@ module.exports = (robot) -> } withCurrentOncall msg, (old_username) -> data = { 'override': override } - pagerDutyPost msg, "/schedules/#{process.env.HUBOT_PAGERDUTY_SCHEDULE_ID}/overrides", data, (json) -> + pagerDutyPost msg, "/schedules/#{pagerDutyScheduleId}/overrides", data, (json) -> if json.override start = moment(json.override.start) end = moment(json.override.end) @@ -194,7 +196,7 @@ withCurrentOncall = (msg, cb) -> until: oneHour, overflow: 'true' } - pagerDutyGet msg, "/schedules/#{process.env.HUBOT_PAGERDUTY_SCHEDULE_ID}/entries", query, (json) -> + pagerDutyGet msg, "/schedules/#{pagerDutyScheduleId}/entries", query, (json) -> if json.entries and json.entries.length > 0 cb(json.entries[0].user.name) From 4084e5a9f90974cedc30b32fe988419fb099a3de Mon Sep 17 00:00:00 2001 From: Josh Nichols Date: Wed, 10 Apr 2013 22:40:05 -0400 Subject: [PATCH 07/17] Better doc for triggering a page --- src/scripts/pagerduty.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/pagerduty.coffee b/src/scripts/pagerduty.coffee index 039997968..872c3e666 100644 --- a/src/scripts/pagerduty.coffee +++ b/src/scripts/pagerduty.coffee @@ -4,7 +4,7 @@ # Commands: # # hubot who's on call - return the username of who's on call -# hubot pager me page - create a new incident +# hubot pager me page - create a new incident with # hubot pager me 60 - take the pager for 60 minutes # hubot pager me as you@yourdomain.com - remember your pager email is you@yourdomain.com # hubot pager me incidents - return the current incidents From c3db4fb7c7c670755c5685db67d680471c376399 Mon Sep 17 00:00:00 2001 From: Josh Nichols Date: Wed, 10 Apr 2013 22:40:24 -0400 Subject: [PATCH 08/17] Check for pagerduty schedule id --- src/scripts/pagerduty.coffee | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/scripts/pagerduty.coffee b/src/scripts/pagerduty.coffee index 872c3e666..d6d13269c 100644 --- a/src/scripts/pagerduty.coffee +++ b/src/scripts/pagerduty.coffee @@ -37,6 +37,8 @@ pagerDutyScheduleId = process.env.HUBOT_PAGERDUTY_SCHEDULE_ID module.exports = (robot) -> robot.respond /pager( me)?$/i, (msg) -> + if missingEnvironmentForApi(msg) + return emailNote = if msg.message.user.pagerdutyEmail "You've told me your PagerDuty email is #{msg.message.user.pagerdutyEmail}" @@ -126,6 +128,9 @@ missingEnvironmentForApi = (msg) -> unless pagerDutyPassword? msg.send "PagerDuty password is missing: Ensure that HUBOT_PAGERDUTY_PASSWORD is set." missingAnything |= true + unless pagerDutyScheduleId? + msg.send "PagerDuty schedule is missing: Ensure that HUBOT_PAGERDUTY_SCHEDULE_ID is set." + missingAnything |= true missingAnything From 722daf69eacd02fe988892ce4a0f68055d3cf559 Mon Sep 17 00:00:00 2001 From: Josh Nichols Date: Wed, 10 Apr 2013 22:40:33 -0400 Subject: [PATCH 09/17] Remove unused variable --- src/scripts/pagerduty.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/src/scripts/pagerduty.coffee b/src/scripts/pagerduty.coffee index d6d13269c..6cc181a29 100644 --- a/src/scripts/pagerduty.coffee +++ b/src/scripts/pagerduty.coffee @@ -70,7 +70,6 @@ module.exports = (robot) -> msg.send "Sorry, I couldn't find a PagerDuty user for #{email}. Double check you have a user, and that I know your PagerDuty email with `hubot pager me as you@yourdomain.com`" return - now = new Date() start = moment().format() minutes = parseInt msg.match[2] end = moment().add('minutes', minutes).format() From 6056ac5cbffe630ebb1319266fd35ba15213db0b Mon Sep 17 00:00:00 2001 From: Josh Nichols Date: Wed, 10 Apr 2013 22:48:13 -0400 Subject: [PATCH 10/17] Rename page to trigger, to reflect pagerduty language. --- src/scripts/pagerduty.coffee | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/scripts/pagerduty.coffee b/src/scripts/pagerduty.coffee index 6cc181a29..f446ca967 100644 --- a/src/scripts/pagerduty.coffee +++ b/src/scripts/pagerduty.coffee @@ -4,13 +4,14 @@ # Commands: # # hubot who's on call - return the username of who's on call -# hubot pager me page - create a new incident with +# hubot pager me trigger - create a new incident with # hubot pager me 60 - take the pager for 60 minutes # hubot pager me as you@yourdomain.com - remember your pager email is you@yourdomain.com # hubot pager me incidents - return the current incidents +# hubot pager me note - add note to incident # with # hubot pager me problems - return all open inicidents -# hubot pager me ack 24 - ack incident #24 -# hubot pager me resolve 24 - resolve incident #24 +# hubot pager me ack - ack incident # +# hubot pager me resolve - resolve incident # # # Dependencies: # "moment": "1.6.2" @@ -101,7 +102,7 @@ module.exports = (robot) -> else msg.send "Chillin" - robot.respond /(pager|major)( me)? page (.+)$/i, (msg) -> + robot.respond /(pager|major)( me)? trigger (.+)$/i, (msg) -> pagerDutyIntegrationAPI msg, "trigger", msg.match[3], (json) -> msg.reply "#{json.status}, key: #{json.incident_key}" From 790808c89eecb4860cf071e6aa7a396cbe58e1db Mon Sep 17 00:00:00 2001 From: Josh Nichols Date: Thu, 11 Apr 2013 20:54:22 -0400 Subject: [PATCH 11/17] Add support for notes --- src/scripts/pagerduty.coffee | 48 ++++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/src/scripts/pagerduty.coffee b/src/scripts/pagerduty.coffee index f446ca967..ab0a94cfd 100644 --- a/src/scripts/pagerduty.coffee +++ b/src/scripts/pagerduty.coffee @@ -60,16 +60,9 @@ module.exports = (robot) -> # Assumes your Campfire usernames and PagerDuty names are identical robot.respond /pager( me)? (\d+)/i, (msg) -> withPagerDutyUsers msg, (users) -> - email = msg.message.user.pagerdutyEmail || msg.message.user.email_address - unless email - msg.send "Sorry, I can't figure out your email address :( Can you tell me with `hubot pager me as you@yourdomain.com`?" - return - userId = users[email].id - - unless userId - msg.send "Sorry, I couldn't find a PagerDuty user for #{email}. Double check you have a user, and that I know your PagerDuty email with `hubot pager me as you@yourdomain.com`" - return + userId = pagerDutyUserId(msg, users) + return unless userId start = moment().format() minutes = parseInt msg.match[2] @@ -100,7 +93,7 @@ module.exports = (robot) -> buffer = buffer + formatIncident(incident) msg.send buffer else - msg.send "Chillin" + msg.send "No open incidents" robot.respond /(pager|major)( me)? trigger (.+)$/i, (msg) -> pagerDutyIntegrationAPI msg, "trigger", msg.match[3], (json) -> @@ -112,6 +105,27 @@ module.exports = (robot) -> robot.respond /(pager|major)( me)? res(olve)?(d)? (.+)$/i, (msg) -> updateIncident(msg, msg.match[5], 'resolved') + robot.respond /(pager|major)( me)? note ([\d\w]+) (.+)$/i, (msg) -> + incidentId = msg.match[3] + content = msg.match[4] + + withPagerDutyUsers msg, (users) -> + + userId = pagerDutyUserId(msg, users) + return unless userId + + data = + note: + content: content + requester_id: userId + + pagerDutyPost msg, "/incidents/#{incidentId}/notes", data, (json) -> + if json && json.note + msg.send "Got it! Note created: #{json.note.content}" + else + msg.send "Sorry, I couldn't do it :(" + + # who is on call? robot.respond /who('s|s| is)? (on call|oncall)/i, (msg) -> withCurrentOncall msg, (username) -> @@ -134,6 +148,20 @@ missingEnvironmentForApi = (msg) -> missingAnything +pagerDutyUserId = (msg, users) -> + email = msg.message.user.pagerdutyEmail || msg.message.user.email_address + unless email + msg.send "Sorry, I can't figure out your email address :( Can you tell me with `hubot pager me as you@yourdomain.com`?" + return + + userId = users[email].id + + unless userId + msg.send "Sorry, I couldn't find a PagerDuty user for #{email}. Double check you have a user, and that I know your PagerDuty email with `hubot pager me as you@yourdomain.com`" + return + + userId + pagerDutyGet = (msg, url, query, cb) -> if missingEnvironmentForApi(msg) return From 0aec8cce39afcb4fcd9c71ea4a8c3e21403ac5af Mon Sep 17 00:00:00 2001 From: Josh Nichols Date: Thu, 11 Apr 2013 20:58:50 -0400 Subject: [PATCH 12/17] Only display until time since start time is now. And don't use calendar, since timezones are hard --- src/scripts/pagerduty.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/pagerduty.coffee b/src/scripts/pagerduty.coffee index ab0a94cfd..42d03d915 100644 --- a/src/scripts/pagerduty.coffee +++ b/src/scripts/pagerduty.coffee @@ -78,7 +78,7 @@ module.exports = (robot) -> if json.override start = moment(json.override.start) end = moment(json.override.end) - msg.send "Rejoice, #{old_username}! #{json.override.user.name} has the pager from #{start.calendar()} until #{end.calendar()}" + msg.send "Rejoice, #{old_username}! #{json.override.user.name} has the pager until #{end.format()}" robot.respond /(pager|major)( me)? (inc|incidents|sup|problems)$/i, (msg) -> pagerDutyIncidents msg, (incidents) -> From f09741a001a7c5d9b72392cce0b494b73f2bab70 Mon Sep 17 00:00:00 2001 From: Josh Nichols Date: Thu, 11 Apr 2013 21:04:38 -0400 Subject: [PATCH 13/17] Update msg.sends to use robot.name instead of hardcoded hubot --- src/scripts/pagerduty.coffee | 372 +++++++++++++++++------------------ 1 file changed, 186 insertions(+), 186 deletions(-) diff --git a/src/scripts/pagerduty.coffee b/src/scripts/pagerduty.coffee index 42d03d915..a21a3d495 100644 --- a/src/scripts/pagerduty.coffee +++ b/src/scripts/pagerduty.coffee @@ -6,7 +6,7 @@ # hubot who's on call - return the username of who's on call # hubot pager me trigger - create a new incident with # hubot pager me 60 - take the pager for 60 minutes -# hubot pager me as you@yourdomain.com - remember your pager email is you@yourdomain.com +# hubot pager me as - remember your pager email is # hubot pager me incidents - return the current incidents # hubot pager me note - add note to incident # with # hubot pager me problems - return all open inicidents @@ -46,7 +46,7 @@ module.exports = (robot) -> else if msg.message.user.email_address "I'm assuming your PagerDuty email is #{msg.message.user.email_address}. Change it with `hubot pager me as you@yourdomain.com`" else - "I don't know your PagerDuty email. Change it with `hubot pager me as you@yourdomain.com`" + "I don't know your PagerDuty email. Change it with `#{robot.name} pager me as you@yourdomain.com`" cmds = robot.helpCommands() cmds = (cmd for cmd in cmds when cmd.match(/(pager me |who's on call)/)) @@ -131,189 +131,189 @@ module.exports = (robot) -> withCurrentOncall msg, (username) -> msg.reply "#{username} is on call" -missingEnvironmentForApi = (msg) -> - missingAnything = false - unless pagerDutySubdomain? - msg.send "PagerDuty Subdomain is missing: Ensure that HUBOT_PAGERDUTY_SUBDOMAIN is set." - missingAnything |= true - unless pagerDutyUsername? - msg.send "PagerDuty username is missing: Ensure that HUBOT_PAGERDUTY_USERNAME is set." - missingAnything |= true - unless pagerDutyPassword? - msg.send "PagerDuty password is missing: Ensure that HUBOT_PAGERDUTY_PASSWORD is set." - missingAnything |= true - unless pagerDutyScheduleId? - msg.send "PagerDuty schedule is missing: Ensure that HUBOT_PAGERDUTY_SCHEDULE_ID is set." - missingAnything |= true - missingAnything - - -pagerDutyUserId = (msg, users) -> - email = msg.message.user.pagerdutyEmail || msg.message.user.email_address - unless email - msg.send "Sorry, I can't figure out your email address :( Can you tell me with `hubot pager me as you@yourdomain.com`?" - return - - userId = users[email].id - - unless userId - msg.send "Sorry, I couldn't find a PagerDuty user for #{email}. Double check you have a user, and that I know your PagerDuty email with `hubot pager me as you@yourdomain.com`" - return - - userId - -pagerDutyGet = (msg, url, query, cb) -> - if missingEnvironmentForApi(msg) - return - - auth = 'Basic ' + new Buffer(pagerDutyUsername + ':' + pagerDutyPassword).toString('base64') - msg.http(pagerDutyBaseUrl + url) - .query(query) - .headers(Authorization: auth, Accept: 'application/json') - .get() (err, res, body) -> - json_body = null - switch res.statusCode - when 200 then json_body = JSON.parse(body) - else - console.log res.statusCode - console.log body - json_body = null - cb json_body - -pagerDutyPut = (msg, url, data, cb) -> - if missingEnvironmentForApi(msg) - return - - json = JSON.stringify(data) - auth = 'Basic ' + new Buffer(pagerDutyUsername + ':' + pagerDutyPassword).toString('base64') - msg.http(pagerDutyBaseUrl + url) - .headers(Authorization: auth, Accept: 'application/json') - .header("content-type","application/json") - .header("content-length",json.length) - .put(json) (err, res, body) -> - json_body = null - switch res.statusCode - when 200 then json_body = JSON.parse(body) - else - console.log res.statusCode - console.log body - json_body = null - cb json_body - -pagerDutyPost = (msg, url, data, cb) -> - if missingEnvironmentForApi(msg) - return - - json = JSON.stringify(data) - auth = 'Basic ' + new Buffer(pagerDutyUsername + ':' + pagerDutyPassword).toString('base64') - msg.http(pagerDutyBaseUrl + url) - .headers(Authorization: auth, Accept: 'application/json') - .header("content-type","application/json") - .header("content-length",json.length) - .post(json) (err, res, body) -> - json_body = null - switch res.statusCode - when 201 then json_body = JSON.parse(body) - else - console.log res.statusCode - console.log body - json_body = null - cb json_body - -withCurrentOncall = (msg, cb) -> - oneHour = moment().add('hours', 1).format() - now = moment().format() - - query = { - since: now, - until: oneHour, - overflow: 'true' - } - pagerDutyGet msg, "/schedules/#{pagerDutyScheduleId}/entries", query, (json) -> - if json.entries and json.entries.length > 0 - cb(json.entries[0].user.name) - -withPagerDutyUsers = (msg, cb) -> - if pagerDutyUsers['loaded'] != true - pagerDutyGet msg, "/users", {}, (json) -> - pagerDutyUsers['loaded'] = true - for user in json.users - pagerDutyUsers[user.id] = user - pagerDutyUsers[user.email] = user - pagerDutyUsers[user.name] = user - cb(pagerDutyUsers) - else - cb(pagerDutyUsers) - -pagerDutyIncidents = (msg, cb) -> - query = - status: "triggered,acknowledged" - sort_by: "incident_number:asc" - pagerDutyGet msg, "/incidents", query, (json) -> - cb(json.incidents) - -pagerDutyIntegrationAPI = (msg, cmd, args, cb) -> - unless pagerDutyApiKey? - msg.send "PagerDuty API service key is missing." - msg.send "Ensure that HUBOT_PAGERDUTY_APIKEY is set." - return - - data = null - switch cmd - when "trigger" - data = JSON.stringify { service_key: pagerDutyApiKey, event_type: "trigger", description: "#{args}"} - pagerDutyIntergrationPost msg, data, (json) -> - cb(json) - -formatIncident = (inc) -> - # { pd_nagios_object: 'service', - # HOSTNAME: 'fs1a', - # SERVICEDESC: 'snapshot_repositories', - # SERVICESTATE: 'CRITICAL', - # HOSTSTATE: 'UP' }, - if inc.incident_number - if inc.trigger_summary_data.description - "#{inc.incident_number}: #{inc.trigger_summary_data.description} - assigned to #{inc.assigned_to_user.name}\n" - else if inc.trigger_summary_data.pd_nagios_object == 'service' - "#{inc.incident_number}: #{inc.trigger_summary_data.HOSTNAME}/#{inc.trigger_summary_data.SERVICEDESC} - assigned to #{inc.assigned_to_user.name}\n" - else if inc.trigger_summary_data.pd_nagios_object == 'host' - "#{inc.incident_number}: #{inc.trigger_summary_data.HOSTNAME}/#{inc.trigger_summary_data.HOSTSTATE} - assigned to #{inc.assigned_to_user.name}\n" - else - "" - -updateIncident = (msg, incident_number, status) -> - pagerDutyIncidents msg, (incidents) -> - foundIncidents = [] - for incident in incidents - if "#{incident.incident_number}" == incident_number - foundIncidents = [ incident ] - # loljson - data = { - incidents: [ - { - 'id': incident.id, - 'status': status - } - ] - } - pagerDutyPut msg, "/incidents", data, (json) -> - if incident = json.incidents[0] - msg.reply "Incident #{incident.incident_number} #{incident.status}." + missingEnvironmentForApi = (msg) -> + missingAnything = false + unless pagerDutySubdomain? + msg.send "PagerDuty Subdomain is missing: Ensure that HUBOT_PAGERDUTY_SUBDOMAIN is set." + missingAnything |= true + unless pagerDutyUsername? + msg.send "PagerDuty username is missing: Ensure that HUBOT_PAGERDUTY_USERNAME is set." + missingAnything |= true + unless pagerDutyPassword? + msg.send "PagerDuty password is missing: Ensure that HUBOT_PAGERDUTY_PASSWORD is set." + missingAnything |= true + unless pagerDutyScheduleId? + msg.send "PagerDuty schedule is missing: Ensure that HUBOT_PAGERDUTY_SCHEDULE_ID is set." + missingAnything |= true + missingAnything + + + pagerDutyUserId = (msg, users) -> + email = msg.message.user.pagerdutyEmail || msg.message.user.email_address + unless email + msg.send "Sorry, I can't figure out your email address :( Can you tell me with `#{robot.name} pager me as you@yourdomain.com`?" + return + + user = users[email] + + unless user + msg.send "Sorry, I couldn't find a PagerDuty user for #{email}. Double check you have a user, and that I know your PagerDuty email with `#{robot.name} pager me as you@yourdomain.com`" + return + + users[email].id + + pagerDutyGet = (msg, url, query, cb) -> + if missingEnvironmentForApi(msg) + return + + auth = 'Basic ' + new Buffer(pagerDutyUsername + ':' + pagerDutyPassword).toString('base64') + msg.http(pagerDutyBaseUrl + url) + .query(query) + .headers(Authorization: auth, Accept: 'application/json') + .get() (err, res, body) -> + json_body = null + switch res.statusCode + when 200 then json_body = JSON.parse(body) else - msg.reply "Problem updating incident #{incident_number}" - if foundIncidents.length == 0 - msg.reply "Couldn't find incident #{incident_number}" - - -pagerDutyIntergrationPost = (msg, json, cb) -> - msg.http('https://events.pagerduty.com/generic/2010-04-15/create_event.json') - .header("content-type","application/json") - .header("content-length",json.length) - .post(json) (err, res, body) -> - switch res.statusCode - when 200 - json = JSON.parse(body) + console.log res.statusCode + console.log body + json_body = null + cb json_body + + pagerDutyPut = (msg, url, data, cb) -> + if missingEnvironmentForApi(msg) + return + + json = JSON.stringify(data) + auth = 'Basic ' + new Buffer(pagerDutyUsername + ':' + pagerDutyPassword).toString('base64') + msg.http(pagerDutyBaseUrl + url) + .headers(Authorization: auth, Accept: 'application/json') + .header("content-type","application/json") + .header("content-length",json.length) + .put(json) (err, res, body) -> + json_body = null + switch res.statusCode + when 200 then json_body = JSON.parse(body) + else + console.log res.statusCode + console.log body + json_body = null + cb json_body + + pagerDutyPost = (msg, url, data, cb) -> + if missingEnvironmentForApi(msg) + return + + json = JSON.stringify(data) + auth = 'Basic ' + new Buffer(pagerDutyUsername + ':' + pagerDutyPassword).toString('base64') + msg.http(pagerDutyBaseUrl + url) + .headers(Authorization: auth, Accept: 'application/json') + .header("content-type","application/json") + .header("content-length",json.length) + .post(json) (err, res, body) -> + json_body = null + switch res.statusCode + when 201 then json_body = JSON.parse(body) + else + console.log res.statusCode + console.log body + json_body = null + cb json_body + + withCurrentOncall = (msg, cb) -> + oneHour = moment().add('hours', 1).format() + now = moment().format() + + query = { + since: now, + until: oneHour, + overflow: 'true' + } + pagerDutyGet msg, "/schedules/#{pagerDutyScheduleId}/entries", query, (json) -> + if json.entries and json.entries.length > 0 + cb(json.entries[0].user.name) + + withPagerDutyUsers = (msg, cb) -> + if pagerDutyUsers['loaded'] != true + pagerDutyGet msg, "/users", {}, (json) -> + pagerDutyUsers['loaded'] = true + for user in json.users + pagerDutyUsers[user.id] = user + pagerDutyUsers[user.email] = user + pagerDutyUsers[user.name] = user + cb(pagerDutyUsers) + else + cb(pagerDutyUsers) + + pagerDutyIncidents = (msg, cb) -> + query = + status: "triggered,acknowledged" + sort_by: "incident_number:asc" + pagerDutyGet msg, "/incidents", query, (json) -> + cb(json.incidents) + + pagerDutyIntegrationAPI = (msg, cmd, args, cb) -> + unless pagerDutyApiKey? + msg.send "PagerDuty API service key is missing." + msg.send "Ensure that HUBOT_PAGERDUTY_APIKEY is set." + return + + data = null + switch cmd + when "trigger" + data = JSON.stringify { service_key: pagerDutyApiKey, event_type: "trigger", description: "#{args}"} + pagerDutyIntergrationPost msg, data, (json) -> cb(json) - else - console.log res.statusCode - console.log body + + formatIncident = (inc) -> + # { pd_nagios_object: 'service', + # HOSTNAME: 'fs1a', + # SERVICEDESC: 'snapshot_repositories', + # SERVICESTATE: 'CRITICAL', + # HOSTSTATE: 'UP' }, + if inc.incident_number + if inc.trigger_summary_data.description + "#{inc.incident_number}: #{inc.trigger_summary_data.description} - assigned to #{inc.assigned_to_user.name}\n" + else if inc.trigger_summary_data.pd_nagios_object == 'service' + "#{inc.incident_number}: #{inc.trigger_summary_data.HOSTNAME}/#{inc.trigger_summary_data.SERVICEDESC} - assigned to #{inc.assigned_to_user.name}\n" + else if inc.trigger_summary_data.pd_nagios_object == 'host' + "#{inc.incident_number}: #{inc.trigger_summary_data.HOSTNAME}/#{inc.trigger_summary_data.HOSTSTATE} - assigned to #{inc.assigned_to_user.name}\n" + else + "" + + updateIncident = (msg, incident_number, status) -> + pagerDutyIncidents msg, (incidents) -> + foundIncidents = [] + for incident in incidents + if "#{incident.incident_number}" == incident_number + foundIncidents = [ incident ] + # loljson + data = { + incidents: [ + { + 'id': incident.id, + 'status': status + } + ] + } + pagerDutyPut msg, "/incidents", data, (json) -> + if incident = json.incidents[0] + msg.reply "Incident #{incident.incident_number} #{incident.status}." + else + msg.reply "Problem updating incident #{incident_number}" + if foundIncidents.length == 0 + msg.reply "Couldn't find incident #{incident_number}" + + + pagerDutyIntergrationPost = (msg, json, cb) -> + msg.http('https://events.pagerduty.com/generic/2010-04-15/create_event.json') + .header("content-type","application/json") + .header("content-length",json.length) + .post(json) (err, res, body) -> + switch res.statusCode + when 200 + json = JSON.parse(body) + cb(json) + else + console.log res.statusCode + console.log body From 655272f198241d6976fa301578b68a4014217c4f Mon Sep 17 00:00:00 2001 From: Josh Nichols Date: Thu, 11 Apr 2013 22:46:03 -0400 Subject: [PATCH 14/17] Replace username/password auth with token auth. This let's us use request_id in places, so when you look at PagerDuty, it reports which user ack/resolved, instead of the logged in user. As part of this, needed to rename HUBOT_PAGERDUTY_APIKEY to HUBOT_PAGERDUTY_SERVICE_API_KEY. --- src/scripts/pagerduty.coffee | 86 ++++++++++++++++++------------------ 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/src/scripts/pagerduty.coffee b/src/scripts/pagerduty.coffee index a21a3d495..9f9929d7e 100644 --- a/src/scripts/pagerduty.coffee +++ b/src/scripts/pagerduty.coffee @@ -18,10 +18,9 @@ # # Configuration: # -# HUBOT_PAGERDUTY_USERNAME -# HUBOT_PAGERDUTY_PASSWORD +# HUBOT_PAGERDUTY_API_KEY - API Access Key # HUBOT_PAGERDUTY_SUBDOMAIN -# HUBOT_PAGERDUTY_APIKEY Service API Key from a 'General API Service' +# HUBOT_PAGERDUTY_SERVICE_API_KEY - Service API Key from a 'General API Service' # HUBOT_PAGERDUTY_SCHEDULE_ID inspect = require('util').inspect @@ -29,12 +28,11 @@ inspect = require('util').inspect moment = require('moment') pagerDutyUsers = {} -pagerDutyUsername = process.env.HUBOT_PAGERDUTY_USERNAME -pagerDutyPassword = process.env.HUBOT_PAGERDUTY_PASSWORD -pagerDutySubdomain = process.env.HUBOT_PAGERDUTY_SUBDOMAIN -pagerDutyBaseUrl = "https://#{pagerDutySubdomain}.pagerduty.com/api/v1" -pagerDutyApiKey = process.env.HUBOT_PAGERDUTY_APIKEY -pagerDutyScheduleId = process.env.HUBOT_PAGERDUTY_SCHEDULE_ID +pagerDutyApiKey = process.env.HUBOT_PAGERDUTY_API_KEY +pagerDutySubdomain = process.env.HUBOT_PAGERDUTY_SUBDOMAIN +pagerDutyBaseUrl = "https://#{pagerDutySubdomain}.pagerduty.com/api/v1" +pagerDutyServiceApiKey = process.env.HUBOT_PAGERDUTY_SERVICE_API_KEY +pagerDutyScheduleId = process.env.HUBOT_PAGERDUTY_SCHEDULE_ID module.exports = (robot) -> robot.respond /pager( me)?$/i, (msg) -> @@ -136,14 +134,11 @@ module.exports = (robot) -> unless pagerDutySubdomain? msg.send "PagerDuty Subdomain is missing: Ensure that HUBOT_PAGERDUTY_SUBDOMAIN is set." missingAnything |= true - unless pagerDutyUsername? - msg.send "PagerDuty username is missing: Ensure that HUBOT_PAGERDUTY_USERNAME is set." - missingAnything |= true - unless pagerDutyPassword? - msg.send "PagerDuty password is missing: Ensure that HUBOT_PAGERDUTY_PASSWORD is set." + unless pagerDutyApiKey? + msg.send "PagerDuty API Key is missing: Ensure that HUBOT_PAGERDUTY_API_KEY is set." missingAnything |= true unless pagerDutyScheduleId? - msg.send "PagerDuty schedule is missing: Ensure that HUBOT_PAGERDUTY_SCHEDULE_ID is set." + msg.send "PagerDuty Schedule ID is missing: Ensure that HUBOT_PAGERDUTY_SCHEDULE_ID is set." missingAnything |= true missingAnything @@ -166,7 +161,7 @@ module.exports = (robot) -> if missingEnvironmentForApi(msg) return - auth = 'Basic ' + new Buffer(pagerDutyUsername + ':' + pagerDutyPassword).toString('base64') + auth = "Token token=#{pagerDutyApiKey}" msg.http(pagerDutyBaseUrl + url) .query(query) .headers(Authorization: auth, Accept: 'application/json') @@ -185,7 +180,7 @@ module.exports = (robot) -> return json = JSON.stringify(data) - auth = 'Basic ' + new Buffer(pagerDutyUsername + ':' + pagerDutyPassword).toString('base64') + auth = "Token token=#{pagerDutyApiKey}" msg.http(pagerDutyBaseUrl + url) .headers(Authorization: auth, Accept: 'application/json') .header("content-type","application/json") @@ -205,7 +200,7 @@ module.exports = (robot) -> return json = JSON.stringify(data) - auth = 'Basic ' + new Buffer(pagerDutyUsername + ':' + pagerDutyPassword).toString('base64') + auth = "Token token=#{pagerDutyApiKey}" msg.http(pagerDutyBaseUrl + url) .headers(Authorization: auth, Accept: 'application/json') .header("content-type","application/json") @@ -253,15 +248,15 @@ module.exports = (robot) -> cb(json.incidents) pagerDutyIntegrationAPI = (msg, cmd, args, cb) -> - unless pagerDutyApiKey? + unless pagerDutyServiceApiKey? msg.send "PagerDuty API service key is missing." - msg.send "Ensure that HUBOT_PAGERDUTY_APIKEY is set." + msg.send "Ensure that HUBOT_PAGERDUTY_SERVICE_API_KEY is set." return data = null switch cmd when "trigger" - data = JSON.stringify { service_key: pagerDutyApiKey, event_type: "trigger", description: "#{args}"} + data = JSON.stringify { service_key: pagerDutyServiceApiKey, event_type: "trigger", description: "#{args}"} pagerDutyIntergrationPost msg, data, (json) -> cb(json) @@ -282,33 +277,38 @@ module.exports = (robot) -> "" updateIncident = (msg, incident_number, status) -> - pagerDutyIncidents msg, (incidents) -> - foundIncidents = [] - for incident in incidents - if "#{incident.incident_number}" == incident_number - foundIncidents = [ incident ] - # loljson - data = { - incidents: [ - { - 'id': incident.id, - 'status': status - } - ] - } - pagerDutyPut msg, "/incidents", data, (json) -> - if incident = json.incidents[0] - msg.reply "Incident #{incident.incident_number} #{incident.status}." - else - msg.reply "Problem updating incident #{incident_number}" - if foundIncidents.length == 0 - msg.reply "Couldn't find incident #{incident_number}" + withPagerDutyUsers msg, (users) -> + userId = pagerDutyUserId(msg, users) + return unless userId + + pagerDutyIncidents msg, (incidents) -> + foundIncidents = [] + for incident in incidents + if "#{incident.incident_number}" == incident_number + foundIncidents = [ incident ] + # loljson + data = { + requester_id: userId + incidents: [ + { + 'id': incident.id, + 'status': status + } + ] + } + pagerDutyPut msg, "/incidents", data, (json) -> + if incident = json.incidents[0] + msg.reply "Incident #{incident.incident_number} #{incident.status}." + else + msg.reply "Problem updating incident #{incident_number}" + if foundIncidents.length == 0 + msg.reply "Couldn't find incident #{incident_number}" pagerDutyIntergrationPost = (msg, json, cb) -> msg.http('https://events.pagerduty.com/generic/2010-04-15/create_event.json') .header("content-type","application/json") - .header("content-length",json.length) + .header("content-length", json.length) .post(json) (err, res, body) -> switch res.statusCode when 200 From 0e94503d19ba3f5b47194db1cc9647db23ac611a Mon Sep 17 00:00:00 2001 From: Josh Nichols Date: Fri, 12 Apr 2013 11:32:54 -0400 Subject: [PATCH 15/17] Add back 'pager page' as an alternate to 'pager trigger' --- src/scripts/pagerduty.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/pagerduty.coffee b/src/scripts/pagerduty.coffee index 9f9929d7e..654d2b2a7 100644 --- a/src/scripts/pagerduty.coffee +++ b/src/scripts/pagerduty.coffee @@ -93,7 +93,7 @@ module.exports = (robot) -> else msg.send "No open incidents" - robot.respond /(pager|major)( me)? trigger (.+)$/i, (msg) -> + robot.respond /(pager|major)( me)? (?:trigger|page) (.+)$/i, (msg) -> pagerDutyIntegrationAPI msg, "trigger", msg.match[3], (json) -> msg.reply "#{json.status}, key: #{json.incident_key}" From e13a6b9ed28b3f0ab2470568b7c629f513113b63 Mon Sep 17 00:00:00 2001 From: Josh Nichols Date: Fri, 12 Apr 2013 11:43:26 -0400 Subject: [PATCH 16/17] Add 'pager notes ' --- src/scripts/pagerduty.coffee | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/scripts/pagerduty.coffee b/src/scripts/pagerduty.coffee index 654d2b2a7..ab39c6f53 100644 --- a/src/scripts/pagerduty.coffee +++ b/src/scripts/pagerduty.coffee @@ -9,6 +9,7 @@ # hubot pager me as - remember your pager email is # hubot pager me incidents - return the current incidents # hubot pager me note - add note to incident # with +# hubot pager me notes - show notes for incident # # hubot pager me problems - return all open inicidents # hubot pager me ack - ack incident # # hubot pager me resolve - resolve incident # @@ -103,6 +104,15 @@ module.exports = (robot) -> robot.respond /(pager|major)( me)? res(olve)?(d)? (.+)$/i, (msg) -> updateIncident(msg, msg.match[5], 'resolved') + robot.respond /(pager|major)( me)? notes (.+)$/i, (msg) -> + incidentId = msg.match[3] + pagerDutyGet msg, "/incidents/#{incidentId}/notes", {}, (json) -> + buffer = "" + for note in json.notes + buffer += "#{note.created_at} #{note.user.name}: #{note.content}\n" + msg.send buffer + + robot.respond /(pager|major)( me)? note ([\d\w]+) (.+)$/i, (msg) -> incidentId = msg.match[3] content = msg.match[4] From de86f589e812c54f8a5a6d815ed375d76ed1b640 Mon Sep 17 00:00:00 2001 From: Josh Nichols Date: Fri, 12 Apr 2013 15:30:06 -0400 Subject: [PATCH 17/17] Fix pager notes doc --- src/scripts/pagerduty.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/pagerduty.coffee b/src/scripts/pagerduty.coffee index ab39c6f53..a0086679f 100644 --- a/src/scripts/pagerduty.coffee +++ b/src/scripts/pagerduty.coffee @@ -9,7 +9,7 @@ # hubot pager me as - remember your pager email is # hubot pager me incidents - return the current incidents # hubot pager me note - add note to incident # with -# hubot pager me notes - show notes for incident # +# hubot pager me notes - show notes for incident # # hubot pager me problems - return all open inicidents # hubot pager me ack - ack incident # # hubot pager me resolve - resolve incident #