MINOR: cli: new stats socket command: show servers state

new command 'show servers state' which dumps all variable parameters
of a server during an HAProxy process life.
Purpose is to dump current server state at current run time in order to
read them right after the reload.

The format of the output is versionned and we support version 1 for now.
This commit is contained in:
Baptiste Assmann 2015-07-03 08:01:20 +02:00 committed by Willy Tarreau
parent 41472f4d98
commit 2828946cb5
2 changed files with 120 additions and 0 deletions

View File

@ -112,6 +112,9 @@ struct appctx {
struct { struct {
struct dns_resolvers *ptr; struct dns_resolvers *ptr;
} resolvers; } resolvers;
struct {
struct proxy *backend;
} server_state;
} ctx; /* used by stats I/O handlers to dump the stats */ } ctx; /* used by stats I/O handlers to dump the stats */
}; };

View File

@ -92,6 +92,7 @@ enum {
STAT_CLI_O_POOLS, /* dump memory pools */ STAT_CLI_O_POOLS, /* dump memory pools */
STAT_CLI_O_TLSK, /* list all TLS ticket keys references */ STAT_CLI_O_TLSK, /* list all TLS ticket keys references */
STAT_CLI_O_RESOLVERS,/* dump a resolver's section nameservers counters */ STAT_CLI_O_RESOLVERS,/* dump a resolver's section nameservers counters */
STAT_CLI_O_SERVERS_STATE, /* dump server state and changing information */
}; };
/* Actions available for the stats admin forms */ /* Actions available for the stats admin forms */
@ -128,6 +129,7 @@ enum {
}; };
static int stats_dump_info_to_buffer(struct stream_interface *si); static int stats_dump_info_to_buffer(struct stream_interface *si);
static int stats_dump_servers_state_to_buffer(struct stream_interface *si);
static int stats_dump_pools_to_buffer(struct stream_interface *si); static int stats_dump_pools_to_buffer(struct stream_interface *si);
static int stats_dump_full_sess_to_buffer(struct stream_interface *si, struct stream *sess); static int stats_dump_full_sess_to_buffer(struct stream_interface *si, struct stream *sess);
static int stats_dump_sess_to_buffer(struct stream_interface *si); static int stats_dump_sess_to_buffer(struct stream_interface *si);
@ -144,11 +146,14 @@ static int stats_tlskeys_list(struct stream_interface *si);
#endif #endif
static void cli_release_handler(struct appctx *appctx); static void cli_release_handler(struct appctx *appctx);
static void dump_servers_state(struct proxy *backend, struct chunk *buf);
/* /*
* cli_io_handler() * cli_io_handler()
* -> stats_dump_sess_to_buffer() // "show sess" * -> stats_dump_sess_to_buffer() // "show sess"
* -> stats_dump_errors_to_buffer() // "show errors" * -> stats_dump_errors_to_buffer() // "show errors"
* -> stats_dump_info_to_buffer() // "show info" * -> stats_dump_info_to_buffer() // "show info"
* -> stats_dump_servers_state_to_buffer() // "show servers state [<backend name>]"
* -> stats_dump_stat_to_buffer() // "show stat" * -> stats_dump_stat_to_buffer() // "show stat"
* -> stats_dump_resolvers_to_buffer() // "show stat resolver <id>" * -> stats_dump_resolvers_to_buffer() // "show stat resolver <id>"
* -> stats_dump_csv_header() * -> stats_dump_csv_header()
@ -188,6 +193,7 @@ static const char stats_sock_usage_msg[] =
" show errors : report last request and response errors for each proxy\n" " show errors : report last request and response errors for each proxy\n"
" show sess [id] : report the list of current sessions or dump this session\n" " show sess [id] : report the list of current sessions or dump this session\n"
" show table [id]: report table usage stats or dump this table's contents\n" " show table [id]: report table usage stats or dump this table's contents\n"
" show servers state [id]: dump volatile server information (for backend <id>)\n"
" get weight : report a server's current weight\n" " get weight : report a server's current weight\n"
" set weight : change a server's weight\n" " set weight : change a server's weight\n"
" set server : change a server's state, weight or address\n" " set server : change a server's state, weight or address\n"
@ -1189,6 +1195,24 @@ static int stats_sock_parse_request(struct stream_interface *si, char *line)
appctx->st2 = STAT_ST_INIT; appctx->st2 = STAT_ST_INIT;
appctx->st0 = STAT_CLI_O_INFO; // stats_dump_info_to_buffer appctx->st0 = STAT_CLI_O_INFO; // stats_dump_info_to_buffer
} }
else if (strcmp(args[1], "servers") == 0 && strcmp(args[2], "state") == 0) {
appctx->ctx.server_state.backend = NULL;
/* check if a backend name has been provided */
if (*args[3]) {
/* read server state from local file */
appctx->ctx.server_state.backend = proxy_be_by_name(args[3]);
if (appctx->ctx.server_state.backend == NULL) {
appctx->ctx.cli.msg = "Can't find backend.\n";
appctx->st0 = STAT_CLI_PRINT;
return 1;
}
}
appctx->st2 = STAT_ST_INIT;
appctx->st0 = STAT_CLI_O_SERVERS_STATE; // stats_dump_servers_state_to_buffer
return 1;
}
else if (strcmp(args[1], "pools") == 0) { else if (strcmp(args[1], "pools") == 0) {
appctx->st2 = STAT_ST_INIT; appctx->st2 = STAT_ST_INIT;
appctx->st0 = STAT_CLI_O_POOLS; // stats_dump_pools_to_buffer appctx->st0 = STAT_CLI_O_POOLS; // stats_dump_pools_to_buffer
@ -2476,6 +2500,10 @@ static void cli_io_handler(struct appctx *appctx)
if (stats_dump_info_to_buffer(si)) if (stats_dump_info_to_buffer(si))
appctx->st0 = STAT_CLI_PROMPT; appctx->st0 = STAT_CLI_PROMPT;
break; break;
case STAT_CLI_O_SERVERS_STATE:
if (stats_dump_servers_state_to_buffer(si))
appctx->st0 = STAT_CLI_PROMPT;
break;
case STAT_CLI_O_STAT: case STAT_CLI_O_STAT:
if (stats_dump_stat_to_buffer(si, NULL)) if (stats_dump_stat_to_buffer(si, NULL))
appctx->st0 = STAT_CLI_PROMPT; appctx->st0 = STAT_CLI_PROMPT;
@ -2694,6 +2722,95 @@ static int stats_dump_info_to_buffer(struct stream_interface *si)
return 1; return 1;
} }
/* dumps server state information into <buf> for all the servers found in <backend>
* These information are all the parameters which may change during HAProxy runtime.
* By default, we only export to the last known server state file format.
* These information can be used at next startup to recover same level of server state.
*/
static void dump_servers_state(struct proxy *backend, struct chunk *buf)
{
struct server *srv;
char srv_addr[INET6_ADDRSTRLEN + 1];
time_t srv_time_since_last_change;
int bk_f_forced_id, srv_f_forced_id;
/* we don't want to report any state if the backend is not enabled on this process */
if (backend->bind_proc && !(backend->bind_proc & (1UL << (relative_pid - 1))))
return;
srv = backend->srv;
while (srv) {
srv_addr[0] = '\0';
srv_time_since_last_change = 0;
bk_f_forced_id = 0;
srv_f_forced_id = 0;
switch (srv->addr.ss_family) {
case AF_INET:
inet_ntop(srv->addr.ss_family, &((struct sockaddr_in *)&srv->addr)->sin_addr,
srv_addr, INET_ADDRSTRLEN + 1);
break;
case AF_INET6:
inet_ntop(srv->addr.ss_family, &((struct sockaddr_in6 *)&srv->addr)->sin6_addr,
srv_addr, INET6_ADDRSTRLEN + 1);
break;
}
srv_time_since_last_change = now.tv_sec - srv->last_change;
bk_f_forced_id = backend->options & PR_O_FORCED_ID ? 1 : 0;
srv_f_forced_id = srv->flags & SRV_F_FORCED_ID ? 1 : 0;
chunk_appendf(buf,
"%d %s "
"%d %s %s "
"%d %d %d %d %ld "
"%d %d %d %d %d "
"%d %d"
"\n",
backend->uuid, backend->id,
srv->puid, srv->id, srv_addr,
srv->state, srv->admin, srv->uweight, srv->iweight, srv_time_since_last_change,
srv->check.status, srv->check.result, srv->check.health, srv->check.state, srv->agent.state,
bk_f_forced_id, srv_f_forced_id);
srv = srv->next;
}
}
/* Parses backend list or simply use backend name provided by the user to return
* states of servers to stdout.
*/
static int stats_dump_servers_state_to_buffer(struct stream_interface *si)
{
struct appctx *appctx = __objt_appctx(si->end);
extern struct proxy *proxy;
struct proxy *curproxy;
chunk_reset(&trash);
chunk_printf(&trash, "%d\n# %s\n", SRV_STATE_FILE_VERSION, SRV_STATE_FILE_FIELD_NAMES);
if (appctx->ctx.server_state.backend) {
dump_servers_state(appctx->ctx.server_state.backend, &trash);
}
else {
for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
/* servers are only in backends */
if (!(curproxy->cap & PR_CAP_BE))
continue;
dump_servers_state(curproxy, &trash);
}
}
if (bi_putchk(si_ic(si), &trash) == -1) {
si_applet_cant_put(si);
return 0;
}
return 1;
}
/* This function dumps memory usage information onto the stream interface's /* This function dumps memory usage information onto the stream interface's
* read buffer. It returns 0 as long as it does not complete, non-zero upon * read buffer. It returns 0 as long as it does not complete, non-zero upon
* completion. No state is used. * completion. No state is used.