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 */
};
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);
#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()
" 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"
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
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;
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.