Browse Source

feat(monitor-checks): fix validation of checks

bertyhell/feature/monitor-checks
Bert Verhelst 3 years ago
parent
commit
b8dc487468
  1. 28
      server/model/monitor.js
  2. 10
      server/server.js
  3. 31
      server/validate-monitor-checks.js
  4. 2
      src/components/MonitorCheckEditor.vue

28
server/model/monitor.js

@ -49,13 +49,7 @@ class Monitor extends BeanModel {
} }
const tags = await R.getAll("SELECT mt.*, tag.name, tag.color FROM monitor_tag mt JOIN tag ON mt.tag_id = tag.id WHERE mt.monitor_id = ?", [this.id]); const tags = await R.getAll("SELECT mt.*, tag.name, tag.color FROM monitor_tag mt JOIN tag ON mt.tag_id = tag.id WHERE mt.monitor_id = ?", [this.id]);
const checks = await R.getAll("SELECT mc.* FROM monitor_checks mc WHERE mc.monitor_id = ?", [this.id]); const checks = await this.getMonitorChecks();
checks.forEach(check => {
if (MONITOR_CHECK_SELECTOR_TYPES.includes(check.type) && typeof check.value === "string" && check.value.startsWith("{")) {
check.value = JSON.parse(check.value);
}
});
return { return {
id: this.id, id: this.id,
@ -168,7 +162,7 @@ class Monitor extends BeanModel {
debug("Cert Info Query Time: " + (dayjs().valueOf() - certInfoStartTime) + "ms"); debug("Cert Info Query Time: " + (dayjs().valueOf() - certInfoStartTime) + "ms");
validateMonitorChecks(res, this.checks, bean); validateMonitorChecks(res, await this.getMonitorChecks(), bean);
if (this.type === "http") { if (this.type === "http") {
bean.status = UP; bean.status = UP;
} else { } else {
@ -497,11 +491,29 @@ class Monitor extends BeanModel {
/** /**
* Send Uptime * Send Uptime
* @param duration : int Hours * @param duration : int Hours
* @param io
* @param monitorID
* @param userID
*/ */
static async sendUptime(duration, io, monitorID, userID) { static async sendUptime(duration, io, monitorID, userID) {
const uptime = await this.calcUptime(duration, monitorID); const uptime = await this.calcUptime(duration, monitorID);
io.to(userID).emit("uptime", monitorID, duration, uptime); io.to(userID).emit("uptime", monitorID, duration, uptime);
} }
async getMonitorChecks() {
const checks = await R.getAll("SELECT mc.* FROM monitor_checks mc WHERE mc.monitor_id = ?", [this.id]);
checks.forEach(check => {
if (MONITOR_CHECK_SELECTOR_TYPES.includes(check.type) && typeof check.value === "string" && check.value.startsWith("{")) {
check.value = JSON.parse(check.value);
}
if (check.type === "HTTP_STATUS_CODE_SHOULD_EQUAL" && typeof check.value === "string" && check.value.startsWith("[")) {
check.value = JSON.parse(check.value);
}
});
return checks;
}
} }
module.exports = Monitor; module.exports = Monitor;

10
server/server.js

@ -539,17 +539,17 @@ exports.entryPage = "dashboard";
let trx = await R.begin(); let trx = await R.begin();
try { try {
// delete existing checks for monitor // delete existing checks for monitor
const existingMonitorChecks = await R.find("monitor_checks", " monitor_id = ?", [bean.id]); await trx.exec("DELETE FROM `monitor_checks` WHERE monitor_id = ?", [bean.id]);
await trx.trashAll(existingMonitorChecks);
// Replace them with new checks // Replace them with new checks
for (let i = 0; i < (checks || []).length; i++) { for (let i = 0; i < (checks || []).length; i++) {
let checkBean = trx.dispense("monitor_checks"); let checkBean = trx.dispense("monitor_checks");
checks[i].monitor_id = bean.id; checkBean.type = checks[i].type;
checks[i].value = typeof checks[i].value === "object" ? JSON.stringify(checks[i].value) : checks[i].value; checkBean.value = typeof checks[i].value === "object" ? JSON.stringify(checks[i].value) : checks[i].value;
checkBean.import(checks[i]); checkBean.monitor_id = bean.id;
await trx.store(checkBean); await trx.store(checkBean);
} }
await trx.commit();
} catch (err) { } catch (err) {
await trx.rollback(); await trx.rollback();
throw err; throw err;

31
server/validate-monitor-checks.js

@ -4,9 +4,8 @@ const get = require("lodash.get");
function validateMonitorChecks(res, checks, bean) { function validateMonitorChecks(res, checks, bean) {
const responseText = typeof data === "string" ? res.data : JSON.stringify(res.data); const responseText = typeof data === "string" ? res.data : JSON.stringify(res.data);
let checkObj;
(this.checks || []).forEach(check => { (checks || []).forEach(check => {
switch (check.type) { switch (check.type) {
case "HTTP_STATUS_CODE_SHOULD_EQUAL": case "HTTP_STATUS_CODE_SHOULD_EQUAL":
if (checkStatusCode(res.status, check.value)) { if (checkStatusCode(res.status, check.value)) {
@ -54,42 +53,38 @@ function validateMonitorChecks(res, checks, bean) {
break; break;
case "RESPONSE_SELECTOR_SHOULD_EQUAL": case "RESPONSE_SELECTOR_SHOULD_EQUAL":
checkObj = JSON.parse(check.value); if (get(res.data, check.value.selectorPath) === check.value.selectorValue) {
if (get(res, checkObj.selector) === checkObj.value) { bean.msg += `, response selector equals '${check.value.selectorValue}'`;
bean.msg += `, response selector equals '${checkObj.value}'`;
bean.status = UP; bean.status = UP;
} else { } else {
throw new Error(`${bean.msg}, but response selector '${checkObj.selector}' does not equal '${checkObj.value}'`); throw new Error(`${bean.msg}, but response selector '${check.value.selectorPath}' does not equal '${check.value.selectorValue}'`);
} }
break; break;
case "RESPONSE_SELECTOR_SHOULD_NOT_EQUAL": case "RESPONSE_SELECTOR_SHOULD_NOT_EQUAL":
checkObj = JSON.parse(check.value); if (get(res.data, check.value.selectorPath) !== check.value.selectorValue) {
if (get(res, checkObj.selector) !== checkObj.value) { bean.msg += `, response selector does not equal '${check.value.selectorValue}'`;
bean.msg += `, response selector does not equal '${checkObj.value}'`;
bean.status = UP; bean.status = UP;
} else { } else {
throw new Error(`${bean.msg}, but response selector '${checkObj.selector}' does equal '${checkObj.value}'`); throw new Error(`${bean.msg}, but response selector '${check.value.selectorPath}' does equal '${check.value.selectorValue}'`);
} }
break; break;
case "RESPONSE_SELECTOR_SHOULD_MATCH_REGEX": case "RESPONSE_SELECTOR_SHOULD_MATCH_REGEX":
checkObj = JSON.parse(check.value); if (get(res.data, check.value.selectorPath).test(new RegExp(check.value.selectorValue))) {
if (get(res, checkObj.selector).test(new RegExp(checkObj.value))) { bean.msg += `, response selector matches regex '${check.value.selectorValue}'`;
bean.msg += `, response selector matches regex '${checkObj.value}'`;
bean.status = UP; bean.status = UP;
} else { } else {
throw new Error(`${bean.msg}, but response selector '${checkObj.selector}' does not match regex '${checkObj.value}'`); throw new Error(`${bean.msg}, but response selector '${check.value.selectorPath}' does not match regex '${check.value.selectorValue}'`);
} }
break; break;
case "RESPONSE_SELECTOR_SHOULD_NOT_MATCH_REGEX": case "RESPONSE_SELECTOR_SHOULD_NOT_MATCH_REGEX":
checkObj = JSON.parse(check.value); if (!get(res.data, check.value.selectorPath).test(new RegExp(check.value.selectorValue))) {
if (!get(res, checkObj.selector).test(new RegExp(checkObj.value))) { bean.msg += `, response selector does not match regex '${check.value.selectorValue}'`;
bean.msg += `, response selector does not match regex '${checkObj.value}'`;
bean.status = UP; bean.status = UP;
} else { } else {
throw new Error(`${bean.msg}, but response selector '${checkObj.selector}' does match regex '${checkObj.value}'`); throw new Error(`${bean.msg}, but response selector '${check.value.selectorPath}' does match regex '${check.value.selectorValue}'`);
} }
break; break;

2
src/components/MonitorCheckEditor.vue

@ -43,7 +43,7 @@
:max-height="600" :max-height="600"
:taggable="true" :taggable="true"
:modelValue="monitorCheck.value" :modelValue="monitorCheck.value"
@update:modelValue="changeValue($event.target.value)" @update:model-value="changeValue"
></VueMultiselect> ></VueMultiselect>
</div> </div>
<div v-if="monitorCheck.type === 'RESPONSE_SHOULD_CONTAIN_TEXT' || monitorCheck.type === 'RESPONSE_SHOULD_NOT_CONTAIN_TEXT'"> <div v-if="monitorCheck.type === 'RESPONSE_SHOULD_CONTAIN_TEXT' || monitorCheck.type === 'RESPONSE_SHOULD_NOT_CONTAIN_TEXT'">

Loading…
Cancel
Save