Refactor check_pgsql

This commit is contained in:
Lorenz Kästle 2025-03-12 02:16:41 +01:00
parent 003b96741d
commit de392a81ed
3 changed files with 128 additions and 77 deletions

View file

@ -61,6 +61,7 @@ EXTRA_DIST = t \
check_mysql_query.d \
check_mrtg.d \
check_apt.d \
check_pgsql.d \
check_by_ssh.d \
check_smtp.d \
check_mysql.d \

View file

@ -28,6 +28,7 @@
*
*****************************************************************************/
#include "states.h"
const char *progname = "check_pgsql";
const char *copyright = "1999-2024";
const char *email = "devel@monitoring-plugins.org";
@ -35,12 +36,13 @@ const char *email = "devel@monitoring-plugins.org";
#include "common.h"
#include "utils.h"
#include "utils_cmd.h"
#include "check_pgsql.d/config.h"
#include "thresholds.h"
#include "netutils.h"
#include <libpq-fe.h>
#include <pg_config_manual.h>
#define DEFAULT_DB "template1"
#define DEFAULT_HOST "127.0.0.1"
/* return the PSQL server version as a 3-tuple */
@ -53,33 +55,18 @@ const char *email = "devel@monitoring-plugins.org";
#define PSQL_SOCKET3(host, port) \
((NULL == (host)) || ('\0' == *(host))) ? DEFAULT_PGSOCKET_DIR : host, PSQL_IS_UNIX_DOMAIN_SOCKET(host) ? "/.s.PGSQL." : ":", port
enum {
DEFAULT_PORT = 5432,
DEFAULT_WARN = 2,
DEFAULT_CRIT = 8
};
typedef struct {
int errorcode;
check_pgsql_config config;
} check_pgsql_config_wrapper;
static check_pgsql_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
static int process_arguments(int /*argc*/, char ** /*argv*/);
static void print_help(void);
static bool is_pg_logname(char * /*username*/);
static int do_query(PGconn * /*conn*/, char * /*query*/);
static mp_state_enum do_query(PGconn * /*conn*/, char * /*query*/, const char /*pgqueryname*/[], thresholds * /*qthresholds*/,
char * /*query_warning*/, char * /*query_critical*/);
void print_usage(void);
static char *pghost = NULL; /* host name of the backend server */
static char *pgport = NULL; /* port of the backend server */
static char *pgoptions = NULL;
static char *pgtty = NULL;
static char dbName[NAMEDATALEN] = DEFAULT_DB;
static char *pguser = NULL;
static char *pgpasswd = NULL;
static char *pgparams = NULL;
static double twarn = (double)DEFAULT_WARN;
static double tcrit = (double)DEFAULT_CRIT;
static char *pgquery = NULL;
static char *pgqueryname = NULL;
static char *query_warning = NULL;
static char *query_critical = NULL;
static thresholds *qthresholds = NULL;
static int verbose = 0;
#define OPTID_QUERYNAME -1000
@ -139,20 +126,16 @@ int main(int argc, char **argv) {
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
/* begin, by setting the parameters for a backend connection if the
* parameters are null, then the system will try to use reasonable
* defaults by looking up environment variables or, failing that,
* using hardwired constants */
pgoptions = NULL; /* special options to start up the backend server */
pgtty = NULL; /* debugging tty for the backend server */
/* Parse extra opts if any */
argv = np_extra_opts(&argc, argv, progname);
if (process_arguments(argc, argv) == ERROR) {
check_pgsql_config_wrapper tmp_config = process_arguments(argc, argv);
if (tmp_config.errorcode == ERROR) {
usage4(_("Could not parse arguments"));
}
const check_pgsql_config config = tmp_config.config;
if (verbose > 2) {
printf("Arguments initialized\n");
}
@ -164,31 +147,31 @@ int main(int argc, char **argv) {
alarm(timeout_interval);
char *conninfo = NULL;
if (pgparams) {
asprintf(&conninfo, "%s ", pgparams);
if (config.pgparams) {
asprintf(&conninfo, "%s ", config.pgparams);
}
asprintf(&conninfo, "%sdbname = '%s'", conninfo ? conninfo : "", dbName);
if (pghost) {
asprintf(&conninfo, "%s host = '%s'", conninfo, pghost);
asprintf(&conninfo, "%sdbname = '%s'", conninfo ? conninfo : "", config.dbName);
if (config.pghost) {
asprintf(&conninfo, "%s host = '%s'", conninfo, config.pghost);
}
if (pgport) {
asprintf(&conninfo, "%s port = '%s'", conninfo, pgport);
if (config.pgport) {
asprintf(&conninfo, "%s port = '%s'", conninfo, config.pgport);
}
if (pgoptions) {
asprintf(&conninfo, "%s options = '%s'", conninfo, pgoptions);
if (config.pgoptions) {
asprintf(&conninfo, "%s options = '%s'", conninfo, config.pgoptions);
}
/* if (pgtty) -- ignored by PQconnectdb */
if (pguser) {
asprintf(&conninfo, "%s user = '%s'", conninfo, pguser);
if (config.pguser) {
asprintf(&conninfo, "%s user = '%s'", conninfo, config.pguser);
}
if (verbose) { /* do not include password (see right below) in output */
printf("Connecting to PostgreSQL using conninfo: %s%s\n", conninfo, pgpasswd ? " password = <hidden>" : "");
printf("Connecting to PostgreSQL using conninfo: %s%s\n", conninfo, config.pgpasswd ? " password = <hidden>" : "");
}
if (pgpasswd) {
asprintf(&conninfo, "%s password = '%s'", conninfo, pgpasswd);
if (config.pgpasswd) {
asprintf(&conninfo, "%s password = '%s'", conninfo, config.pgpasswd);
}
/* make a connection to the database */
@ -203,7 +186,7 @@ int main(int argc, char **argv) {
end_timeval.tv_usec += 1000000;
}
double elapsed_time =
(double)(end_timeval.tv_sec - start_timeval.tv_sec) + (double)(end_timeval.tv_usec - start_timeval.tv_usec) / 1000000.0;
(double)(end_timeval.tv_sec - start_timeval.tv_sec) + ((double)(end_timeval.tv_usec - start_timeval.tv_usec) / 1000000.0);
if (verbose) {
printf("Time elapsed: %f\n", elapsed_time);
@ -214,15 +197,15 @@ int main(int argc, char **argv) {
printf("Verifying connection\n");
}
if (PQstatus(conn) == CONNECTION_BAD) {
printf(_("CRITICAL - no connection to '%s' (%s).\n"), dbName, PQerrorMessage(conn));
printf(_("CRITICAL - no connection to '%s' (%s).\n"), config.dbName, PQerrorMessage(conn));
PQfinish(conn);
return STATE_CRITICAL;
}
int status = STATE_UNKNOWN;
if (elapsed_time > tcrit) {
mp_state_enum status = STATE_UNKNOWN;
if (elapsed_time > config.tcrit) {
status = STATE_CRITICAL;
} else if (elapsed_time > twarn) {
} else if (elapsed_time > config.twarn) {
status = STATE_WARNING;
} else {
status = STATE_OK;
@ -239,23 +222,23 @@ int main(int argc, char **argv) {
PQprotocolVersion(conn), PQbackendPID(conn));
}
printf(_(" %s - database %s (%f sec.)|%s\n"), state_text(status), dbName, elapsed_time,
fperfdata("time", elapsed_time, "s", !!(twarn > 0.0), twarn, !!(tcrit > 0.0), tcrit, true, 0, false, 0));
printf(_(" %s - database %s (%f sec.)|%s\n"), state_text(status), config.dbName, elapsed_time,
fperfdata("time", elapsed_time, "s", (config.twarn > 0.0), config.twarn, (config.tcrit > 0.0), config.tcrit, true, 0, false, 0));
int query_status = STATE_UNKNOWN;
if (pgquery) {
query_status = do_query(conn, pgquery);
mp_state_enum query_status = STATE_UNKNOWN;
if (config.pgquery) {
query_status = do_query(conn, config.pgquery, config.pgqueryname, config.qthresholds, config.query_warning, config.query_critical);
}
if (verbose) {
printf("Closing connection\n");
}
PQfinish(conn);
return (pgquery && query_status > status) ? query_status : status;
return (config.pgquery && query_status > status) ? query_status : status;
}
/* process command-line arguments */
int process_arguments(int argc, char **argv) {
check_pgsql_config_wrapper process_arguments(int argc, char **argv) {
static struct option longopts[] = {{"help", no_argument, 0, 'h'},
{"version", no_argument, 0, 'V'},
{"timeout", required_argument, 0, 't'},
@ -275,6 +258,11 @@ int process_arguments(int argc, char **argv) {
{"verbose", no_argument, 0, 'v'},
{0, 0, 0, 0}};
check_pgsql_config_wrapper result = {
.errorcode = OK,
.config = check_pgsql_config_init(),
};
while (true) {
int option = 0;
int option_char = getopt_long(argc, argv, "hVt:c:w:H:P:d:l:p:a:o:q:C:W:v", longopts, &option);
@ -303,65 +291,65 @@ int process_arguments(int argc, char **argv) {
if (!is_nonnegative(optarg)) {
usage2(_("Critical threshold must be a positive integer"), optarg);
} else {
tcrit = strtod(optarg, NULL);
result.config.tcrit = strtod(optarg, NULL);
}
break;
case 'w': /* warning time threshold */
if (!is_nonnegative(optarg)) {
usage2(_("Warning threshold must be a positive integer"), optarg);
} else {
twarn = strtod(optarg, NULL);
result.config.twarn = strtod(optarg, NULL);
}
break;
case 'C': /* critical query threshold */
query_critical = optarg;
result.config.query_critical = optarg;
break;
case 'W': /* warning query threshold */
query_warning = optarg;
result.config.query_warning = optarg;
break;
case 'H': /* host */
if ((*optarg != '/') && (!is_host(optarg))) {
usage2(_("Invalid hostname/address"), optarg);
} else {
pghost = optarg;
result.config.pghost = optarg;
}
break;
case 'P': /* port */
if (!is_integer(optarg)) {
usage2(_("Port must be a positive integer"), optarg);
} else {
pgport = optarg;
result.config.pgport = optarg;
}
break;
case 'd': /* database name */
if (strlen(optarg) >= NAMEDATALEN) {
usage2(_("Database name exceeds the maximum length"), optarg);
}
snprintf(dbName, NAMEDATALEN, "%s", optarg);
snprintf(result.config.dbName, NAMEDATALEN, "%s", optarg);
break;
case 'l': /* login name */
if (!is_pg_logname(optarg)) {
usage2(_("User name is not valid"), optarg);
} else {
pguser = optarg;
result.config.pguser = optarg;
}
break;
case 'p': /* authentication password */
case 'a':
pgpasswd = optarg;
result.config.pgpasswd = optarg;
break;
case 'o':
if (pgparams) {
asprintf(&pgparams, "%s %s", pgparams, optarg);
if (result.config.pgparams) {
asprintf(&result.config.pgparams, "%s %s", result.config.pgparams, optarg);
} else {
asprintf(&pgparams, "%s", optarg);
asprintf(&result.config.pgparams, "%s", optarg);
}
break;
case 'q':
pgquery = optarg;
result.config.pgquery = optarg;
break;
case OPTID_QUERYNAME:
pgqueryname = optarg;
result.config.pgqueryname = optarg;
break;
case 'v':
verbose++;
@ -369,9 +357,9 @@ int process_arguments(int argc, char **argv) {
}
}
set_thresholds(&qthresholds, query_warning, query_critical);
set_thresholds(&result.config.qthresholds, result.config.query_warning, result.config.query_critical);
return OK;
return result;
}
/**
@ -416,7 +404,7 @@ bool is_pg_logname(char *username) {
void print_help(void) {
char *myport;
xasprintf(&myport, "%d", DEFAULT_PORT);
xasprintf(&myport, "%d", 5432);
print_revision(progname, NP_VERSION);
@ -504,7 +492,8 @@ void print_usage(void) {
"[-q <query>] [-C <critical query range>] [-W <warning query range>]\n");
}
int do_query(PGconn *conn, char *query) {
mp_state_enum do_query(PGconn *conn, char *query, const char pgqueryname[], thresholds *qthresholds, char *query_warning,
char *query_critical) {
if (verbose) {
printf("Executing SQL query \"%s\".\n", query);
}
@ -548,7 +537,7 @@ int do_query(PGconn *conn, char *query) {
}
}
int my_status = get_status(value, qthresholds);
mp_state_enum my_status = get_status(value, qthresholds);
printf("QUERY %s - ", (my_status == STATE_OK) ? _("OK")
: (my_status == STATE_WARNING) ? _("WARNING")
: (my_status == STATE_CRITICAL) ? _("CRITICAL")

View file

@ -0,0 +1,61 @@
#pragma once
#include "../../config.h"
#include "thresholds.h"
#include <stddef.h>
#include <pg_config_manual.h>
#define DEFAULT_DB "template1"
enum {
DEFAULT_WARN = 2,
DEFAULT_CRIT = 8,
};
typedef struct {
char *pghost; /* host name of the backend server */
char *pgport; /* port of the backend server */
char *pgoptions; /* special options to start up the backend server */
char *pgtty; /* debugging tty for the backend server */
char dbName[NAMEDATALEN];
char *pguser;
char *pgpasswd;
char *pgparams;
char *pgquery;
char *pgqueryname;
double twarn;
double tcrit;
thresholds *qthresholds;
char *query_warning;
char *query_critical;
} check_pgsql_config;
/* begin, by setting the parameters for a backend connection if the
* parameters are null, then the system will try to use reasonable
* defaults by looking up environment variables or, failing that,
* using hardwired constants
* this targets .pgoptions and .pgtty
*/
check_pgsql_config check_pgsql_config_init() {
check_pgsql_config tmp = {
.pghost = NULL,
.pgport = NULL,
.pgoptions = NULL,
.pgtty = NULL,
.dbName = DEFAULT_DB,
.pguser = NULL,
.pgpasswd = NULL,
.pgparams = NULL,
.pgquery = NULL,
.pgqueryname = NULL,
.twarn = (double)DEFAULT_WARN,
.tcrit = (double)DEFAULT_CRIT,
.qthresholds = NULL,
.query_warning = NULL,
.query_critical = NULL,
};
return tmp;
}