Merge pull request #1310 from MarcHagen/feature/pagerduty

Add support for PagerDuty notifications
This commit is contained in:
Louis Lam 2022-05-25 23:26:33 +08:00 committed by GitHub
commit 058e5442af
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 166 additions and 0 deletions

View File

@ -0,0 +1,113 @@
const NotificationProvider = require("./notification-provider");
const axios = require("axios");
const { UP, DOWN, getMonitorRelativeURL } = require("../../src/util");
const { setting } = require("../util-server");
let successMessage = "Sent Successfully.";
class PagerDuty extends NotificationProvider {
name = "PagerDuty";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
try {
if (heartbeatJSON == null) {
const title = "Uptime Kuma Alert";
const monitor = {
type: "ping",
url: "Uptime Kuma Test Button",
};
return this.postNotification(notification, title, msg, monitor);
}
if (heartbeatJSON.status === UP) {
const title = "Uptime Kuma Monitor ✅ Up";
const eventAction = notification.pagerdutyAutoResolve || null;
return this.postNotification(notification, title, heartbeatJSON.msg, monitorJSON, eventAction);
}
if (heartbeatJSON.status === DOWN) {
const title = "Uptime Kuma Monitor 🔴 Down";
return this.postNotification(notification, title, heartbeatJSON.msg, monitorJSON, "trigger");
}
} catch (error) {
this.throwGeneralAxiosError(error);
}
}
/**
* Check if result is successful, result code should be in range 2xx
* @param {Object} result Axios response object
* @throws {Error} The status code is not in range 2xx
*/
checkResult(result) {
if (result.status == null) {
throw new Error("PagerDuty notification failed with invalid response!");
}
if (result.status < 200 || result.status >= 300) {
throw new Error("PagerDuty notification failed with status code " + result.status);
}
}
/**
* Send the message
* @param {BeanModel} notification Message title
* @param {string} title Message title
* @param {string} body Message
* @param {Object} monitorInfo Monitor details (For Up/Down only)
* @param {?string} eventAction Action event for PagerDuty (trigger, acknowledge, resolve)
* @returns {string}
*/
async postNotification(notification, title, body, monitorInfo, eventAction = "trigger") {
if (eventAction == null) {
return "No action required";
}
let monitorUrl;
if (monitorInfo.type === "port") {
monitorUrl = monitorInfo.hostname;
if (monitorInfo.port) {
monitorUrl += ":" + monitorInfo.port;
}
} else if (monitorInfo.hostname != null) {
monitorUrl = monitorInfo.hostname;
} else {
monitorUrl = monitorInfo.url;
}
const options = {
method: "POST",
url: notification.pagerdutyIntegrationUrl,
headers: { "Content-Type": "application/json" },
data: {
payload: {
summary: `[${title}] [${monitorInfo.name}] ${body}`,
severity: notification.pagerdutyPriority || "warning",
source: monitorUrl,
},
routing_key: notification.pagerdutyIntegrationKey,
event_action: eventAction,
dedup_key: "Uptime Kuma/" + monitorInfo.id,
}
};
const baseURL = await setting("primaryBaseURL");
if (baseURL && monitorInfo) {
options.client = "Uptime Kuma";
options.client_url = baseURL + getMonitorRelativeURL(monitorInfo.id);
}
let result = await axios.request(options);
this.checkResult(result);
if (result.statusText != null) {
return "PagerDuty notification succeed: " + result.statusText;
}
return successMessage;
}
}
module.exports = PagerDuty;

View File

@ -29,6 +29,7 @@ const SerwerSMS = require("./notification-providers/serwersms");
const Stackfield = require("./notification-providers/stackfield"); const Stackfield = require("./notification-providers/stackfield");
const WeCom = require("./notification-providers/wecom"); const WeCom = require("./notification-providers/wecom");
const GoogleChat = require("./notification-providers/google-chat"); const GoogleChat = require("./notification-providers/google-chat");
const PagerDuty = require("./notification-providers/pagerduty");
const Gorush = require("./notification-providers/gorush"); const Gorush = require("./notification-providers/gorush");
const Alerta = require("./notification-providers/alerta"); const Alerta = require("./notification-providers/alerta");
const OneBot = require("./notification-providers/onebot"); const OneBot = require("./notification-providers/onebot");
@ -74,6 +75,7 @@ class Notification {
new Stackfield(), new Stackfield(),
new WeCom(), new WeCom(),
new GoogleChat(), new GoogleChat(),
new PagerDuty(),
new Gorush(), new Gorush(),
new Alerta(), new Alerta(),
new OneBot(), new OneBot(),

View File

@ -0,0 +1,40 @@
<template>
<div class="mb-3">
<label for="pagerduty-integration-key" class="form-label">{{ $t("Integration Key") }}</label>
<HiddenInput id="pagerduty-integration-key" v-model="$parent.notification.pagerdutyIntegrationKey" :required="true" autocomplete="false"></HiddenInput>
<i18n-t tag="div" keypath="wayToGetPagerDutyKey" class="form-text">
<a href="https://support.pagerduty.com/docs/services-and-integrations" target="_blank">{{ $t("here") }}</a>
</i18n-t>
</div>
<div class="mb-3">
<label for="pagerduty-integration-url" class="form-label">{{ $t("Integration URL") }}</label>
<input id="pagerduty-integration-url" v-model="$parent.notification.pagerdutyIntegrationUrl" type="text" class="form-control" autocomplete="false" value="https://events.pagerduty.com/v2/enqueue">
</div>
<div class="mb-3">
<label for="pagerduty-priority" class="form-label">{{ $t("Priority") }}</label>
<select id="pagerduty-priority" v-model="$parent.notification.pagerdutyPriority" class="form-select">
<option value="info">{{ $t("info") }}</option>
<option value="warning" selected="selected">{{ $t("warning") }}</option>
<option value="error">{{ $t("error") }}</option>
<option value="critical">{{ $t("critical") }}</option>
</select>
</div>
<div class="mb-3">
<label for="pagerduty-resolve" class="form-label">{{ $t("Auto resolve or acknowledged") }}</label>
<select id="pagerduty-resolve" v-model="$parent.notification.pagerdutyAutoResolve" class="form-select">
<option value="0" selected="selected">{{ $t("do nothing") }}</option>
<option value="acknowledge">{{ $t("auto acknowledged") }}</option>
<option value="resolve">{{ $t("auto resolve") }}</option>
</select>
</div>
</template>
<script>
import HiddenInput from "../HiddenInput.vue";
export default {
components: {
HiddenInput,
},
};
</script>

View File

@ -27,6 +27,7 @@ import SerwerSMS from "./SerwerSMS.vue";
import Stackfield from "./Stackfield.vue"; import Stackfield from "./Stackfield.vue";
import WeCom from "./WeCom.vue"; import WeCom from "./WeCom.vue";
import GoogleChat from "./GoogleChat.vue"; import GoogleChat from "./GoogleChat.vue";
import PagerDuty from "./PagerDuty.vue";
import Gorush from "./Gorush.vue"; import Gorush from "./Gorush.vue";
import Alerta from "./Alerta.vue"; import Alerta from "./Alerta.vue";
import OneBot from "./OneBot.vue"; import OneBot from "./OneBot.vue";
@ -67,6 +68,7 @@ const NotificationFormList = {
"stackfield": Stackfield, "stackfield": Stackfield,
"WeCom": WeCom, "WeCom": WeCom,
"GoogleChat": GoogleChat, "GoogleChat": GoogleChat,
"PagerDuty": PagerDuty,
"gorush": Gorush, "gorush": Gorush,
"alerta": Alerta, "alerta": Alerta,
"OneBot": OneBot, "OneBot": OneBot,

View File

@ -331,6 +331,8 @@ export default {
info: "info", info: "info",
warning: "warning", warning: "warning",
danger: "danger", danger: "danger",
error: "error",
critical: "critical",
primary: "primary", primary: "primary",
light: "light", light: "light",
dark: "dark", dark: "dark",
@ -371,6 +373,13 @@ export default {
smtpDkimHashAlgo: "Hash Algorithm (Optional)", smtpDkimHashAlgo: "Hash Algorithm (Optional)",
smtpDkimheaderFieldNames: "Header Keys to sign (Optional)", smtpDkimheaderFieldNames: "Header Keys to sign (Optional)",
smtpDkimskipFields: "Header Keys not to sign (Optional)", smtpDkimskipFields: "Header Keys not to sign (Optional)",
wayToGetPagerDutyKey: "You can get this by going to Service -> Service Directory -> (Select a service) -> Integrations -> Add integration. Here you can search for \"Events API V2\". More info {0}",
"Integration Key": "Integration Key",
"Integration URL": "Integration URL",
"Auto resolve or acknowledged": "Auto resolve or acknowledged",
"do nothing": "do nothing",
"auto acknowledged": "auto acknowledged",
"auto resolve": "auto resolve",
gorush: "Gorush", gorush: "Gorush",
alerta: "Alerta", alerta: "Alerta",
alertaApiEndpoint: "API Endpoint", alertaApiEndpoint: "API Endpoint",