mirror of
https://github.com/louislam/uptime-kuma.git
synced 2025-02-26 13:35:56 +00:00
Merge b398ba7497
into 223cde831f
This commit is contained in:
commit
b2dbfc83ac
6 changed files with 66 additions and 10 deletions
|
@ -0,0 +1,13 @@
|
||||||
|
exports.up = function (knex) {
|
||||||
|
return knex.schema
|
||||||
|
.alterTable("monitor", function (table) {
|
||||||
|
table.boolean("database_query_handle_empty_as_failure").notNullable().defaultTo(false);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.down = function (knex) {
|
||||||
|
return knex.schema
|
||||||
|
.alterTable("monitor", function (table) {
|
||||||
|
table.dropColumn("database_query_handle_empty_as_failure");
|
||||||
|
});
|
||||||
|
};
|
|
@ -129,6 +129,7 @@ class Monitor extends BeanModel {
|
||||||
mqttSuccessMessage: this.mqttSuccessMessage,
|
mqttSuccessMessage: this.mqttSuccessMessage,
|
||||||
mqttCheckType: this.mqttCheckType,
|
mqttCheckType: this.mqttCheckType,
|
||||||
databaseQuery: this.databaseQuery,
|
databaseQuery: this.databaseQuery,
|
||||||
|
databaseQueryHandleEmptyAsFailure: this.isDatabaseQueryHandleEmptyAsFailure(),
|
||||||
authMethod: this.authMethod,
|
authMethod: this.authMethod,
|
||||||
grpcUrl: this.grpcUrl,
|
grpcUrl: this.grpcUrl,
|
||||||
grpcProtobuf: this.grpcProtobuf,
|
grpcProtobuf: this.grpcProtobuf,
|
||||||
|
@ -271,6 +272,14 @@ class Monitor extends BeanModel {
|
||||||
return Boolean(this.invertKeyword);
|
return Boolean(this.invertKeyword);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse to boolean
|
||||||
|
* @returns {boolean} Is sql query empty result handled as failure?
|
||||||
|
*/
|
||||||
|
isDatabaseQueryHandleEmptyAsFailure() {
|
||||||
|
return Boolean(this.databaseQueryHandleEmptyAsFailure);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse to boolean
|
* Parse to boolean
|
||||||
* @returns {boolean} Enable TLS for gRPC?
|
* @returns {boolean} Enable TLS for gRPC?
|
||||||
|
@ -760,7 +769,7 @@ class Monitor extends BeanModel {
|
||||||
} else if (this.type === "sqlserver") {
|
} else if (this.type === "sqlserver") {
|
||||||
let startTime = dayjs().valueOf();
|
let startTime = dayjs().valueOf();
|
||||||
|
|
||||||
await mssqlQuery(this.databaseConnectionString, this.databaseQuery || "SELECT 1");
|
await mssqlQuery(this.databaseConnectionString, this.databaseQueryHandleEmptyAsFailure, this.databaseQuery || "SELECT 1");
|
||||||
|
|
||||||
bean.msg = "";
|
bean.msg = "";
|
||||||
bean.status = UP;
|
bean.status = UP;
|
||||||
|
@ -799,7 +808,7 @@ class Monitor extends BeanModel {
|
||||||
} else if (this.type === "postgres") {
|
} else if (this.type === "postgres") {
|
||||||
let startTime = dayjs().valueOf();
|
let startTime = dayjs().valueOf();
|
||||||
|
|
||||||
await postgresQuery(this.databaseConnectionString, this.databaseQuery || "SELECT 1");
|
await postgresQuery(this.databaseConnectionString, this.databaseQueryHandleEmptyAsFailure, this.databaseQuery || "SELECT 1");
|
||||||
|
|
||||||
bean.msg = "";
|
bean.msg = "";
|
||||||
bean.status = UP;
|
bean.status = UP;
|
||||||
|
@ -811,7 +820,7 @@ class Monitor extends BeanModel {
|
||||||
// TODO: rename `radius_password` to `password` later for general use
|
// TODO: rename `radius_password` to `password` later for general use
|
||||||
let mysqlPassword = this.radiusPassword;
|
let mysqlPassword = this.radiusPassword;
|
||||||
|
|
||||||
bean.msg = await mysqlQuery(this.databaseConnectionString, this.databaseQuery || "SELECT 1", mysqlPassword);
|
bean.msg = await mysqlQuery(this.databaseConnectionString, this.databaseQueryHandleEmptyAsFailure, this.databaseQuery || "SELECT 1", mysqlPassword);
|
||||||
bean.status = UP;
|
bean.status = UP;
|
||||||
bean.ping = dayjs().valueOf() - startTime;
|
bean.ping = dayjs().valueOf() - startTime;
|
||||||
} else if (this.type === "radius") {
|
} else if (this.type === "radius") {
|
||||||
|
|
|
@ -837,6 +837,7 @@ let needSetup = false;
|
||||||
bean.mqttCheckType = monitor.mqttCheckType;
|
bean.mqttCheckType = monitor.mqttCheckType;
|
||||||
bean.databaseConnectionString = monitor.databaseConnectionString;
|
bean.databaseConnectionString = monitor.databaseConnectionString;
|
||||||
bean.databaseQuery = monitor.databaseQuery;
|
bean.databaseQuery = monitor.databaseQuery;
|
||||||
|
bean.databaseQueryHandleEmptyAsFailure = monitor.databaseQueryHandleEmptyAsFailure;
|
||||||
bean.authMethod = monitor.authMethod;
|
bean.authMethod = monitor.authMethod;
|
||||||
bean.authWorkstation = monitor.authWorkstation;
|
bean.authWorkstation = monitor.authWorkstation;
|
||||||
bean.authDomain = monitor.authDomain;
|
bean.authDomain = monitor.authDomain;
|
||||||
|
|
|
@ -318,11 +318,12 @@ exports.dnsResolve = function (hostname, resolverServer, resolverPort, rrtype) {
|
||||||
/**
|
/**
|
||||||
* Run a query on SQL Server
|
* Run a query on SQL Server
|
||||||
* @param {string} connectionString The database connection string
|
* @param {string} connectionString The database connection string
|
||||||
|
* @param {boolean} handleEmptyResult Should empty results be handled as an error
|
||||||
* @param {string} query The query to validate the database with
|
* @param {string} query The query to validate the database with
|
||||||
* @returns {Promise<(string[] | object[] | object)>} Response from
|
* @returns {Promise<(string[] | object[] | object)>} Response from
|
||||||
* server
|
* server
|
||||||
*/
|
*/
|
||||||
exports.mssqlQuery = async function (connectionString, query) {
|
exports.mssqlQuery = async function (connectionString, handleEmptyResult, query) {
|
||||||
let pool;
|
let pool;
|
||||||
try {
|
try {
|
||||||
pool = new mssql.ConnectionPool(connectionString);
|
pool = new mssql.ConnectionPool(connectionString);
|
||||||
|
@ -330,7 +331,12 @@ exports.mssqlQuery = async function (connectionString, query) {
|
||||||
if (!query) {
|
if (!query) {
|
||||||
query = "SELECT 1";
|
query = "SELECT 1";
|
||||||
}
|
}
|
||||||
await pool.request().query(query);
|
const result = await pool.request().query(query);
|
||||||
|
if (Array.isArray(result.recordset)) {
|
||||||
|
if (handleEmptyResult && result.recordset.length === 0) {
|
||||||
|
throw new Error("No rows returned");
|
||||||
|
}
|
||||||
|
}
|
||||||
pool.close();
|
pool.close();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (pool) {
|
if (pool) {
|
||||||
|
@ -343,11 +349,12 @@ exports.mssqlQuery = async function (connectionString, query) {
|
||||||
/**
|
/**
|
||||||
* Run a query on Postgres
|
* Run a query on Postgres
|
||||||
* @param {string} connectionString The database connection string
|
* @param {string} connectionString The database connection string
|
||||||
|
* @param {boolean} handleEmptyResult Should empty results be handled as an error
|
||||||
* @param {string} query The query to validate the database with
|
* @param {string} query The query to validate the database with
|
||||||
* @returns {Promise<(string[] | object[] | object)>} Response from
|
* @returns {Promise<(string[] | object[] | object)>} Response from
|
||||||
* server
|
* server
|
||||||
*/
|
*/
|
||||||
exports.postgresQuery = function (connectionString, query) {
|
exports.postgresQuery = function (connectionString, handleEmptyResult, query) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const config = postgresConParse(connectionString);
|
const config = postgresConParse(connectionString);
|
||||||
|
|
||||||
|
@ -383,9 +390,15 @@ exports.postgresQuery = function (connectionString, query) {
|
||||||
client.query(query, (err, res) => {
|
client.query(query, (err, res) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
reject(err);
|
reject(err);
|
||||||
|
} else {
|
||||||
|
if (Array.isArray(res.rows)) {
|
||||||
|
if (handleEmptyResult && res.rows.length === 0) {
|
||||||
|
reject(new Error("No rows returned"));
|
||||||
} else {
|
} else {
|
||||||
resolve(res);
|
resolve(res);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
client.end();
|
client.end();
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -401,11 +414,12 @@ exports.postgresQuery = function (connectionString, query) {
|
||||||
/**
|
/**
|
||||||
* Run a query on MySQL/MariaDB
|
* Run a query on MySQL/MariaDB
|
||||||
* @param {string} connectionString The database connection string
|
* @param {string} connectionString The database connection string
|
||||||
|
* @param {boolean} handleEmptyResult Should empty results be handled as an error
|
||||||
* @param {string} query The query to validate the database with
|
* @param {string} query The query to validate the database with
|
||||||
* @param {?string} password The password to use
|
* @param {?string} password The password to use
|
||||||
* @returns {Promise<(string)>} Response from server
|
* @returns {Promise<(string)>} Response from server
|
||||||
*/
|
*/
|
||||||
exports.mysqlQuery = function (connectionString, query, password = undefined) {
|
exports.mysqlQuery = function (connectionString, handleEmptyResult, query, password = undefined) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const connection = mysql.createConnection({
|
const connection = mysql.createConnection({
|
||||||
uri: connectionString,
|
uri: connectionString,
|
||||||
|
@ -421,7 +435,11 @@ exports.mysqlQuery = function (connectionString, query, password = undefined) {
|
||||||
reject(err);
|
reject(err);
|
||||||
} else {
|
} else {
|
||||||
if (Array.isArray(res)) {
|
if (Array.isArray(res)) {
|
||||||
|
if (handleEmptyResult && res.length === 0) {
|
||||||
|
reject(new Error("No rows returned"));
|
||||||
|
} else {
|
||||||
resolve("Rows: " + res.length);
|
resolve("Rows: " + res.length);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
resolve("No Error, but the result is not an array. Type: " + typeof res);
|
resolve("No Error, but the result is not an array. Type: " + typeof res);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1051,5 +1051,7 @@
|
||||||
"RabbitMQ Password": "RabbitMQ Password",
|
"RabbitMQ Password": "RabbitMQ Password",
|
||||||
"rabbitmqHelpText": "To use the monitor, you will need to enable the Management Plugin in your RabbitMQ setup. For more information, please consult the {rabitmq_documentation}.",
|
"rabbitmqHelpText": "To use the monitor, you will need to enable the Management Plugin in your RabbitMQ setup. For more information, please consult the {rabitmq_documentation}.",
|
||||||
"SendGrid API Key": "SendGrid API Key",
|
"SendGrid API Key": "SendGrid API Key",
|
||||||
"Separate multiple email addresses with commas": "Separate multiple email addresses with commas"
|
"Separate multiple email addresses with commas": "Separate multiple email addresses with commas",
|
||||||
|
"Handle empty result as error": "Handle empty result as error",
|
||||||
|
"handleEmptyResultDescription": "If the query returns no results, the monitor will be treated as down."
|
||||||
}
|
}
|
||||||
|
|
|
@ -539,6 +539,19 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<!-- SQL Server / PostgreSQL / MySQL Error Handling -->
|
||||||
|
<template v-if="monitor.type === 'sqlserver' || monitor.type === 'postgres' || monitor.type === 'mysql'">
|
||||||
|
<div class="my-3 form-check">
|
||||||
|
<input id="sqlErrorHandling" v-model="monitor.databaseQueryHandleEmptyAsFailure" class="form-check-input" type="checkbox">
|
||||||
|
<label class="form-check-label" for="sqlErrorHandling">
|
||||||
|
{{ $t("Handle empty result as error") }}
|
||||||
|
</label>
|
||||||
|
<div class="form-text">
|
||||||
|
{{ $t("handleEmptyResultDescription") }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
<!-- MongoDB -->
|
<!-- MongoDB -->
|
||||||
<template v-if="monitor.type === 'mongodb'">
|
<template v-if="monitor.type === 'mongodb'">
|
||||||
<div class="my-3">
|
<div class="my-3">
|
||||||
|
|
Loading…
Add table
Reference in a new issue