From 2828946cb5b22fabe10e1f89cacf6b08cbd182b9 Mon Sep 17 00:00:00 2001 From: Baptiste Assmann Date: Fri, 3 Jul 2015 08:01:20 +0200 Subject: [PATCH] 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. --- include/types/applet.h | 3 ++ src/dumpstats.c | 117 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+) diff --git a/include/types/applet.h b/include/types/applet.h index 2e8a297ff..6b46f4945 100644 --- a/include/types/applet.h +++ b/include/types/applet.h @@ -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 */ }; diff --git a/src/dumpstats.c b/src/dumpstats.c index 92f2dead5..27f83404b 100644 --- a/src/dumpstats.c +++ b/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 []" * -> stats_dump_stat_to_buffer() // "show stat" * -> stats_dump_resolvers_to_buffer() // "show stat resolver " * -> 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 )\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 for all the servers found in + * 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.