mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-02-01 11:01:46 +00:00
BUG/MEDIUM: stats: show servers state may show an empty or incomplete result
It was reported that the unix socket command "show servers state" returned an empty response while "show servers state <backend>" worked. In fact, both cases can reproduce the issue. It happens when the response can't fit in one buffer. The fix consists in processing the response in several steps, as it is done in some others commands, by restarting where it was stopped after the buffer is sent to the client. This fix should be backported to haproxy 1.6
This commit is contained in:
parent
8bf242b764
commit
76a99784f4
@ -131,7 +131,9 @@ struct appctx {
|
||||
struct dns_resolvers *ptr;
|
||||
} resolvers;
|
||||
struct {
|
||||
struct proxy *backend;
|
||||
int iid; /* if >= 0, ID of the proxy to filter on */
|
||||
struct proxy *px; /* current proxy being dumped, NULL = not started yet. */
|
||||
struct server *sv; /* current server being dumped, NULL = not started yet. */
|
||||
} server_state;
|
||||
struct {
|
||||
char **var;
|
||||
|
@ -303,7 +303,7 @@ 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);
|
||||
static int dump_servers_state(struct stream_interface *si, struct chunk *buf);
|
||||
|
||||
/*
|
||||
* cli_io_handler()
|
||||
@ -1379,18 +1379,21 @@ static int stats_sock_parse_request(struct stream_interface *si, char *line)
|
||||
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;
|
||||
appctx->ctx.server_state.iid = 0;
|
||||
appctx->ctx.server_state.px = NULL;
|
||||
appctx->ctx.server_state.sv = 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]);
|
||||
appctx->ctx.server_state.px = proxy_be_by_name(args[3]);
|
||||
|
||||
if (appctx->ctx.server_state.backend == NULL) {
|
||||
if (!appctx->ctx.server_state.px) {
|
||||
appctx->ctx.cli.msg = "Can't find backend.\n";
|
||||
appctx->st0 = STAT_CLI_PRINT;
|
||||
return 1;
|
||||
}
|
||||
appctx->ctx.server_state.iid = appctx->ctx.server_state.px->uuid;
|
||||
}
|
||||
appctx->st2 = STAT_ST_INIT;
|
||||
appctx->st0 = STAT_CLI_O_SERVERS_STATE; // stats_dump_servers_state_to_buffer
|
||||
@ -3057,20 +3060,21 @@ static int stats_dump_info_to_buffer(struct stream_interface *si)
|
||||
* 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)
|
||||
static int dump_servers_state(struct stream_interface *si, struct chunk *buf)
|
||||
{
|
||||
struct appctx *appctx = __objt_appctx(si->end);
|
||||
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;
|
||||
if (appctx->ctx.server_state.px->bind_proc && !(appctx->ctx.server_state.px->bind_proc & (1UL << (relative_pid - 1))))
|
||||
return 1;
|
||||
|
||||
srv = backend->srv;
|
||||
|
||||
while (srv) {
|
||||
for (; appctx->ctx.server_state.sv != NULL; appctx->ctx.server_state.sv = srv->next) {
|
||||
srv = appctx->ctx.server_state.sv;
|
||||
srv_addr[0] = '\0';
|
||||
srv_time_since_last_change = 0;
|
||||
bk_f_forced_id = 0;
|
||||
@ -3087,7 +3091,7 @@ static void dump_servers_state(struct proxy *backend, struct chunk *buf)
|
||||
break;
|
||||
}
|
||||
srv_time_since_last_change = now.tv_sec - srv->last_change;
|
||||
bk_f_forced_id = backend->options & PR_O_FORCED_ID ? 1 : 0;
|
||||
bk_f_forced_id = appctx->ctx.server_state.px->options & PR_O_FORCED_ID ? 1 : 0;
|
||||
srv_f_forced_id = srv->flags & SRV_F_FORCED_ID ? 1 : 0;
|
||||
|
||||
chunk_appendf(buf,
|
||||
@ -3097,14 +3101,17 @@ static void dump_servers_state(struct proxy *backend, struct chunk *buf)
|
||||
"%d %d %d %d %d "
|
||||
"%d %d"
|
||||
"\n",
|
||||
backend->uuid, backend->id,
|
||||
appctx->ctx.server_state.px->uuid, appctx->ctx.server_state.px->id,
|
||||
srv->puid, srv->id, srv_addr,
|
||||
srv->state, srv->admin, srv->uweight, srv->iweight, (long int)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;
|
||||
if (bi_putchk(si_ic(si), &trash) == -1) {
|
||||
si_applet_cant_put(si);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Parses backend list and simply report backend names */
|
||||
@ -3147,24 +3154,32 @@ static int stats_dump_servers_state_to_buffer(struct stream_interface *si)
|
||||
|
||||
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 (!appctx->ctx.server_state.px) {
|
||||
chunk_printf(&trash, "%d\n# %s\n", SRV_STATE_FILE_VERSION, SRV_STATE_FILE_FIELD_NAMES);
|
||||
if (bi_putchk(si_ic(si), &trash) == -1) {
|
||||
si_applet_cant_put(si);
|
||||
return 0;
|
||||
}
|
||||
appctx->ctx.server_state.px = proxy;
|
||||
}
|
||||
|
||||
if (bi_putchk(si_ic(si), &trash) == -1) {
|
||||
si_applet_cant_put(si);
|
||||
return 0;
|
||||
for (; appctx->ctx.server_state.px != NULL; appctx->ctx.server_state.px = curproxy->next) {
|
||||
curproxy = appctx->ctx.server_state.px;
|
||||
if (!appctx->ctx.server_state.sv)
|
||||
appctx->ctx.server_state.sv = appctx->ctx.server_state.px->srv;
|
||||
/* servers are only in backends */
|
||||
if (curproxy->cap & PR_CAP_BE) {
|
||||
if (!dump_servers_state(si, &trash))
|
||||
return 0;
|
||||
|
||||
if (bi_putchk(si_ic(si), &trash) == -1) {
|
||||
si_applet_cant_put(si);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* only the selected proxy is dumped */
|
||||
if (appctx->ctx.server_state.iid)
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
Loading…
Reference in New Issue
Block a user