-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 8b642a1
Showing
4 changed files
with
295 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
Pagerduty PHP | ||
|
||
- A PHP library of handy functions utilising the Pagerduty API. | ||
|
||
|
||
* What's included? | ||
|
||
pagerduty.php - The file which has all the functions that can be used. I say all, so far I only have two, and both relate to getting the current person on call. | ||
pagerdutycron.php - A script designed to run from cron that will either ping irccat or send an email (or both) when the person on call in your rotations changes. | ||
timeago.php - A support function provided by alex at nyoc dot net. | ||
|
||
* How do I use it? | ||
|
||
You need to enter some basic configuration information into pagerduty.php before you can use it, relating to your login and your schedules. | ||
|
||
After you've done this, you are free to include pagerduty.php and use the functions in the file. Keep reading for info on other files. | ||
|
||
|
||
* pagerdutycron.php | ||
|
||
Setup is fairly simple; there are a few configuration options at the top of the file relating to whether you want to send an email, or send a message to irccat, or both, and where to send those messages. | ||
After you've done that, run it by hand once to ensure everything works as planned, and then set it up in cron to run as often as you please (for example, 1 minute). | ||
|
||
When it detects a change in rotation, it will perform your selected action to alert the relevant parties. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
<?php | ||
|
||
# Feel free to tweak this to your preferred timezone or let your OS take care of it | ||
date_default_timezone_set('America/New_York'); | ||
include_once('timeago.php'); | ||
|
||
# The base URL... Everyone has their own subdomain, set yours here. | ||
$baseurl = "https://yourcompany.pagerduty.com/api/v1/schedules/"; | ||
|
||
# Each schedule has its own ID. Get yours by visting the Pagerduty website. | ||
# When you look at your schedule, the URL will have something like: | ||
# http://yourcompany.pagerduty.com/schedule/rotations/AB1ABCD | ||
# The last part of this URL is the schedule ID. | ||
# Add it in this array with a reasonable name to identify it. | ||
$schedules = array ('ops' => 'AB1ABCD', 'dev' => 'CD1CDEFG'); | ||
|
||
# Your Pagerduty username is required for basic auth for access to the API. | ||
# I suggest creating a new account just for this. | ||
$username = "automationuser@yourcompany.com"; | ||
$password = "yourpassword"; | ||
|
||
|
||
|
||
function whoIsOnCall($schedule, $time = "") { | ||
global $baseurl, $schedules, $username, $password; | ||
if($time == "") $time = time(); | ||
|
||
if(!$scheduleid = array_key_exists($schedule, $schedules)) { | ||
echo "Cannot find that schedule. Define in pagerduty.php"; | ||
die(); | ||
} | ||
|
||
$context = stream_context_create(array( | ||
'http' => array( | ||
'header' => "Authorization: Basic " . base64_encode("$username:$password") | ||
) | ||
)); | ||
|
||
$time = date("c", $time); | ||
$json = file_get_contents($baseurl . $schedules[$schedule] . "/entries?since={$time}&until={$time}&overflow=true", false, $context); | ||
|
||
if (false == ($scheddata = json_decode($json))) { | ||
echo "There was an error with the data from PagerDuty, please try again later."; | ||
return false; | ||
} | ||
|
||
if ($scheddata->entries['0']->user->name == "") { | ||
echo "No data from Pagerduty for that date, sorry."; | ||
return false; | ||
} | ||
|
||
$oncalldetails = array(); | ||
$oncalldetails['person'] = $scheddata->entries['0']->user->name; | ||
$oncalldetails['start'] = strtotime($scheddata->entries['0']->start); | ||
$oncalldetails['end'] = strtotime($scheddata->entries['0']->end); | ||
|
||
return $oncalldetails; | ||
|
||
} | ||
|
||
function printPersonOnCallNow($team) { | ||
if($results = whoIsOnCall($team)) { | ||
echo $results['person'] . " is on call until " . date("d-m-Y H:i:s", $results['end']); | ||
} | ||
} | ||
|
||
function printPersonOnCallAt($team, $time) { | ||
$time = strtotime($time); | ||
if($results = whoIsOnCall($team, $time)) { | ||
echo $results['person'] . " is on call from " . timeago($results['start']) . " until " . timeago($results['end']); | ||
} | ||
} | ||
|
||
?> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
#!/usr/bin/php | ||
<? | ||
|
||
# A script designed to be run from cron at an interval (e.g. 1 minute) and then alerts you when changes | ||
# to the on call rotation happen. For example, be emailed when a new person comes on call. | ||
|
||
# Include the libs | ||
include('pagerduty.php'); | ||
include_once('timeago.php'); | ||
|
||
if (!isset($argv[1])) { | ||
echo "Must be run with an argument for which schedule you want to monitor, e.g. pagerdutycron.php ops\n"; | ||
die(); | ||
} | ||
|
||
|
||
$schedule = $argv[1]; | ||
|
||
# CONFIG | ||
# | ||
# ** Remember to set up the base options in pagerduty.php ** | ||
# | ||
# Choose your options here: | ||
# | ||
# $emailalert = This controls whether to send an email on change in the on call schedule | ||
$emailalert = true; | ||
|
||
# $emailrecipient = An array mapping of schedule names to email addresses. Leave blank to not email this schedule | ||
$emailrecipient = array('ops' => "ops@yourcompany.com", 'dev' => ""); | ||
|
||
# $irccatalert = This controls whether to send a message to IRC on change in the on call schedule | ||
$irccatalert = false; | ||
|
||
# $ircchannel = An array mapping of schedules to irc channels. Leave blank to not irccat announce this schedule | ||
$ircchannel = array('ops' => '#ops', 'dev' => '#dev'); | ||
|
||
# $irccathost = Hostname of the irccat server | ||
$irccathost = "127.0.0.1"; | ||
|
||
# $schedulefile = Where you want to store the temporary state information for the schedule. Must be writeable! | ||
$schedulefile = "/tmp/pagerduty-{$schedule}"; | ||
|
||
|
||
# END CONFIG | ||
# | ||
# Edit things under here for additional control. | ||
# | ||
|
||
logline("Starting run to check Pagerduty schedule {$schedule} for changes"); | ||
|
||
if(!is_readable($schedulefile)) { # If the schedule file isn't readable, it probably never existed. Populate it. | ||
logline("Schedule file is unreadable... Attempting to initial populate"); | ||
if (!is_writable($schedulefile)) { | ||
if($results = whoIsOnCall($schedule)) { | ||
$fh = fopen($schedulefile, "w"); | ||
fwrite($fh, $results['person']); | ||
logline("Wrote initial data to schedule file. Person on call is currently {$results['person']}"); | ||
fclose($fh); | ||
} else { | ||
logline("Pagerduty call failed; I cannot proceed. Try again later."); | ||
die(); | ||
} | ||
} else { | ||
logline("Your schedule file is unwriteable. Please choose a different path."); | ||
die(); | ||
} | ||
} | ||
|
||
unset($results); | ||
logline("Checking schedule for updates..."); | ||
|
||
# Basic checking of the file... Don't want any errors. | ||
if (!is_readable($schedulefile)) { | ||
logline("Schedule file is no longer readable, bailing."); | ||
die(); | ||
} | ||
if (!is_writable($schedulefile)) { | ||
logline("Schedule file is not writeable, bailing. "); | ||
die(); | ||
} | ||
|
||
if($results = whoIsOnCall($schedule)) { | ||
logline("Person on call is now {$results['person']}"); | ||
$fh = fopen($schedulefile, "r"); | ||
$lastoncall = fgets($fh); | ||
fclose($fh); | ||
if ($lastoncall == $results['person']) { # No change in on call rotation | ||
logline("Person on call last == person on call now ({$lastoncall} == {$results['person']}), nothing to do"); | ||
} else { # A change has occured! Alert the relevant places and write the new person to our temp file | ||
logline("Person on call has changed! Was {$lastoncall} is now {$results['person']}."); | ||
if ($irccatalert) { | ||
irccat("On call person for {$schedule} is now {$results['person']} until " . timeago($results['end'])); | ||
irccat("Thanks to {$lastoncall}, you are now free. Remember to tip your on call guy/gal!"); | ||
} | ||
|
||
if ($emailalert) { | ||
$emailmessage = "Hi! \n\nThis is an automated email to let you know that the on call person for schedule {$schedule} has changed.\n\n"; | ||
$emailmessage .= "The on call person for {$schedule} is now {$results['person']} until " . date("r", $results['end']) . " (" . timeago($results['end']) . ")\n\n"; | ||
$emailmessage .= "Thanks to {$lastoncall} who is now relieved from duty. \n\n"; | ||
$emailmessage .= "Thank you!\nPagerduty email bot"; | ||
email($emailmessage); | ||
} | ||
logline("Writing new on call person to log file..."); | ||
$fh = fopen($schedulefile, "w"); | ||
fwrite($fh, $results['person']); | ||
fclose($fh); | ||
} | ||
} else { | ||
logline("Pagerduty call failed, trying again later."); | ||
} | ||
logline("Run completed"); | ||
|
||
|
||
|
||
|
||
function logline($message) { | ||
echo date(DATE_RFC822) . " " . $message . "\n"; | ||
} | ||
|
||
function irccat($message) { | ||
global $ircchannel, $schedule, $irccathost; | ||
if ($ircchannel[$schedule] == "") { | ||
logline("Bailing on IRC, no channel set for this schedule"); | ||
return false; | ||
} | ||
echo "IRC MESSAGE: {$message} \n"; | ||
$irccat = fsockopen($irccathost, 12345); | ||
if ($irccat) { | ||
fwrite($irccat, $ircchannel[$schedule] . " " . $message); | ||
fclose($irccat); | ||
} | ||
} | ||
|
||
function email($message) { | ||
global $emailrecipient, $schedule; | ||
if ($emailrecipient[$schedule] == "") { | ||
logline("Bailing on sending email, no recipient set for this schedule"); | ||
return false; | ||
} | ||
$emailsubject = "New on-call person for {$schedule}"; | ||
if (mail($emailrecipient[$schedule], $emailsubject, $message)) { | ||
logline("Email sent successfully"); | ||
return true; | ||
} else { | ||
logline("Email sending failed"); | ||
return false; | ||
} | ||
|
||
} | ||
|
||
?> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
<?php | ||
## alex at nyoc dot net | ||
## Feel free to better for your needs | ||
|
||
function timeago($referencedate=0, $timepointer='', $measureby='', $autotext=true){ ## Measureby can be: s, m, h, d, or y | ||
if($timepointer == '') $timepointer = time(); | ||
$Raw = $timepointer-$referencedate; ## Raw time difference | ||
$Clean = abs($Raw); | ||
$calcNum = array(array('s', 60), array('m', 60*60), array('h', 60*60*60), array('d', 60*60*60*24), array('mo', 60*60*60*24*30)); ## Used for calculating | ||
$calc = array('s' => array(1, 'second'), 'm' => array(60, 'minute'), 'h' => array(60*60, 'hour'), 'd' => array(60*60*24, 'day'), 'mo' => array(60*60*24*30, 'month')); ## Used for units and determining actual differences per unit (there probably is a more efficient way to do this) | ||
|
||
|
||
if($measureby == ''){ ## Only use if nothing is referenced in the function parameters | ||
$usemeasure = 's'; ## Default unit | ||
|
||
for($i=0; $i<count($calcNum); $i++){ ## Loop through calcNum until we find a low enough unit | ||
if($Clean <= $calcNum[$i][1]){ ## Checks to see if the Raw is less than the unit, uses calcNum b/c system is based on seconds being 60 | ||
$usemeasure = $calcNum[$i][0]; ## The if statement okayed the proposed unit, we will use this friendly key to output the time left | ||
$i = count($calcNum); ## Skip all other units by maxing out the current loop position | ||
} | ||
} | ||
}else{ | ||
$usemeasure = $measureby; ## Used if a unit is provided | ||
} | ||
|
||
$datedifference = floor($Clean/$calc[$usemeasure][0]); ## Rounded date difference | ||
|
||
if($autotext==true && ($timepointer==time())){ | ||
if($Raw < 0){ | ||
$prospect = 'from now'; | ||
}else{ | ||
$prospect = 'ago'; | ||
} | ||
} | ||
|
||
if($referencedate != 0){ ## Check to make sure a date in the past was supplied | ||
if($datedifference == 1){ ## Checks for grammar (plural/singular) | ||
return $datedifference . ' ' . $calc[$usemeasure][1] . ' ' . $prospect; | ||
}else{ | ||
return $datedifference . ' ' . $calc[$usemeasure][1] . 's ' . $prospect; | ||
} | ||
}else{ | ||
return 'No input time referenced.'; | ||
} | ||
} | ||
?> |