Merge 046d9c1afb into 9169a647cb
This commit is contained in:
commit
9d72fae5cc
@ -42,6 +42,7 @@ const {
|
|||||||
axiosAbortSignal,
|
axiosAbortSignal,
|
||||||
checkCertificateHostname,
|
checkCertificateHostname,
|
||||||
} = require("../util-server");
|
} = require("../util-server");
|
||||||
|
const { Settings } = require("../settings");
|
||||||
const { R } = require("redbean-node");
|
const { R } = require("redbean-node");
|
||||||
const { BeanModel } = require("redbean-node/dist/bean-model");
|
const { BeanModel } = require("redbean-node/dist/bean-model");
|
||||||
const { Notification } = require("../notification");
|
const { Notification } = require("../notification");
|
||||||
@ -441,6 +442,16 @@ class Monitor extends BeanModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the monitor designated to represent healthy connectivity is down,
|
||||||
|
* then we can just stop here.
|
||||||
|
*/
|
||||||
|
const systemIsHealthy = await this.systemIsHealthy();
|
||||||
|
if (systemIsHealthy === false) {
|
||||||
|
log.warn("monitor", "Health check monitor is down, monitoring paused!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Expose here for prometheus update
|
// Expose here for prometheus update
|
||||||
// undefined if not https
|
// undefined if not https
|
||||||
let tlsInfo = undefined;
|
let tlsInfo = undefined;
|
||||||
@ -2158,6 +2169,42 @@ class Monitor extends BeanModel {
|
|||||||
await this.checkCertExpiryNotifications(tlsInfo);
|
await this.checkCertExpiryNotifications(tlsInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the monitor selected for the health check is down.
|
||||||
|
* @returns {Promise<boolean>} If true, the system is healthy.
|
||||||
|
*/
|
||||||
|
async systemIsHealthy() {
|
||||||
|
let healthCheckMonitorId = await Settings.get("healthCheckMonitorId");
|
||||||
|
|
||||||
|
// User hasn't made a selection yet, save in the database as null
|
||||||
|
if (healthCheckMonitorId === undefined) {
|
||||||
|
await setSetting("healthCheckMonitorId", null);
|
||||||
|
healthCheckMonitorId = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No health check monitor is specified, nothing to do!
|
||||||
|
if (healthCheckMonitorId === null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We still need to check the health check monitor
|
||||||
|
if (healthCheckMonitorId === this.id) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const healthCheckMonitor = await R.findOne("heartbeat", " monitor_id = ? ORDER BY time DESC", [
|
||||||
|
healthCheckMonitorId,
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (healthCheckMonitor) {
|
||||||
|
return healthCheckMonitor.status === UP;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default to indicative of being healthy, this shouldn't happen
|
||||||
|
// Better to be safe if we can't find the selected monitor, it may have been deleted
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Monitor;
|
module.exports = Monitor;
|
||||||
|
|||||||
83
src/components/HealthCheckAlert.vue
Normal file
83
src/components/HealthCheckAlert.vue
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
<template>
|
||||||
|
<div v-if="!healthCheckStatus" id="health-check" class="d-flex flex-wrap py-3 mx-4">
|
||||||
|
<div class="alert alert-danger w-100 d-inline-flex align-items-center justify-content-between">
|
||||||
|
<div class="px-3">Monitoring is paused, the health check monitor is down!</div>
|
||||||
|
<div>
|
||||||
|
<router-link :to="monitorURL(healthCheckMonitor.id)" class="btn btn-danger text-nowrap">
|
||||||
|
View {{ healthCheckMonitor.name }}
|
||||||
|
</router-link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { UP } from "../util.ts";
|
||||||
|
import { getMonitorRelativeURL } from "../util.ts";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
settings: {},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
/**
|
||||||
|
* Find the designated health check monitor from the monitor list
|
||||||
|
* @returns {*|null} A monitor object if the health check monitor id is set
|
||||||
|
*/
|
||||||
|
healthCheckMonitor() {
|
||||||
|
const healthCheckMonitorId = this.settings?.healthCheckMonitorId;
|
||||||
|
|
||||||
|
if (this.$root.monitorList[healthCheckMonitorId]) {
|
||||||
|
return this.$root.monitorList[healthCheckMonitorId];
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if the designated health check monitor is down
|
||||||
|
* @returns {boolean} The health check monitor status
|
||||||
|
*/
|
||||||
|
healthCheckStatus() {
|
||||||
|
const healthCheckMonitorId = this.healthCheckMonitor?.id;
|
||||||
|
|
||||||
|
if (
|
||||||
|
healthCheckMonitorId in this.$root.lastHeartbeatList &&
|
||||||
|
this.$root.lastHeartbeatList[healthCheckMonitorId]
|
||||||
|
) {
|
||||||
|
return this.$root.lastHeartbeatList[healthCheckMonitorId].status === UP;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
this.loadSettings();
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
/**
|
||||||
|
* Load settings from server
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
loadSettings() {
|
||||||
|
this.$root.getSocket().emit("getSettings", (res) => {
|
||||||
|
this.settings = res.data;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get URL of monitor
|
||||||
|
* @param {number} id ID of monitor
|
||||||
|
* @returns {string} Relative URL of monitor
|
||||||
|
*/
|
||||||
|
monitorURL(id) {
|
||||||
|
return getMonitorRelativeURL(id);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
@ -54,6 +54,25 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div v-if="settingsLoaded" class="my-4 pt-4">
|
||||||
|
<h5 class="my-4 settings-subheading">{{ $t("Heath Check") }}</h5>
|
||||||
|
<p>{{ $t("HealthCheckDescription") }}</p>
|
||||||
|
|
||||||
|
<div class="my-4">
|
||||||
|
<label for="timezone" class="form-label">
|
||||||
|
{{ $t("Monitor") }}
|
||||||
|
</label>
|
||||||
|
<select id="timezone" v-model="settings.healthCheckMonitorId" class="form-select">
|
||||||
|
<option :value="null">
|
||||||
|
{{ $t("Select") }}
|
||||||
|
</option>
|
||||||
|
<option v-for="(monitor, index) in $root.monitorList" :key="index" :value="monitor.id">
|
||||||
|
{{ monitor.name }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="my-4 pt-4">
|
<div class="my-4 pt-4">
|
||||||
<h5 class="my-4 settings-subheading">{{ $t("settingsCertificateExpiry") }}</h5>
|
<h5 class="my-4 settings-subheading">{{ $t("settingsCertificateExpiry") }}</h5>
|
||||||
<p>{{ $t("certificationExpiryDescription") }}</p>
|
<p>{{ $t("certificationExpiryDescription") }}</p>
|
||||||
|
|||||||
@ -1278,6 +1278,8 @@
|
|||||||
"Plain Text": "Plain Text",
|
"Plain Text": "Plain Text",
|
||||||
"Message Template": "Message Template",
|
"Message Template": "Message Template",
|
||||||
"Template Format": "Template Format",
|
"Template Format": "Template Format",
|
||||||
|
"Heath Check": "Heath Check",
|
||||||
|
"HealthCheckDescription": "If the selected monitor is offline, all notifications will be paused and downtime ignored. Ideal for monitoring connectivity to the internet.",
|
||||||
"Font Twemoji by Twitter licensed under": "Font Twemoji by Twitter licensed under",
|
"Font Twemoji by Twitter licensed under": "Font Twemoji by Twitter licensed under",
|
||||||
"smsplanetApiToken": "Token for the SMSPlanet API",
|
"smsplanetApiToken": "Token for the SMSPlanet API",
|
||||||
"smsplanetApiDocs": "Detailed information on obtaining API tokens can be found in {the_smsplanet_documentation}.",
|
"smsplanetApiDocs": "Detailed information on obtaining API tokens can be found in {the_smsplanet_documentation}.",
|
||||||
|
|||||||
@ -126,6 +126,7 @@
|
|||||||
</header>
|
</header>
|
||||||
|
|
||||||
<main>
|
<main>
|
||||||
|
<health-check-alert v-if="$root.loggedIn" />
|
||||||
<router-view v-if="$root.loggedIn" />
|
<router-view v-if="$root.loggedIn" />
|
||||||
<Login v-if="!$root.loggedIn && $root.allowLoginDialog" />
|
<Login v-if="!$root.loggedIn && $root.allowLoginDialog" />
|
||||||
</main>
|
</main>
|
||||||
@ -169,10 +170,12 @@
|
|||||||
import Login from "../components/Login.vue";
|
import Login from "../components/Login.vue";
|
||||||
import compareVersions from "compare-versions";
|
import compareVersions from "compare-versions";
|
||||||
import { useToast } from "vue-toastification";
|
import { useToast } from "vue-toastification";
|
||||||
|
import HealthCheckAlert from "../components/HealthCheckAlert.vue";
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
HealthCheckAlert,
|
||||||
Login,
|
Login,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@ -188,6 +188,10 @@ export default {
|
|||||||
this.settings.trustProxy = false;
|
this.settings.trustProxy = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.settings.healthCheckMonitorId === undefined) {
|
||||||
|
this.settings.healthCheckMonitorId = null;
|
||||||
|
}
|
||||||
|
|
||||||
this.settingsLoaded = true;
|
this.settingsLoaded = true;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user