[feat] Adding PagerDuty notification
This commit is contained in:
		
							parent
							
								
									35b8e89457
								
							
						
					
					
						commit
						5830f1e0b5
					
				
					 5 changed files with 166 additions and 0 deletions
				
			
		
							
								
								
									
										113
									
								
								server/notification-providers/pagerduty.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								server/notification-providers/pagerduty.js
									
									
									
									
									
										Normal 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; | ||||||
|  | @ -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(), | ||||||
|  |  | ||||||
							
								
								
									
										40
									
								
								src/components/notifications/PagerDuty.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/components/notifications/PagerDuty.vue
									
									
									
									
									
										Normal 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> | ||||||
|  | @ -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, | ||||||
|  |  | ||||||
|  | @ -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", | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue