MINOR: cli: add socket commands and config to prepend informational messages with severity

Adds cli commands to change at runtime whether informational messages
are prepended with severity level or not, with support for numeric and
worded severity in line with syslog severity level.

Adds stats socket config keyword severity-output to set default behavior
per socket on startup.
This commit is contained in:
Andjelko Iharos 2017-07-20 11:59:48 +02:00 committed by Willy Tarreau
parent ed0d96cac4
commit c4df59e914
7 changed files with 120 additions and 2 deletions

View File

@ -10554,6 +10554,18 @@ level <level>
- "admin" should be used with care, as everything is permitted (eg: clear
all counters).
severity-output <format>
This setting is used with the stats sockets only to configure severity
level output prepended to informational feedback messages. Severity
level of messages can range between 0 and 7, conforming to syslog
rfc5424. Valid and successful socket commands requesting data
(i.e. "show map", "get acl foo" etc.) will never have a severity level
prepended. It is ignored by other sockets. <format> can be one of :
- "none" (default) no severity level is prepended to feedback messages.
- "number" severity level is prepended as a number.
- "string" severity level is prepended as a string following the
rfc5424 convention.
maxconn <maxconn>
Limits the sockets to this number of concurrent connections. Extraneous
connections will remain in the system's backlog until a connection is

View File

@ -1672,6 +1672,10 @@ set server <backend>/<server> weight <weight>[%]
set server <backend>/<server> fqdn <FQDN>
Change a server's FQDN to the value passed in argument.
set severity-output [ none | number | string ]
Change the severity output format of the stats socket connected to for the
duration of the current session.
set ssl ocsp-response <response>
This command is used to update an OCSP Response for a certificate (see "crt"
on "bind" lines). Same controls are performed as during the initial loading of

View File

@ -25,6 +25,7 @@
#include <string.h>
#include <types/listener.h>
#include <types/cli.h>
/* This function tries to temporarily disable a listener, depending on the OS
* capabilities. Linux unbinds the listen socket after a SHUT_RD, and ignores
@ -122,6 +123,7 @@ static inline struct bind_conf *bind_conf_alloc(struct proxy *fe, const char *fi
bind_conf->ux.mode = 0;
bind_conf->xprt = xprt;
bind_conf->frontend = fe;
bind_conf->severity_output = CLI_SEVERITY_NONE;
LIST_INIT(&bind_conf->listeners);
return bind_conf;

View File

@ -65,6 +65,7 @@ struct appctx {
int (*io_handler)(struct appctx *appctx); /* used within the cli_io_handler when st0 = CLI_ST_CALLBACK */
void (*io_release)(struct appctx *appctx); /* used within the cli_io_handler when st0 = CLI_ST_CALLBACK,
if the command is terminated or the session released */
int cli_severity_output; /* used within the cli_io_handler to format severity output of informational feedback */
struct buffer_wait buffer_wait; /* position in the list of objects waiting for a buffer */
unsigned long process_mask; /* mask of thread IDs authorized to process the applet */
@ -97,6 +98,7 @@ struct appctx {
} spoe; /* used by SPOE filter */
struct {
const char *msg; /* pointer to a persistent message to be returned in CLI_ST_PRINT state */
int severity; /* severity of the message to be returned according to (syslog) rfc5424 */
char *err; /* pointer to a 'must free' message to be returned in CLI_ST_PRINT_FREE state */
void *p0, *p1; /* general purpose pointers and integers for registered commands, initialized */
int i0, i1; /* to 0 by the CLI before first invocation of the keyword parser. */

View File

@ -50,5 +50,13 @@ enum {
CLI_ST_CALLBACK, /* custom callback pointer */
};
/* CLI severity output formats */
enum {
CLI_SEVERITY_UNDEFINED = 0, /* undefined severity format */
CLI_SEVERITY_NONE, /* no severity information prepended */
CLI_SEVERITY_NUMBER, /* prepend informational cli messages with a severity as number */
CLI_SEVERITY_STRING, /* prepend informational cli messages with a severity as string */
};
#endif /* _TYPES_CLI_H */

View File

@ -161,6 +161,7 @@ struct bind_conf {
mode_t mode; /* 0 to leave unchanged */
} ux;
int level; /* stats access level (ACCESS_LVL_*) */
int severity_output; /* default severity output format in cli feedback messages */
struct list by_fe; /* next binding for the same frontend, or NULL */
struct list listeners; /* list of listeners using this bind config */
uint32_t ns_cip_magic; /* Excepted NetScaler Client IP magic number */

View File

@ -392,6 +392,13 @@ int cli_has_level(struct appctx *appctx, int level)
return 1;
}
/* Returns severity_output for the current session if set, or default for the socket */
static int cli_get_severity_output(struct appctx *appctx)
{
if (appctx->cli_severity_output)
return appctx->cli_severity_output;
return strm_li(si_strm(appctx->owner))->bind_conf->severity_output;
}
/* Processes the CLI interpreter on the stats socket. This function is called
* from the CLI's IO handler running in an appctx context. The function returns 1
@ -472,6 +479,38 @@ static int cli_parse_request(struct appctx *appctx, char *line)
return 1;
}
/* prepends then outputs the argument msg with a syslog-type severity depending on severity_output value */
static int cli_output_msg(struct channel *chn, const char *msg, int severity, int severity_output)
{
struct chunk *tmp;
if (likely(severity_output == CLI_SEVERITY_NONE))
return bi_putblk(chn, msg, strlen(msg));
tmp = get_trash_chunk();
chunk_reset(tmp);
if (severity < 0 || severity > 7) {
Warning("socket command feedback with invalid severity %d", severity);
chunk_printf(tmp, "[%d]: ", severity);
}
else {
switch (severity_output) {
case CLI_SEVERITY_NUMBER:
chunk_printf(tmp, "[%d]: ", severity);
break;
case CLI_SEVERITY_STRING:
chunk_printf(tmp, "[%s]: ", log_levels[severity]);
break;
default:
Warning("Unrecognized severity output %d", severity_output);
}
}
chunk_appendf(tmp, "%s", msg);
return bi_putblk(chn, tmp->str, strlen(tmp->str));
}
/* This I/O handler runs as an applet embedded in a stream interface. It is
* used to processes I/O from/to the stats unix socket. The system relies on a
* state machine handling requests and various responses. We read a request,
@ -485,6 +524,7 @@ static void cli_io_handler(struct appctx *appctx)
struct stream_interface *si = appctx->owner;
struct channel *req = si_oc(si);
struct channel *res = si_ic(si);
struct bind_conf *bind_conf = strm_li(si_strm(si))->bind_conf;
int reql;
int len;
@ -501,6 +541,8 @@ static void cli_io_handler(struct appctx *appctx)
if (appctx->st0 == CLI_ST_INIT) {
/* Stats output not initialized yet */
memset(&appctx->ctx.stats, 0, sizeof(appctx->ctx.stats));
/* reset severity to default at init */
appctx->cli_severity_output = bind_conf->severity_output;
appctx->st0 = CLI_ST_GETREQ;
}
else if (appctx->st0 == CLI_ST_END) {
@ -600,13 +642,14 @@ static void cli_io_handler(struct appctx *appctx)
case CLI_ST_PROMPT:
break;
case CLI_ST_PRINT:
if (bi_putstr(si_ic(si), appctx->ctx.cli.msg) != -1)
if (cli_output_msg(res, appctx->ctx.cli.msg, appctx->ctx.cli.severity,
cli_get_severity_output(appctx)) != -1)
appctx->st0 = CLI_ST_PROMPT;
else
si_applet_cant_put(si);
break;
case CLI_ST_PRINT_FREE:
if (bi_putstr(si_ic(si), appctx->ctx.cli.err) != -1) {
if (cli_output_msg(res, appctx->ctx.cli.err, LOG_ERR, cli_get_severity_output(appctx)) != -1) {
free(appctx->ctx.cli.err);
appctx->st0 = CLI_ST_PROMPT;
}
@ -1049,6 +1092,34 @@ static int cli_parse_set_maxconn_global(char **args, struct appctx *appctx, void
return 1;
}
static int set_severity_output(int *target, char *argument)
{
if (!strcmp(argument, "none")) {
*target = CLI_SEVERITY_NONE;
return 1;
}
else if (!strcmp(argument, "number")) {
*target = CLI_SEVERITY_NUMBER;
return 1;
}
else if (!strcmp(argument, "string")) {
*target = CLI_SEVERITY_STRING;
return 1;
}
return 0;
}
/* parse a "set severity-output" command. */
static int cli_parse_set_severity_output(char **args, struct appctx *appctx, void *private)
{
if (*args[2] && set_severity_output(&appctx->cli_severity_output, args[2]))
return 0;
appctx->ctx.cli.severity = LOG_ERR;
appctx->ctx.cli.msg = "one of 'none', 'number', 'string' is a required argument";
appctx->st0 = CLI_ST_PRINT;
return 1;
}
int cli_parse_default(char **args, struct appctx *appctx, void *private)
{
@ -1156,6 +1227,22 @@ static int bind_parse_level(char **args, int cur_arg, struct proxy *px, struct b
return 0;
}
static int bind_parse_severity_output(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
{
if (!*args[cur_arg + 1]) {
memprintf(err, "'%s' : missing severity format", args[cur_arg]);
return ERR_ALERT | ERR_FATAL;
}
if (set_severity_output(&conf->severity_output, args[cur_arg+1]))
return 0;
else {
memprintf(err, "'%s' only supports 'none', 'number', and 'string' (got '%s')",
args[cur_arg], args[cur_arg+1]);
return ERR_ALERT | ERR_FATAL;
}
}
/* Send all the bound sockets, always returns 1 */
static int _getsocks(char **args, struct appctx *appctx, void *private)
{
@ -1349,6 +1436,7 @@ static struct applet cli_applet = {
static struct cli_kw_list cli_kws = {{ },{
{ { "set", "maxconn", "global", NULL }, "set maxconn global : change the per-process maxconn setting", cli_parse_set_maxconn_global, NULL },
{ { "set", "rate-limit", NULL }, "set rate-limit : change a rate limiting value", cli_parse_set_ratelimit, NULL },
{ { "set", "severity-output", NULL }, "set severity-output [none|number|string] : set presence of severity level in feedback information", cli_parse_set_severity_output, NULL, NULL },
{ { "set", "timeout", NULL }, "set timeout : change a timeout setting", cli_parse_set_timeout, NULL, NULL },
{ { "show", "env", NULL }, "show env [var] : dump environment variables known to the process", cli_parse_show_env, cli_io_handler_show_env, NULL },
{ { "show", "cli", "sockets", NULL }, "show cli sockets : dump list of cli sockets", cli_parse_default, cli_io_handler_show_cli_sock, NULL },
@ -1365,6 +1453,7 @@ static struct cfg_kw_list cfg_kws = {ILH, {
static struct bind_kw_list bind_kws = { "STAT", { }, {
{ "level", bind_parse_level, 1 }, /* set the unix socket admin level */
{ "expose-fd", bind_parse_expose_fd, 1 }, /* set the unix socket expose fd rights */
{ "severity-output", bind_parse_severity_output, 1 }, /* set the severity output format */
{ NULL, NULL, 0 },
}};