mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2024-12-14 15:34:35 +00:00
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:
parent
41472f4d98
commit
2828946cb5
@ -112,6 +112,9 @@ struct appctx {
|
||||
struct {
|
||||
struct dns_resolvers *ptr;
|
||||
} resolvers;
|
||||
struct {
|
||||
struct proxy *backend;
|
||||
} server_state;
|
||||
} ctx; /* used by stats I/O handlers to dump the stats */
|
||||
};
|
||||
|
||||
|
117
src/dumpstats.c
117
src/dumpstats.c
@ -92,6 +92,7 @@ enum {
|
||||
STAT_CLI_O_POOLS, /* dump memory pools */
|
||||
STAT_CLI_O_TLSK, /* list all TLS ticket keys references */
|
||||
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 */
|
||||
@ -128,6 +129,7 @@ enum {
|
||||
};
|
||||
|
||||
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_full_sess_to_buffer(struct stream_interface *si, struct stream *sess);
|
||||
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
|
||||
static void cli_release_handler(struct appctx *appctx);
|
||||
|
||||
static void dump_servers_state(struct proxy *backend, struct chunk *buf);
|
||||
|
||||
/*
|
||||
* cli_io_handler()
|
||||
* -> stats_dump_sess_to_buffer() // "show sess"
|
||||
* -> stats_dump_errors_to_buffer() // "show errors"
|
||||
* -> 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_resolvers_to_buffer() // "show stat resolver <id>"
|
||||
* -> 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 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 servers state [id]: dump volatile server information (for backend <id>)\n"
|
||||
" get weight : report a server's current weight\n"
|
||||
" set weight : change a server's weight\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->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) {
|
||||
appctx->st2 = STAT_ST_INIT;
|
||||
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))
|
||||
appctx->st0 = STAT_CLI_PROMPT;
|
||||
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:
|
||||
if (stats_dump_stat_to_buffer(si, NULL))
|
||||
appctx->st0 = STAT_CLI_PROMPT;
|
||||
@ -2694,6 +2722,95 @@ static int stats_dump_info_to_buffer(struct stream_interface *si)
|
||||
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
|
||||
* read buffer. It returns 0 as long as it does not complete, non-zero upon
|
||||
* completion. No state is used.
|
||||
|
Loading…
Reference in New Issue
Block a user