[FreePBX] PagerDuty On-Call koppeling via PHPAgi

PagerPBX

Sinds enkele maanden gebruiken wij op kantoor PagerDuty zodat alle monitoring systemen samen komen tot één notificatiesysteem met mooie functies. Eén van de functies die PagerDuty aanbiedt is de mogelijkheid om schema’s te maken waarin kan worden aangegeven welk persoon op dat moment bijvoorbeeld storingsdienst heeft. Van deze functie maken wij dan ook veelvuldig gebruik, echter zaten wij met het “probleem” dat bij elke dienstwisseling de telefooncentrale aangepast moest worden.

Om hier een einde aan te maken en dus niet telkens meer handmatig het storingsnummer naar iemand anders moeten laten verwijzen, heb ik een script geschreven dat via PHPAgi, FreePBX en de API van PagerDuty automatisch de juiste persoon gaat bellen wanneer dit nodig is.

Note: het PHP script is waarschijnlijk compacter te maken, echter ben ik geen programmeur dus het kan wat slordig geschreven zijn

In deze handleiding ga ik ervan uit dat je al bezit over de laatste versie van FreePBX en dat de PHPAgi al is geïnstalleerd. Als eerste moet er gezorgd worden voor een read-only API key van PagerDuty, de eigenaar van het account kan de API key vinden bij de instellingen behorend bij het account.

Het PHP script wat zo dadelijk wordt uitgelegd moet worden geplaatst in de map /var/lib/asterisk/agi-bin en gaat in mijn geval oncall.php heten. We beginnen met het include van de PHPAgi library dat later in het script nodig is en het zetten van een aantal variable die nodig zijn voor de API call.

require('/var/lib/asterisk/agi-bin/phpagi.php');

ob_start();
$SUBDOMAIN='<SUBDOMAIN>';
$SCHEDULE_ID = '<ID>';
$START = date('Y-m-d\TH:i\Z');
$END = date('Y-m-d\TH:i\Z', time() + 60);
$URL = 'https://' . urlencode($SUBDOMAIN) . '.pagerduty.com/api/v1/schedules/' . urlencode($SCHEDULE_ID) . '/users?since=' . $START . '&until=' . $END . '';
$API_ACCESS_KEY = '<API_KEY>';

Het subdomain is het accountnaam dat is gekozen bij het aanmaken van een account bij PagerDuty. De schedule_ID is o.a. te vinden via een andere API call, deze kan je hier vinden. De start en einddatum zijn verplicht om op te geven zodat de API weet tussen welk tijdsbestek er gezocht moet worden. Tevens is het niet mogelijk om de start en einddatum gelijk te houden, vandaar dat ik naast de datum ook de tijd erbij zet. Bij de einddatum hou ik dezelfde dag aan, echter is het daar 1 minuut later dan mijn begindatum zodat de API de call accepteert. Als laatste geef je de read-only API key op.

$session = curl_init();
curl_setopt($session, CURLOPT_URL, $URL);
curl_setopt($session, CURLOPT_HTTPHEADER, array(
'Content-type: application/json',
'Authorization: Token token=' . $API_ACCESS_KEY
));

$jsonstring = curl_exec($session)

Met dit stukje code gaan we de API call opzetten en versturen naar de server.

curl_close($session);
$bufferstr = ob_get_contents();
ob_end_clean();
$json = json_decode($bufferstr,true);
#print_r($json);
$name = $json["users"][0]["name"];

Nu de API call is verstuurd en de teruggestuurde JSON data is ontvangen, gaan we de benodigde data eruit filteren. Omdat de data wordt teruggestuurd in een Array waarin weer een Array zit, moeten we meerdere blokken opgeven waarin de data gevonden kan worden (zie laatste regel). Om erachter te komen welke blokken je allemaal moet hebben, kan je eerst de ontvangen JSON output volledig tonen door de functie print_r($variable); te gebruiken.

if($name === 'Naam 1') {
    $oncall = '100';

} elseif ($name === 'Naam 2') {
    $oncall = '101';

} elseif ($name === 'Naam 3') {
    $oncall = '102';

} elseif ($name === 'Naam 4') {
    $oncall = '103';

} else {
    $oncall = "104";
}

Als de naam eruit is gefilterd gaan we met een simpele if / else constructie de variable $oncall zetten. Het nummer dat achter de $oncall staat is gelijk aan de ring group nummers die zijn gedefinieerd in FreePBX. Achter elke ring group zit dus een mobiel nummer dat weer corresponderend met de persoon die allemaal storingsdienst kunnen hebben. Het kan natuurlijk altijd voorkomen dat PagerDuty storing heeft waardoor de API niet te benaderen is, in dit geval is er een fallback (in dit geval ring group 104) waarin al onze mobiele nummers staan.

$agi = new AGI();
$agi->answer();
$agi->exec('Goto',"ext-group,$oncall,1");

Als laatste gaan we de PHPAgi library aanspreken en gaan we het ontvangende telefoongesprek doorzetten naar de persoon die op dat moment storingsdienst heeft. Het volledige script ziet er dan als volgt uit:

#!/usr/bin/php -q
<?php
require('/var/lib/asterisk/agi-bin/phpagi.php');

ob_start();
$SUBDOMAIN='mijnbedrijf';
$SCHEDULE_ID = 'PBIG5MW';
$START = date('Y-m-d\TH:i\Z');
$END = date('Y-m-d\TH:i\Z', time() + 60);
$URL = 'https://' . urlencode($SUBDOMAIN) . '.pagerduty.com/api/v1/schedules/' . urlencode($SCHEDULE_ID) . '/users?since=' . $START . '&until=' . $END . '';
$API_ACCESS_KEY = 'Ysadr34DjkdkeOdDojEbnU';

$session = curl_init();
curl_setopt($session, CURLOPT_URL, $URL);
curl_setopt($session, CURLOPT_HTTPHEADER, array(
'Content-type: application/json',
'Authorization: Token token=' . $API_ACCESS_KEY
));

$jsonstring = curl_exec($session);
curl_close($session);
$bufferstr = ob_get_contents();
ob_end_clean();
$json = json_decode($bufferstr,true);
#print_r($json);
$name = $json["users"][0]["name"];

if($name === 'Naam 1') {
    $oncall = '100';

} elseif ($name === 'Naam 2') {
    $oncall = '101';

} elseif ($name === 'Naam 3') {
    $oncall = '102';

} elseif ($name === 'Naam 4') {
    $oncall = '103';

} else {
    $oncall = "104";
}

$agi = new AGI();
$agi->answer();
$agi->exec('Goto',"ext-group,$oncall,1");
?>

Sla het script op en zorg dat het script uitvoerbaar is (chmod 755 & chown asterisk:asterisk). Nu gaan we een custom extension aanmaken waarin we een koppeling maken naar het oncall.php script dat we zojuist hebben gemaakt. Open het bestand /etc/asterisk/extensions_custom.conf en zet daar de volgende regels:

[custom-oncall]
exten=>2000,1,Answer
exten=>2000,2,Wait(1)
exten=>2000,3,AGI(oncall.php)
exten=>2000,4,Hangup

Het tekst tussen de blokhaken is de context, in dit geval heet het “customer-oncall”. Daarna zeggen we dat extensie 2000 (naar eigen wens aan te passen) het gesprek moet aannemen en heel even moet wachten. En daarna het gesprek moet doorzetten naar het script oncall.php en als de verzendende of ontvangende partij de verbinding verbreekt het gesprek ook moet worden afgesloten.

Als de bovenstaande scripts zijn gemaakt, dan kunnen we in de backend van FreePBX een custom destination gaan maken. Dit is te vinden onder het tabblad “Admin” –> “Custom Destination”. Bij Custom Destination vullen we dan in “custom-oncall,2000,1“, dit houdt in dat hij moet zoeken in het bestand extensions_custom.conf naar het blok genaamd “custom-oncall”. Dat deze extensie 2000 heeft een prioriteit nummer 1 heeft. Het is dan ook zeer belangrijk dat het de naam geven tussen de blokhaken gelijk is aan wat je aangeeft bij Custom Destination. Bij Description kan je de een mooie naamgeving neerzetten voor de custom destination en ook een notitie kan erbij worden neergezet. Daarna kan je de custom destination opslaan.

pagerpbx_1

De laatste stap is om een inkomende route te laten verwijzen naar de nieuwe custom destination. Ga naar “Connectivity” –> “Inbound routes” en kies daar het nummer wat aan de custom destination moet worden gekoppeld. Scroll dan helemaal naar beneden en kies bij “Set Destination” de custom destination “PagerDuty OnCall”. Sla de aanpassingen op en herlaad de configuratie van FreePBX/Asterisk en voortaan zal automatisch de juiste persoon worden gebeld bij een storing!

pagerpbx_2